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