xref: /kernel/linux/linux-6.6/arch/x86/kernel/cpu/match.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <asm/cpu_device_id.h>
362306a36Sopenharmony_ci#include <asm/cpufeature.h>
462306a36Sopenharmony_ci#include <linux/cpu.h>
562306a36Sopenharmony_ci#include <linux/export.h>
662306a36Sopenharmony_ci#include <linux/slab.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/**
962306a36Sopenharmony_ci * x86_match_cpu - match current CPU again an array of x86_cpu_ids
1062306a36Sopenharmony_ci * @match: Pointer to array of x86_cpu_ids. Last entry terminated with
1162306a36Sopenharmony_ci *         {}.
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * Return the entry if the current CPU matches the entries in the
1462306a36Sopenharmony_ci * passed x86_cpu_id match table. Otherwise NULL.  The match table
1562306a36Sopenharmony_ci * contains vendor (X86_VENDOR_*), family, model and feature bits or
1662306a36Sopenharmony_ci * respective wildcard entries.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * A typical table entry would be to match a specific CPU
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, INTEL_FAM6_BROADWELL,
2162306a36Sopenharmony_ci *				      X86_FEATURE_ANY, NULL);
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * Fields can be wildcarded with %X86_VENDOR_ANY, %X86_FAMILY_ANY,
2462306a36Sopenharmony_ci * %X86_MODEL_ANY, %X86_FEATURE_ANY (except for vendor)
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * asm/cpu_device_id.h contains a set of useful macros which are shortcuts
2762306a36Sopenharmony_ci * for various common selections. The above can be shortened to:
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * X86_MATCH_INTEL_FAM6_MODEL(BROADWELL, NULL);
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci * Arrays used to match for this should also be declared using
3262306a36Sopenharmony_ci * MODULE_DEVICE_TABLE(x86cpu, ...)
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * This always matches against the boot cpu, assuming models and features are
3562306a36Sopenharmony_ci * consistent over all CPUs.
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_ciconst struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	const struct x86_cpu_id *m;
4062306a36Sopenharmony_ci	struct cpuinfo_x86 *c = &boot_cpu_data;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	for (m = match;
4362306a36Sopenharmony_ci	     m->vendor | m->family | m->model | m->steppings | m->feature;
4462306a36Sopenharmony_ci	     m++) {
4562306a36Sopenharmony_ci		if (m->vendor != X86_VENDOR_ANY && c->x86_vendor != m->vendor)
4662306a36Sopenharmony_ci			continue;
4762306a36Sopenharmony_ci		if (m->family != X86_FAMILY_ANY && c->x86 != m->family)
4862306a36Sopenharmony_ci			continue;
4962306a36Sopenharmony_ci		if (m->model != X86_MODEL_ANY && c->x86_model != m->model)
5062306a36Sopenharmony_ci			continue;
5162306a36Sopenharmony_ci		if (m->steppings != X86_STEPPING_ANY &&
5262306a36Sopenharmony_ci		    !(BIT(c->x86_stepping) & m->steppings))
5362306a36Sopenharmony_ci			continue;
5462306a36Sopenharmony_ci		if (m->feature != X86_FEATURE_ANY && !cpu_has(c, m->feature))
5562306a36Sopenharmony_ci			continue;
5662306a36Sopenharmony_ci		return m;
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci	return NULL;
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ciEXPORT_SYMBOL(x86_match_cpu);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic const struct x86_cpu_desc *
6362306a36Sopenharmony_cix86_match_cpu_with_stepping(const struct x86_cpu_desc *match)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	struct cpuinfo_x86 *c = &boot_cpu_data;
6662306a36Sopenharmony_ci	const struct x86_cpu_desc *m;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	for (m = match; m->x86_family | m->x86_model; m++) {
6962306a36Sopenharmony_ci		if (c->x86_vendor != m->x86_vendor)
7062306a36Sopenharmony_ci			continue;
7162306a36Sopenharmony_ci		if (c->x86 != m->x86_family)
7262306a36Sopenharmony_ci			continue;
7362306a36Sopenharmony_ci		if (c->x86_model != m->x86_model)
7462306a36Sopenharmony_ci			continue;
7562306a36Sopenharmony_ci		if (c->x86_stepping != m->x86_stepping)
7662306a36Sopenharmony_ci			continue;
7762306a36Sopenharmony_ci		return m;
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci	return NULL;
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cibool x86_cpu_has_min_microcode_rev(const struct x86_cpu_desc *table)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	const struct x86_cpu_desc *res = x86_match_cpu_with_stepping(table);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	if (!res || res->x86_microcode_rev > boot_cpu_data.microcode)
8762306a36Sopenharmony_ci		return false;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	return true;
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(x86_cpu_has_min_microcode_rev);
92