git: 5fb3aea2d8c4 - main - linuxkpi: Add x86 CPU ID matching functions and macros

From: Jean-Sébastien Pédron <dumbbell_at_FreeBSD.org>
Date: Mon, 14 Sep 2026 20:12:14 UTC
The branch main has been updated by dumbbell:

URL: https://cgit.FreeBSD.org/src/commit/?id=5fb3aea2d8c436afa87605d8d7798ae8b09d558c

commit 5fb3aea2d8c436afa87605d8d7798ae8b09d558c
Author:     Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
AuthorDate: 2026-06-17 14:01:05 +0000
Commit:     Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
CommitDate: 2026-09-14 20:06:50 +0000

    linuxkpi: Add x86 CPU ID matching functions and macros
    
    There are two parts that go together:
    * `X86_MATCH_VFM()` to declare a matching pattern
    * `x86_match_cpu()` to check if the current CPU matches one of the
      patterns in an array.
    
    The i915 DRM driver started to use this in Linux 6.14.
    
    Reviewed by:    kib
    Sponsored by:   The FreeBSD Foundation
    Differential Revision: https://reviews.freebsd.org/D57700
---
 .../linuxkpi/common/include/asm/cpu_device_id.h    | 25 +++++++++++++++
 sys/compat/linuxkpi/common/include/linux/bits.h    |  2 ++
 .../common/include/linux/mod_devicetable.h         | 17 ++++++++++
 sys/compat/linuxkpi/common/src/linux_compat.c      | 37 ++++++++++++++++++++++
 4 files changed, 81 insertions(+)

diff --git a/sys/compat/linuxkpi/common/include/asm/cpu_device_id.h b/sys/compat/linuxkpi/common/include/asm/cpu_device_id.h
index a01d63a75a7e..5741cddd52b1 100644
--- a/sys/compat/linuxkpi/common/include/asm/cpu_device_id.h
+++ b/sys/compat/linuxkpi/common/include/asm/cpu_device_id.h
@@ -7,6 +7,8 @@
 #ifndef _LINUXKPI_ASM_CPU_DEVICE_ID_H_
 #define	_LINUXKPI_ASM_CPU_DEVICE_ID_H_
 
+#include <linux/bits.h>
+
 #define	VFM_MODEL_BIT	0
 #define	VFM_FAMILY_BIT	8
 #define	VFM_VENDOR_BIT	16
@@ -30,4 +32,27 @@
 #include <asm/intel-family.h>
 #include <asm/processor.h>
 
+#define	X86_CPU_ID_FLAG_ENTRY_VALID	BIT(0)
+
+#define	X86_MATCH_VENDORID_FAM_MODEL_STEPPINGS_FEATURE(			\
+    _vendor, _family, _model, _steppings, _feature) {			\
+	.vendor		= _vendor,					\
+	.family		= _family,					\
+	.model		= _model,					\
+	.steppings	= _steppings,					\
+	.feature	= _feature,					\
+	.flags          = X86_CPU_ID_FLAG_ENTRY_VALID,			\
+}
+
+#define	X86_MATCH_VFM(_vfm, _data)					\
+    X86_MATCH_VENDORID_FAM_MODEL_STEPPINGS_FEATURE(			\
+	VFM_VENDOR(_vfm),						\
+	VFM_FAMILY(_vfm),						\
+	VFM_MODEL(_vfm),						\
+	X86_STEPPING_ANY,						\
+	X86_FEATURE_ANY)
+
+const struct x86_cpu_id *linuxkpi_x86_match_cpu(const struct x86_cpu_id *match_array);
+#define	x86_match_cpu(match_array) linuxkpi_x86_match_cpu(match_array)
+
 #endif /* _LINUXKPI_ASM_CPU_DEVICE_ID_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/bits.h b/sys/compat/linuxkpi/common/include/linux/bits.h
