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