Blame SOURCES/kvm-i386-Populate-AMD-Processor-Cache-Information-for-cp.patch

1bdc94
From a24dd4151d27389947c011293d6775327268b1c2 Mon Sep 17 00:00:00 2001
1bdc94
From: Eduardo Habkost <ehabkost@redhat.com>
1bdc94
Date: Tue, 3 Jul 2018 17:23:52 +0200
1bdc94
Subject: [PATCH 07/89] i386: Populate AMD Processor Cache Information for
1bdc94
 cpuid 0x8000001D
1bdc94
1bdc94
RH-Author: Eduardo Habkost <ehabkost@redhat.com>
1bdc94
Message-id: <20180703172356.21038-7-ehabkost@redhat.com>
1bdc94
Patchwork-id: 81216
1bdc94
O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH v3 06/10] i386: Populate AMD Processor Cache Information for cpuid 0x8000001D
1bdc94
Bugzilla: 1481253
1bdc94
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
1bdc94
RH-Acked-by: Igor Mammedov <imammedo@redhat.com>
1bdc94
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
1bdc94
1bdc94
From: Babu Moger <babu.moger@amd.com>
1bdc94
1bdc94
Add information for cpuid 0x8000001D leaf. Populate cache topology information
1bdc94
for different cache types (Data Cache, Instruction Cache, L2 and L3) supported
1bdc94
by 0x8000001D leaf. Please refer to the Processor Programming Reference (PPR)
1bdc94
for AMD Family 17h Model for more details.
1bdc94
1bdc94
Signed-off-by: Babu Moger <babu.moger@amd.com>
1bdc94
Message-Id: <1527176614-26271-3-git-send-email-babu.moger@amd.com>
1bdc94
Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>
1bdc94
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
1bdc94
(cherry picked from commit 8f4202fb1080f86958782b1fca0bf0279f67d136)
1bdc94
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
1bdc94
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
1bdc94
---
1bdc94
 target/i386/cpu.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1bdc94
 target/i386/kvm.c |  29 ++++++++++++--
1bdc94
 2 files changed, 143 insertions(+), 3 deletions(-)
1bdc94
1bdc94
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
1bdc94
index 41d0b72..57f74c6 100644
1bdc94
--- a/target/i386/cpu.c
1bdc94
+++ b/target/i386/cpu.c
1bdc94
@@ -337,6 +337,99 @@ static void encode_cache_cpuid80000006(CPUCacheInfo *l2,
1bdc94
 }
1bdc94
 
