Add a new iterator, for_each_parsed_cpuid_0x2_desc(), for retrieving parsed
CPUID(0x2) entries as 1-byte descriptors.
This new macro is aimed to replace for_each_cpuid_0x2_desc(), which
operates on directly queried CPUID data instead.
Assert that the passed "regs" are the same size as "union leaf_0x2_regs".
Use a size equivalence check, instead of a typeof() check, to give callers
the freedom to either pass a "struct cpuid_regs" pointer or a "struct
leaf_0x2_0" pointer; where both can returned by the parsed CPUID API at
<asm/cpuid/api.h>. This size comparison matches what other kernel CPUID
APIs do; e.g. cpuid_read() and cpuid_read_subleaf() at <asm/cpuid/api.h>.
Put the size equivalence check inside a GNU statement expression, ({..})
so that it can be placed inside the macro's loop initialization.
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
arch/x86/include/asm/cpuid/api.h | 43 ++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/arch/x86/include/asm/cpuid/api.h b/arch/x86/include/asm/cpuid/api.h
index 3d5a0d4918cc..a55a28e9f0f6 100644
--- a/arch/x86/include/asm/cpuid/api.h
+++ b/arch/x86/include/asm/cpuid/api.h
@@ -528,6 +528,49 @@ static inline bool cpuid_amd_hygon_has_l3_cache(void)
__cpuid_table_nr_filled_subleaves(&(_cpuinfo)->cpuid, _leaf, n); \
})
+/*
+ * Convenience leaf-specific functions (using parsed CPUID data):
+ */
+
+/*
+ * CPUID(0x2)
+ */
+
+/**
+ * for_each_parsed_cpuid_0x2_desc() - Iterator for parsed CPUID(0x2) descriptors
+ * @_regs: Leaf 0x2 register output, as returned by cpuid_leaf_raw()
+ * @_ptr: u8 pointer, for macro internal use only
+ * @_desc: Pointer to parsed descriptor information at each iteration
+ *
+ * Loop over the 1-byte descriptors in the passed CPUID(0x2) output registers
+ * @_regs. Provide the parsed information for each descriptor through @_desc.
+ *
+ * To handle cache-specific descriptors, switch on @_desc->c_type. For TLB
+ * descriptors, switch on @_desc->t_type.
+ *
+ * Example usage for cache descriptors::
+ *
+ * const struct leaf_0x2_table *desc;
+ * const struct cpuid_regs *regs;
+ * const u8 *ptr;
+ *
+ * regs = cpuid_leaf_raw(c, 0x2);
+ * if (!regs) {
+ * // Handle error
+ * }
+ *
+ * for_each_parsed_cpuid_0x2_desc(regs, ptr, desc) {
+ * switch (desc->c_type) {
+ * ...
+ * }
+ * }
+ */
+#define for_each_parsed_cpuid_0x2_desc(_regs, _ptr, _desc) \
+ for (({ static_assert(sizeof(*_regs) == sizeof(union leaf_0x2_regs)); }), \
+ _ptr = &((const union leaf_0x2_regs *)(_regs))->desc[1]; \
+ _ptr < &((const union leaf_0x2_regs *)(_regs))->desc[16] && (_desc = &cpuid_0x2_table[*_ptr]);\
+ _ptr++)
+
/*
* CPUID parser exported APIs:
*/
--
2.53.0