--- libgomp/env.c.jj	2021-10-11 12:20:21.926063118 +0200
+++ libgomp/env.c	2021-10-14 15:25:48.816212823 +0200
@@ -696,6 +696,11 @@ parse_places_var (const char *name, bool
       env += 7;
       level = 3;
     }
+  else if (strncasecmp (env, "ll_caches", 9) == 0)
+    {
+      env += 9;
+      level = 4;
+    }
   if (level)
     {
       count = ULONG_MAX;
--- libgomp/config/linux/affinity.c.jj	2021-07-13 09:50:46.270677237 +0200
+++ libgomp/config/linux/affinity.c	2021-10-14 17:13:12.811302863 +0200
@@ -223,6 +223,46 @@ gomp_affinity_finalize_place_list (bool
   return true;
 }
 
+/* Find the index of the last level cache.  We assume the index
+   of the last level cache is the same for all logical CPUs.
+   Also, if there are multiple caches with the same highest level,
+   assume they have the same shared_cpu_list and pick the last one
+   from them (highest index number).  */
+
+static int
+gomp_affinity_find_last_cache_level (char *name, size_t prefix_len,
+				     unsigned long cpu)
+{
+  int ret = -1;
+  unsigned long maxval = 0;
+  char *line = NULL;
+  size_t linelen = 0;
+  FILE *f;
+
+  for (int l = 0; l < 128; l++)
+    {
+      sprintf (name + prefix_len, "%lu/cache/index%u/level", cpu, l);
+      f = fopen (name, "r");
+      if (f == NULL)
+	break;
+      if (getline (&line, &linelen, f) > 0)
+	{
+	  unsigned long val;
+	  char *p;
+	  errno = 0;
+	  val = strtoul (line, &p, 10);
+	  if (!errno && val >= maxval)
+	    {
+	      ret = l;
+	      maxval = val;
+	    }
+	}
+      fclose (f);
+    }
+  free (line);
+  return ret;
+}
+
 static void
 gomp_affinity_init_level_1 (int level, int this_level, unsigned long count,
 			    cpu_set_t *copy, char *name, bool quiet)
@@ -232,12 +272,29 @@ gomp_affinity_init_level_1 (int level, i
   char *line = NULL;
   size_t linelen = 0;
   unsigned long i, max = 8 * gomp_cpuset_size;
+  int init = -1;
 
   for (i = 0; i < max && gomp_places_list_len < count; i++)
     if (CPU_ISSET_S (i, gomp_cpuset_size, copy))
       {
-	sprintf (name + prefix_len, "%lu/topology/%s_siblings_list",
-		 i, this_level == 3 ? "core" : "thread");
+	if (level == 4)
+	  {
+	    if (init == -1)
+	      {
+		init = gomp_affinity_find_last_cache_level (name, prefix_len,
+							    i);
+		if (init == -1)
+		  {
+		    CPU_CLR_S (i, gomp_cpuset_size, copy);
+		    continue;
+		  }
+		sprintf (name + prefix_len,
+			 "%lu/cache/index%u/shared_cpu_list", i, init);
+	      }
+	  }
+	else
+	  sprintf (name + prefix_len, "%lu/topology/%s_siblings_list",
+		   i, this_level == 3 ? "core" : "thread");
 	f = fopen (name, "r");
 	if (f == NULL)
 	  {
@@ -302,7 +359,7 @@ bool
 gomp_affinity_init_level (int level, unsigned long count, bool quiet)
 {
   char name[sizeof ("/sys/devices/system/cpu/cpu/topology/"
-		    "thread_siblings_list") + 3 * sizeof (unsigned long)];
+		    "thread_siblings_list") + 6 * sizeof (unsigned long)];
   cpu_set_t *copy;
 
   if (gomp_cpusetp)
@@ -320,7 +377,8 @@ gomp_affinity_init_level (int level, uns
   copy = gomp_alloca (gomp_cpuset_size);
   strcpy (name, "/sys/devices/system/cpu/cpu");
   memcpy (copy, gomp_cpusetp, gomp_cpuset_size);
-  gomp_affinity_init_level_1 (level, 3, count, copy, name, quiet);
+  gomp_affinity_init_level_1 (level, level > 3 ? level : 3, count, copy, name,
+			      quiet);
   if (gomp_places_list_len == 0)
     {
       if (!quiet)
--- libgomp/testsuite/libgomp.c/places-1.c.jj	2021-10-15 11:19:37.763993802 +0200
+++ libgomp/testsuite/libgomp.c/places-1.c	2021-10-15 11:30:52.161264852 +0200
@@ -0,0 +1,10 @@
+/* { dg-set-target-env-var OMP_PLACES "threads" } */
+
+#include <omp.h>
+
+int
+main ()
+{
+  omp_display_env (0);
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/places-2.c.jj	2021-10-15 11:19:44.057903005 +0200
+++ libgomp/testsuite/libgomp.c/places-2.c	2021-10-15 11:31:36.367627131 +0200
@@ -0,0 +1,10 @@
+/* { dg-set-target-env-var OMP_PLACES "cores" } */
+
+#include <omp.h>
+
+int
+main ()
+{
+  omp_display_env (0);
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/places-3.c.jj	2021-10-15 11:20:11.802502758 +0200
+++ libgomp/testsuite/libgomp.c/places-3.c	2021-10-15 11:31:43.388525848 +0200
@@ -0,0 +1,10 @@
+/* { dg-set-target-env-var OMP_PLACES "sockets" } */
+
+#include <omp.h>
+
+int
+main ()
+{
+  omp_display_env (0);
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/places-4.c.jj	2021-10-15 11:20:27.669273860 +0200
+++ libgomp/testsuite/libgomp.c/places-4.c	2021-10-15 11:31:51.049415333 +0200
@@ -0,0 +1,10 @@
+/* { dg-set-target-env-var OMP_PLACES "ll_caches" } */
+
+#include <omp.h>
+
+int
+main ()
+{
+  omp_display_env (0);
+  return 0;
+}
