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 converted as appropriate
41 * for consumption by the specific hardware driver.
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 = resctrl_arch_preconvert_bw(r, bw);
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_rcu(d, &r->ctrl_domains, hdr.list, lockdep_is_cpus_held()) {
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 rdtgrp = rdtgroup_kn_lock_live(of->kn);
316 if (!rdtgrp) {
317 rdtgroup_kn_unlock(of->kn);
318 return -ENOENT;
319 }
320
321 /* Valid input requires a trailing newline */
322 if (nbytes == 0 || buf[nbytes - 1] != '\n') {
323 rdt_last_cmd_puts("schemata: Invalid input\n");
324 ret = -EINVAL;
325 goto out_unlock;
326 }
327
328 buf[nbytes - 1] = '\0';
329
330 /*
331 * No changes to pseudo-locked region allowed. It has to be removed
332 * and re-created instead.
333 */
334 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
335 ret = -EINVAL;
336 rdt_last_cmd_puts("Resource group is pseudo-locked\n");
337 goto out_unlock;
338 }
339
340 rdt_staged_configs_clear();
341
342 while ((tok = strsep(&buf, "\n")) != NULL) {
343 resname = strim(strsep(&tok, ":"));
344 if (!tok) {
345 rdt_last_cmd_puts("Missing ':'\n");
346 ret = -EINVAL;
347 goto out_clear_staged;
348 }
349 if (tok[0] == '\0') {
350 rdt_last_cmd_printf("Missing '%s' value\n", resname);
351 ret = -EINVAL;
352 goto out_clear_staged;
353 }
354 ret = rdtgroup_parse_resource(resname, tok, rdtgrp);
355 if (ret)
356 goto out_clear_staged;
357 }
358
359 list_for_each_entry(s, &resctrl_schema_all, list) {
360 r = s->res;
361
362 /*
363 * Writes to mba_sc resources update the software controller,
364 * not the control MSR.
365 */
366 if (is_mba_sc(r))
367 continue;
368
369 ret = resctrl_arch_update_domains(r, rdtgrp->closid);
370 if (ret)
371 goto out_clear_staged;
372 }
373
374 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
375 /*
376 * If pseudo-locking fails we keep the resource group in
377 * mode RDT_MODE_PSEUDO_LOCKSETUP with its class of service
378 * active and updated for just the domain the pseudo-locked
379 * region was requested for.
380 */
381 ret = rdtgroup_pseudo_lock_create(rdtgrp);
382 }
383
384 out_clear_staged:
385 rdt_staged_configs_clear();
386 out_unlock:
387 rdtgroup_kn_unlock(of->kn);
388 return ret ?: nbytes;
389 }
390
show_doms(struct seq_file * s,struct resctrl_schema * schema,char * resource_name,int closid)391 static void show_doms(struct seq_file *s, struct resctrl_schema *schema,
392 char *resource_name, int closid)
393 {
394 struct rdt_resource *r = schema->res;
395 struct rdt_ctrl_domain *dom;
396 bool sep = false;
397 u32 ctrl_val;
398
399 /* Walking r->domains, ensure it can't race with cpuhp */
400 lockdep_assert_cpus_held();
401
402 if (resource_name)
403 seq_printf(s, "%*s:", max_name_width, resource_name);
404 list_for_each_entry_rcu(dom, &r->ctrl_domains, hdr.list, lockdep_is_cpus_held()) {
405 if (sep)
406 seq_puts(s, ";");
407
408 if (is_mba_sc(r))
409 ctrl_val = dom->mbps_val[closid];
410 else
411 ctrl_val = resctrl_arch_get_config(r, dom, closid,
412 schema->conf_type);
413
414 seq_printf(s, schema->fmt_str, dom->hdr.id, ctrl_val);
415 sep = true;
416 }
417 seq_puts(s, "\n");
418 }
419
rdtgroup_schemata_show(struct kernfs_open_file * of,struct seq_file * s,void * v)420 int rdtgroup_schemata_show(struct kernfs_open_file *of,
421 struct seq_file *s, void *v)
422 {
423 struct resctrl_schema *schema;
424 struct rdtgroup *rdtgrp;
425 int ret = 0;
426 u32 closid;
427
428 rdtgrp = rdtgroup_kn_lock_live(of->kn);
429 if (rdtgrp) {
430 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
431 list_for_each_entry(schema, &resctrl_schema_all, list) {
432 seq_printf(s, "%s:uninitialized\n", schema->name);
433 }
434 } else if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
435 if (!rdtgrp->plr->d) {
436 rdt_last_cmd_puts("Cache domain offline\n");
437 ret = -ENODEV;
438 } else {
439 seq_printf(s, "%s:%d=%x\n",
440 rdtgrp->plr->s->res->name,
441 rdtgrp->plr->d->hdr.id,
442 rdtgrp->plr->cbm);
443 }
444 } else {
445 closid = rdtgrp->closid;
446 list_for_each_entry(schema, &resctrl_schema_all, list) {
447 if (closid < schema->num_closid)
448 show_doms(s, schema, schema->name, closid);
449 }
450 }
451 } else {
452 ret = -ENOENT;
453 }
454 rdtgroup_kn_unlock(of->kn);
455 return ret;
456 }
457
smp_mon_event_count(void * arg)458 static int smp_mon_event_count(void *arg)
459 {
460 mon_event_count(arg);
461
462 return 0;
463 }
464
rdtgroup_mba_mbps_event_write(struct kernfs_open_file * of,char * buf,size_t nbytes,loff_t off)465 ssize_t rdtgroup_mba_mbps_event_write(struct kernfs_open_file *of,
466 char *buf, size_t nbytes, loff_t off)
467 {
468 struct rdtgroup *rdtgrp;
469 int ret = 0;
470
471 rdtgrp = rdtgroup_kn_lock_live(of->kn);
472 if (!rdtgrp) {
473 rdtgroup_kn_unlock(of->kn);
474 return -ENOENT;
475 }
476
477 /* Valid input requires a trailing newline */
478 if (nbytes == 0 || buf[nbytes - 1] != '\n') {
479 rdt_last_cmd_puts("mba_MBps_event: Invalid input\n");
480 ret = -EINVAL;
481 goto out_unlock;
482 }
483
484 buf[nbytes - 1] = '\0';
485
486 if (!strcmp(buf, "mbm_local_bytes")) {
487 if (resctrl_is_mon_event_enabled(QOS_L3_MBM_LOCAL_EVENT_ID))
488 rdtgrp->mba_mbps_event = QOS_L3_MBM_LOCAL_EVENT_ID;
489 else
490 ret = -EINVAL;
491 } else if (!strcmp(buf, "mbm_total_bytes")) {
492 if (resctrl_is_mon_event_enabled(QOS_L3_MBM_TOTAL_EVENT_ID))
493 rdtgrp->mba_mbps_event = QOS_L3_MBM_TOTAL_EVENT_ID;
494 else
495 ret = -EINVAL;
496 } else {
497 ret = -EINVAL;
498 }
499
500 if (ret)
501 rdt_last_cmd_printf("Unsupported event id '%s'\n", buf);
502
503 out_unlock:
504 rdtgroup_kn_unlock(of->kn);
505
506 return ret ?: nbytes;
507 }
508
rdtgroup_mba_mbps_event_show(struct kernfs_open_file * of,struct seq_file * s,void * v)509 int rdtgroup_mba_mbps_event_show(struct kernfs_open_file *of,
510 struct seq_file *s, void *v)
511 {
512 struct rdtgroup *rdtgrp;
513 int ret = 0;
514
515 rdtgrp = rdtgroup_kn_lock_live(of->kn);
516
517 if (rdtgrp) {
518 switch (rdtgrp->mba_mbps_event) {
519 case QOS_L3_MBM_LOCAL_EVENT_ID:
520 seq_puts(s, "mbm_local_bytes\n");
521 break;
522 case QOS_L3_MBM_TOTAL_EVENT_ID:
523 seq_puts(s, "mbm_total_bytes\n");
524 break;
525 default:
526 pr_warn_once("Bad event %d\n", rdtgrp->mba_mbps_event);
527 ret = -EINVAL;
528 break;
529 }
530 } else {
531 ret = -ENOENT;
532 }
533
534 rdtgroup_kn_unlock(of->kn);
535
536 return ret;
537 }
538
resctrl_find_domain(struct list_head * h,int id,struct list_head ** pos)539 struct rdt_domain_hdr *resctrl_find_domain(struct list_head *h, int id,
540 struct list_head **pos)
541 {
542 struct rdt_domain_hdr *d;
543 struct list_head *l;
544
545 lockdep_assert_cpus_held();
546
547 list_for_each(l, h) {
548 d = list_entry(l, struct rdt_domain_hdr, list);
549 /* When id is found, return its domain. */
550 if (id == d->id)
551 return d;
552 /* Stop searching when finding id's position in sorted list. */
553 if (id < d->id)
554 break;
555 }
556
557 if (pos)
558 *pos = l;
559
560 return NULL;
561 }
562
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)563 void mon_event_read(struct rmid_read *rr, struct rdt_resource *r,
564 struct rdt_domain_hdr *hdr, struct rdtgroup *rdtgrp,
565 cpumask_t *cpumask, struct mon_evt *evt, int first)
566 {
567 int cpu;
568
569 /* When picking a CPU from cpu_mask, ensure it can't race with cpuhp */
570 lockdep_assert_cpus_held();
571
572 /*
573 * Setup the parameters to pass to mon_event_count() to read the data.
574 */
575 rr->rgrp = rdtgrp;
576 rr->evt = evt;
577 rr->r = r;
578 rr->hdr = hdr;
579 rr->first = first;
580 if (resctrl_arch_mbm_cntr_assign_enabled(r) &&
581 resctrl_is_mbm_event(evt->evtid)) {
582 rr->is_mbm_cntr = true;
583 } else {
584 rr->arch_mon_ctx = resctrl_arch_mon_ctx_alloc(r, evt->evtid);
585 if (IS_ERR(rr->arch_mon_ctx)) {
586 rr->err = -EINVAL;
587 return;
588 }
589 }
590
591 if (evt->any_cpu) {
592 mon_event_count(rr);
593 goto out_ctx_free;
594 }
595
596 cpu = cpumask_any_housekeeping(cpumask, RESCTRL_PICK_ANY_CPU);
597
598 /*
599 * cpumask_any_housekeeping() prefers housekeeping CPUs, but
600 * are all the CPUs nohz_full? If yes, pick a CPU to IPI.
601 * MPAM's resctrl_arch_rmid_read() is unable to read the
602 * counters on some platforms if its called in IRQ context.
603 */
604 if (tick_nohz_full_cpu(cpu))
605 smp_call_function_any(cpumask, mon_event_count, rr, 1);
606 else
607 smp_call_on_cpu(cpu, smp_mon_event_count, rr, false);
608
609 out_ctx_free:
610 if (rr->arch_mon_ctx)
611 resctrl_arch_mon_ctx_free(r, evt->evtid, rr->arch_mon_ctx);
612 }
613
614 /*
615 * Decimal place precision to use for each number of fixed-point
616 * binary bits computed from ceil(binary_bits * log10(2)) except
617 * binary_bits == 0 which will print "value.0"
618 */
619 static const unsigned int decplaces[MAX_BINARY_BITS + 1] = {
620 [0] = 1,
621 [1] = 1,
622 [2] = 1,
623 [3] = 1,
624 [4] = 2,
625 [5] = 2,
626 [6] = 2,
627 [7] = 3,
628 [8] = 3,
629 [9] = 3,
630 [10] = 4,
631 [11] = 4,
632 [12] = 4,
633 [13] = 4,
634 [14] = 5,
635 [15] = 5,
636 [16] = 5,
637 [17] = 6,
638 [18] = 6,
639 [19] = 6,
640 [20] = 7,
641 [21] = 7,
642 [22] = 7,
643 [23] = 7,
644 [24] = 8,
645 [25] = 8,
646 [26] = 8,
647 [27] = 9
648 };
649
print_event_value(struct seq_file * m,unsigned int binary_bits,u64 val)650 static void print_event_value(struct seq_file *m, unsigned int binary_bits, u64 val)
651 {
652 unsigned long long frac = 0;
653
654 if (binary_bits) {
655 /* Mask off the integer part of the fixed-point value. */
656 frac = val & GENMASK_ULL(binary_bits - 1, 0);
657
658 /*
659 * Multiply by 10^{desired decimal places}. The integer part of
660 * the fixed point value is now almost what is needed.
661 */
662 frac *= int_pow(10ull, decplaces[binary_bits]);
663
664 /*
665 * Round to nearest by adding a value that would be a "1" in the
666 * binary_bits + 1 place. Integer part of fixed point value is
667 * now the needed value.
668 */
669 frac += 1ull << (binary_bits - 1);
670
671 /*
672 * Extract the integer part of the value. This is the decimal
673 * representation of the original fixed-point fractional value.
674 */
675 frac >>= binary_bits;
676 }
677
678 /*
679 * "frac" is now in the range [0 .. 10^decplaces). I.e. string
680 * representation will fit into chosen number of decimal places.
681 */
682 seq_printf(m, "%llu.%0*llu\n", val >> binary_bits, decplaces[binary_bits], frac);
683 }
684
rdtgroup_mondata_show(struct seq_file * m,void * arg)685 int rdtgroup_mondata_show(struct seq_file *m, void *arg)
686 {
687 struct kernfs_open_file *of = m->private;
688 enum resctrl_res_level resid;
689 struct rdt_domain_hdr *hdr;
690 struct rmid_read rr = {0};
691 struct rdtgroup *rdtgrp;
692 int domid, cpu, ret = 0;
693 struct rdt_resource *r;
694 struct cacheinfo *ci;
695 struct mon_evt *evt;
696 struct mon_data *md;
697
698 rdtgrp = rdtgroup_kn_lock_live(of->kn);
699 if (!rdtgrp) {
700 ret = -ENOENT;
701 goto out;
702 }
703
704 md = of->kn->priv;
705 if (WARN_ON_ONCE(!md)) {
706 ret = -EIO;
707 goto out;
708 }
709
710 resid = md->rid;
711 domid = md->domid;
712 evt = md->evt;
713 r = resctrl_arch_get_resource(resid);
714
715 if (md->sum) {
716 struct rdt_l3_mon_domain *d;
717
718 if (WARN_ON_ONCE(resid != RDT_RESOURCE_L3)) {
719 ret = -EINVAL;
720 goto out;
721 }
722
723 /*
724 * This file requires summing across all domains that share
725 * the L3 cache id that was provided in the "domid" field of the
726 * struct mon_data. Search all domains in the resource for
727 * one that matches this cache id.
728 */
729 list_for_each_entry_rcu(d, &r->mon_domains, hdr.list, lockdep_is_cpus_held()) {
730 if (d->ci_id == domid) {
731 cpu = cpumask_any(&d->hdr.cpu_mask);
732 ci = get_cpu_cacheinfo_level(cpu, RESCTRL_L3_CACHE);
733 if (!ci)
734 continue;
735 rr.ci = ci;
736 mon_event_read(&rr, r, NULL, rdtgrp,
737 &ci->shared_cpu_map, evt, false);
738 goto checkresult;
739 }
740 }
741 ret = -ENOENT;
742 goto out;
743 } else {
744 /*
745 * This file provides data from a single domain. Search
746 * the resource to find the domain with "domid".
747 */
748 hdr = resctrl_find_domain(&r->mon_domains, domid, NULL);
749 if (!hdr) {
750 ret = -ENOENT;
751 goto out;
752 }
753 mon_event_read(&rr, r, hdr, rdtgrp, &hdr->cpu_mask, evt, false);
754 }
755
756 checkresult:
757
758 /*
759 * -ENOENT is a special case, set only when "mbm_event" counter assignment
760 * mode is enabled and no counter has been assigned.
761 */
762 if (rr.err == -EIO)
763 seq_puts(m, "Error\n");
764 else if (rr.err == -EINVAL)
765 seq_puts(m, "Unavailable\n");
766 else if (rr.err == -ENOENT)
767 seq_puts(m, "Unassigned\n");
768 else if (evt->is_floating_point)
769 print_event_value(m, evt->binary_bits, rr.val);
770 else
771 seq_printf(m, "%llu\n", rr.val);
772
773 out:
774 rdtgroup_kn_unlock(of->kn);
775 return ret;
776 }
777
resctrl_io_alloc_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)778 int resctrl_io_alloc_show(struct kernfs_open_file *of, struct seq_file *seq, void *v)
779 {
780 struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
781 struct rdt_resource *r;
782
783 if (!info_kn_lock(of->kn))
784 return -ENOENT;
785
786 r = s->res;
787 if (r->cache.io_alloc_capable) {
788 if (resctrl_arch_get_io_alloc_enabled(r))
789 seq_puts(seq, "enabled\n");
790 else
791 seq_puts(seq, "disabled\n");
792 } else {
793 seq_puts(seq, "not supported\n");
794 }
795
796 info_kn_unlock(of->kn);
797
798 return 0;
799 }
800
801 /*
802 * resctrl_io_alloc_closid_supported() - io_alloc feature utilizes the
803 * highest CLOSID value to direct I/O traffic. Ensure that io_alloc_closid
804 * is in the supported range.
805 */
resctrl_io_alloc_closid_supported(u32 io_alloc_closid)806 static bool resctrl_io_alloc_closid_supported(u32 io_alloc_closid)
807 {
808 return io_alloc_closid < closids_supported();
809 }
810
811 /*
812 * Initialize io_alloc CLOSID cache resource CBM with all usable (shared
813 * and unused) cache portions.
814 */
resctrl_io_alloc_init_cbm(struct resctrl_schema * s,u32 closid)815 static int resctrl_io_alloc_init_cbm(struct resctrl_schema *s, u32 closid)
816 {
817 enum resctrl_conf_type peer_type;
818 struct rdt_resource *r = s->res;
819 struct rdt_ctrl_domain *d;
820 int ret;
821
822 rdt_staged_configs_clear();
823
824 ret = rdtgroup_init_cat(s, closid);
825 if (ret < 0)
826 goto out;
827
828 /* Keep CDP_CODE and CDP_DATA of io_alloc CLOSID's CBM in sync. */
829 if (resctrl_arch_get_cdp_enabled(r->rid)) {
830 peer_type = resctrl_peer_type(s->conf_type);
831 list_for_each_entry_rcu(d, &s->res->ctrl_domains, hdr.list, lockdep_is_cpus_held())
832 memcpy(&d->staged_config[peer_type],
833 &d->staged_config[s->conf_type],
834 sizeof(d->staged_config[0]));
835 }
836
837 ret = resctrl_arch_update_domains(r, closid);
838 out:
839 rdt_staged_configs_clear();
840 return ret;
841 }
842
843 /*
844 * resctrl_io_alloc_closid() - io_alloc feature routes I/O traffic using
845 * the highest available CLOSID. Retrieve the maximum CLOSID supported by the
846 * resource. Note that if Code Data Prioritization (CDP) is enabled, the number
847 * of available CLOSIDs is reduced by half.
848 */
resctrl_io_alloc_closid(struct rdt_resource * r)849 u32 resctrl_io_alloc_closid(struct rdt_resource *r)
850 {
851 if (resctrl_arch_get_cdp_enabled(r->rid))
852 return resctrl_arch_get_num_closid(r) / 2 - 1;
853 else
854 return resctrl_arch_get_num_closid(r) - 1;
855 }
856
resctrl_io_alloc_write(struct kernfs_open_file * of,char * buf,size_t nbytes,loff_t off)857 ssize_t resctrl_io_alloc_write(struct kernfs_open_file *of, char *buf,
858 size_t nbytes, loff_t off)
859 {
860 struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
861 struct rdt_resource *r;
862 char const *grp_name;
863 u32 io_alloc_closid;
864 bool enable;
865 int ret;
866
867 if (!info_kn_lock(of->kn))
868 return -ENOENT;
869
870 r = s->res;
871 rdt_last_cmd_clear();
872
873 ret = kstrtobool(buf, &enable);
874 if (ret) {
875 rdt_last_cmd_puts("io_alloc: Invalid input\n");
876 goto out_unlock;
877 }
878
879 if (!r->cache.io_alloc_capable) {
880 rdt_last_cmd_printf("io_alloc is not supported on %s\n", s->name);
881 ret = -ENODEV;
882 goto out_unlock;
883 }
884
885 /* If the feature is already up to date, no action is needed. */
886 if (resctrl_arch_get_io_alloc_enabled(r) == enable)
887 goto out_unlock;
888
889 io_alloc_closid = resctrl_io_alloc_closid(r);
890 if (!resctrl_io_alloc_closid_supported(io_alloc_closid)) {
891 rdt_last_cmd_printf("io_alloc CLOSID (ctrl_hw_id) %u is not available\n",
892 io_alloc_closid);
893 ret = -EINVAL;
894 goto out_unlock;
895 }
896
897 if (enable) {
898 if (!closid_alloc_fixed(io_alloc_closid)) {
899 grp_name = rdtgroup_name_by_closid(io_alloc_closid);
900 WARN_ON_ONCE(!grp_name);
901 rdt_last_cmd_printf("CLOSID (ctrl_hw_id) %u for io_alloc is used by %s group\n",
902 io_alloc_closid, grp_name ? grp_name : "another");
903 ret = -ENOSPC;
904 goto out_unlock;
905 }
906
907 ret = resctrl_io_alloc_init_cbm(s, io_alloc_closid);
908 if (ret) {
909 rdt_last_cmd_puts("Failed to initialize io_alloc allocations\n");
910 closid_free(io_alloc_closid);
911 goto out_unlock;
912 }
913 } else {
914 closid_free(io_alloc_closid);
915 }
916
917 ret = resctrl_arch_io_alloc_enable(r, enable);
918 if (enable && ret) {
919 rdt_last_cmd_puts("Failed to enable io_alloc feature\n");
920 closid_free(io_alloc_closid);
921 }
922
923 out_unlock:
924 info_kn_unlock(of->kn);
925
926 return ret ?: nbytes;
927 }
928
resctrl_io_alloc_cbm_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)929 int resctrl_io_alloc_cbm_show(struct kernfs_open_file *of, struct seq_file *seq, void *v)
930 {
931 struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
932 struct rdt_resource *r;
933 int ret = 0;
934
935 if (!info_kn_lock(of->kn))
936 return -ENOENT;
937
938 rdt_last_cmd_clear();
939
940 r = s->res;
941 if (!r->cache.io_alloc_capable) {
942 rdt_last_cmd_printf("io_alloc is not supported on %s\n", s->name);
943 ret = -ENODEV;
944 goto out_unlock;
945 }
946
947 if (!resctrl_arch_get_io_alloc_enabled(r)) {
948 rdt_last_cmd_printf("io_alloc is not enabled on %s\n", s->name);
949 ret = -EINVAL;
950 goto out_unlock;
951 }
952
953 /*
954 * When CDP is enabled, the CBMs of the highest CLOSID of CDP_CODE and
955 * CDP_DATA are kept in sync. As a result, the io_alloc CBMs shown for
956 * either CDP resource are identical and accurately represent the CBMs
957 * used for I/O.
958 */
959 show_doms(seq, s, NULL, resctrl_io_alloc_closid(r));
960
961 out_unlock:
962 info_kn_unlock(of->kn);
963 return ret;
964 }
965
resctrl_io_alloc_parse_line(char * line,struct rdt_resource * r,struct resctrl_schema * s,u32 closid)966 static int resctrl_io_alloc_parse_line(char *line, struct rdt_resource *r,
967 struct resctrl_schema *s, u32 closid)
968 {
969 enum resctrl_conf_type peer_type;
970 unsigned long dom_id = ULONG_MAX;
971 struct rdt_parse_data data;
972 struct rdt_ctrl_domain *d;
973 bool update_all = false;
974 char *dom = NULL, *id;
975
976 next:
977 if (!line || line[0] == '\0')
978 return 0;
979
980 if (update_all) {
981 rdt_last_cmd_puts("Configurations after global '*'\n");
982 return -EINVAL;
983 }
984
985 dom = strsep(&line, ";");
986 id = strsep(&dom, "=");
987
988 if (dom && !strcmp(id, "*")) {
989 update_all = true;
990 } else if (!dom || kstrtoul(id, 10, &dom_id)) {
991 rdt_last_cmd_puts("Missing '=' or non-numeric domain\n");
992 return -EINVAL;
993 }
994
995 dom = strim(dom);
996 list_for_each_entry_rcu(d, &r->ctrl_domains, hdr.list, lockdep_is_cpus_held()) {
997 if (update_all || d->hdr.id == dom_id) {
998 data.buf = dom;
999 data.mode = RDT_MODE_SHAREABLE;
1000 data.closid = closid;
1001 if (parse_cbm(&data, s, d))
1002 return -EINVAL;
1003 /*
1004 * Keep io_alloc CLOSID's CBM of CDP_CODE and CDP_DATA
1005 * in sync.
1006 */
1007 if (resctrl_arch_get_cdp_enabled(r->rid)) {
1008 peer_type = resctrl_peer_type(s->conf_type);
1009 memcpy(&d->staged_config[peer_type],
1010 &d->staged_config[s->conf_type],
1011 sizeof(d->staged_config[0]));
1012 }
1013 if (!update_all)
1014 goto next;
1015 }
1016 }
1017
1018 if (update_all)
1019 goto next;
1020
1021 rdt_last_cmd_printf("Invalid domain %lu\n", dom_id);
1022 return -EINVAL;
1023 }
1024
resctrl_io_alloc_cbm_write(struct kernfs_open_file * of,char * buf,size_t nbytes,loff_t off)1025 ssize_t resctrl_io_alloc_cbm_write(struct kernfs_open_file *of, char *buf,
1026 size_t nbytes, loff_t off)
1027 {
1028 struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
1029 struct rdt_resource *r;
1030 u32 io_alloc_closid;
1031 int ret = 0;
1032
1033 if (!info_kn_lock(of->kn))
1034 return -ENOENT;
1035 rdt_last_cmd_clear();
1036
1037 r = s->res;
1038
1039 /* Valid input requires a trailing newline */
1040 if (nbytes == 0 || buf[nbytes - 1] != '\n') {
1041 rdt_last_cmd_puts("io_alloc_cbm: Invalid input\n");
1042 ret = -EINVAL;
1043 goto out_unlock;
1044 }
1045
1046 buf[nbytes - 1] = '\0';
1047
1048 if (!r->cache.io_alloc_capable) {
1049 rdt_last_cmd_printf("io_alloc is not supported on %s\n", s->name);
1050 ret = -ENODEV;
1051 goto out_unlock;
1052 }
1053
1054 if (!resctrl_arch_get_io_alloc_enabled(r)) {
1055 rdt_last_cmd_printf("io_alloc is not enabled on %s\n", s->name);
1056 ret = -EINVAL;
1057 goto out_unlock;
1058 }
1059
1060 io_alloc_closid = resctrl_io_alloc_closid(r);
1061
1062 rdt_staged_configs_clear();
1063 ret = resctrl_io_alloc_parse_line(buf, r, s, io_alloc_closid);
1064 if (ret)
1065 goto out_clear_configs;
1066
1067 ret = resctrl_arch_update_domains(r, io_alloc_closid);
1068
1069 out_clear_configs:
1070 rdt_staged_configs_clear();
1071 out_unlock:
1072 info_kn_unlock(of->kn);
1073
1074 return ret ?: nbytes;
1075 }
1076