From: Andi Kleen <ak@xxxxxxxxxxxxxxx> For bug workarounds or checks it is useful to check for specific microcode versions. Add a new table format to check for steppings with min/max microcode revisions. This does not change the existing x86_cpu_id because it's an ABI shared with modutils, and also has quite difference requirements, as in no wildcards, but everything has to be matched exactly. Signed-off-by: Andi Kleen <ak@xxxxxxxxxxxxxxx> --- arch/x86/include/asm/cpu_device_id.h | 22 ++++++++++++++ arch/x86/kernel/cpu/match.c | 43 ++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/arch/x86/include/asm/cpu_device_id.h b/arch/x86/include/asm/cpu_device_id.h index baeba0567126..bf2222d5438c 100644 --- a/arch/x86/include/asm/cpu_device_id.h +++ b/arch/x86/include/asm/cpu_device_id.h @@ -11,4 +11,26 @@ extern const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match); +/* + * Match specific microcodes or steppings. + * + * vendor/family/model/stepping must be all set. + * min_ucode/max_ucode/driver_data are optional and can be 0. + */ + +struct x86_ucode_id { + __u16 vendor; + __u16 family; + __u16 model; + __u16 stepping; + __u32 min_ucode; + __u32 max_ucode; + kernel_ulong_t driver_data; +}; + +extern const struct x86_ucode_id * +x86_match_ucode_cpu(int cpu, const struct x86_ucode_id *match); +extern const struct x86_ucode_id * +x86_match_ucode_all(const struct x86_ucode_id *match); + #endif diff --git a/arch/x86/kernel/cpu/match.c b/arch/x86/kernel/cpu/match.c index 3fed38812eea..f29a21b2809c 100644 --- a/arch/x86/kernel/cpu/match.c +++ b/arch/x86/kernel/cpu/match.c @@ -48,3 +48,46 @@ const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match) return NULL; } EXPORT_SYMBOL(x86_match_cpu); + +const struct x86_ucode_id *x86_match_ucode_cpu(int cpu, + const struct x86_ucode_id *match) +{ + const struct x86_ucode_id *m; + struct cpuinfo_x86 *c = &cpu_data(cpu); + + for (m = match; m->vendor | m->family | m->model; m++) { + if (c->x86_vendor != m->vendor) + continue; + if (c->x86 != m->family) + continue; + if (c->x86_model != m->model) + continue; + if (c->x86_stepping != m->stepping) + continue; + if (m->min_ucode && c->microcode < m->min_ucode) + continue; + if (m->max_ucode && c->microcode > m->max_ucode) + continue; + return m; + } + return NULL; +} + +/* Check all CPUs */ +const struct x86_ucode_id *x86_match_ucode_all(const struct x86_ucode_id *match) +{ + int cpu; + const struct x86_ucode_id *all_m = NULL; + bool first = true; + + for_each_online_cpu(cpu) { + const struct x86_ucode_id *m = x86_match_ucode_cpu(cpu, match); + + if (first) + all_m = m; + else if (m != all_m) + return NULL; + first = false; + } + return all_m; +} -- 2.17.1