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

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