| 1 | /* Declare dependencies between CPUIDs */ | 
|---|
| 2 | #include <linux/kernel.h> | 
|---|
| 3 | #include <linux/init.h> | 
|---|
| 4 | #include <linux/module.h> | 
|---|
| 5 | #include <asm/cpufeature.h> | 
|---|
| 6 |  | 
|---|
| 7 | struct cpuid_dep { | 
|---|
| 8 | unsigned int	feature; | 
|---|
| 9 | unsigned int	depends; | 
|---|
| 10 | }; | 
|---|
| 11 |  | 
|---|
| 12 | /* | 
|---|
| 13 | * Table of CPUID features that depend on others. | 
|---|
| 14 | * | 
|---|
| 15 | * This only includes dependencies that can be usefully disabled, not | 
|---|
| 16 | * features part of the base set (like FPU). | 
|---|
| 17 | * | 
|---|
| 18 | * Note this all is not __init / __initdata because it can be | 
|---|
| 19 | * called from cpu hotplug. It shouldn't do anything in this case, | 
|---|
| 20 | * but it's difficult to tell that to the init reference checker. | 
|---|
| 21 | */ | 
|---|
| 22 | static const struct cpuid_dep cpuid_deps[] = { | 
|---|
| 23 | { X86_FEATURE_FXSR,			X86_FEATURE_FPU	      }, | 
|---|
| 24 | { X86_FEATURE_XSAVEOPT,			X86_FEATURE_XSAVE     }, | 
|---|
| 25 | { X86_FEATURE_XSAVEC,			X86_FEATURE_XSAVE     }, | 
|---|
| 26 | { X86_FEATURE_XSAVES,			X86_FEATURE_XSAVE     }, | 
|---|
| 27 | { X86_FEATURE_AVX,			X86_FEATURE_XSAVE     }, | 
|---|
| 28 | { X86_FEATURE_PKU,			X86_FEATURE_XSAVE     }, | 
|---|
| 29 | { X86_FEATURE_MPX,			X86_FEATURE_XSAVE     }, | 
|---|
| 30 | { X86_FEATURE_XGETBV1,			X86_FEATURE_XSAVE     }, | 
|---|
| 31 | { X86_FEATURE_APX,			X86_FEATURE_XSAVE     }, | 
|---|
| 32 | { X86_FEATURE_CMOV,			X86_FEATURE_FXSR      }, | 
|---|
| 33 | { X86_FEATURE_MMX,			X86_FEATURE_FXSR      }, | 
|---|
| 34 | { X86_FEATURE_MMXEXT,			X86_FEATURE_MMX       }, | 
|---|
| 35 | { X86_FEATURE_FXSR_OPT,			X86_FEATURE_FXSR      }, | 
|---|
| 36 | { X86_FEATURE_XSAVE,			X86_FEATURE_FXSR      }, | 
|---|
| 37 | { X86_FEATURE_XMM,			X86_FEATURE_FXSR      }, | 
|---|
| 38 | { X86_FEATURE_XMM2,			X86_FEATURE_XMM       }, | 
|---|
| 39 | { X86_FEATURE_XMM3,			X86_FEATURE_XMM2      }, | 
|---|
| 40 | { X86_FEATURE_XMM4_1,			X86_FEATURE_XMM2      }, | 
|---|
| 41 | { X86_FEATURE_XMM4_2,			X86_FEATURE_XMM2      }, | 
|---|
| 42 | { X86_FEATURE_XMM3,			X86_FEATURE_XMM2      }, | 
|---|
| 43 | { X86_FEATURE_PCLMULQDQ,		X86_FEATURE_XMM2      }, | 
|---|
| 44 | { X86_FEATURE_SSSE3,			X86_FEATURE_XMM2,     }, | 
|---|
| 45 | { X86_FEATURE_F16C,			X86_FEATURE_XMM2,     }, | 
|---|
| 46 | { X86_FEATURE_AES,			X86_FEATURE_XMM2      }, | 
|---|
| 47 | { X86_FEATURE_SHA_NI,			X86_FEATURE_XMM2      }, | 
|---|
| 48 | { X86_FEATURE_GFNI,			X86_FEATURE_XMM2      }, | 
|---|
| 49 | { X86_FEATURE_AVX_VNNI,			X86_FEATURE_AVX       }, | 
|---|
| 50 | { X86_FEATURE_FMA,			X86_FEATURE_AVX       }, | 
|---|
| 51 | { X86_FEATURE_VAES,			X86_FEATURE_AVX       }, | 
|---|
| 52 | { X86_FEATURE_VPCLMULQDQ,		X86_FEATURE_AVX       }, | 
|---|
| 53 | { X86_FEATURE_AVX2,			X86_FEATURE_AVX,      }, | 
|---|
| 54 | { X86_FEATURE_AVX512F,			X86_FEATURE_AVX,      }, | 
|---|
| 55 | { X86_FEATURE_AVX512IFMA,		X86_FEATURE_AVX512F   }, | 
|---|
| 56 | { X86_FEATURE_AVX512PF,			X86_FEATURE_AVX512F   }, | 
|---|
| 57 | { X86_FEATURE_AVX512ER,			X86_FEATURE_AVX512F   }, | 
|---|
| 58 | { X86_FEATURE_AVX512CD,			X86_FEATURE_AVX512F   }, | 
|---|
| 59 | { X86_FEATURE_AVX512DQ,			X86_FEATURE_AVX512F   }, | 
|---|
| 60 | { X86_FEATURE_AVX512BW,			X86_FEATURE_AVX512F   }, | 
|---|
| 61 | { X86_FEATURE_AVX512VL,			X86_FEATURE_AVX512F   }, | 
|---|
| 62 | { X86_FEATURE_AVX512VBMI,		X86_FEATURE_AVX512F   }, | 
|---|
| 63 | { X86_FEATURE_AVX512_VBMI2,		X86_FEATURE_AVX512VL  }, | 
|---|
| 64 | { X86_FEATURE_AVX512_VNNI,		X86_FEATURE_AVX512VL  }, | 
|---|
| 65 | { X86_FEATURE_AVX512_BITALG,		X86_FEATURE_AVX512VL  }, | 
|---|
| 66 | { X86_FEATURE_AVX512_4VNNIW,		X86_FEATURE_AVX512F   }, | 
|---|
| 67 | { X86_FEATURE_AVX512_4FMAPS,		X86_FEATURE_AVX512F   }, | 
|---|
| 68 | { X86_FEATURE_AVX512_VPOPCNTDQ,		X86_FEATURE_AVX512F   }, | 
|---|
| 69 | { X86_FEATURE_AVX512_VP2INTERSECT,	X86_FEATURE_AVX512VL  }, | 
|---|
| 70 | { X86_FEATURE_CQM_OCCUP_LLC,		X86_FEATURE_CQM_LLC   }, | 
|---|
| 71 | { X86_FEATURE_CQM_MBM_TOTAL,		X86_FEATURE_CQM_LLC   }, | 
|---|
| 72 | { X86_FEATURE_CQM_MBM_LOCAL,		X86_FEATURE_CQM_LLC   }, | 
|---|
| 73 | { X86_FEATURE_BMEC,			X86_FEATURE_CQM_MBM_TOTAL   }, | 
|---|
| 74 | { X86_FEATURE_BMEC,			X86_FEATURE_CQM_MBM_LOCAL   }, | 
|---|
| 75 | { X86_FEATURE_AVX512_BF16,		X86_FEATURE_AVX512VL  }, | 
|---|
| 76 | { X86_FEATURE_AVX512_FP16,		X86_FEATURE_AVX512BW  }, | 
|---|
| 77 | { X86_FEATURE_ENQCMD,			X86_FEATURE_XSAVES    }, | 
|---|
| 78 | { X86_FEATURE_PER_THREAD_MBA,		X86_FEATURE_MBA       }, | 
|---|
| 79 | { X86_FEATURE_SGX_LC,			X86_FEATURE_SGX	      }, | 
|---|
| 80 | { X86_FEATURE_SGX1,			X86_FEATURE_SGX       }, | 
|---|
| 81 | { X86_FEATURE_SGX2,			X86_FEATURE_SGX1      }, | 
|---|
| 82 | { X86_FEATURE_SGX_EDECCSSA,		X86_FEATURE_SGX1      }, | 
|---|
| 83 | { X86_FEATURE_XFD,			X86_FEATURE_XSAVES    }, | 
|---|
| 84 | { X86_FEATURE_XFD,			X86_FEATURE_XGETBV1   }, | 
|---|
| 85 | { X86_FEATURE_AMX_TILE,			X86_FEATURE_XFD       }, | 
|---|
| 86 | { X86_FEATURE_AMX_FP16,			X86_FEATURE_AMX_TILE  }, | 
|---|
| 87 | { X86_FEATURE_AMX_BF16,			X86_FEATURE_AMX_TILE  }, | 
|---|
| 88 | { X86_FEATURE_AMX_INT8,			X86_FEATURE_AMX_TILE  }, | 
|---|
| 89 | { X86_FEATURE_SHSTK,			X86_FEATURE_XSAVES    }, | 
|---|
| 90 | { X86_FEATURE_FRED,			X86_FEATURE_LKGS      }, | 
|---|
| 91 | { X86_FEATURE_SPEC_CTRL_SSBD,		X86_FEATURE_SPEC_CTRL }, | 
|---|
| 92 | {} | 
|---|
| 93 | }; | 
|---|
| 94 |  | 
|---|
| 95 | static inline void clear_feature(struct cpuinfo_x86 *c, unsigned int feature) | 
|---|
| 96 | { | 
|---|
| 97 | /* | 
|---|
| 98 | * Note: This could use the non atomic __*_bit() variants, but the | 
|---|
| 99 | * rest of the cpufeature code uses atomics as well, so keep it for | 
|---|
| 100 | * consistency. Cleanup all of it separately. | 
|---|
| 101 | */ | 
|---|
| 102 | if (!c) { | 
|---|
| 103 | clear_cpu_cap(c: &boot_cpu_data, bit: feature); | 
|---|
| 104 | set_bit(nr: feature, addr: (unsigned long *)cpu_caps_cleared); | 
|---|
| 105 | } else { | 
|---|
| 106 | clear_bit(nr: feature, addr: (unsigned long *)c->x86_capability); | 
|---|
| 107 | } | 
|---|
| 108 | } | 
|---|
| 109 |  | 
|---|
| 110 | /* Take the capabilities and the BUG bits into account */ | 
|---|
| 111 | #define MAX_FEATURE_BITS ((NCAPINTS + NBUGINTS) * sizeof(u32) * 8) | 
|---|
| 112 |  | 
|---|
| 113 | static void do_clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature) | 
|---|
| 114 | { | 
|---|
| 115 | DECLARE_BITMAP(disable, MAX_FEATURE_BITS); | 
|---|
| 116 | const struct cpuid_dep *d; | 
|---|
| 117 | bool changed; | 
|---|
| 118 |  | 
|---|
| 119 | if (WARN_ON(feature >= MAX_FEATURE_BITS)) | 
|---|
| 120 | return; | 
|---|
| 121 |  | 
|---|
| 122 | if (boot_cpu_has(feature)) | 
|---|
| 123 | WARN_ON(alternatives_patched); | 
|---|
| 124 |  | 
|---|
| 125 | clear_feature(c, feature); | 
|---|
| 126 |  | 
|---|
| 127 | /* Collect all features to disable, handling dependencies */ | 
|---|
| 128 | memset(s: disable, c: 0, n: sizeof(disable)); | 
|---|
| 129 | __set_bit(feature, disable); | 
|---|
| 130 |  | 
|---|
| 131 | /* Loop until we get a stable state. */ | 
|---|
| 132 | do { | 
|---|
| 133 | changed = false; | 
|---|
| 134 | for (d = cpuid_deps; d->feature; d++) { | 
|---|
| 135 | if (!test_bit(d->depends, disable)) | 
|---|
| 136 | continue; | 
|---|
| 137 | if (__test_and_set_bit(d->feature, disable)) | 
|---|
| 138 | continue; | 
|---|
| 139 |  | 
|---|
| 140 | changed = true; | 
|---|
| 141 | clear_feature(c, feature: d->feature); | 
|---|
| 142 | } | 
|---|
| 143 | } while (changed); | 
|---|
| 144 | } | 
|---|
| 145 |  | 
|---|
| 146 | void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature) | 
|---|
| 147 | { | 
|---|
| 148 | do_clear_cpu_cap(c, feature); | 
|---|
| 149 | } | 
|---|
| 150 |  | 
|---|
| 151 | void setup_clear_cpu_cap(unsigned int feature) | 
|---|
| 152 | { | 
|---|
| 153 | do_clear_cpu_cap(NULL, feature); | 
|---|
| 154 | } | 
|---|
| 155 |  | 
|---|
| 156 | /* | 
|---|
| 157 | * Return the feature "name" if available, otherwise return | 
|---|
| 158 | * the X86_FEATURE_* numerals to make it easier to identify | 
|---|
| 159 | * the feature. | 
|---|
| 160 | */ | 
|---|
| 161 | static const char *x86_feature_name(unsigned int feature, char *buf) | 
|---|
| 162 | { | 
|---|
| 163 | if (x86_cap_flags[feature]) | 
|---|
| 164 | return x86_cap_flags[feature]; | 
|---|
| 165 |  | 
|---|
| 166 | snprintf(buf, size: 16, fmt: "%d*32+%2d", feature / 32, feature % 32); | 
|---|
| 167 |  | 
|---|
| 168 | return buf; | 
|---|
| 169 | } | 
|---|
| 170 |  | 
|---|
| 171 | void check_cpufeature_deps(struct cpuinfo_x86 *c) | 
|---|
| 172 | { | 
|---|
| 173 | char feature_buf[16], depends_buf[16]; | 
|---|
| 174 | const struct cpuid_dep *d; | 
|---|
| 175 |  | 
|---|
| 176 | for (d = cpuid_deps; d->feature; d++) { | 
|---|
| 177 | if (cpu_has(c, d->feature) && !cpu_has(c, d->depends)) { | 
|---|
| 178 | /* | 
|---|
| 179 | * Only warn about the first unmet dependency on the | 
|---|
| 180 | * first CPU where it is encountered to avoid spamming | 
|---|
| 181 | * the kernel log. | 
|---|
| 182 | */ | 
|---|
| 183 | pr_warn_once( "x86 CPU feature dependency check failure: CPU%d has '%s' enabled but '%s' disabled. Kernel might be fine, but no guarantees.\n", | 
|---|
| 184 | smp_processor_id(), | 
|---|
| 185 | x86_feature_name(d->feature, feature_buf), | 
|---|
| 186 | x86_feature_name(d->depends, depends_buf)); | 
|---|
| 187 | } | 
|---|
| 188 | } | 
|---|
| 189 | } | 
|---|
| 190 |  | 
|---|