[PATCH v6 80/90] x86/cpuid: Introduce X86_FEATURE and CPUID word APIs

Ahmed S. Darwish posted 90 patches 6 days, 16 hours ago
[PATCH v6 80/90] x86/cpuid: Introduce X86_FEATURE and CPUID word APIs
Posted by Ahmed S. Darwish 6 days, 16 hours ago
Introduce helper APIs to translate:

  - X86_FEATURE symbols from <asm/cpufeatures.h>
  - CPUID word indices from <asm/cpufeature.h>

into offsets within the cached CPUID tables.

These helpers will be used to route all X86_FEATURE and CPUID word querying
into the centralized CPUID tables, instead of their current routing to
cpuinfo_x86::x86_capability[].  Thus removing the latter from the kernel.

Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
 arch/x86/include/asm/cpuid/api.h | 125 +++++++++++++++++++++++++++++++
 1 file changed, 125 insertions(+)

diff --git a/arch/x86/include/asm/cpuid/api.h b/arch/x86/include/asm/cpuid/api.h
index 611ee8596115..b60a408c8fec 100644
--- a/arch/x86/include/asm/cpuid/api.h
+++ b/arch/x86/include/asm/cpuid/api.h
@@ -504,6 +504,131 @@ static inline bool cpuid_amd_hygon_has_l3_cache(struct cpuinfo_x86 *c)
 	return el6 && el6->l3_assoc;
 }
 
+/*
+ * X86_FEATURE mapping:
+ *
+ * These macros are for the internal <asm/cpufeature.h> X86_FEATURE querying.
+ * Do everything at compile-time to preserve that header's query optimizations.
+ *
+ * @_feature: <asm/cpufeatures.h> X86_FEATURE symbol
+ */
+
+#define __feature_word(_feature)	((_feature) / 32)
+#define __feature_word_bit(_feature)	((_feature) % 32)
+
+/*
+ * Return cached CPUID output offset for @_feature; within 'struct cpuid_leaves'.
+ */
+#define __feature_byte_offset(_feature)						\
+({										\
+	struct cpuid_cpufeature ____map[] = CPUID_FEATURE_WORDS_MAP;		\
+	unsigned int ____word = __feature_word(_feature);			\
+										\
+	____map[____word].leaves_offset;					\
+})
+
+/*
+ * Return CPUID output register for @_feature; i.e., CPUID_EAX -> CPUID_EDX.
+ */
+#define __feature_register(_feature)						\
+({										\
+	struct cpuid_cpufeature ____map[] = CPUID_FEATURE_WORDS_MAP;		\
+	unsigned int ____word = __feature_word(_feature);			\
+										\
+	____map[____word].cpuid_reg;						\
+})
+
+/*
+ * Return bit offset for @_feature.  This is for bitops, where the offset is
+ * relative to ((u8 *)&cpuid_leaves + __feature_byte_offset(@_feature)).
+ */
+#define __feature_bit_offset(_feature)						\
+({										\
+	32 * __feature_register(_feature) + __feature_word_bit(_feature);	\
+})
+
+/**
+ * cpuid_feature_byte_offset() - Return X86_FEATURE byte offset
+ * @_feature:	X86_FEATURE symbol from <asm/cpufeatures.h>
+ *
+ * Return CPUID table 'struct cpuid_leaves' byte offset, for @_feature.
+ */
+#define cpuid_feature_byte_offset(_feature)	__feature_byte_offset(_feature)
+
+/**
+ * cpuid_feature_bitmap() - Return X86_FEATURE bitmap
+ * @_cpuinfo:	CPU capability structure ('struct cpuinfo_x86')
+ * @_feature:	X86_FEATURE symbol from <asm/cpufeatures.h>
+ *
+ * Return CPUID table bitmap, within @_cpuinfo, for @_feature.  The returned
+ * bitmap is unsigned long aligned, for bitops access.
+ */
+#define cpuid_feature_bitmap(_cpuinfo, _feature)				\
+	(unsigned long *)((u8 *)&(_cpuinfo)->cpuid.leaves + __feature_byte_offset(_feature))
+
+/**
+ * cpuid_feature_bit_offset()
+ * @_feature:	X86_FEATURE symbol from <asm/cpufeatures.h>
+ *
+ * Return CPUID table bit offset, for @_feature, within the bitmap returned by
+ * cpuid_feature_bitmap().
+ */
+#define cpuid_feature_bit_offset(_feature)	__feature_bit_offset(_feature)
+
+/*
+ * CPUID word mapping:
+ */
+
+static inline u32 *__cpuid_word_address(struct cpuinfo_x86 *c, u16 word)
+{
+	u16 feature = word * 32;
+
+	return (u32 *)cpuid_feature_bitmap(c, feature) + __feature_register(feature);
+}
+
+/**
+ * cpuid_word() - Return the CPUID word's raw u32 value
+ * @c:		CPU capability structure ('struct cpuinfo_x86')
+ * @word:	CPUID word number as defined at "enum cpuid_leafs"
+ */
+static inline u32 cpuid_word(struct cpuinfo_x86 *c, u16 word)
+{
+	return *__cpuid_word_address(c, word);
+}
+
+/**
+ * cpuid_word_set() - Set the CPUID word's raw u32 value
+ * @c:		CPU capability structure ('struct cpuinfo_x86')
+ * @word:	CPUID word number as defined at "enum cpuid_leafs"
+ * @val:	Raw u32 value to set the word to
+ */
+static inline void cpuid_word_set(struct cpuinfo_x86 *c, u16 word, u32 val)
+{
+	*__cpuid_word_address(c, word) = val;
+}
+
+/**
+ * cpuid_word_set_bits() - Set bits at CPUID word according to passed map
+ * @c:		CPU capability structure ('struct cpuinfo_x86')
+ * @word:	CPUID word number as defined at "enum cpuid_leafs"
+ * @map:	Map of bits to be set
+ */
+static inline void cpuid_word_set_bits(struct cpuinfo_x86 *c, u16 word, u32 map)
+{
+	*__cpuid_word_address(c, word) |= map;
+}
+
+/**
+ * cpuid_word_clear_bits() - Clear bits at CPUID word according to passed map
+ * @c:		CPU capability structure ('struct cpuinfo_x86')
+ * @word:	CPUID word number as defined at "enum cpuid_leafs"
+ * @map:	Map of bits to be cleared
+ */
+static inline void cpuid_word_clear_bits(struct cpuinfo_x86 *c, u16 word, u32 map)
+{
+	*__cpuid_word_address(c, word) &= ~map;
+}
+
 /*
  * CPUID parser exported APIs:
  */
-- 
2.53.0