-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
x86/cpuid: Add generic table for CPUID dependencies
Some CPUID features depend on other features. Currently it's possible to to clear dependent features, but not clear the base features, which can cause various interesting problems. This patch implements a generic table to describe dependencies between CPUID features, to be used by all code that clears CPUID. Some subsystems (like XSAVE) had an own implementation of this, but it's better to do it all in a single place for everyone. Then clear_cpu_cap and setup_clear_cpu_cap always look up this table and clear all dependencies too. This is intended to be a practical table: only for features that make sense to clear. If someone for example clears FPU, or other features that are essentially part of the required base feature set, not much is going to work. Handling that is right now out of scope. We're only handling features which can be usefully cleared. Signed-off-by: Andi Kleen <ak@linux.intel.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Cc: Jonathan McDowell <noodles@earth.li> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/20171013215645.23166-3-andi@firstfloor.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
- Loading branch information
Andi Kleen
authored and
Ingo Molnar
committed
Oct 17, 2017
1 parent
cbe9637
commit 0b00de8
Showing
4 changed files
with
123 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
/* Declare dependencies between CPUIDs */ | ||
#include <linux/kernel.h> | ||
#include <linux/init.h> | ||
#include <linux/module.h> | ||
#include <asm/cpufeature.h> | ||
|
||
struct cpuid_dep { | ||
unsigned int feature; | ||
unsigned int depends; | ||
}; | ||
|
||
/* | ||
* Table of CPUID features that depend on others. | ||
* | ||
* This only includes dependencies that can be usefully disabled, not | ||
* features part of the base set (like FPU). | ||
* | ||
* Note this all is not __init / __initdata because it can be | ||
* called from cpu hotplug. It shouldn't do anything in this case, | ||
* but it's difficult to tell that to the init reference checker. | ||
*/ | ||
const static struct cpuid_dep cpuid_deps[] = { | ||
{ X86_FEATURE_XSAVEOPT, X86_FEATURE_XSAVE }, | ||
{ X86_FEATURE_XSAVEC, X86_FEATURE_XSAVE }, | ||
{ X86_FEATURE_XSAVES, X86_FEATURE_XSAVE }, | ||
{ X86_FEATURE_AVX, X86_FEATURE_XSAVE }, | ||
{ X86_FEATURE_PKU, X86_FEATURE_XSAVE }, | ||
{ X86_FEATURE_MPX, X86_FEATURE_XSAVE }, | ||
{ X86_FEATURE_XGETBV1, X86_FEATURE_XSAVE }, | ||
{ X86_FEATURE_FXSR_OPT, X86_FEATURE_FXSR }, | ||
{ X86_FEATURE_XMM, X86_FEATURE_FXSR }, | ||
{ X86_FEATURE_XMM2, X86_FEATURE_XMM }, | ||
{ X86_FEATURE_XMM3, X86_FEATURE_XMM2 }, | ||
{ X86_FEATURE_XMM4_1, X86_FEATURE_XMM2 }, | ||
{ X86_FEATURE_XMM4_2, X86_FEATURE_XMM2 }, | ||
{ X86_FEATURE_XMM3, X86_FEATURE_XMM2 }, | ||
{ X86_FEATURE_PCLMULQDQ, X86_FEATURE_XMM2 }, | ||
{ X86_FEATURE_SSSE3, X86_FEATURE_XMM2, }, | ||
{ X86_FEATURE_F16C, X86_FEATURE_XMM2, }, | ||
{ X86_FEATURE_AES, X86_FEATURE_XMM2 }, | ||
{ X86_FEATURE_SHA_NI, X86_FEATURE_XMM2 }, | ||
{ X86_FEATURE_FMA, X86_FEATURE_AVX }, | ||
{ X86_FEATURE_AVX2, X86_FEATURE_AVX, }, | ||
{ X86_FEATURE_AVX512F, X86_FEATURE_AVX, }, | ||
{ X86_FEATURE_AVX512IFMA, X86_FEATURE_AVX512F }, | ||
{ X86_FEATURE_AVX512PF, X86_FEATURE_AVX512F }, | ||
{ X86_FEATURE_AVX512ER, X86_FEATURE_AVX512F }, | ||
{ X86_FEATURE_AVX512CD, X86_FEATURE_AVX512F }, | ||
{ X86_FEATURE_AVX512DQ, X86_FEATURE_AVX512F }, | ||
{ X86_FEATURE_AVX512BW, X86_FEATURE_AVX512F }, | ||
{ X86_FEATURE_AVX512VL, X86_FEATURE_AVX512F }, | ||
{ X86_FEATURE_AVX512VBMI, X86_FEATURE_AVX512F }, | ||
{ X86_FEATURE_AVX512_4VNNIW, X86_FEATURE_AVX512F }, | ||
{ X86_FEATURE_AVX512_4FMAPS, X86_FEATURE_AVX512F }, | ||
{ X86_FEATURE_AVX512_VPOPCNTDQ, X86_FEATURE_AVX512F }, | ||
{} | ||
}; | ||
|
||
static inline void __clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit) | ||
{ | ||
clear_bit32(bit, c->x86_capability); | ||
} | ||
|
||
static inline void __setup_clear_cpu_cap(unsigned int bit) | ||
{ | ||
clear_cpu_cap(&boot_cpu_data, bit); | ||
set_bit32(bit, cpu_caps_cleared); | ||
} | ||
|
||
static inline void clear_feature(struct cpuinfo_x86 *c, unsigned int feature) | ||
{ | ||
if (!c) | ||
__setup_clear_cpu_cap(feature); | ||
else | ||
__clear_cpu_cap(c, feature); | ||
} | ||
|
||
static void do_clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature) | ||
{ | ||
bool changed; | ||
DECLARE_BITMAP(disable, NCAPINTS * sizeof(u32) * 8); | ||
const struct cpuid_dep *d; | ||
|
||
clear_feature(c, feature); | ||
|
||
/* Collect all features to disable, handling dependencies */ | ||
memset(disable, 0, sizeof(disable)); | ||
__set_bit(feature, disable); | ||
|
||
/* Loop until we get a stable state. */ | ||
do { | ||
changed = false; | ||
for (d = cpuid_deps; d->feature; d++) { | ||
if (!test_bit(d->depends, disable)) | ||
continue; | ||
if (__test_and_set_bit(d->feature, disable)) | ||
continue; | ||
|
||
changed = true; | ||
clear_feature(c, d->feature); | ||
} | ||
} while (changed); | ||
} | ||
|
||
void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature) | ||
{ | ||
do_clear_cpu_cap(c, feature); | ||
} | ||
|
||
void setup_clear_cpu_cap(unsigned int feature) | ||
{ | ||
do_clear_cpu_cap(NULL, feature); | ||
} |