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