]>
Commit | Line | Data |
---|---|---|
78e99b4a FY |
1 | /* |
2 | * Resource Director Technology(RDT) | |
3 | * - Cache Allocation code. | |
4 | * | |
5 | * Copyright (C) 2016 Intel Corporation | |
6 | * | |
7 | * Authors: | |
8 | * Fenghua Yu <fenghua.yu@intel.com> | |
9 | * Tony Luck <tony.luck@intel.com> | |
10 | * Vikas Shivappa <vikas.shivappa@intel.com> | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or modify it | |
13 | * under the terms and conditions of the GNU General Public License, | |
14 | * version 2, as published by the Free Software Foundation. | |
15 | * | |
16 | * This program is distributed in the hope it will be useful, but WITHOUT | |
17 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
18 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
19 | * more details. | |
20 | * | |
21 | * More information about RDT be found in the Intel (R) x86 Architecture | |
22 | * Software Developer Manual June 2016, volume 3, section 17.17. | |
23 | */ | |
24 | ||
25 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
26 | ||
27 | #include <linux/slab.h> | |
28 | #include <linux/err.h> | |
29 | ||
113c6097 FY |
30 | #include <asm/intel_rdt_common.h> |
31 | #include <asm/intel-family.h> | |
32 | #include <asm/intel_rdt.h> | |
33 | ||
c1c7c3f9 FY |
34 | #define domain_init(id) LIST_HEAD_INIT(rdt_resources_all[id].domains) |
35 | ||
36 | struct rdt_resource rdt_resources_all[] = { | |
37 | { | |
38 | .name = "L3", | |
39 | .domains = domain_init(RDT_RESOURCE_L3), | |
40 | .msr_base = IA32_L3_CBM_BASE, | |
41 | .min_cbm_bits = 1, | |
42 | .cache_level = 3, | |
43 | .cbm_idx_multi = 1, | |
44 | .cbm_idx_offset = 0 | |
45 | }, | |
46 | { | |
47 | .name = "L3DATA", | |
48 | .domains = domain_init(RDT_RESOURCE_L3DATA), | |
49 | .msr_base = IA32_L3_CBM_BASE, | |
50 | .min_cbm_bits = 1, | |
51 | .cache_level = 3, | |
52 | .cbm_idx_multi = 2, | |
53 | .cbm_idx_offset = 0 | |
54 | }, | |
55 | { | |
56 | .name = "L3CODE", | |
57 | .domains = domain_init(RDT_RESOURCE_L3CODE), | |
58 | .msr_base = IA32_L3_CBM_BASE, | |
59 | .min_cbm_bits = 1, | |
60 | .cache_level = 3, | |
61 | .cbm_idx_multi = 2, | |
62 | .cbm_idx_offset = 1 | |
63 | }, | |
64 | { | |
65 | .name = "L2", | |
66 | .domains = domain_init(RDT_RESOURCE_L2), | |
67 | .msr_base = IA32_L2_CBM_BASE, | |
68 | .min_cbm_bits = 1, | |
69 | .cache_level = 2, | |
70 | .cbm_idx_multi = 1, | |
71 | .cbm_idx_offset = 0 | |
72 | }, | |
73 | }; | |
74 | ||
113c6097 FY |
75 | /* |
76 | * cache_alloc_hsw_probe() - Have to probe for Intel haswell server CPUs | |
77 | * as they do not have CPUID enumeration support for Cache allocation. | |
78 | * The check for Vendor/Family/Model is not enough to guarantee that | |
79 | * the MSRs won't #GP fault because only the following SKUs support | |
80 | * CAT: | |
81 | * Intel(R) Xeon(R) CPU E5-2658 v3 @ 2.20GHz | |
82 | * Intel(R) Xeon(R) CPU E5-2648L v3 @ 1.80GHz | |
83 | * Intel(R) Xeon(R) CPU E5-2628L v3 @ 2.00GHz | |
84 | * Intel(R) Xeon(R) CPU E5-2618L v3 @ 2.30GHz | |
85 | * Intel(R) Xeon(R) CPU E5-2608L v3 @ 2.00GHz | |
86 | * Intel(R) Xeon(R) CPU E5-2658A v3 @ 2.20GHz | |
87 | * | |
88 | * Probe by trying to write the first of the L3 cach mask registers | |
89 | * and checking that the bits stick. Max CLOSids is always 4 and max cbm length | |
90 | * is always 20 on hsw server parts. The minimum cache bitmask length | |
91 | * allowed for HSW server is always 2 bits. Hardcode all of them. | |
92 | */ | |
93 | static inline bool cache_alloc_hsw_probe(void) | |
94 | { | |
95 | if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && | |
96 | boot_cpu_data.x86 == 6 && | |
97 | boot_cpu_data.x86_model == INTEL_FAM6_HASWELL_X) { | |
c1c7c3f9 | 98 | struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3]; |
113c6097 FY |
99 | u32 l, h, max_cbm = BIT_MASK(20) - 1; |
100 | ||
101 | if (wrmsr_safe(IA32_L3_CBM_BASE, max_cbm, 0)) | |
102 | return false; | |
103 | rdmsr(IA32_L3_CBM_BASE, l, h); | |
104 | ||
105 | /* If all the bits were set in MSR, return success */ | |
c1c7c3f9 FY |
106 | if (l != max_cbm) |
107 | return false; | |
108 | ||
109 | r->num_closid = 4; | |
110 | r->cbm_len = 20; | |
111 | r->max_cbm = max_cbm; | |
112 | r->min_cbm_bits = 2; | |
113 | r->capable = true; | |
114 | r->enabled = true; | |
115 | ||
116 | return true; | |
113c6097 FY |
117 | } |
118 | ||
119 | return false; | |
120 | } | |
121 | ||
c1c7c3f9 FY |
122 | static void rdt_get_config(int idx, struct rdt_resource *r) |
123 | { | |
124 | union cpuid_0x10_1_eax eax; | |
125 | union cpuid_0x10_1_edx edx; | |
126 | u32 ebx, ecx; | |
127 | ||
128 | cpuid_count(0x00000010, idx, &eax.full, &ebx, &ecx, &edx.full); | |
129 | r->num_closid = edx.split.cos_max + 1; | |
130 | r->cbm_len = eax.split.cbm_len + 1; | |
131 | r->max_cbm = BIT_MASK(eax.split.cbm_len + 1) - 1; | |
132 | r->capable = true; | |
133 | r->enabled = true; | |
134 | } | |
135 | ||
136 | static void rdt_get_cdp_l3_config(int type) | |
137 | { | |
138 | struct rdt_resource *r_l3 = &rdt_resources_all[RDT_RESOURCE_L3]; | |
139 | struct rdt_resource *r = &rdt_resources_all[type]; | |
140 | ||
141 | r->num_closid = r_l3->num_closid / 2; | |
142 | r->cbm_len = r_l3->cbm_len; | |
143 | r->max_cbm = r_l3->max_cbm; | |
144 | r->capable = true; | |
145 | /* | |
146 | * By default, CDP is disabled. CDP can be enabled by mount parameter | |
147 | * "cdp" during resctrl file system mount time. | |
148 | */ | |
149 | r->enabled = false; | |
150 | } | |
151 | ||
78e99b4a FY |
152 | static inline bool get_rdt_resources(void) |
153 | { | |
c1c7c3f9 FY |
154 | bool ret = false; |
155 | ||
113c6097 FY |
156 | if (cache_alloc_hsw_probe()) |
157 | return true; | |
78e99b4a FY |
158 | |
159 | if (!boot_cpu_has(X86_FEATURE_RDT_A)) | |
160 | return false; | |
78e99b4a | 161 | |
c1c7c3f9 FY |
162 | if (boot_cpu_has(X86_FEATURE_CAT_L3)) { |
163 | rdt_get_config(1, &rdt_resources_all[RDT_RESOURCE_L3]); | |
164 | if (boot_cpu_has(X86_FEATURE_CDP_L3)) { | |
165 | rdt_get_cdp_l3_config(RDT_RESOURCE_L3DATA); | |
166 | rdt_get_cdp_l3_config(RDT_RESOURCE_L3CODE); | |
167 | } | |
168 | ret = true; | |
169 | } | |
170 | if (boot_cpu_has(X86_FEATURE_CAT_L2)) { | |
171 | /* CPUID 0x10.2 fields are same format at 0x10.1 */ | |
172 | rdt_get_config(2, &rdt_resources_all[RDT_RESOURCE_L2]); | |
173 | ret = true; | |
174 | } | |
175 | ||
176 | return ret; | |
78e99b4a FY |
177 | } |
178 | ||
179 | static int __init intel_rdt_late_init(void) | |
180 | { | |
c1c7c3f9 FY |
181 | struct rdt_resource *r; |
182 | ||
78e99b4a FY |
183 | if (!get_rdt_resources()) |
184 | return -ENODEV; | |
185 | ||
c1c7c3f9 FY |
186 | for_each_capable_rdt_resource(r) |
187 | pr_info("Intel RDT %s allocation detected\n", r->name); | |
78e99b4a FY |
188 | |
189 | return 0; | |
190 | } | |
191 | ||
192 | late_initcall(intel_rdt_late_init); |