Parse CPUID(0x2).
Query it only for Intel, Centaur, and Zhaoxin, given that
kernel/cpu/cacheinfo.c :: init_intel_cacheinfo()
is called by:
kernel/cpu/intel.c cpu_dev.c_x86_vendor = X86_VENDOR_INTEL
kernel/cpu/centaur.c cpu_dev.c_x86_vendor = X86_VENDOR_CENTAUR
kernel/cpu/zhaoxin.c cpu_dev.c_x86_vendor = X86_VENDOR_ZHAOXIN
At the CPUID tables, keep CPUID(0x2) marked as invalid if the whole leaf,
or all of its output registers separately, were malformed.
Note, cpuid_leaf_0x2() at <asm/cpuid/api.h> will be removed once all call
sites are transformed to new CPUID APIs.
References: fe78079ec07f ("x86/cpu: Introduce and use CPUID leaf 0x2 parsing helpers")
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/include/asm/cpuid/types.h | 1 +
arch/x86/kernel/cpu/cpuid_parser.c | 36 ++++++++++++++++++++++++++++++
arch/x86/kernel/cpu/cpuid_parser.h | 2 ++
3 files changed, 39 insertions(+)
diff --git a/arch/x86/include/asm/cpuid/types.h b/arch/x86/include/asm/cpuid/types.h
index 8cc9f81e9526..c35de721f652 100644
--- a/arch/x86/include/asm/cpuid/types.h
+++ b/arch/x86/include/asm/cpuid/types.h
@@ -210,6 +210,7 @@ struct cpuid_leaves {
/* Leaf Subleaf number (or max number of subleaves) */
CPUID_LEAF ( 0x0, 0 );
CPUID_LEAF ( 0x1, 0 );
+ CPUID_LEAF ( 0x2, 0 );
CPUID_LEAF ( 0x16, 0 );
CPUID_LEAF ( 0x80000000, 0 );
CPUID_LEAF ( 0x80000002, 0 );
diff --git a/arch/x86/kernel/cpu/cpuid_parser.c b/arch/x86/kernel/cpu/cpuid_parser.c
index a7e6692f767b..be340b202182 100644
--- a/arch/x86/kernel/cpu/cpuid_parser.c
+++ b/arch/x86/kernel/cpu/cpuid_parser.c
@@ -42,6 +42,42 @@ cpuid_read_generic(const struct cpuid_parse_entry *e, const struct cpuid_read_ou
cpuid_read_subleaf(e->leaf, e->subleaf + i, regs);
}
+static void
+cpuid_read_0x2(const struct cpuid_parse_entry *e, const struct cpuid_read_output *output)
+{
+ union leaf_0x2_regs *regs = (union leaf_0x2_regs *)output->regs;
+ struct leaf_0x2_0 *l = (struct leaf_0x2_0 *)output->regs;
+ int invalid_regs = 0;
+
+ /*
+ * All Intel CPUs must report an iteration count of 1. For broken hardware,
+ * keep the leaf marked as invalid at the CPUID table.
+ */
+ cpuid_read_subleaf(e->leaf, e->subleaf, l);
+ if (l->iteration_count != 0x01)
+ return;
+
+ /*
+ * The most significant bit (MSB) of each CPUID(0x2) register must be clear.
+ * If a register is malformed, replace its 1-byte descriptors with NULL.
+ */
+ for (int i = 0; i < 4; i++) {
+ if (regs->reg[i].invalid) {
+ regs->regv[i] = 0;
+ invalid_regs++;
+ }
+ }
+
+ /*
+ * If all of the CPUID(0x2) output registers were malformed, keep the leaf
+ * marked as invalid at the CPUID table.
+ */
+ if (invalid_regs == 4)
+ return;
+
+ output->info->nr_entries = 1;
+}
+
/*
* Define an extended range CPUID read function
*
diff --git a/arch/x86/kernel/cpu/cpuid_parser.h b/arch/x86/kernel/cpu/cpuid_parser.h
index 76a87a71b430..1de239370652 100644
--- a/arch/x86/kernel/cpu/cpuid_parser.h
+++ b/arch/x86/kernel/cpu/cpuid_parser.h
@@ -144,6 +144,7 @@ struct cpuid_parse_entry {
*/
#define CPUID_COMMON_ENTRIES \
/* Leaf Subleaf Reader function */ \
+ CPUID_PARSE_ENTRY ( 0x2, 0, 0x2 ), \
CPUID_PARSE_ENTRY ( 0x16, 0, generic ), \
CPUID_PARSE_ENTRY ( 0x80000000, 0, 0x80000000 ), \
CPUID_PARSE_ENTRY ( 0x80000002, 0, generic ), \
@@ -190,6 +191,7 @@ struct cpuid_vendor_entry {
#define CPUID_VENDOR_ENTRIES \
/* Leaf Vendor list */ \
+ CPUID_VENDOR_ENTRY(0x2, X86_VENDOR_INTEL, X86_VENDOR_CENTAUR, X86_VENDOR_ZHAOXIN),\
CPUID_VENDOR_ENTRY(0x16, X86_VENDOR_INTEL), \
CPUID_VENDOR_ENTRY(0x80860000, X86_VENDOR_TRANSMETA), \
CPUID_VENDOR_ENTRY(0x80860001, X86_VENDOR_TRANSMETA), \
--
2.53.0