1 | // SPDX-License-Identifier: GPL-2.0 |
---|---|
2 | /* |
3 | * Intel PCONFIG instruction support. |
4 | * |
5 | * Copyright (C) 2017 Intel Corporation |
6 | * |
7 | * Author: |
8 | * Kirill A. Shutemov <kirill.shutemov@linux.intel.com> |
9 | */ |
10 | |
11 | #include <asm/cpufeature.h> |
12 | #include <asm/intel_pconfig.h> |
13 | |
14 | #define PCONFIG_CPUID 0x1b |
15 | |
16 | #define PCONFIG_CPUID_SUBLEAF_MASK ((1 << 12) - 1) |
17 | |
18 | /* Subleaf type (EAX) for PCONFIG CPUID leaf (0x1B) */ |
19 | enum { |
20 | PCONFIG_CPUID_SUBLEAF_INVALID = 0, |
21 | PCONFIG_CPUID_SUBLEAF_TARGETID = 1, |
22 | }; |
23 | |
24 | /* Bitmask of supported targets */ |
25 | static u64 targets_supported __read_mostly; |
26 | |
27 | int pconfig_target_supported(enum pconfig_target target) |
28 | { |
29 | /* |
30 | * We would need to re-think the implementation once we get > 64 |
31 | * PCONFIG targets. Spec allows up to 2^32 targets. |
32 | */ |
33 | BUILD_BUG_ON(PCONFIG_TARGET_NR >= 64); |
34 | |
35 | if (WARN_ON_ONCE(target >= 64)) |
36 | return 0; |
37 | return targets_supported & (1ULL << target); |
38 | } |
39 | |
40 | static int __init intel_pconfig_init(void) |
41 | { |
42 | int subleaf; |
43 | |
44 | if (!boot_cpu_has(X86_FEATURE_PCONFIG)) |
45 | return 0; |
46 | |
47 | /* |
48 | * Scan subleafs of PCONFIG CPUID leaf. |
49 | * |
50 | * Subleafs of the same type need not to be consecutive. |
51 | * |
52 | * Stop on the first invalid subleaf type. All subleafs after the first |
53 | * invalid are invalid too. |
54 | */ |
55 | for (subleaf = 0; subleaf < INT_MAX; subleaf++) { |
56 | struct cpuid_regs regs; |
57 | |
58 | cpuid_count(PCONFIG_CPUID, count: subleaf, |
59 | eax: ®s.eax, ebx: ®s.ebx, ecx: ®s.ecx, edx: ®s.edx); |
60 | |
61 | switch (regs.eax & PCONFIG_CPUID_SUBLEAF_MASK) { |
62 | case PCONFIG_CPUID_SUBLEAF_INVALID: |
63 | /* Stop on the first invalid subleaf */ |
64 | goto out; |
65 | case PCONFIG_CPUID_SUBLEAF_TARGETID: |
66 | /* Mark supported PCONFIG targets */ |
67 | if (regs.ebx < 64) |
68 | targets_supported |= (1ULL << regs.ebx); |
69 | if (regs.ecx < 64) |
70 | targets_supported |= (1ULL << regs.ecx); |
71 | if (regs.edx < 64) |
72 | targets_supported |= (1ULL << regs.edx); |
73 | break; |
74 | default: |
75 | /* Unknown CPUID.PCONFIG subleaf: ignore */ |
76 | break; |
77 | } |
78 | } |
79 | out: |
80 | return 0; |
81 | } |
82 | arch_initcall(intel_pconfig_init); |
83 |