1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
25
26#include <linux/kernfs.h>
27#include <linux/seq_file.h>
28#include <linux/slab.h>
29#include "intel_rdt.h"
30
31
32
33
34
35
36
37static bool bw_validate(char *buf, unsigned long *data, struct rdt_resource *r)
38{
39 unsigned long bw;
40 int ret;
41
42
43
44
45 if (!r->membw.delay_linear) {
46 rdt_last_cmd_puts("No support for non-linear MB domains\n");
47 return false;
48 }
49
50 ret = kstrtoul(buf, 10, &bw);
51 if (ret) {
52 rdt_last_cmd_printf("Non-decimal digit in MB value %s\n", buf);
53 return false;
54 }
55
56 if ((bw < r->membw.min_bw || bw > r->default_ctrl) &&
57 !is_mba_sc(r)) {
58 rdt_last_cmd_printf("MB value %ld out of range [%d,%d]\n", bw,
59 r->membw.min_bw, r->default_ctrl);
60 return false;
61 }
62
63 *data = roundup(bw, (unsigned long)r->membw.bw_gran);
64 return true;
65}
66
67int parse_bw(struct rdt_parse_data *data, struct rdt_resource *r,
68 struct rdt_domain *d)
69{
70 unsigned long bw_val;
71
72 if (d->have_new_ctrl) {
73 rdt_last_cmd_printf("duplicate domain %d\n", d->id);
74 return -EINVAL;
75 }
76
77 if (!bw_validate(data->buf, &bw_val, r))
78 return -EINVAL;
79 d->new_ctrl = bw_val;
80 d->have_new_ctrl = true;
81
82 return 0;
83}
84
85
86
87
88
89
90
91static bool cbm_validate(char *buf, u32 *data, struct rdt_resource *r)
92{
93 unsigned long first_bit, zero_bit, val;
94 unsigned int cbm_len = r->cache.cbm_len;
95 int ret;
96
97 ret = kstrtoul(buf, 16, &val);
98 if (ret) {
99 rdt_last_cmd_printf("non-hex character in mask %s\n", buf);
100 return false;
101 }
102
103 if (val == 0 || val > r->default_ctrl) {
104 rdt_last_cmd_puts("mask out of range\n");
105 return false;
106 }
107
108 first_bit = find_first_bit(&val, cbm_len);
109 zero_bit = find_next_zero_bit(&val, cbm_len, first_bit);
110
111 if (find_next_bit(&val, cbm_len, zero_bit) < cbm_len) {
112 rdt_last_cmd_printf("mask %lx has non-consecutive 1-bits\n", val);
113 return false;
114 }
115
116 if ((zero_bit - first_bit) < r->cache.min_cbm_bits) {
117 rdt_last_cmd_printf("Need at least %d bits in mask\n",
118 r->cache.min_cbm_bits);
119 return false;
120 }
121
122 *data = val;
123 return true;
124}
125
126
127
128
129
130int parse_cbm(struct rdt_parse_data *data, struct rdt_resource *r,
131 struct rdt_domain *d)
132{
133 struct rdtgroup *rdtgrp = data->rdtgrp;
134 u32 cbm_val;
135
136 if (d->have_new_ctrl) {
137 rdt_last_cmd_printf("duplicate domain %d\n", d->id);
138 return -EINVAL;
139 }
140
141
142
143
144
145 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP &&
146 rdtgroup_pseudo_locked_in_hierarchy(d)) {
147 rdt_last_cmd_printf("pseudo-locked region in hierarchy\n");
148 return -EINVAL;
149 }
150
151 if (!cbm_validate(data->buf, &cbm_val, r))
152 return -EINVAL;
153
154 if ((rdtgrp->mode == RDT_MODE_EXCLUSIVE ||
155 rdtgrp->mode == RDT_MODE_SHAREABLE) &&
156 rdtgroup_cbm_overlaps_pseudo_locked(d, cbm_val)) {
157 rdt_last_cmd_printf("CBM overlaps with pseudo-locked region\n");
158 return -EINVAL;
159 }
160
161
162
163
164
165 if (rdtgroup_cbm_overlaps(r, d, cbm_val, rdtgrp->closid, true)) {
166 rdt_last_cmd_printf("overlaps with exclusive group\n");
167 return -EINVAL;
168 }
169
170 if (rdtgroup_cbm_overlaps(r, d, cbm_val, rdtgrp->closid, false)) {
171 if (rdtgrp->mode == RDT_MODE_EXCLUSIVE ||
172 rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
173 rdt_last_cmd_printf("overlaps with other group\n");
174 return -EINVAL;
175 }
176 }
177
178 d->new_ctrl = cbm_val;
179 d->have_new_ctrl = true;
180
181 return 0;
182}
183
184
185
186
187
188
189
190static int parse_line(char *line, struct rdt_resource *r,
191 struct rdtgroup *rdtgrp)
192{
193 struct rdt_parse_data data;
194 char *dom = NULL, *id;
195 struct rdt_domain *d;
196 unsigned long dom_id;
197
198 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP &&
199 r->rid == RDT_RESOURCE_MBA) {
200 rdt_last_cmd_puts("Cannot pseudo-lock MBA resource\n");
201 return -EINVAL;
202 }
203
204next:
205 if (!line || line[0] == '\0')
206 return 0;
207 dom = strsep(&line, ";");
208 id = strsep(&dom, "=");
209 if (!dom || kstrtoul(id, 10, &dom_id)) {
210 rdt_last_cmd_puts("Missing '=' or non-numeric domain\n");
211 return -EINVAL;
212 }
213 dom = strim(dom);
214 list_for_each_entry(d, &r->domains, list) {
215 if (d->id == dom_id) {
216 data.buf = dom;
217 data.rdtgrp = rdtgrp;
218 if (r->parse_ctrlval(&data, r, d))
219 return -EINVAL;
220 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
221
222
223
224
225
226
227
228
229 rdtgrp->plr->r = r;
230 rdtgrp->plr->d = d;
231 rdtgrp->plr->cbm = d->new_ctrl;
232 d->plr = rdtgrp->plr;
233 return 0;
234 }
235 goto next;
236 }
237 }
238 return -EINVAL;
239}
240
241int update_domains(struct rdt_resource *r, int closid)
242{
243 struct msr_param msr_param;
244 cpumask_var_t cpu_mask;
245 struct rdt_domain *d;
246 bool mba_sc;
247 u32 *dc;
248 int cpu;
249
250 if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
251 return -ENOMEM;
252
253 msr_param.low = closid;
254 msr_param.high = msr_param.low + 1;
255 msr_param.res = r;
256
257 mba_sc = is_mba_sc(r);
258 list_for_each_entry(d, &r->domains, list) {
259 dc = !mba_sc ? d->ctrl_val : d->mbps_val;
260 if (d->have_new_ctrl && d->new_ctrl != dc[closid]) {
261 cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
262 dc[closid] = d->new_ctrl;
263 }
264 }
265
266
267
268
269
270 if (cpumask_empty(cpu_mask) || mba_sc)
271 goto done;
272 cpu = get_cpu();
273
274 if (cpumask_test_cpu(cpu, cpu_mask))
275 rdt_ctrl_update(&msr_param);
276
277 smp_call_function_many(cpu_mask, rdt_ctrl_update, &msr_param, 1);
278 put_cpu();
279
280done:
281 free_cpumask_var(cpu_mask);
282
283 return 0;
284}
285
286static int rdtgroup_parse_resource(char *resname, char *tok,
287 struct rdtgroup *rdtgrp)
288{
289 struct rdt_resource *r;
290
291 for_each_alloc_enabled_rdt_resource(r) {
292 if (!strcmp(resname, r->name) && rdtgrp->closid < r->num_closid)
293 return parse_line(tok, r, rdtgrp);
294 }
295 rdt_last_cmd_printf("unknown/unsupported resource name '%s'\n", resname);
296 return -EINVAL;
297}
298
299ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
300 char *buf, size_t nbytes, loff_t off)
301{
302 struct rdtgroup *rdtgrp;
303 struct rdt_domain *dom;
304 struct rdt_resource *r;
305 char *tok, *resname;
306 int ret = 0;
307
308
309 if (nbytes == 0 || buf[nbytes - 1] != '\n')
310 return -EINVAL;
311 buf[nbytes - 1] = '\0';
312
313 rdtgrp = rdtgroup_kn_lock_live(of->kn);
314 if (!rdtgrp) {
315 rdtgroup_kn_unlock(of->kn);
316 return -ENOENT;
317 }
318 rdt_last_cmd_clear();
319
320
321
322
323
324 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
325 ret = -EINVAL;
326 rdt_last_cmd_puts("resource group is pseudo-locked\n");
327 goto out;
328 }
329
330 for_each_alloc_enabled_rdt_resource(r) {
331 list_for_each_entry(dom, &r->domains, list)
332 dom->have_new_ctrl = false;
333 }
334
335 while ((tok = strsep(&buf, "\n")) != NULL) {
336 resname = strim(strsep(&tok, ":"));
337 if (!tok) {
338 rdt_last_cmd_puts("Missing ':'\n");
339 ret = -EINVAL;
340 goto out;
341 }
342 if (tok[0] == '\0') {
343 rdt_last_cmd_printf("Missing '%s' value\n", resname);
344 ret = -EINVAL;
345 goto out;
346 }
347 ret = rdtgroup_parse_resource(resname, tok, rdtgrp);
348 if (ret)
349 goto out;
350 }
351
352 for_each_alloc_enabled_rdt_resource(r) {
353 ret = update_domains(r, rdtgrp->closid);
354 if (ret)
355 goto out;
356 }
357
358 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
359
360
361
362
363
364
365 ret = rdtgroup_pseudo_lock_create(rdtgrp);
366 }
367
368out:
369 rdtgroup_kn_unlock(of->kn);
370 return ret ?: nbytes;
371}
372
373static void show_doms(struct seq_file *s, struct rdt_resource *r, int closid)
374{
375 struct rdt_domain *dom;
376 bool sep = false;
377 u32 ctrl_val;
378
379 seq_printf(s, "%*s:", max_name_width, r->name);
380 list_for_each_entry(dom, &r->domains, list) {
381 if (sep)
382 seq_puts(s, ";");
383
384 ctrl_val = (!is_mba_sc(r) ? dom->ctrl_val[closid] :
385 dom->mbps_val[closid]);
386 seq_printf(s, r->format_str, dom->id, max_data_width,
387 ctrl_val);
388 sep = true;
389 }
390 seq_puts(s, "\n");
391}
392
393int rdtgroup_schemata_show(struct kernfs_open_file *of,
394 struct seq_file *s, void *v)
395{
396 struct rdtgroup *rdtgrp;
397 struct rdt_resource *r;
398 int ret = 0;
399 u32 closid;
400
401 rdtgrp = rdtgroup_kn_lock_live(of->kn);
402 if (rdtgrp) {
403 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
404 for_each_alloc_enabled_rdt_resource(r)
405 seq_printf(s, "%s:uninitialized\n", r->name);
406 } else if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
407 seq_printf(s, "%s:%d=%x\n", rdtgrp->plr->r->name,
408 rdtgrp->plr->d->id, rdtgrp->plr->cbm);
409 } else {
410 closid = rdtgrp->closid;
411 for_each_alloc_enabled_rdt_resource(r) {
412 if (closid < r->num_closid)
413 show_doms(s, r, closid);
414 }
415 }
416 } else {
417 ret = -ENOENT;
418 }
419 rdtgroup_kn_unlock(of->kn);
420 return ret;
421}
422
423void mon_event_read(struct rmid_read *rr, struct rdt_domain *d,
424 struct rdtgroup *rdtgrp, int evtid, int first)
425{
426
427
428
429 rr->rgrp = rdtgrp;
430 rr->evtid = evtid;
431 rr->d = d;
432 rr->val = 0;
433 rr->first = first;
434
435 smp_call_function_any(&d->cpu_mask, mon_event_count, rr, 1);
436}
437
438int rdtgroup_mondata_show(struct seq_file *m, void *arg)
439{
440 struct kernfs_open_file *of = m->private;
441 u32 resid, evtid, domid;
442 struct rdtgroup *rdtgrp;
443 struct rdt_resource *r;
444 union mon_data_bits md;
445 struct rdt_domain *d;
446 struct rmid_read rr;
447 int ret = 0;
448
449 rdtgrp = rdtgroup_kn_lock_live(of->kn);
450
451 md.priv = of->kn->priv;
452 resid = md.u.rid;
453 domid = md.u.domid;
454 evtid = md.u.evtid;
455
456 r = &rdt_resources_all[resid];
457 d = rdt_find_domain(r, domid, NULL);
458 if (!d) {
459 ret = -ENOENT;
460 goto out;
461 }
462
463 mon_event_read(&rr, d, rdtgrp, evtid, false);
464
465 if (rr.val & RMID_VAL_ERROR)
466 seq_puts(m, "Error\n");
467 else if (rr.val & RMID_VAL_UNAVAIL)
468 seq_puts(m, "Unavailable\n");
469 else
470 seq_printf(m, "%llu\n", rr.val * r->mon_scale);
471
472out:
473 rdtgroup_kn_unlock(of->kn);
474 return ret;
475}
476