[PATCH v6 25/90] x86/cpuid: Parse Transmeta and Centaur extended ranges

Ahmed S. Darwish posted 90 patches 6 days, 16 hours ago
[PATCH v6 25/90] x86/cpuid: Parse Transmeta and Centaur extended ranges
Posted by Ahmed S. Darwish 6 days, 16 hours ago
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