]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
x86/cpu: Introduce and use CPUID leaf 0x2 parsing helpers
authorAhmed S. Darwish <darwi@linutronix.de>
Mon, 24 Mar 2025 13:32:58 +0000 (14:32 +0100)
committerIngo Molnar <mingo@kernel.org>
Tue, 25 Mar 2025 09:22:06 +0000 (10:22 +0100)
Introduce CPUID leaf 0x2 parsing helpers at <asm/cpuid/leaf_0x2_api.h>.
This allows sharing the leaf 0x2's output validation and iteration logic
across both x86/cpu intel.c and cacheinfo.c.

Start by converting intel.c to the new API.

Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: https://lore.kernel.org/r/20250324133324.23458-4-darwi@linutronix.de
arch/x86/include/asm/cpuid.h
arch/x86/include/asm/cpuid/leaf_0x2_api.h [new file with mode: 0644]
arch/x86/include/asm/cpuid/types.h
arch/x86/kernel/cpu/intel.c

index d5749b25fa10c6480c2084c1c0d4c04800430d79..585819331dc6b3f22d04445675e7eafc3b245b3d 100644 (file)
@@ -4,5 +4,6 @@
 #define _ASM_X86_CPUID_H
 
 #include <asm/cpuid/api.h>
+#include <asm/cpuid/leaf_0x2_api.h>
 
 #endif /* _ASM_X86_CPUID_H */
diff --git a/arch/x86/include/asm/cpuid/leaf_0x2_api.h b/arch/x86/include/asm/cpuid/leaf_0x2_api.h
new file mode 100644 (file)
index 0000000..4c845fc
--- /dev/null
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_CPUID_LEAF_0x2_API_H
+#define _ASM_X86_CPUID_LEAF_0x2_API_H
+
+#include <asm/cpuid/api.h>
+#include <asm/cpuid/types.h>
+
+/**
+ * cpuid_get_leaf_0x2_regs() - Return sanitized leaf 0x2 register output
+ * @regs:      Output parameter
+ *
+ * Query CPUID leaf 0x2 and store its output in @regs. Force set any
+ * invalid 1-byte descriptor returned by the hardware to zero (the NULL
+ * cache/TLB descriptor) before returning it to the caller.
+ *
+ * Use for_each_leaf_0x2_desc() to iterate over the returned output.
+ */
+static inline void cpuid_get_leaf_0x2_regs(union leaf_0x2_regs *regs)
+{
+       cpuid_leaf(0x2, regs);
+
+       /*
+        * All Intel CPUs must report an iteration count of 1.  In case
+        * of bogus hardware, treat all returned descriptors as NULL.
+        */
+       if (regs->desc[0] != 0x01) {
+               for (int i = 0; i < 4; i++)
+                       regs->regv[i] = 0;
+               return;
+       }
+
+       /*
+        * The most significant bit (MSB) of each register must be clear.
+        * If a register is invalid, replace its descriptors with NULL.
+        */
+       for (int i = 0; i < 4; i++) {
+               if (regs->reg[i].invalid)
+                       regs->regv[i] = 0;
+       }
+}
+
+/**
+ * for_each_leaf_0x2_desc() - Iterator for CPUID leaf 0x2 descriptors
+ * @regs:      Leaf 0x2 output, as returned by cpuid_get_leaf_0x2_regs()
+ * @desc:      Pointer to the returned descriptor for each iteration
+ *
+ * Loop over the 1-byte descriptors in the passed leaf 0x2 output registers
+ * @regs.  Provide each descriptor through @desc.
+ *
+ * Note that the first byte is skipped as it is not a descriptor.
+ *
+ * Sample usage::
+ *
+ *     union leaf_0x2_regs regs;
+ *     u8 *desc;
+ *
+ *     cpuid_get_leaf_0x2_regs(&regs);
+ *     for_each_leaf_0x2_desc(regs, desc) {
+ *             // Handle *desc value
+ *     }
+ */
+#define for_each_leaf_0x2_desc(regs, desc)                             \
+       for (desc = &(regs).desc[1]; desc < &(regs).desc[16]; desc++)
+
+#endif /* _ASM_X86_CPUID_LEAF_0x2_API_H */
index 8582e27e836d518de9efaaf1b962b666ab7fb61a..753f6c4514f45c610b5b447db789a257da87c622 100644 (file)
@@ -29,4 +29,20 @@ enum cpuid_regs_idx {
 #define CPUID_LEAF_FREQ                0x16
 #define CPUID_LEAF_TILE                0x1d
 
+/*
+ * Types for CPUID(0x2) parsing
+ * Check <asm/cpuid/leaf_0x2_api.h>
+ */
+
+struct leaf_0x2_reg {
+               u32             : 31,
+                       invalid : 1;
+};
+
+union leaf_0x2_regs {
+       struct leaf_0x2_reg     reg[4];
+       u32                     regv[4];
+       u8                      desc[16];
+};
+
 #endif /* _ASM_X86_CPUID_TYPES_H */
index 0570d4d8600674c4f1ecf494cfa10de10ba04d51..aeb7d6d48379241137ec59bb48069d58dd7206f6 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/cpu_device_id.h>
 #include <asm/cpufeature.h>
 #include <asm/cpu.h>
+#include <asm/cpuid.h>
 #include <asm/hwcap2.h>
 #include <asm/intel-family.h>
 #include <asm/microcode.h>
@@ -778,27 +779,15 @@ static void intel_tlb_lookup(const unsigned char desc)
 
 static void intel_detect_tlb(struct cpuinfo_x86 *c)
 {
-       u32 regs[4];
-       u8 *desc = (u8 *)regs;
+       union leaf_0x2_regs regs;
+       u8 *desc;
 
        if (c->cpuid_level < 2)
                return;
 
-       cpuid(2, &regs[0], &regs[1], &regs[2], &regs[3]);
-
-       /* Intel CPUs must report an iteration count of 1 */
-       if (desc[0] != 0x01)
-               return;
-
-       /* If a register's bit 31 is set, it is an unknown format */
-       for (int i = 0; i < 4; i++) {
-               if (regs[i] & (1 << 31))
-                       regs[i] = 0;
-       }
-
-       /* Skip the first byte as it is not a descriptor */
-       for (int i = 1; i < 16; i++)
-               intel_tlb_lookup(desc[i]);
+       cpuid_get_leaf_0x2_regs(&regs);
+       for_each_leaf_0x2_desc(regs, desc)
+               intel_tlb_lookup(*desc);
 }
 
 static const struct cpu_dev intel_cpu_dev = {