1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * AMD L3 cache_disable_{0,1} sysfs handling
4 * Documentation/ABI/testing/sysfs-devices-system-cpu
5 */
6
7 #include <linux/cacheinfo.h>
8 #include <linux/capability.h>
9 #include <linux/pci.h>
10 #include <linux/sysfs.h>
11
12 #include <asm/amd/nb.h>
13
14 #include "cpu.h"
15
16 /*
17 * L3 cache descriptors
18 */
amd_calc_l3_indices(struct amd_northbridge * nb)19 static void amd_calc_l3_indices(struct amd_northbridge *nb)
20 {
21 struct amd_l3_cache *l3 = &nb->l3_cache;
22 unsigned int sc0, sc1, sc2, sc3;
23 u32 val = 0;
24
25 pci_read_config_dword(nb->misc, 0x1C4, &val);
26
27 /* calculate subcache sizes */
28 l3->subcaches[0] = sc0 = !(val & BIT(0));
29 l3->subcaches[1] = sc1 = !(val & BIT(4));
30
31 if (boot_cpu_data.x86 == 0x15) {
32 l3->subcaches[0] = sc0 += !(val & BIT(1));
33 l3->subcaches[1] = sc1 += !(val & BIT(5));
34 }
35
36 l3->subcaches[2] = sc2 = !(val & BIT(8)) + !(val & BIT(9));
37 l3->subcaches[3] = sc3 = !(val & BIT(12)) + !(val & BIT(13));
38
39 l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1;
40 }
41
42 /*
43 * check whether a slot used for disabling an L3 index is occupied.
44 * @l3: L3 cache descriptor
45 * @slot: slot number (0..1)
46 *
47 * @returns: the disabled index if used or negative value if slot free.
48 */
amd_get_l3_disable_slot(struct amd_northbridge * nb,unsigned int slot)49 static int amd_get_l3_disable_slot(struct amd_northbridge *nb, unsigned int slot)
50 {
51 unsigned int reg = 0;
52
53 pci_read_config_dword(nb->misc, 0x1BC + slot * 4, ®);
54
55 /* check whether this slot is activated already */
56 if (reg & (3UL << 30))
57 return reg & 0xfff;
58
59 return -1;
60 }
61
show_cache_disable(struct cacheinfo * ci,char * buf,unsigned int slot)62 static ssize_t show_cache_disable(struct cacheinfo *ci, char *buf, unsigned int slot)
63 {
64 int index;
65 struct amd_northbridge *nb = ci->priv;
66
67 index = amd_get_l3_disable_slot(nb, slot);
68 if (index >= 0)
69 return sysfs_emit(buf, "%d\n", index);
70
71 return sysfs_emit(buf, "FREE\n");
72 }
73
74 #define SHOW_CACHE_DISABLE(slot) \
75 static ssize_t \
76 cache_disable_##slot##_show(struct device *dev, \
77 struct device_attribute *attr, char *buf) \
78 { \
79 struct cacheinfo *ci = dev_get_drvdata(dev); \
80 return show_cache_disable(ci, buf, slot); \
81 }
82
83 SHOW_CACHE_DISABLE(0)
84 SHOW_CACHE_DISABLE(1)
85
amd_l3_disable_index(struct amd_northbridge * nb,int cpu,unsigned int slot,unsigned long idx)86 static void amd_l3_disable_index(struct amd_northbridge *nb, int cpu,
87 unsigned int slot, unsigned long idx)
88 {
89 int i;
90
91 idx |= BIT(30);
92
93 /*
94 * disable index in all 4 subcaches
95 */
96 for (i = 0; i < 4; i++) {
97 u32 reg = idx | (i << 20);
98
99 if (!nb->l3_cache.subcaches[i])
100 continue;
101
102 pci_write_config_dword(nb->misc, 0x1BC + slot * 4, reg);
103
104 /*
105 * We need to WBINVD on a core on the node containing the L3
106 * cache which indices we disable therefore a simple wbinvd()
107 * is not sufficient.
108 */
109 wbinvd_on_cpu(cpu);
110
111 reg |= BIT(31);
112 pci_write_config_dword(nb->misc, 0x1BC + slot * 4, reg);
113 }
114 }
115
116 /*
117 * disable a L3 cache index by using a disable-slot
118 *
119 * @l3: L3 cache descriptor
120 * @cpu: A CPU on the node containing the L3 cache
121 * @slot: slot number (0..1)
122 * @index: index to disable
123 *
124 * @return: 0 on success, error status on failure
125 */
amd_set_l3_disable_slot(struct amd_northbridge * nb,int cpu,unsigned int slot,unsigned long index)126 static int amd_set_l3_disable_slot(struct amd_northbridge *nb, int cpu,
127 unsigned int slot, unsigned long index)
128 {
129 int ret = 0;
130
131 /* check if @slot is already used or the index is already disabled */
132 ret = amd_get_l3_disable_slot(nb, slot);
133 if (ret >= 0)
134 return -EEXIST;
135
136 if (index > nb->l3_cache.indices)
137 return -EINVAL;
138
139 /* check whether the other slot has disabled the same index already */
140 if (index == amd_get_l3_disable_slot(nb, !slot))
141 return -EEXIST;
142
143 amd_l3_disable_index(nb, cpu, slot, index);
144
145 return 0;
146 }
147
store_cache_disable(struct cacheinfo * ci,const char * buf,size_t count,unsigned int slot)148 static ssize_t store_cache_disable(struct cacheinfo *ci, const char *buf,
149 size_t count, unsigned int slot)
150 {
151 struct amd_northbridge *nb = ci->priv;
152 unsigned long val = 0;
153 int cpu, err = 0;
154
155 if (!capable(CAP_SYS_ADMIN))
156 return -EPERM;
157
158 cpu = cpumask_first(&ci->shared_cpu_map);
159
160 if (kstrtoul(buf, 10, &val) < 0)
161 return -EINVAL;
162
163 err = amd_set_l3_disable_slot(nb, cpu, slot, val);
164 if (err) {
165 if (err == -EEXIST)
166 pr_warn("L3 slot %d in use/index already disabled!\n",
167 slot);
168 return err;
169 }
170 return count;
171 }
172
173 #define STORE_CACHE_DISABLE(slot) \
174 static ssize_t \
175 cache_disable_##slot##_store(struct device *dev, \
176 struct device_attribute *attr, \
177 const char *buf, size_t count) \
178 { \
179 struct cacheinfo *ci = dev_get_drvdata(dev); \
180 return store_cache_disable(ci, buf, count, slot); \
181 }
182
183 STORE_CACHE_DISABLE(0)
184 STORE_CACHE_DISABLE(1)
185
subcaches_show(struct device * dev,struct device_attribute * attr,char * buf)186 static ssize_t subcaches_show(struct device *dev, struct device_attribute *attr,
187 char *buf)
188 {
189 struct cacheinfo *ci = dev_get_drvdata(dev);
190 int cpu = cpumask_first(&ci->shared_cpu_map);
191
192 return sysfs_emit(buf, "%x\n", amd_get_subcaches(cpu));
193 }
194
subcaches_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)195 static ssize_t subcaches_store(struct device *dev,
196 struct device_attribute *attr,
197 const char *buf, size_t count)
198 {
199 struct cacheinfo *ci = dev_get_drvdata(dev);
200 int cpu = cpumask_first(&ci->shared_cpu_map);
201 unsigned long val;
202
203 if (!capable(CAP_SYS_ADMIN))
204 return -EPERM;
205
206 if (kstrtoul(buf, 16, &val) < 0)
207 return -EINVAL;
208
209 if (amd_set_subcaches(cpu, val))
210 return -EINVAL;
211
212 return count;
213 }
214
215 static DEVICE_ATTR_RW(cache_disable_0);
216 static DEVICE_ATTR_RW(cache_disable_1);
217 static DEVICE_ATTR_RW(subcaches);
218
cache_private_attrs_is_visible(struct kobject * kobj,struct attribute * attr,int unused)219 static umode_t cache_private_attrs_is_visible(struct kobject *kobj,
220 struct attribute *attr, int unused)
221 {
222 struct device *dev = kobj_to_dev(kobj);
223 struct cacheinfo *ci = dev_get_drvdata(dev);
224 umode_t mode = attr->mode;
225
226 if (!ci->priv)
227 return 0;
228
229 if ((attr == &dev_attr_subcaches.attr) &&
230 amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
231 return mode;
232
233 if ((attr == &dev_attr_cache_disable_0.attr ||
234 attr == &dev_attr_cache_disable_1.attr) &&
235 amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
236 return mode;
237
238 return 0;
239 }
240
241 static struct attribute_group cache_private_group = {
242 .is_visible = cache_private_attrs_is_visible,
243 };
244
init_amd_l3_attrs(void)245 static void init_amd_l3_attrs(void)
246 {
247 static struct attribute **amd_l3_attrs;
248 int n = 1;
249
250 if (amd_l3_attrs) /* already initialized */
251 return;
252
253 if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
254 n += 2;
255 if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
256 n += 1;
257
258 amd_l3_attrs = kcalloc(n, sizeof(*amd_l3_attrs), GFP_KERNEL);
259 if (!amd_l3_attrs)
260 return;
261
262 n = 0;
263 if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) {
264 amd_l3_attrs[n++] = &dev_attr_cache_disable_0.attr;
265 amd_l3_attrs[n++] = &dev_attr_cache_disable_1.attr;
266 }
267 if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
268 amd_l3_attrs[n++] = &dev_attr_subcaches.attr;
269
270 cache_private_group.attrs = amd_l3_attrs;
271 }
272
cache_get_priv_group(struct cacheinfo * ci)273 const struct attribute_group *cache_get_priv_group(struct cacheinfo *ci)
274 {
275 struct amd_northbridge *nb = ci->priv;
276
277 if (ci->level < 3 || !nb)
278 return NULL;
279
280 if (nb && nb->l3_cache.indices)
281 init_amd_l3_attrs();
282
283 return &cache_private_group;
284 }
285
amd_init_l3_cache(int index)286 struct amd_northbridge *amd_init_l3_cache(int index)
287 {
288 struct amd_northbridge *nb;
289 int node;
290
291 /* only for L3, and not in virtualized environments */
292 if (index < 3)
293 return NULL;
294
295 node = topology_amd_node_id(smp_processor_id());
296 nb = node_to_amd_nb(node);
297 if (nb && !nb->l3_cache.indices)
298 amd_calc_l3_indices(nb);
299
300 return nb;
301 }
302