index 53deb7cbbe88..f5e688cdb7c0 100644
--- a/sys/compat/linuxkpi/common/include/linux/bits.h
+++ b/sys/compat/linuxkpi/common/include/linux/bits.h
@@ -8,6 +8,8 @@
 #ifndef _LINUXKPI_LINUX_BITS_H_
 #define	_LINUXKPI_LINUX_BITS_H_
 
+#include <linux/bitops.h>
+
 #define	GENMASK(h, l)		(((~0UL) >> (BITS_PER_LONG - (h) - 1)) & ((~0UL) << (l)))
 #define	GENMASK_ULL(h, l)	(((~0ULL) >> (BITS_PER_LONG_LONG - (h) - 1)) & ((~0ULL) << (l)))
 
diff --git a/sys/compat/linuxkpi/common/include/linux/mod_devicetable.h b/sys/compat/linuxkpi/common/include/linux/mod_devicetable.h
index b345b98325e1..e015bde5061e 100644
--- a/sys/compat/linuxkpi/common/include/linux/mod_devicetable.h
+++ b/sys/compat/linuxkpi/common/include/linux/mod_devicetable.h
@@ -81,6 +81,23 @@ struct dmi_system_id {
 
 #define	ACPI_ID_LEN		16
 
+struct x86_cpu_id {
+	uint16_t vendor;
+	uint16_t family;
+	uint16_t model;
+	uint16_t steppings;
+	uint16_t feature;
+	uint16_t flags;
+};
+
+#define	X86_VENDOR_ANY		0xffff
+#define	X86_FAMILY_ANY		0
+#define	X86_MODEL_ANY		0
+#define	X86_STEPPING_ANY	0
+#define	X86_STEP_MIN		0
+#define	X86_STEP_MAX		0xf
+#define	X86_FEATURE_ANY		0
+
 /* -----------------------------------------------------------------------------
  * USB
  */
diff --git a/sys/compat/linuxkpi/common/src/linux_compat.c b/sys/compat/linuxkpi/common/src/linux_compat.c
index 8fb09d5914fb..3cdeb8e2d297 100644
--- a/sys/compat/linuxkpi/common/src/linux_compat.c
+++ b/sys/compat/linuxkpi/common/src/linux_compat.c
@@ -100,8 +100,11 @@
 #include <linux/printk.h>
 #include <linux/seq_file.h>
 #include <linux/uuid.h>
+#include <linux/mod_devicetable.h>
 
 #if defined(__i386__) || defined(__amd64__)
+#include <asm/cpu_device_id.h>
+#include <asm/cpufeature.h>
 #include <asm/smp.h>
 #include <asm/processor.h>
 #endif
@@ -3084,6 +3087,40 @@ linux_compat_uninit(void *arg)
 }
 SYSUNINIT(linux_compat, SI_SUB_DRIVERS, SI_ORDER_SECOND, linux_compat_uninit, NULL);
 
+const struct x86_cpu_id *
+linuxkpi_x86_match_cpu(const struct x86_cpu_id *match_array)
+{
+	const struct x86_cpu_id *match;
+
+	for (match = match_array;
+	    (match->flags & X86_CPU_ID_FLAG_ENTRY_VALID) != 0;
+	    match++) {
+		if (match->vendor != X86_VENDOR_ANY &&
+		    match->vendor != boot_cpu_data.x86_vendor)
+			continue;
+
+		if (match->family != X86_FAMILY_ANY &&
+		    match->family != boot_cpu_data.x86)
+			continue;
+
+		if (match->model != X86_MODEL_ANY &&
+		    match->model != boot_cpu_data.x86_model)
+			continue;
+
+		if (match->model != X86_STEPPING_ANY &&
+		    (match->steppings & BIT(boot_cpu_data.x86_stepping)) == 0)
+			continue;
+
+		if (match->feature != X86_FEATURE_ANY &&
+		    !static_cpu_has(match->feature))
+			continue;
+
+		return (match);
+	}
+
+	return (NULL);
+}
+
 /*
  * NOTE: Linux frequently uses "unsigned long" for pointer to integer
  * conversion and vice versa, where in FreeBSD "uintptr_t" would be