1 | /* |
2 | * Routines to identify additional cpu features that are scattered in |
3 | * cpuid space. |
4 | */ |
5 | #include <linux/cpu.h> |
6 | |
7 | #include <asm/memtype.h> |
8 | #include <asm/apic.h> |
9 | #include <asm/processor.h> |
10 | |
11 | #include "cpu.h" |
12 | |
13 | struct cpuid_bit { |
14 | u16 feature; |
15 | u8 reg; |
16 | u8 bit; |
17 | u32 level; |
18 | u32 sub_leaf; |
19 | }; |
20 | |
21 | /* |
22 | * Please keep the leaf sorted by cpuid_bit.level for faster search. |
23 | * X86_FEATURE_MBA is supported by both Intel and AMD. But the CPUID |
24 | * levels are different and there is a separate entry for each. |
25 | */ |
26 | static const struct cpuid_bit cpuid_bits[] = { |
27 | { X86_FEATURE_APERFMPERF, CPUID_ECX, 0, 0x00000006, 0 }, |
28 | { X86_FEATURE_EPB, CPUID_ECX, 3, 0x00000006, 0 }, |
29 | { X86_FEATURE_INTEL_PPIN, CPUID_EBX, 0, 0x00000007, 1 }, |
30 | { X86_FEATURE_RRSBA_CTRL, CPUID_EDX, 2, 0x00000007, 2 }, |
31 | { X86_FEATURE_BHI_CTRL, CPUID_EDX, 4, 0x00000007, 2 }, |
32 | { X86_FEATURE_CQM_LLC, CPUID_EDX, 1, 0x0000000f, 0 }, |
33 | { X86_FEATURE_CQM_OCCUP_LLC, CPUID_EDX, 0, 0x0000000f, 1 }, |
34 | { X86_FEATURE_CQM_MBM_TOTAL, CPUID_EDX, 1, 0x0000000f, 1 }, |
35 | { X86_FEATURE_CQM_MBM_LOCAL, CPUID_EDX, 2, 0x0000000f, 1 }, |
36 | { X86_FEATURE_CAT_L3, CPUID_EBX, 1, 0x00000010, 0 }, |
37 | { X86_FEATURE_CAT_L2, CPUID_EBX, 2, 0x00000010, 0 }, |
38 | { X86_FEATURE_CDP_L3, CPUID_ECX, 2, 0x00000010, 1 }, |
39 | { X86_FEATURE_CDP_L2, CPUID_ECX, 2, 0x00000010, 2 }, |
40 | { X86_FEATURE_MBA, CPUID_EBX, 3, 0x00000010, 0 }, |
41 | { X86_FEATURE_PER_THREAD_MBA, CPUID_ECX, 0, 0x00000010, 3 }, |
42 | { X86_FEATURE_SGX1, CPUID_EAX, 0, 0x00000012, 0 }, |
43 | { X86_FEATURE_SGX2, CPUID_EAX, 1, 0x00000012, 0 }, |
44 | { X86_FEATURE_SGX_EDECCSSA, CPUID_EAX, 11, 0x00000012, 0 }, |
45 | { X86_FEATURE_HW_PSTATE, CPUID_EDX, 7, 0x80000007, 0 }, |
46 | { X86_FEATURE_CPB, CPUID_EDX, 9, 0x80000007, 0 }, |
47 | { X86_FEATURE_PROC_FEEDBACK, CPUID_EDX, 11, 0x80000007, 0 }, |
48 | { X86_FEATURE_MBA, CPUID_EBX, 6, 0x80000008, 0 }, |
49 | { X86_FEATURE_SMBA, CPUID_EBX, 2, 0x80000020, 0 }, |
50 | { X86_FEATURE_BMEC, CPUID_EBX, 3, 0x80000020, 0 }, |
51 | { X86_FEATURE_PERFMON_V2, CPUID_EAX, 0, 0x80000022, 0 }, |
52 | { X86_FEATURE_AMD_LBR_V2, CPUID_EAX, 1, 0x80000022, 0 }, |
53 | { X86_FEATURE_AMD_LBR_PMC_FREEZE, CPUID_EAX, 2, 0x80000022, 0 }, |
54 | { 0, 0, 0, 0, 0 } |
55 | }; |
56 | |
57 | void init_scattered_cpuid_features(struct cpuinfo_x86 *c) |
58 | { |
59 | u32 max_level; |
60 | u32 regs[4]; |
61 | const struct cpuid_bit *cb; |
62 | |
63 | for (cb = cpuid_bits; cb->feature; cb++) { |
64 | |
65 | /* Verify that the level is valid */ |
66 | max_level = cpuid_eax(op: cb->level & 0xffff0000); |
67 | if (max_level < cb->level || |
68 | max_level > (cb->level | 0xffff)) |
69 | continue; |
70 | |
71 | cpuid_count(op: cb->level, count: cb->sub_leaf, eax: ®s[CPUID_EAX], |
72 | ebx: ®s[CPUID_EBX], ecx: ®s[CPUID_ECX], |
73 | edx: ®s[CPUID_EDX]); |
74 | |
75 | if (regs[cb->reg] & (1 << cb->bit)) |
76 | set_cpu_cap(c, cb->feature); |
77 | } |
78 | } |
79 | |