File Index
Files and directories
Sign in
FILE

ctrlmondata.c

File preview with syntax highlighting.

linux-6.19.14/fs/resctrl/ctrlmondata.c C
  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
 26struct rdt_parse_data {
 27	u32			closid;
 28	enum rdtgrp_mode	mode;
 29	char			*buf;
 30};
 31
 32typedef 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 */
 42static 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
 77static 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 */
115static 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 */
157static 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 */
220static 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
253next:
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
292static 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
305ssize_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
380out:
381	rdt_staged_configs_clear();
382	rdtgroup_kn_unlock(of->kn);
383	return ret ?: nbytes;
384}
385
386static 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
415int 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
454static int smp_mon_event_count(void *arg)
455{
456	mon_event_count(arg);
457
458	return 0;
459}
460
461ssize_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
501int 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
531struct 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
553void mon_event_read(struct rmid_read *rr, struct rdt_resource *r,
554		    struct rdt_mon_domain *d, struct rdtgroup *rdtgrp,
555		    cpumask_t *cpumask, int evtid, 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->evtid = evtid;
567	rr->r = r;
568	rr->d = d;
569	rr->first = first;
570	if (resctrl_arch_mbm_cntr_assign_enabled(r) &&
571	    resctrl_is_mbm_event(evtid)) {
572		rr->is_mbm_cntr = true;
573	} else {
574		rr->arch_mon_ctx = resctrl_arch_mon_ctx_alloc(r, evtid);
575		if (IS_ERR(rr->arch_mon_ctx)) {
576			rr->err = -EINVAL;
577			return;
578		}
579	}
580
581	cpu = cpumask_any_housekeeping(cpumask, RESCTRL_PICK_ANY_CPU);
582
583	/*
584	 * cpumask_any_housekeeping() prefers housekeeping CPUs, but
585	 * are all the CPUs nohz_full? If yes, pick a CPU to IPI.
586	 * MPAM's resctrl_arch_rmid_read() is unable to read the
587	 * counters on some platforms if its called in IRQ context.
588	 */
589	if (tick_nohz_full_cpu(cpu))
590		smp_call_function_any(cpumask, mon_event_count, rr, 1);
591	else
592		smp_call_on_cpu(cpu, smp_mon_event_count, rr, false);
593
594	if (rr->arch_mon_ctx)
595		resctrl_arch_mon_ctx_free(r, evtid, rr->arch_mon_ctx);
596}
597
598int rdtgroup_mondata_show(struct seq_file *m, void *arg)
599{
600	struct kernfs_open_file *of = m->private;
601	enum resctrl_res_level resid;
602	enum resctrl_event_id evtid;
603	struct rdt_domain_hdr *hdr;
604	struct rmid_read rr = {0};
605	struct rdt_mon_domain *d;
606	struct rdtgroup *rdtgrp;
607	int domid, cpu, ret = 0;
608	struct rdt_resource *r;
609	struct cacheinfo *ci;
610	struct mon_data *md;
611
612	rdtgrp = rdtgroup_kn_lock_live(of->kn);
613	if (!rdtgrp) {
614		ret = -ENOENT;
615		goto out;
616	}
617
618	md = of->kn->priv;
619	if (WARN_ON_ONCE(!md)) {
620		ret = -EIO;
621		goto out;
622	}
623
624	resid = md->rid;
625	domid = md->domid;
626	evtid = md->evtid;
627	r = resctrl_arch_get_resource(resid);
628
629	if (md->sum) {
630		/*
631		 * This file requires summing across all domains that share
632		 * the L3 cache id that was provided in the "domid" field of the
633		 * struct mon_data. Search all domains in the resource for
634		 * one that matches this cache id.
635		 */
636		list_for_each_entry(d, &r->mon_domains, hdr.list) {
637			if (d->ci_id == domid) {
638				cpu = cpumask_any(&d->hdr.cpu_mask);
639				ci = get_cpu_cacheinfo_level(cpu, RESCTRL_L3_CACHE);
640				if (!ci)
641					continue;
642				rr.ci = ci;
643				mon_event_read(&rr, r, NULL, rdtgrp,
644					       &ci->shared_cpu_map, evtid, false);
645				goto checkresult;
646			}
647		}
648		ret = -ENOENT;
649		goto out;
650	} else {
651		/*
652		 * This file provides data from a single domain. Search
653		 * the resource to find the domain with "domid".
654		 */
655		hdr = resctrl_find_domain(&r->mon_domains, domid, NULL);
656		if (!hdr || WARN_ON_ONCE(hdr->type != RESCTRL_MON_DOMAIN)) {
657			ret = -ENOENT;
658			goto out;
659		}
660		d = container_of(hdr, struct rdt_mon_domain, hdr);
661		mon_event_read(&rr, r, d, rdtgrp, &d->hdr.cpu_mask, evtid, false);
662	}
663
664checkresult:
665
666	/*
667	 * -ENOENT is a special case, set only when "mbm_event" counter assignment
668	 * mode is enabled and no counter has been assigned.
669	 */
670	if (rr.err == -EIO)
671		seq_puts(m, "Error\n");
672	else if (rr.err == -EINVAL)
673		seq_puts(m, "Unavailable\n");
674	else if (rr.err == -ENOENT)
675		seq_puts(m, "Unassigned\n");
676	else
677		seq_printf(m, "%llu\n", rr.val);
678
679out:
680	rdtgroup_kn_unlock(of->kn);
681	return ret;
682}
683
684int resctrl_io_alloc_show(struct kernfs_open_file *of, struct seq_file *seq, void *v)
685{
686	struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
687	struct rdt_resource *r = s->res;
688
689	mutex_lock(&rdtgroup_mutex);
690
691	if (r->cache.io_alloc_capable) {
692		if (resctrl_arch_get_io_alloc_enabled(r))
693			seq_puts(seq, "enabled\n");
694		else
695			seq_puts(seq, "disabled\n");
696	} else {
697		seq_puts(seq, "not supported\n");
698	}
699
700	mutex_unlock(&rdtgroup_mutex);
701
702	return 0;
703}
704
705/*
706 * resctrl_io_alloc_closid_supported() - io_alloc feature utilizes the
707 * highest CLOSID value to direct I/O traffic. Ensure that io_alloc_closid
708 * is in the supported range.
709 */
710static bool resctrl_io_alloc_closid_supported(u32 io_alloc_closid)
711{
712	return io_alloc_closid < closids_supported();
713}
714
715/*
716 * Initialize io_alloc CLOSID cache resource CBM with all usable (shared
717 * and unused) cache portions.
718 */
719static int resctrl_io_alloc_init_cbm(struct resctrl_schema *s, u32 closid)
720{
721	enum resctrl_conf_type peer_type;
722	struct rdt_resource *r = s->res;
723	struct rdt_ctrl_domain *d;
724	int ret;
725
726	rdt_staged_configs_clear();
727
728	ret = rdtgroup_init_cat(s, closid);
729	if (ret < 0)
730		goto out;
731
732	/* Keep CDP_CODE and CDP_DATA of io_alloc CLOSID's CBM in sync. */
733	if (resctrl_arch_get_cdp_enabled(r->rid)) {
734		peer_type = resctrl_peer_type(s->conf_type);
735		list_for_each_entry(d, &s->res->ctrl_domains, hdr.list)
736			memcpy(&d->staged_config[peer_type],
737			       &d->staged_config[s->conf_type],
738			       sizeof(d->staged_config[0]));
739	}
740
741	ret = resctrl_arch_update_domains(r, closid);
742out:
743	rdt_staged_configs_clear();
744	return ret;
745}
746
747/*
748 * resctrl_io_alloc_closid() - io_alloc feature routes I/O traffic using
749 * the highest available CLOSID. Retrieve the maximum CLOSID supported by the
750 * resource. Note that if Code Data Prioritization (CDP) is enabled, the number
751 * of available CLOSIDs is reduced by half.
752 */
753u32 resctrl_io_alloc_closid(struct rdt_resource *r)
754{
755	if (resctrl_arch_get_cdp_enabled(r->rid))
756		return resctrl_arch_get_num_closid(r) / 2  - 1;
757	else
758		return resctrl_arch_get_num_closid(r) - 1;
759}
760
761ssize_t resctrl_io_alloc_write(struct kernfs_open_file *of, char *buf,
762			       size_t nbytes, loff_t off)
763{
764	struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
765	struct rdt_resource *r = s->res;
766	char const *grp_name;
767	u32 io_alloc_closid;
768	bool enable;
769	int ret;
770
771	ret = kstrtobool(buf, &enable);
772	if (ret)
773		return ret;
774
775	cpus_read_lock();
776	mutex_lock(&rdtgroup_mutex);
777
778	rdt_last_cmd_clear();
779
780	if (!r->cache.io_alloc_capable) {
781		rdt_last_cmd_printf("io_alloc is not supported on %s\n", s->name);
782		ret = -ENODEV;
783		goto out_unlock;
784	}
785
786	/* If the feature is already up to date, no action is needed. */
787	if (resctrl_arch_get_io_alloc_enabled(r) == enable)
788		goto out_unlock;
789
790	io_alloc_closid = resctrl_io_alloc_closid(r);
791	if (!resctrl_io_alloc_closid_supported(io_alloc_closid)) {
792		rdt_last_cmd_printf("io_alloc CLOSID (ctrl_hw_id) %u is not available\n",
793				    io_alloc_closid);
794		ret = -EINVAL;
795		goto out_unlock;
796	}
797
798	if (enable) {
799		if (!closid_alloc_fixed(io_alloc_closid)) {
800			grp_name = rdtgroup_name_by_closid(io_alloc_closid);
801			WARN_ON_ONCE(!grp_name);
802			rdt_last_cmd_printf("CLOSID (ctrl_hw_id) %u for io_alloc is used by %s group\n",
803					    io_alloc_closid, grp_name ? grp_name : "another");
804			ret = -ENOSPC;
805			goto out_unlock;
806		}
807
808		ret = resctrl_io_alloc_init_cbm(s, io_alloc_closid);
809		if (ret) {
810			rdt_last_cmd_puts("Failed to initialize io_alloc allocations\n");
811			closid_free(io_alloc_closid);
812			goto out_unlock;
813		}
814	} else {
815		closid_free(io_alloc_closid);
816	}
817
818	ret = resctrl_arch_io_alloc_enable(r, enable);
819	if (enable && ret) {
820		rdt_last_cmd_puts("Failed to enable io_alloc feature\n");
821		closid_free(io_alloc_closid);
822	}
823
824out_unlock:
825	mutex_unlock(&rdtgroup_mutex);
826	cpus_read_unlock();
827
828	return ret ?: nbytes;
829}
830
831int resctrl_io_alloc_cbm_show(struct kernfs_open_file *of, struct seq_file *seq, void *v)
832{
833	struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
834	struct rdt_resource *r = s->res;
835	int ret = 0;
836
837	cpus_read_lock();
838	mutex_lock(&rdtgroup_mutex);
839
840	rdt_last_cmd_clear();
841
842	if (!r->cache.io_alloc_capable) {
843		rdt_last_cmd_printf("io_alloc is not supported on %s\n", s->name);
844		ret = -ENODEV;
845		goto out_unlock;
846	}
847
848	if (!resctrl_arch_get_io_alloc_enabled(r)) {
849		rdt_last_cmd_printf("io_alloc is not enabled on %s\n", s->name);
850		ret = -EINVAL;
851		goto out_unlock;
852	}
853
854	/*
855	 * When CDP is enabled, the CBMs of the highest CLOSID of CDP_CODE and
856	 * CDP_DATA are kept in sync. As a result, the io_alloc CBMs shown for
857	 * either CDP resource are identical and accurately represent the CBMs
858	 * used for I/O.
859	 */
860	show_doms(seq, s, NULL, resctrl_io_alloc_closid(r));
861
862out_unlock:
863	mutex_unlock(&rdtgroup_mutex);
864	cpus_read_unlock();
865	return ret;
866}
867
868static int resctrl_io_alloc_parse_line(char *line,  struct rdt_resource *r,
869				       struct resctrl_schema *s, u32 closid)
870{
871	enum resctrl_conf_type peer_type;
872	struct rdt_parse_data data;
873	struct rdt_ctrl_domain *d;
874	char *dom = NULL, *id;
875	unsigned long dom_id;
876
877next:
878	if (!line || line[0] == '\0')
879		return 0;
880
881	dom = strsep(&line, ";");
882	id = strsep(&dom, "=");
883	if (!dom || kstrtoul(id, 10, &dom_id)) {
884		rdt_last_cmd_puts("Missing '=' or non-numeric domain\n");
885		return -EINVAL;
886	}
887
888	dom = strim(dom);
889	list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
890		if (d->hdr.id == dom_id) {
891			data.buf = dom;
892			data.mode = RDT_MODE_SHAREABLE;
893			data.closid = closid;
894			if (parse_cbm(&data, s, d))
895				return -EINVAL;
896			/*
897			 * Keep io_alloc CLOSID's CBM of CDP_CODE and CDP_DATA
898			 * in sync.
899			 */
900			if (resctrl_arch_get_cdp_enabled(r->rid)) {
901				peer_type = resctrl_peer_type(s->conf_type);
902				memcpy(&d->staged_config[peer_type],
903				       &d->staged_config[s->conf_type],
904				       sizeof(d->staged_config[0]));
905			}
906			goto next;
907		}
908	}
909
910	return -EINVAL;
911}
912
913ssize_t resctrl_io_alloc_cbm_write(struct kernfs_open_file *of, char *buf,
914				   size_t nbytes, loff_t off)
915{
916	struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
917	struct rdt_resource *r = s->res;
918	u32 io_alloc_closid;
919	int ret = 0;
920
921	/* Valid input requires a trailing newline */
922	if (nbytes == 0 || buf[nbytes - 1] != '\n')
923		return -EINVAL;
924
925	buf[nbytes - 1] = '\0';
926
927	cpus_read_lock();
928	mutex_lock(&rdtgroup_mutex);
929	rdt_last_cmd_clear();
930
931	if (!r->cache.io_alloc_capable) {
932		rdt_last_cmd_printf("io_alloc is not supported on %s\n", s->name);
933		ret = -ENODEV;
934		goto out_unlock;
935	}
936
937	if (!resctrl_arch_get_io_alloc_enabled(r)) {
938		rdt_last_cmd_printf("io_alloc is not enabled on %s\n", s->name);
939		ret = -EINVAL;
940		goto out_unlock;
941	}
942
943	io_alloc_closid = resctrl_io_alloc_closid(r);
944
945	rdt_staged_configs_clear();
946	ret = resctrl_io_alloc_parse_line(buf, r, s, io_alloc_closid);
947	if (ret)
948		goto out_clear_configs;
949
950	ret = resctrl_arch_update_domains(r, io_alloc_closid);
951
952out_clear_configs:
953	rdt_staged_configs_clear();
954out_unlock:
955	mutex_unlock(&rdtgroup_mutex);
956	cpus_read_unlock();
957
958	return ret ?: nbytes;
959}
~/ Read-only file preview.