[PATCH v1 14/26] x86/cpuid: Introduce scanned CPUID(0x2) API

"Ahmed S. Darwish" <[email protected]>
Newsgroups dev.linux.lists.x86-cpuid,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Add a new iterator macro, for_each_scanned_leaf_0x2_entry(), for parsing
scanned CPUID(0x2) entries as 1-byte descriptors.

Unlike the existing for_each_leaf_0x2_entry() macro, which operates on
directly retrieved CPUID data, the new one takes its input from the
scanned CPUID data access API.  That is, it is expected to be used as:

    const struct leaf_0x2_table *entry;
    const struct cpuid_regs *regs;
    u8 *ptr;

    regs = cpudata_cpuid_regs(c, 0x2);	// Scanned CPUID access
    for_each_scanned_leaf_0x2_entry(regs, ptr, entry) {
        ...
    }

which should replace the older method:

    const struct leaf_0x2_table *entry;
    union leaf_0x2_regs regs;
    u8 *ptr;

    cpuid_get_leaf_0x2_regs(&regs);	// Direct CPUID access
    for_each_leaf_0x2_entry(regs, ptr, entry) {
        ...
    }

In the new macro, assert that the passed 'regs' is the same size as a
'union leaf_0x2_regs'.  This is necessary since the macro internally
casts 'regs' to that union in order to iterate over the CPUID(0x2) output
as a 1-byte array.

A size equivalence assert is used, 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, both as returned by the scanned CPUID API at
<asm/cpuid/table_api.h>.  That size comparison matches what other kernel
CPUID do; e.g. cpuid_leaf() and cpuid_leaf_reg() at <asm/cpuid/api.h>.

Note, 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 <[email protected]>
---
 arch/x86/include/asm/cpuid/leaf_0x2_api.h | 35 +++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/arch/x86/include/asm/cpuid/leaf_0x2_api.h b/arch/x86/include/asm/cpuid/leaf_0x2_api.h
index 09fa3070b271..be3d7e113421 100644
--- a/arch/x86/include/asm/cpuid/leaf_0x2_api.h
+++ b/arch/x86/include/asm/cpuid/leaf_0x2_api.h
@@ -70,4 +70,39 @@ static inline void cpuid_get_leaf_0x2_regs(union leaf_0x2_regs *regs)
 	     __ptr < &(regs).desc[16] && (entry = &cpuid_0x2_table[*__ptr]);	\
 	     __ptr++)
 
+/**
+ * for_each_scanned_leaf_0x2_entry() - Iterator for parsed CPUID(0x2) descriptors
+ * @regs:   Leaf 0x2 register output, as returned by cpudata_cpuid_regs()
+ * @__ptr:  u8 pointer, for macro internal use only
+ * @entry:  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 @entry.
+ *
+ * To handle cache-specific descriptors, switch on @entry->c_type.  For TLB
+ * descriptors, switch on @entry->t_type.
+ *
+ * Example usage for cache descriptors::
+ *
+ *	const struct leaf_0x2_table *entry;
+ *	struct cpuid_regs *regs;
+ *	u8 *ptr;
+ *
+ *	regs = cpudata_cpuid_regs(c, 0x2);
+ *	if (!regs) {
+ *		// Handle error
+ *	}
+ *
+ *	for_each_scanned_leaf_0x2_entry(regs, ptr, entry) {
+ *		switch (entry->c_type) {
+ *			...
+ *		}
+ *	}
+ */
+#define for_each_scanned_leaf_0x2_entry(regs, __ptr, entry)					\
+	for (({ static_assert(sizeof(*regs) == sizeof(union leaf_0x2_regs)); }),		\
+	     __ptr = &((union leaf_0x2_regs *)(regs))->desc[1];					\
+	     __ptr < &((union leaf_0x2_regs *)(regs))->desc[16] && (entry = &cpuid_0x2_table[*__ptr]);\
+	     __ptr++)
+
 #endif /* _ASM_X86_CPUID_LEAF_0x2_API_H */
-- 
2.49.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.