1bdc94
 /*
1bdc94
+ * Definitions used for building CPUID Leaf 0x8000001D and 0x8000001E
1bdc94
+ * Please refer to the AMD64 Architecture Programmer’s Manual Volume 3.
1bdc94
+ * Define the constants to build the cpu topology. Right now, TOPOEXT
1bdc94
+ * feature is enabled only on EPYC. So, these constants are based on
1bdc94
+ * EPYC supported configurations. We may need to handle the cases if
1bdc94
+ * these values change in future.
1bdc94
+ */
1bdc94
+/* Maximum core complexes in a node */
1bdc94
+#define MAX_CCX 2
1bdc94
+/* Maximum cores in a core complex */
1bdc94
+#define MAX_CORES_IN_CCX 4
1bdc94
+/* Maximum cores in a node */
1bdc94
+#define MAX_CORES_IN_NODE 8
1bdc94
+/* Maximum nodes in a socket */
1bdc94
+#define MAX_NODES_PER_SOCKET 4
1bdc94
+
1bdc94
+/*
1bdc94
+ * Figure out the number of nodes required to build this config.
1bdc94
+ * Max cores in a node is 8
1bdc94
+ */
1bdc94
+static int nodes_in_socket(int nr_cores)
1bdc94
+{
1bdc94
+    int nodes;
1bdc94
+
1bdc94
+    nodes = DIV_ROUND_UP(nr_cores, MAX_CORES_IN_NODE);
1bdc94
+
1bdc94
+   /* Hardware does not support config with 3 nodes, return 4 in that case */
1bdc94
+    return (nodes == 3) ? 4 : nodes;
1bdc94
+}
1bdc94
+
1bdc94
+/*
1bdc94
+ * Decide the number of cores in a core complex with the given nr_cores using
1bdc94
+ * following set constants MAX_CCX, MAX_CORES_IN_CCX, MAX_CORES_IN_NODE and
1bdc94
+ * MAX_NODES_PER_SOCKET. Maintain symmetry as much as possible
1bdc94
+ * L3 cache is shared across all cores in a core complex. So, this will also
1bdc94
+ * tell us how many cores are sharing the L3 cache.
1bdc94
+ */
1bdc94
+static int cores_in_core_complex(int nr_cores)
1bdc94
+{
1bdc94
+    int nodes;
1bdc94
+
1bdc94
+    /* Check if we can fit all the cores in one core complex */
1bdc94
+    if (nr_cores <= MAX_CORES_IN_CCX) {
1bdc94
+        return nr_cores;
1bdc94
+    }
1bdc94
+    /* Get the number of nodes required to build this config */
1bdc94
+    nodes = nodes_in_socket(nr_cores);
1bdc94
+
1bdc94
+    /*
1bdc94
+     * Divide the cores accros all the core complexes
1bdc94
+     * Return rounded up value
1bdc94
+     */
1bdc94
+    return DIV_ROUND_UP(nr_cores, nodes * MAX_CCX);
1bdc94
+}
1bdc94
+
1bdc94
+/* Encode cache info for CPUID[8000001D] */
1bdc94
+static void encode_cache_cpuid8000001d(CPUCacheInfo *cache, CPUState *cs,
1bdc94
+                                uint32_t *eax, uint32_t *ebx,
1bdc94
+                                uint32_t *ecx, uint32_t *edx)
1bdc94
+{
1bdc94
+    uint32_t l3_cores;
1bdc94
+    assert(cache->size == cache->line_size * cache->associativity *
1bdc94
+                          cache->partitions * cache->sets);
1bdc94
+
1bdc94
+    *eax = CACHE_TYPE(cache->type) | CACHE_LEVEL(cache->level) |
1bdc94
+               (cache->self_init ? CACHE_SELF_INIT_LEVEL : 0);
1bdc94
+
1bdc94
+    /* L3 is shared among multiple cores */
1bdc94
+    if (cache->level == 3) {
1bdc94
+        l3_cores = cores_in_core_complex(cs->nr_cores);
1bdc94
+        *eax |= ((l3_cores * cs->nr_threads) - 1) << 14;
1bdc94
+    } else {
1bdc94
+        *eax |= ((cs->nr_threads - 1) << 14);
1bdc94
+    }
1bdc94
+
1bdc94
+    assert(cache->line_size > 0);
1bdc94
+    assert(cache->partitions > 0);
1bdc94
+    assert(cache->associativity > 0);
1bdc94
+    /* We don't implement fully-associative caches */
1bdc94
+    assert(cache->associativity < cache->sets);
1bdc94
+    *ebx = (cache->line_size - 1) |
1bdc94
+           ((cache->partitions - 1) << 12) |
1bdc94
+           ((cache->associativity - 1) << 22);
1bdc94
+
1bdc94
+    assert(cache->sets > 0);
1bdc94
+    *ecx = cache->sets - 1;
1bdc94
+
1bdc94
+    *edx = (cache->no_invd_sharing ? CACHE_NO_INVD_SHARING : 0) |
1bdc94
+           (cache->inclusive ? CACHE_INCLUSIVE : 0) |
1bdc94
+           (cache->complex_indexing ? CACHE_COMPLEX_IDX : 0);
1bdc94
+}
1bdc94
+
1bdc94
+/*
1bdc94
  * Definitions of the hardcoded cache entries we expose:
1bdc94
  * These are legacy cache values. If there is a need to change any
1bdc94
  * of these values please use builtin_x86_defs
1bdc94
@@ -3988,6 +4081,30 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
1bdc94
             *edx = 0;
1bdc94
         }
1bdc94
         break;
1bdc94
+    case 0x8000001D:
1bdc94
+        *eax = 0;
1bdc94
+        switch (count) {
1bdc94
+        case 0: /* L1 dcache info */
1bdc94
+            encode_cache_cpuid8000001d(env->cache_info_amd.l1d_cache, cs,
1bdc94
+                                       eax, ebx, ecx, edx);
1bdc94
+            break;
1bdc94
+        case 1: /* L1 icache info */
1bdc94
+            encode_cache_cpuid8000001d(env->cache_info_amd.l1i_cache, cs,
1bdc94
+                                       eax, ebx, ecx, edx);
1bdc94
+            break;
1bdc94
+        case 2: /* L2 cache info */
1bdc94
+            encode_cache_cpuid8000001d(env->cache_info_amd.l2_cache, cs,
1bdc94
+                                       eax, ebx, ecx, edx);
1bdc94
+            break;
1bdc94
+        case 3: /* L3 cache info */
1bdc94
+            encode_cache_cpuid8000001d(env->cache_info_amd.l3_cache, cs,
1bdc94
+                                       eax, ebx, ecx, edx);
1bdc94
+            break;
1bdc94
+        default: /* end of info */
1bdc94
+            *eax = *ebx = *ecx = *edx = 0;
1bdc94
+            break;
1bdc94
+        }
1bdc94
+        break;
1bdc94
     case 0xC0000000:
1bdc94
         *eax = env->cpuid_xlevel2;
1bdc94
         *ebx = 0;
1bdc94
diff --git a/target/i386/kvm.c b/target/i386/kvm.c
1bdc94
index 19e6aa3..447215b 100644
1bdc94
--- a/target/i386/kvm.c
1bdc94
+++ b/target/i386/kvm.c
1bdc94
@@ -968,9 +968,32 @@ int kvm_arch_init_vcpu(CPUState *cs)
1bdc94
         }
1bdc94
         c = &cpuid_data.entries[cpuid_i++];
1bdc94
 
1bdc94
-        c->function = i;
1bdc94
-        c->flags = 0;
1bdc94
-        cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
1bdc94
+        switch (i) {
1bdc94
+        case 0x8000001d:
1bdc94
+            /* Query for all AMD cache information leaves */
1bdc94
+            for (j = 0; ; j++) {
1bdc94
+                c->function = i;
1bdc94
+                c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
1bdc94
+                c->index = j;
1bdc94
+                cpu_x86_cpuid(env, i, j, &c->eax, &c->ebx, &c->ecx, &c->edx);
1bdc94
+
1bdc94
+                if (c->eax == 0) {
1bdc94
+                    break;
1bdc94
+                }
1bdc94
+                if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
1bdc94
+                    fprintf(stderr, "cpuid_data is full, no space for "
1bdc94
+                            "cpuid(eax:0x%x,ecx:0x%x)\n", i, j);
1bdc94
+                    abort();
1bdc94
+                }
1bdc94
+                c = &cpuid_data.entries[cpuid_i++];
1bdc94
+            }
1bdc94
+            break;
1bdc94
+        default:
1bdc94
+            c->function = i;
1bdc94
+            c->flags = 0;
1bdc94
+            cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
1bdc94
+            break;
1bdc94
+        }
1bdc94
     }
1bdc94
 
1bdc94
     /* Call Centaur's CPUID instructions they are supported. */
1bdc94
-- 
1bdc94
1.8.3.1
1bdc94