1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Resource Director Technology(RDT)
4 * - Cache Allocation code.
5 *
6 * Copyright (C) 2016 Intel Corporation
7 *
8 * Authors:
9 * Fenghua Yu <fenghua.yu@intel.com>
10 * Tony Luck <tony.luck@intel.com>
11 *
12 * More information about RDT be found in the Intel (R) x86 Architecture
13 * Software Developer Manual June 2016, volume 3, section 17.17.
14 */
15
16 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17
18 #include <linux/cpu.h>
19 #include <linux/kernfs.h>
20 #include <linux/math.h>
21 #include <linux/seq_file.h>
22 #include <linux/slab.h>
23 #include <linux/tick.h>
24
25 #include "internal.h"
26
27 struct rdt_parse_data {
28 u32 closid;
29 enum rdtgrp_mode mode;
30 char *buf;
31 };
32
33 typedef int (ctrlval_parser_t)(struct rdt_parse_data *data,
34 struct resctrl_schema *s,
35 struct rdt_ctrl_domain *d);
36
37 /*
38 * Check whether MBA bandwidth percentage value is correct. The value is
39 * checked against the minimum and max bandwidth values specified by the
40 * hardware. The allocated bandwidth percentage is rounded to the next
41 * control step available on the hardware.
42 */
bw_validate(char * buf,u32 * data,struct rdt_resource * r)43 static bool bw_validate(char *buf, u32 *data, struct rdt_resource *r)
44 {
45 int ret;
46 u32 bw;
47
48 /*
49 * Only linear delay values is supported for current Intel SKUs.
50 */
51 if (!r->membw.delay_linear && r->membw.arch_needs_linear) {
52 rdt_last_cmd_puts("No support for non-linear MB domains\n");
53 return false;
54 }
55
56 ret = kstrtou32(buf, 10, &bw);
57 if (ret) {
58 rdt_last_cmd_printf("Invalid MB value %s\n", buf);
59 return false;
60 }
61
62 /* Nothing else to do if software controller is enabled. */
63 if (is_mba_sc(r)) {
64 *data = bw;
65 return true;
66 }
67
68 if (bw < r->membw.min_bw || bw > r->membw.max_bw) {
69 rdt_last_cmd_printf("MB value %u out of range [%d,%d]\n",
70 bw, r->membw.min_bw, r->membw.max_bw);
71 return false;
72 }
73
74 *data = roundup(bw, (unsigned long)r->membw.bw_gran);
75 return true;
76 }
77
parse_bw(struct rdt_parse_data * data,struct resctrl_schema * s,struct rdt_ctrl_domain * d)78 static int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s,
79 struct rdt_ctrl_domain *d)
80 {
81 struct resctrl_staged_config *cfg;
82 struct rdt_resource *r = s->res;
83 u32 closid = data->closid;
84 u32 bw_val;
85
86 cfg = &d->staged_config[s->conf_type];
87 if (cfg->have_new_ctrl) {
88 rdt_last_cmd_printf("Duplicate domain %d\n", d->hdr.id);
89 return -EINVAL;
90 }
91
92 if (!bw_validate(data->buf, &bw_val, r))
93 return -EINVAL;
94
95 if (is_mba_sc(r)) {
96 d->mbps_val[closid] = bw_val;
97 return 0;
98 }
99
100 cfg->new_ctrl = bw_val;
101 cfg->have_new_ctrl = true;
102
103 return 0;
104 }
105
106 /*
107 * Check whether a cache bit mask is valid.
108 * On Intel CPUs, non-contiguous 1s value support is indicated by CPUID:
109 * - CPUID.0x10.1:ECX[3]: L3 non-contiguous 1s value supported if 1
110 * - CPUID.0x10.2:ECX[3]: L2 non-contiguous 1s value supported if 1
111 *
112 * Haswell does not support a non-contiguous 1s value and additionally
113 * requires at least two bits set.
114 * AMD allows non-contiguous bitmasks.
115 */
cbm_validate(char * buf,u32 * data,struct rdt_resource * r)116 static bool cbm_validate(char *buf, u32 *data, struct rdt_resource *r)
117 {
118 u32 supported_bits = BIT_MASK(r->cache.cbm_len) - 1;
119 unsigned int cbm_len = r->cache.cbm_len;
120 unsigned long first_bit, zero_bit, val;
121 int ret;
122
123 ret = kstrtoul(buf, 16, &val);
124 if (ret) {
125 rdt_last_cmd_printf("Non-hex character in the mask %s\n", buf);
126 return false;
127 }
128
129 if ((r->cache.min_cbm_bits > 0 && val == 0) || val > supported_bits) {
130 rdt_last_cmd_puts("Mask out of range\n");
131 return false;
132 }
133
134 first_bit = find_first_bit(&val, cbm_len);
135 zero_bit = find_next_zero_bit(&val, cbm_len, first_bit);
136
137 /* Are non-contiguous bitmasks allowed? */
138 if (!r->cache.arch_has_sparse_bitmasks &&
139 (find_next_bit(&val, cbm_len, zero_bit) < cbm_len)) {
140 rdt_last_cmd_printf("The mask %lx has non-consecutive 1-bits\n", val);
141 return false;
142 }
143
144 if ((zero_bit - first_bit) < r->cache.min_cbm_bits) {
145 rdt_last_cmd_printf("Need at least %d bits in the mask\n",
146 r->cache.min_cbm_bits);
147 return false;
148 }
149
150 *data = val;
151 return true;
152 }
153
154 /*
155 * Read one cache bit mask (hex). Check that it is valid for the current
156 * resource type.
157 */
parse_cbm(struct rdt_parse_data * data,struct resctrl_schema * s,struct rdt_ctrl_domain * d)158 static int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s,
159 struct rdt_ctrl_domain *d)
160 {
161 enum rdtgrp_mode mode = data->mode;
162 struct resctrl_staged_config *cfg;
163 struct rdt_resource *r = s->res;
164 u32 closid = data->closid;
165 u32 cbm_val;
166
167 cfg = &d->staged_config[s->conf_type];
168 if (cfg->have_new_ctrl) {
169 rdt_last_cmd_printf("Duplicate domain %d\n", d->hdr.id);
170 return -EINVAL;
171 }
172
173 /*
174 * Cannot set up more than one pseudo-locked region in a cache
175 * hierarchy.
176 */
177 if (mode == RDT_MODE_PSEUDO_LOCKSETUP &&
178 rdtgroup_pseudo_locked_in_hierarchy(d)) {
179 rdt_last_cmd_puts("Pseudo-locked region in hierarchy\n");
180 return -EINVAL;
181 }
182
183 if (!cbm_validate(data->buf, &cbm_val, r))
184 return -EINVAL;
185
186 if ((mode == RDT_MODE_EXCLUSIVE || mode == RDT_MODE_SHAREABLE) &&
187 rdtgroup_cbm_overlaps_pseudo_locked(d, cbm_val)) {
188 rdt_last_cmd_puts("CBM overlaps with pseudo-locked region\n");
189 return -EINVAL;
190 }
191
192 /*
193 * The CBM may not overlap with the CBM of another closid if
194 * either is exclusive.
195 */
196 if (rdtgroup_cbm_overlaps(s, d, cbm_val, closid, true)) {
197 rdt_last_cmd_puts("Overlaps with exclusive group\n");
198 return -EINVAL;
199 }
200
201 if (rdtgroup_cbm_overlaps(s, d, cbm_val, closid, false)) {
202 if (mode == RDT_MODE_EXCLUSIVE ||
203 mode == RDT_MODE_PSEUDO_LOCKSETUP) {
204 rdt_last_cmd_puts("Overlaps with other group\n");
205 return -EINVAL;
206 }
207 }
208
209 cfg->new_ctrl = cbm_val;
210 cfg->have_new_ctrl = true;
211
212 return 0;
213 }
214
215 /*
216 * For each domain in this resource we expect to find a series of:
217 * id=mask
218 * separated by ";". The "id" is in decimal, and must match one of
219 * the "id"s for this resource.
220 */
parse_line(char * line,struct resctrl_schema * s,struct rdtgroup * rdtgrp)221 static int parse_line(char *line, struct resctrl_schema *s,
222 struct rdtgroup *rdtgrp)
223 {
224 enum resctrl_conf_type t = s->conf_type;
225 ctrlval_parser_t *parse_ctrlval = NULL;
226 struct resctrl_staged_config *cfg;
227 struct rdt_resource *r = s->res;
228 struct rdt_parse_data data;
229 struct rdt_ctrl_domain *d;
230 char *dom = NULL, *id;
231 unsigned long dom_id;
232
233 /* Walking r->domains, ensure it can't race with cpuhp */
234 lockdep_assert_cpus_held();
235
236 switch (r->schema_fmt) {
237 case RESCTRL_SCHEMA_BITMAP:
238 parse_ctrlval = &parse_cbm;
239 break;
240 case RESCTRL_SCHEMA_RANGE:
241 parse_ctrlval = &parse_bw;
242 break;
243 }
244
245 if (WARN_ON_ONCE(!parse_ctrlval))
246 return -EINVAL;
247
248 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP &&
249 (r->rid == RDT_RESOURCE_MBA || r->rid == RDT_RESOURCE_SMBA)) {
250 rdt_last_cmd_puts("Cannot pseudo-lock MBA resource\n");
251 return -EINVAL;
252 }
253
254 next:
255 if (!line || line[0] == '\0')
256 return 0;
257 dom = strsep(&line, ";");
258 id = strsep(&dom, "=");
259 if (!dom || kstrtoul(id, 10, &dom_id)) {
260 rdt_last_cmd_puts("Missing '=' or non-numeric domain\n");
261 return -EINVAL;
262 }
263 dom = strim(dom);
264 list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
265 if (d->hdr.id == dom_id) {
266 data.buf = dom;
267 data.closid = rdtgrp->closid;
268 data.mode = rdtgrp->mode;
269 if (parse_ctrlval(&data, s, d))
270 return -EINVAL;
271 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
272 cfg = &d->staged_config[t];
273 /*
274 * In pseudo-locking setup mode and just
275 * parsed a valid CBM that should be
276 * pseudo-locked. Only one locked region per
277 * resource group and domain so just do
278 * the required initialization for single
279 * region and return.
280 */
281 rdtgrp->plr->s = s;
282 rdtgrp->plr->d = d;
283 rdtgrp->plr->cbm = cfg->new_ctrl;
284 d->plr = rdtgrp->plr;
285 return 0;
286 }
287 goto next;
288 }
289 }
290 return -EINVAL;
291 }
292
rdtgroup_parse_resource(char * resname,char * tok,struct rdtgroup * rdtgrp)293 static int rdtgroup_parse_resource(char *resname, char *tok,
294 struct rdtgroup *rdtgrp)
295 {
296 struct resctrl_schema *s;
297
298 list_for_each_entry(s, &resctrl_schema_all, list) {
299 if (!strcmp(resname, s->name) && rdtgrp->closid < s->num_closid)
300 return parse_line(tok, s, rdtgrp);
301 }
302 rdt_last_cmd_printf("Unknown or unsupported resource name '%s'\n", resname);
303 return -EINVAL;
304 }
305
rdtgroup_schemata_write(struct kernfs_open_file * of,char * buf,size_t nbytes,loff_t off)306 ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
307 char *buf, size_t nbytes, loff_t off)
308 {
309 struct resctrl_schema *s;
310 struct rdtgroup *rdtgrp;
311 struct rdt_resource *r;
312 char *tok, *resname;
313 int ret = 0;
314
315 /* Valid input requires a trailing newline */
316 if (nbytes == 0 || buf[nbytes - 1] != '\n')
317 return -EINVAL;
318 buf[nbytes - 1] = '\0';
319
320 rdtgrp = rdtgroup_kn_lock_live(of->kn);
321 if (!rdtgrp) {
322 rdtgroup_kn_unlock(of->kn);
323 return -ENOENT;
324 }
325 rdt_last_cmd_clear();
326
327 /*
328 * No changes to pseudo-locked region allowed. It has to be removed
329 * and re-created instead.
330 */
331 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
332 ret = -EINVAL;
333 rdt_last_cmd_puts("Resource group is pseudo-locked\n");
334 goto out;
335 }
336
337 rdt_staged_configs_clear();
338
339 while ((tok = strsep(&buf, "\n")) != NULL) {
340 resname = strim(strsep(&tok, ":"));
341 if (!tok) {
342 rdt_last_cmd_puts("Missing ':'\n");
343 ret = -EINVAL;
344 goto out;
345 }
346 if (tok[0] == '\0') {
347 rdt_last_cmd_printf("Missing '%s' value\n", resname);
348 ret = -EINVAL;
349 goto out;
350 }
351 ret = rdtgroup_parse_resource(resname, tok, rdtgrp);
352 if (ret)
353 goto out;
354 }
355
356 list_for_each_entry(s, &resctrl_schema_all, list) {
357 r = s->res;
358
359 /*
360 * Writes to mba_sc resources update the software controller,
361 * not the control MSR.
362 */
363 if (is_mba_sc(r))
364 continue;
365
366 ret = resctrl_arch_update_domains(r, rdtgrp->closid);
367 if (ret)
368 goto out;
369 }
370
371 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
372 /*
373 * If pseudo-locking fails we keep the resource group in
374 * mode RDT_MODE_PSEUDO_LOCKSETUP with its class of service
375 * active and updated for just the domain the pseudo-locked
376 * region was requested for.
377 */
378 ret = rdtgroup_pseudo_lock_create(rdtgrp);
379 }
380
381 out:
382 rdt_staged_configs_clear();
383 rdtgroup_kn_unlock(of->kn);
384 return ret ?: nbytes;
385 }
386
show_doms(struct seq_file * s,struct resctrl_schema * schema,char * resource_name,int closid)387 static void show_doms(struct seq_file *s, struct resctrl_schema *schema,
388 char *resource_name, int closid)
389 {
390 struct rdt_resource *r = schema->res;
391 struct rdt_ctrl_domain *dom;
392 bool sep = false;
393 u32 ctrl_val;
394
395 /* Walking r->domains, ensure it can't race with cpuhp */
396 lockdep_assert_cpus_held();
397
398 if (resource_name)
399 seq_printf(s, "%*s:", max_name_width, resource_name);
400 list_for_each_entry(dom, &r->ctrl_domains, hdr.list) {
401 if (sep)
402 seq_puts(s, ";");
403
404 if (is_mba_sc(r))
405 ctrl_val = dom->mbps_val[closid];
406 else
407 ctrl_val = resctrl_arch_get_config(r, dom, closid,
408 schema->conf_type);
409
410 seq_printf(s, schema->fmt_str, dom->hdr.id, ctrl_val);
411 sep = true;
412 }
413 seq_puts(s, "\n");
414 }
415
rdtgroup_schemata_show(struct kernfs_open_file * of,struct seq_file * s,void * v)416 int rdtgroup_schemata_show(struct kernfs_open_file *of,
417 struct seq_file *s, void *v)
418 {
419 struct resctrl_schema *schema;
420 struct rdtgroup *rdtgrp;
421 int ret = 0;
422 u32 closid;
423
424 rdtgrp = rdtgroup_kn_lock_live(of->kn);
425 if (rdtgrp) {
426 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
427 list_for_each_entry(schema, &resctrl_schema_all, list) {
428 seq_printf(s, "%s:uninitialized\n", schema->name);
429 }
430 } else if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
431 if (!rdtgrp->plr->d) {
432 rdt_last_cmd_clear();
433 rdt_last_cmd_puts("Cache domain offline\n");
434 ret = -ENODEV;
435 } else {
436 seq_printf(s, "%s:%d=%x\n",
437 rdtgrp->plr->s->res->name,
438 rdtgrp->plr->d->hdr.id,
439 rdtgrp->plr->cbm);
440 }
441 } else {
442 closid = rdtgrp->closid;
443 list_for_each_entry(schema, &resctrl_schema_all, list) {
444 if (closid < schema->num_closid)
445 show_doms(s, schema, schema->name, closid);
446 }
447 }
448 } else {
449 ret = -ENOENT;
450 }
451 rdtgroup_kn_unlock(of->kn);
452 return ret;
453 }
454
smp_mon_event_count(void * arg)455 static int smp_mon_event_count(void *arg)
456 {
457 mon_event_count(arg);
458
459 return 0;
460 }
461
rdtgroup_mba_mbps_event_write(struct kernfs_open_file * of,char * buf,size_t nbytes,loff_t off)462 ssize_t rdtgroup_mba_mbps_event_write(struct kernfs_open_file *of,
463 char *buf, size_t nbytes, loff_t off)
464 {
465 struct rdtgroup *rdtgrp;
466 int ret = 0;
467
468 /* Valid input requires a trailing newline */
469 if (nbytes == 0 || buf[nbytes - 1] != '\n')
470 return -EINVAL;
471 buf[nbytes - 1] = '\0';
472
473 rdtgrp = rdtgroup_kn_lock_live(of->kn);
474 if (!rdtgrp) {
475 rdtgroup_kn_unlock(of->kn);
476 return -ENOENT;
477 }
478 rdt_last_cmd_clear();
479
480 if (!strcmp(buf, "mbm_local_bytes")) {
481 if (resctrl_is_mon_event_enabled(QOS_L3_MBM_LOCAL_EVENT_ID))
482 rdtgrp->mba_mbps_event = QOS_L3_MBM_LOCAL_EVENT_ID;
483 else
484 ret = -EINVAL;
485 } else if (!strcmp(buf, "mbm_total_bytes")) {
486 if (resctrl_is_mon_event_enabled(QOS_L3_MBM_TOTAL_EVENT_ID))
487 rdtgrp->mba_mbps_event = QOS_L3_MBM_TOTAL_EVENT_ID;
488 else
489 ret = -EINVAL;
490 } else {
491 ret = -EINVAL;
492 }
493
494 if (ret)
495 rdt_last_cmd_printf("Unsupported event id '%s'\n", buf);
496
497 rdtgroup_kn_unlock(of->kn);
498
499 return ret ?: nbytes;
500 }
501
rdtgroup_mba_mbps_event_show(struct kernfs_open_file * of,struct seq_file * s,void * v)502 int rdtgroup_mba_mbps_event_show(struct kernfs_open_file *of,
503 struct seq_file *s, void *v)
504 {
505 struct rdtgroup *rdtgrp;
506 int ret = 0;
507
508 rdtgrp = rdtgroup_kn_lock_live(of->kn);
509
510 if (rdtgrp) {
511 switch (rdtgrp->mba_mbps_event) {
512 case QOS_L3_MBM_LOCAL_EVENT_ID:
513 seq_puts(s, "mbm_local_bytes\n");
514 break;
515 case QOS_L3_MBM_TOTAL_EVENT_ID:
516 seq_puts(s, "mbm_total_bytes\n");
517 break;
518 default:
519 pr_warn_once("Bad event %d\n", rdtgrp->mba_mbps_event);
520 ret = -EINVAL;
521 break;
522 }
523 } else {
524 ret = -ENOENT;
525 }
526
527 rdtgroup_kn_unlock(of->kn);
528
529 return ret;
530 }
531
resctrl_find_domain(struct list_head * h,int id,struct list_head ** pos)532 struct rdt_domain_hdr *resctrl_find_domain(struct list_head *h, int id,
533 struct list_head **pos)
534 {
535 struct rdt_domain_hdr *d;
536 struct list_head *l;
537
538 list_for_each(l, h) {
539 d = list_entry(l, struct rdt_domain_hdr, list);
540 /* When id is found, return its domain. */
541 if (id == d->id)
542 return d;
543 /* Stop searching when finding id's position in sorted list. */
544 if (id < d->id)
545 break;
546 }
547
548 if (pos)
549 *pos = l;
550
551 return NULL;
552 }
553
mon_event_read(struct rmid_read * rr,struct rdt_resource * r,struct rdt_domain_hdr * hdr,struct rdtgroup * rdtgrp,cpumask_t * cpumask,struct mon_evt * evt,int first)554 void mon_event_read(struct rmid_read *rr, struct rdt_resource *r,
555 struct rdt_domain_hdr *hdr, struct rdtgroup *rdtgrp,
556 cpumask_t *cpumask, struct mon_evt *evt, int first)
557 {
558 int cpu;
559
560 /* When picking a CPU from cpu_mask, ensure it can't race with cpuhp */
561 lockdep_assert_cpus_held();
562
563 /*
564 * Setup the parameters to pass to mon_event_count() to read the data.
565 */
566 rr->rgrp = rdtgrp;
567 rr->evt = evt;
568 rr->r = r;
569 rr->hdr = hdr;
570 rr->first = first;
571 if (resctrl_arch_mbm_cntr_assign_enabled(r) &&
572 resctrl_is_mbm_event(evt->evtid)) {
573 rr->is_mbm_cntr = true;
574 } else {
575 rr->arch_mon_ctx = resctrl_arch_mon_ctx_alloc(r, evt->evtid);
576 if (IS_ERR(rr->arch_mon_ctx)) {
577 rr->err = -EINVAL;
578 return;
579 }
580 }
581
582 if (evt->any_cpu) {
583 mon_event_count(rr);
584 goto out_ctx_free;
585 }
586
587 cpu = cpumask_any_housekeeping(cpumask, RESCTRL_PICK_ANY_CPU);
588
589 /*
590 * cpumask_any_housekeeping() prefers housekeeping CPUs, but
591 * are all the CPUs nohz_full? If yes, pick a CPU to IPI.
592 * MPAM's resctrl_arch_rmid_read() is unable to read the
593 * counters on some platforms if its called in IRQ context.
594 */
595 if (tick_nohz_full_cpu(cpu))
596 smp_call_function_any(cpumask, mon_event_count, rr, 1);
597 else
598 smp_call_on_cpu(cpu, smp_mon_event_count, rr, false);
599
600 out_ctx_free:
601 if (rr->arch_mon_ctx)
602 resctrl_arch_mon_ctx_free(r, evt->evtid, rr->arch_mon_ctx);
603 }
604
605 /*
606 * Decimal place precision to use for each number of fixed-point
607 * binary bits computed from ceil(binary_bits * log10(2)) except
608 * binary_bits == 0 which will print "value.0"
609 */
610 static const unsigned int decplaces[MAX_BINARY_BITS + 1] = {
611 [0] = 1,
612 [1] = 1,
613 [2] = 1,
614 [3] = 1,
615 [4] = 2,
616 [5] = 2,
617 [6] = 2,
618 [7] = 3,
619 [8] = 3,
620 [9] = 3,
621 [10] = 4,
622 [11] = 4,
623 [12] = 4,
624 [13] = 4,
625 [14] = 5,
626 [15] = 5,
627 [16] = 5,
628 [17] = 6,
629 [18] = 6,
630 [19] = 6,
631 [20] = 7,
632 [21] = 7,
633 [22] = 7,
634 [23] = 7,
635 [24] = 8,
636 [25] = 8,
637 [26] = 8,
638 [27] = 9
639 };
640
print_event_value(struct seq_file * m,unsigned int binary_bits,u64 val)641 static void print_event_value(struct seq_file *m, unsigned int binary_bits, u64 val)
642 {
643 unsigned long long frac = 0;
644
645 if (binary_bits) {
646 /* Mask off the integer part of the fixed-point value. */
647 frac = val & GENMASK_ULL(binary_bits - 1, 0);
648
649 /*
650 * Multiply by 10^{desired decimal places}. The integer part of
651 * the fixed point value is now almost what is needed.
652 */
653 frac *= int_pow(10ull, decplaces[binary_bits]);
654
655 /*
656 * Round to nearest by adding a value that would be a "1" in the
657 * binary_bits + 1 place. Integer part of fixed point value is
658 * now the needed value.
659 */
660 frac += 1ull << (binary_bits - 1);
661
662 /*
663 * Extract the integer part of the value. This is the decimal
664 * representation of the original fixed-point fractional value.
665 */
666 frac >>= binary_bits;
667 }
668
669 /*
670 * "frac" is now in the range [0 .. 10^decplaces). I.e. string
671 * representation will fit into chosen number of decimal places.
672 */
673 seq_printf(m, "%llu.%0*llu\n", val >> binary_bits, decplaces[binary_bits], frac);
674 }
675
rdtgroup_mondata_show(struct seq_file * m,void * arg)676 int rdtgroup_mondata_show(struct seq_file *m, void *arg)
677 {
678 struct kernfs_open_file *of = m->private;
679 enum resctrl_res_level resid;
680 struct rdt_domain_hdr *hdr;
681 struct rmid_read rr = {0};
682 struct rdtgroup *rdtgrp;
683 int domid, cpu, ret = 0;
684 struct rdt_resource *r;
685 struct cacheinfo *ci;
686 struct mon_evt *evt;
687 struct mon_data *md;
688
689 rdtgrp = rdtgroup_kn_lock_live(of->kn);
690 if (!rdtgrp) {
691 ret = -ENOENT;
692 goto out;
693 }
694
695 md = of->kn->priv;
696 if (WARN_ON_ONCE(!md)) {
697 ret = -EIO;
698 goto out;
699 }
700
701 resid = md->rid;
702 domid = md->domid;
703 evt = md->evt;
704 r = resctrl_arch_get_resource(resid);
705
706 if (md->sum) {
707 struct rdt_l3_mon_domain *d;
708
709 if (WARN_ON_ONCE(resid != RDT_RESOURCE_L3)) {
710 ret = -EINVAL;
711 goto out;
712 }
713
714 /*
715 * This file requires summing across all domains that share
716 * the L3 cache id that was provided in the "domid" field of the
717 * struct mon_data. Search all domains in the resource for
718 * one that matches this cache id.
719 */
720 list_for_each_entry(d, &r->mon_domains, hdr.list) {
721 if (d->ci_id == domid) {
722 cpu = cpumask_any(&d->hdr.cpu_mask);
723 ci = get_cpu_cacheinfo_level(cpu, RESCTRL_L3_CACHE);
724 if (!ci)
725 continue;
726 rr.ci = ci;
727 mon_event_read(&rr, r, NULL, rdtgrp,
728 &ci->shared_cpu_map, evt, false);
729 goto checkresult;
730 }
731 }
732 ret = -ENOENT;
733 goto out;
734 } else {
735 /*
736 * This file provides data from a single domain. Search
737 * the resource to find the domain with "domid".
738 */
739 hdr = resctrl_find_domain(&r->mon_domains, domid, NULL);
740 if (!hdr) {
741 ret = -ENOENT;
742 goto out;
743 }
744 mon_event_read(&rr, r, hdr, rdtgrp, &hdr->cpu_mask, evt, false);
745 }
746
747 checkresult:
748
749 /*
750 * -ENOENT is a special case, set only when "mbm_event" counter assignment
751 * mode is enabled and no counter has been assigned.
752 */
753 if (rr.err == -EIO)
754 seq_puts(m, "Error\n");
755 else if (rr.err == -EINVAL)
756 seq_puts(m, "Unavailable\n");
757 else if (rr.err == -ENOENT)
758 seq_puts(m, "Unassigned\n");
759 else if (evt->is_floating_point)
760 print_event_value(m, evt->binary_bits, rr.val);
761 else
762 seq_printf(m, "%llu\n", rr.val);
763
764 out:
765 rdtgroup_kn_unlock(of->kn);
766 return ret;
767 }
768
resctrl_io_alloc_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)769 int resctrl_io_alloc_show(struct kernfs_open_file *of, struct seq_file *seq, void *v)
770 {
771 struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
772 struct rdt_resource *r = s->res;
773
774 mutex_lock(&rdtgroup_mutex);
775
776 if (r->cache.io_alloc_capable) {
777 if (resctrl_arch_get_io_alloc_enabled(r))
778 seq_puts(seq, "enabled\n");
779 else
780 seq_puts(seq, "disabled\n");
781 } else {
782 seq_puts(seq, "not supported\n");
783 }
784
785 mutex_unlock(&rdtgroup_mutex);
786
787 return 0;
788 }
789
790 /*
791 * resctrl_io_alloc_closid_supported() - io_alloc feature utilizes the
792 * highest CLOSID value to direct I/O traffic. Ensure that io_alloc_closid
793 * is in the supported range.
794 */
resctrl_io_alloc_closid_supported(u32 io_alloc_closid)795 static bool resctrl_io_alloc_closid_supported(u32 io_alloc_closid)
796 {
797 return io_alloc_closid < closids_supported();
798 }
799
800 /*
801 * Initialize io_alloc CLOSID cache resource CBM with all usable (shared
802 * and unused) cache portions.
803 */
resctrl_io_alloc_init_cbm(struct resctrl_schema * s,u32 closid)804 static int resctrl_io_alloc_init_cbm(struct resctrl_schema *s, u32 closid)
805 {
806 enum resctrl_conf_type peer_type;
807 struct rdt_resource *r = s->res;
808 struct rdt_ctrl_domain *d;
809 int ret;
810
811 rdt_staged_configs_clear();
812
813 ret = rdtgroup_init_cat(s, closid);
814 if (ret < 0)
815 goto out;
816
817 /* Keep CDP_CODE and CDP_DATA of io_alloc CLOSID's CBM in sync. */
818 if (resctrl_arch_get_cdp_enabled(r->rid)) {
819 peer_type = resctrl_peer_type(s->conf_type);
820 list_for_each_entry(d, &s->res->ctrl_domains, hdr.list)
821 memcpy(&d->staged_config[peer_type],
822 &d->staged_config[s->conf_type],
823 sizeof(d->staged_config[0]));
824 }
825
826 ret = resctrl_arch_update_domains(r, closid);
827 out:
828 rdt_staged_configs_clear();
829 return ret;
830 }
831
832 /*
833 * resctrl_io_alloc_closid() - io_alloc feature routes I/O traffic using
834 * the highest available CLOSID. Retrieve the maximum CLOSID supported by the
835 * resource. Note that if Code Data Prioritization (CDP) is enabled, the number
836 * of available CLOSIDs is reduced by half.
837 */
resctrl_io_alloc_closid(struct rdt_resource * r)838 u32 resctrl_io_alloc_closid(struct rdt_resource *r)
839 {
840 if (resctrl_arch_get_cdp_enabled(r->rid))
841 return resctrl_arch_get_num_closid(r) / 2 - 1;
842 else
843 return resctrl_arch_get_num_closid(r) - 1;
844 }
845
resctrl_io_alloc_write(struct kernfs_open_file * of,char * buf,size_t nbytes,loff_t off)846 ssize_t resctrl_io_alloc_write(struct kernfs_open_file *of, char *buf,
847 size_t nbytes, loff_t off)
848 {
849 struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
850 struct rdt_resource *r = s->res;
851 char const *grp_name;
852 u32 io_alloc_closid;
853 bool enable;
854 int ret;
855
856 ret = kstrtobool(buf, &enable);
857 if (ret)
858 return ret;
859
860 cpus_read_lock();
861 mutex_lock(&rdtgroup_mutex);
862
863 rdt_last_cmd_clear();
864
865 if (!r->cache.io_alloc_capable) {
866 rdt_last_cmd_printf("io_alloc is not supported on %s\n", s->name);
867 ret = -ENODEV;
868 goto out_unlock;
869 }
870
871 /* If the feature is already up to date, no action is needed. */
872 if (resctrl_arch_get_io_alloc_enabled(r) == enable)
873 goto out_unlock;
874
875 io_alloc_closid = resctrl_io_alloc_closid(r);
876 if (!resctrl_io_alloc_closid_supported(io_alloc_closid)) {
877 rdt_last_cmd_printf("io_alloc CLOSID (ctrl_hw_id) %u is not available\n",
878 io_alloc_closid);
879 ret = -EINVAL;
880 goto out_unlock;
881 }
882
883 if (enable) {
884 if (!closid_alloc_fixed(io_alloc_closid)) {
885 grp_name = rdtgroup_name_by_closid(io_alloc_closid);
886 WARN_ON_ONCE(!grp_name);
887 rdt_last_cmd_printf("CLOSID (ctrl_hw_id) %u for io_alloc is used by %s group\n",
888 io_alloc_closid, grp_name ? grp_name : "another");
889 ret = -ENOSPC;
890 goto out_unlock;
891 }
892
893 ret = resctrl_io_alloc_init_cbm(s, io_alloc_closid);
894 if (ret) {
895 rdt_last_cmd_puts("Failed to initialize io_alloc allocations\n");
896 closid_free(io_alloc_closid);
897 goto out_unlock;
898 }
899 } else {
900 closid_free(io_alloc_closid);
901 }
902
903 ret = resctrl_arch_io_alloc_enable(r, enable);
904 if (enable && ret) {
905 rdt_last_cmd_puts("Failed to enable io_alloc feature\n");
906 closid_free(io_alloc_closid);
907 }
908
909 out_unlock:
910 mutex_unlock(&rdtgroup_mutex);
911 cpus_read_unlock();
912
913 return ret ?: nbytes;
914 }
915
resctrl_io_alloc_cbm_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)916 int resctrl_io_alloc_cbm_show(struct kernfs_open_file *of, struct seq_file *seq, void *v)
917 {
918 struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
919 struct rdt_resource *r = s->res;
920 int ret = 0;
921
922 cpus_read_lock();
923 mutex_lock(&rdtgroup_mutex);
924
925 rdt_last_cmd_clear();
926
927 if (!r->cache.io_alloc_capable) {
928 rdt_last_cmd_printf("io_alloc is not supported on %s\n", s->name);
929 ret = -ENODEV;
930 goto out_unlock;
931 }
932
933 if (!resctrl_arch_get_io_alloc_enabled(r)) {
934 rdt_last_cmd_printf("io_alloc is not enabled on %s\n", s->name);
935 ret = -EINVAL;
936 goto out_unlock;
937 }
938
939 /*
940 * When CDP is enabled, the CBMs of the highest CLOSID of CDP_CODE and
941 * CDP_DATA are kept in sync. As a result, the io_alloc CBMs shown for
942 * either CDP resource are identical and accurately represent the CBMs
943 * used for I/O.
944 */
945 show_doms(seq, s, NULL, resctrl_io_alloc_closid(r));
946
947 out_unlock:
948 mutex_unlock(&rdtgroup_mutex);
949 cpus_read_unlock();
950 return ret;
951 }
952
resctrl_io_alloc_parse_line(char * line,struct rdt_resource * r,struct resctrl_schema * s,u32 closid)953 static int resctrl_io_alloc_parse_line(char *line, struct rdt_resource *r,
954 struct resctrl_schema *s, u32 closid)
955 {
956 enum resctrl_conf_type peer_type;
957 struct rdt_parse_data data;
958 struct rdt_ctrl_domain *d;
959 char *dom = NULL, *id;
960 unsigned long dom_id;
961
962 next:
963 if (!line || line[0] == '\0')
964 return 0;
965
966 dom = strsep(&line, ";");
967 id = strsep(&dom, "=");
968 if (!dom || kstrtoul(id, 10, &dom_id)) {
969 rdt_last_cmd_puts("Missing '=' or non-numeric domain\n");
970 return -EINVAL;
971 }
972
973 dom = strim(dom);
974 list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
975 if (d->hdr.id == dom_id) {
976 data.buf = dom;
977 data.mode = RDT_MODE_SHAREABLE;
978 data.closid = closid;
979 if (parse_cbm(&data, s, d))
980 return -EINVAL;
981 /*
982 * Keep io_alloc CLOSID's CBM of CDP_CODE and CDP_DATA
983 * in sync.
984 */
985 if (resctrl_arch_get_cdp_enabled(r->rid)) {
986 peer_type = resctrl_peer_type(s->conf_type);
987 memcpy(&d->staged_config[peer_type],
988 &d->staged_config[s->conf_type],
989 sizeof(d->staged_config[0]));
990 }
991 goto next;
992 }
993 }
994
995 return -EINVAL;
996 }
997
resctrl_io_alloc_cbm_write(struct kernfs_open_file * of,char * buf,size_t nbytes,loff_t off)998 ssize_t resctrl_io_alloc_cbm_write(struct kernfs_open_file *of, char *buf,
999 size_t nbytes, loff_t off)
1000 {
1001 struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
1002 struct rdt_resource *r = s->res;
1003 u32 io_alloc_closid;
1004 int ret = 0;
1005
1006 /* Valid input requires a trailing newline */
1007 if (nbytes == 0 || buf[nbytes - 1] != '\n')
1008 return -EINVAL;
1009
1010 buf[nbytes - 1] = '\0';
1011
1012 cpus_read_lock();
1013 mutex_lock(&rdtgroup_mutex);
1014 rdt_last_cmd_clear();
1015
1016 if (!r->cache.io_alloc_capable) {
1017 rdt_last_cmd_printf("io_alloc is not supported on %s\n", s->name);
1018 ret = -ENODEV;
1019 goto out_unlock;
1020 }
1021
1022 if (!resctrl_arch_get_io_alloc_enabled(r)) {
1023 rdt_last_cmd_printf("io_alloc is not enabled on %s\n", s->name);
1024 ret = -EINVAL;
1025 goto out_unlock;
1026 }
1027
1028 io_alloc_closid = resctrl_io_alloc_closid(r);
1029
1030 rdt_staged_configs_clear();
1031 ret = resctrl_io_alloc_parse_line(buf, r, s, io_alloc_closid);
1032 if (ret)
1033 goto out_clear_configs;
1034
1035 ret = resctrl_arch_update_domains(r, io_alloc_closid);
1036
1037 out_clear_configs:
1038 rdt_staged_configs_clear();
1039 out_unlock:
1040 mutex_unlock(&rdtgroup_mutex);
1041 cpus_read_unlock();
1042
1043 return ret ?: nbytes;
1044 }
1045