Parse the Transmeta extended CPUID(0x80860000)->CPUID(0x80860006) range.
Reuse the CPUID(0x80000000) read function and its safety guards against
CPUs repeating the output of the highest standard CPUID leaf. Transmeta's
code at early_init_transmeta() already carries a similar guard.
Parse Centaur/Zhaoxin extended CPUID(0xc0000000) and CPUID(0xc0000001).
Add x86 vendor tags for the Transmeta and Centaur/Zhaoxin CPUID leaves so
that they are not parsed on other vendors.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/include/asm/cpuid/types.h | 13 ++++++++
arch/x86/kernel/cpu/cpuid_parser.c | 48 +++++++++++++++++++-----------
arch/x86/kernel/cpu/cpuid_parser.h | 18 +++++++++++
3 files changed, 61 insertions(+), 18 deletions(-)
diff --git a/arch/x86/include/asm/cpuid/types.h b/arch/x86/include/asm/cpuid/types.h
index 2939ad095f6c..8cc9f81e9526 100644
--- a/arch/x86/include/asm/cpuid/types.h
+++ b/arch/x86/include/asm/cpuid/types.h
@@ -37,9 +37,13 @@ enum cpuid_regs_idx {
#define CPUID_BASE_START 0x00000000
#define CPUID_EXT_START 0x80000000
+#define CPUID_TMX_START 0x80860000
+#define CPUID_CTR_START 0xc0000000
#define CPUID_BASE_END CPUID_RANGE_MAX(CPUID_BASE_START)
#define CPUID_EXT_END CPUID_RANGE_MAX(CPUID_EXT_START)
+#define CPUID_TMX_END CPUID_RANGE_MAX(CPUID_TMX_START)
+#define CPUID_CTR_END CPUID_RANGE_MAX(CPUID_CTR_START)
/*
* Types for CPUID(0x2) parsing:
@@ -211,6 +215,15 @@ struct cpuid_leaves {
CPUID_LEAF ( 0x80000002, 0 );
CPUID_LEAF ( 0x80000003, 0 );
CPUID_LEAF ( 0x80000004, 0 );
+ CPUID_LEAF ( 0x80860000, 0 );
+ CPUID_LEAF ( 0x80860001, 0 );
+ CPUID_LEAF ( 0x80860002, 0 );
+ CPUID_LEAF ( 0x80860003, 0 );
+ CPUID_LEAF ( 0x80860004, 0 );
+ CPUID_LEAF ( 0x80860005, 0 );
+ CPUID_LEAF ( 0x80860006, 0 );
+ CPUID_LEAF ( 0xc0000000, 0 );
+ CPUID_LEAF ( 0xc0000001, 0 );
};
/*
diff --git a/arch/x86/kernel/cpu/cpuid_parser.c b/arch/x86/kernel/cpu/cpuid_parser.c
index ab736f03051e..a7e6692f767b 100644
--- a/arch/x86/kernel/cpu/cpuid_parser.c
+++ b/arch/x86/kernel/cpu/cpuid_parser.c
@@ -42,24 +42,30 @@ 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_0x80000000(const struct cpuid_parse_entry *e, const struct cpuid_read_output *output)
-{
- struct leaf_0x80000000_0 *el0 = (struct leaf_0x80000000_0 *)output->regs;
-
- cpuid_read_subleaf(e->leaf, e->subleaf, el0);
-
- /*
- * Protect against Intel 32-bit CPUs lacking an extended CPUID range. A
- * CPUID(0x80000000) query on such machines will repeat the output of the
- * highest standard CPUID leaf instead.
- */
- if (CPUID_RANGE(el0->max_ext_leaf) != CPUID_EXT_START)
- return;
-
- output->info->nr_entries = 1;
+/*
+ * Define an extended range CPUID read function
+ *
+ * Guard against CPUs lacking the passed range leaf; e.g. Intel 32-bit CPUs lacking
+ * CPUID(0x80000000). A query on such machines will just repeat the output of the
+ * highest standard CPUID leaf.
+ */
+#define define_cpuid_range_read_function(_range, _name) \
+static void \
+cpuid_read_##_range(const struct cpuid_parse_entry *e, const struct cpuid_read_output *output) \
+{ \
+ struct leaf_##_range##_0 *l = (struct leaf_##_range##_0 *)output->regs; \
+ \
+ cpuid_read_subleaf(e->leaf, e->subleaf, l); \
+ if (CPUID_RANGE(l->max_##_name##_leaf) != _range) \
+ return; \
+ \
+ output->info->nr_entries = 1; \
}
+define_cpuid_range_read_function(0x80000000, ext);
+define_cpuid_range_read_function(0x80860000, tra);
+define_cpuid_range_read_function(0xc0000000, cntr);
+
/*
* CPUID parser tables:
*
@@ -115,10 +121,14 @@ static unsigned int cpuid_range_max_leaf(const struct cpuid_table *t, unsigned i
{
const struct leaf_0x0_0 *l0 = __cpuid_table_subleaf(t, 0x0, 0);
const struct leaf_0x80000000_0 *el0 = __cpuid_table_subleaf(t, 0x80000000, 0);
+ const struct leaf_0x80860000_0 *tl0 = __cpuid_table_subleaf(t, 0x80860000, 0);
+ const struct leaf_0xc0000000_0 *cl0 = __cpuid_table_subleaf(t, 0xc0000000, 0);
switch (range) {
- case CPUID_BASE_START: return l0 ? l0->max_std_leaf : 0;
- case CPUID_EXT_START: return el0 ? el0->max_ext_leaf : 0;
+ case CPUID_BASE_START: return l0 ? l0->max_std_leaf : 0;
+ case CPUID_EXT_START: return el0 ? el0->max_ext_leaf : 0;
+ case CPUID_TMX_START: return tl0 ? tl0->max_tra_leaf : 0;
+ case CPUID_CTR_START: return cl0 ? cl0->max_cntr_leaf : 0;
default: return 0;
}
}
@@ -180,6 +190,8 @@ cpuid_fill_table(struct cpuid_table *t, const struct cpuid_parse_entry entries[]
} ranges[] = {
{ CPUID_BASE_START, CPUID_BASE_END },
{ CPUID_EXT_START, CPUID_EXT_END },
+ { CPUID_TMX_START, CPUID_TMX_END },
+ { CPUID_CTR_START, CPUID_CTR_END },
};
for (unsigned int i = 0; i < ARRAY_SIZE(ranges); i++)
diff --git a/arch/x86/kernel/cpu/cpuid_parser.h b/arch/x86/kernel/cpu/cpuid_parser.h
index ee1958f3d369..76a87a71b430 100644
--- a/arch/x86/kernel/cpu/cpuid_parser.h
+++ b/arch/x86/kernel/cpu/cpuid_parser.h
@@ -149,6 +149,15 @@ struct cpuid_parse_entry {
CPUID_PARSE_ENTRY ( 0x80000002, 0, generic ), \
CPUID_PARSE_ENTRY ( 0x80000003, 0, generic ), \
CPUID_PARSE_ENTRY ( 0x80000004, 0, generic ), \
+ CPUID_PARSE_ENTRY ( 0x80860000, 0, 0x80860000 ), \
+ CPUID_PARSE_ENTRY ( 0x80860001, 0, generic ), \
+ CPUID_PARSE_ENTRY ( 0x80860002, 0, generic ), \
+ CPUID_PARSE_ENTRY ( 0x80860003, 0, generic ), \
+ CPUID_PARSE_ENTRY ( 0x80860004, 0, generic ), \
+ CPUID_PARSE_ENTRY ( 0x80860005, 0, generic ), \
+ CPUID_PARSE_ENTRY ( 0x80860006, 0, generic ), \
+ CPUID_PARSE_ENTRY ( 0xc0000000, 0, 0xc0000000 ), \
+ CPUID_PARSE_ENTRY ( 0xc0000001, 0, generic ), \
/*
* CPUID parser phases:
@@ -182,5 +191,14 @@ struct cpuid_vendor_entry {
#define CPUID_VENDOR_ENTRIES \
/* Leaf Vendor list */ \
CPUID_VENDOR_ENTRY(0x16, X86_VENDOR_INTEL), \
+ CPUID_VENDOR_ENTRY(0x80860000, X86_VENDOR_TRANSMETA), \
+ CPUID_VENDOR_ENTRY(0x80860001, X86_VENDOR_TRANSMETA), \
+ CPUID_VENDOR_ENTRY(0x80860002, X86_VENDOR_TRANSMETA), \
+ CPUID_VENDOR_ENTRY(0x80860003, X86_VENDOR_TRANSMETA), \
+ CPUID_VENDOR_ENTRY(0x80860004, X86_VENDOR_TRANSMETA), \
+ CPUID_VENDOR_ENTRY(0x80860005, X86_VENDOR_TRANSMETA), \
+ CPUID_VENDOR_ENTRY(0x80860006, X86_VENDOR_TRANSMETA), \
+ CPUID_VENDOR_ENTRY(0xc0000000, X86_VENDOR_CENTAUR, X86_VENDOR_ZHAOXIN), \
+ CPUID_VENDOR_ENTRY(0xc0000001, X86_VENDOR_CENTAUR, X86_VENDOR_ZHAOXIN), \
#endif /* _ARCH_X86_CPUID_PARSER_H */
--
2.53.0