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