xref: /linux/fs/resctrl/rdtgroup.c (revision 5c00eca95a9a20e662bd290c3ef3f2e07dfa9baa)
17168ae33SJames Morse // SPDX-License-Identifier: GPL-2.0-only
27168ae33SJames Morse /*
37168ae33SJames Morse  * User interface for Resource Allocation in Resource Director Technology(RDT)
47168ae33SJames Morse  *
57168ae33SJames Morse  * Copyright (C) 2016 Intel Corporation
67168ae33SJames Morse  *
77168ae33SJames Morse  * Author: Fenghua Yu <fenghua.yu@intel.com>
87168ae33SJames Morse  *
97168ae33SJames Morse  * More information about RDT be found in the Intel (R) x86 Architecture
107168ae33SJames Morse  * Software Developer Manual.
117168ae33SJames Morse  */
127168ae33SJames Morse 
137168ae33SJames Morse #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
147168ae33SJames Morse 
157168ae33SJames Morse #include <linux/cpu.h>
167168ae33SJames Morse #include <linux/debugfs.h>
177168ae33SJames Morse #include <linux/fs.h>
187168ae33SJames Morse #include <linux/fs_parser.h>
197168ae33SJames Morse #include <linux/sysfs.h>
207168ae33SJames Morse #include <linux/kernfs.h>
217168ae33SJames Morse #include <linux/resctrl.h>
227168ae33SJames Morse #include <linux/seq_buf.h>
237168ae33SJames Morse #include <linux/seq_file.h>
247168ae33SJames Morse #include <linux/sched/task.h>
257168ae33SJames Morse #include <linux/slab.h>
267168ae33SJames Morse #include <linux/user_namespace.h>
277168ae33SJames Morse 
287168ae33SJames Morse #include <uapi/linux/magic.h>
297168ae33SJames Morse 
307168ae33SJames Morse #include "internal.h"
317168ae33SJames Morse 
327168ae33SJames Morse /* Mutex to protect rdtgroup access. */
337168ae33SJames Morse DEFINE_MUTEX(rdtgroup_mutex);
347168ae33SJames Morse 
357168ae33SJames Morse static struct kernfs_root *rdt_root;
367168ae33SJames Morse 
377168ae33SJames Morse struct rdtgroup rdtgroup_default;
387168ae33SJames Morse 
397168ae33SJames Morse LIST_HEAD(rdt_all_groups);
407168ae33SJames Morse 
417168ae33SJames Morse /* list of entries for the schemata file */
427168ae33SJames Morse LIST_HEAD(resctrl_schema_all);
437168ae33SJames Morse 
447168ae33SJames Morse /*
457168ae33SJames Morse  * List of struct mon_data containing private data of event files for use by
467168ae33SJames Morse  * rdtgroup_mondata_show(). Protected by rdtgroup_mutex.
477168ae33SJames Morse  */
487168ae33SJames Morse static LIST_HEAD(mon_data_kn_priv_list);
497168ae33SJames Morse 
507168ae33SJames Morse /* The filesystem can only be mounted once. */
517168ae33SJames Morse bool resctrl_mounted;
527168ae33SJames Morse 
537168ae33SJames Morse /* Kernel fs node for "info" directory under root */
547168ae33SJames Morse static struct kernfs_node *kn_info;
557168ae33SJames Morse 
567168ae33SJames Morse /* Kernel fs node for "mon_groups" directory under root */
577168ae33SJames Morse static struct kernfs_node *kn_mongrp;
587168ae33SJames Morse 
597168ae33SJames Morse /* Kernel fs node for "mon_data" directory under root */
607168ae33SJames Morse static struct kernfs_node *kn_mondata;
617168ae33SJames Morse 
627168ae33SJames Morse /*
637168ae33SJames Morse  * Used to store the max resource name width to display the schemata names in
647168ae33SJames Morse  * a tabular format.
657168ae33SJames Morse  */
667168ae33SJames Morse int max_name_width;
677168ae33SJames Morse 
687168ae33SJames Morse static struct seq_buf last_cmd_status;
697168ae33SJames Morse 
707168ae33SJames Morse static char last_cmd_status_buf[512];
717168ae33SJames Morse 
727168ae33SJames Morse static int rdtgroup_setup_root(struct rdt_fs_context *ctx);
737168ae33SJames Morse 
747168ae33SJames Morse static void rdtgroup_destroy_root(void);
757168ae33SJames Morse 
767168ae33SJames Morse struct dentry *debugfs_resctrl;
777168ae33SJames Morse 
787168ae33SJames Morse /*
797168ae33SJames Morse  * Memory bandwidth monitoring event to use for the default CTRL_MON group
807168ae33SJames Morse  * and each new CTRL_MON group created by the user.  Only relevant when
817168ae33SJames Morse  * the filesystem is mounted with the "mba_MBps" option so it does not
827168ae33SJames Morse  * matter that it remains uninitialized on systems that do not support
837168ae33SJames Morse  * the "mba_MBps" option.
847168ae33SJames Morse  */
857168ae33SJames Morse enum resctrl_event_id mba_mbps_default_event;
867168ae33SJames Morse 
877168ae33SJames Morse static bool resctrl_debug;
887168ae33SJames Morse 
rdt_last_cmd_clear(void)897168ae33SJames Morse void rdt_last_cmd_clear(void)
907168ae33SJames Morse {
917168ae33SJames Morse 	lockdep_assert_held(&rdtgroup_mutex);
927168ae33SJames Morse 	seq_buf_clear(&last_cmd_status);
937168ae33SJames Morse }
947168ae33SJames Morse 
rdt_last_cmd_puts(const char * s)957168ae33SJames Morse void rdt_last_cmd_puts(const char *s)
967168ae33SJames Morse {
977168ae33SJames Morse 	lockdep_assert_held(&rdtgroup_mutex);
987168ae33SJames Morse 	seq_buf_puts(&last_cmd_status, s);
997168ae33SJames Morse }
1007168ae33SJames Morse 
rdt_last_cmd_printf(const char * fmt,...)1017168ae33SJames Morse void rdt_last_cmd_printf(const char *fmt, ...)
1027168ae33SJames Morse {
1037168ae33SJames Morse 	va_list ap;
1047168ae33SJames Morse 
1057168ae33SJames Morse 	va_start(ap, fmt);
1067168ae33SJames Morse 	lockdep_assert_held(&rdtgroup_mutex);
1077168ae33SJames Morse 	seq_buf_vprintf(&last_cmd_status, fmt, ap);
1087168ae33SJames Morse 	va_end(ap);
1097168ae33SJames Morse }
1107168ae33SJames Morse 
rdt_staged_configs_clear(void)1117168ae33SJames Morse void rdt_staged_configs_clear(void)
1127168ae33SJames Morse {
1137168ae33SJames Morse 	struct rdt_ctrl_domain *dom;
1147168ae33SJames Morse 	struct rdt_resource *r;
1157168ae33SJames Morse 
1167168ae33SJames Morse 	lockdep_assert_held(&rdtgroup_mutex);
1177168ae33SJames Morse 
1187168ae33SJames Morse 	for_each_alloc_capable_rdt_resource(r) {
1197168ae33SJames Morse 		list_for_each_entry(dom, &r->ctrl_domains, hdr.list)
1207168ae33SJames Morse 			memset(dom->staged_config, 0, sizeof(dom->staged_config));
1217168ae33SJames Morse 	}
1227168ae33SJames Morse }
1237168ae33SJames Morse 
resctrl_is_mbm_enabled(void)1247168ae33SJames Morse static bool resctrl_is_mbm_enabled(void)
1257168ae33SJames Morse {
1267168ae33SJames Morse 	return (resctrl_arch_is_mbm_total_enabled() ||
1277168ae33SJames Morse 		resctrl_arch_is_mbm_local_enabled());
1287168ae33SJames Morse }
1297168ae33SJames Morse 
resctrl_is_mbm_event(int e)1307168ae33SJames Morse static bool resctrl_is_mbm_event(int e)
1317168ae33SJames Morse {
1327168ae33SJames Morse 	return (e >= QOS_L3_MBM_TOTAL_EVENT_ID &&
1337168ae33SJames Morse 		e <= QOS_L3_MBM_LOCAL_EVENT_ID);
1347168ae33SJames Morse }
1357168ae33SJames Morse 
1367168ae33SJames Morse /*
1377168ae33SJames Morse  * Trivial allocator for CLOSIDs. Use BITMAP APIs to manipulate a bitmap
1387168ae33SJames Morse  * of free CLOSIDs.
1397168ae33SJames Morse  *
1407168ae33SJames Morse  * Using a global CLOSID across all resources has some advantages and
1417168ae33SJames Morse  * some drawbacks:
1427168ae33SJames Morse  * + We can simply set current's closid to assign a task to a resource
1437168ae33SJames Morse  *   group.
1447168ae33SJames Morse  * + Context switch code can avoid extra memory references deciding which
1457168ae33SJames Morse  *   CLOSID to load into the PQR_ASSOC MSR
1467168ae33SJames Morse  * - We give up some options in configuring resource groups across multi-socket
1477168ae33SJames Morse  *   systems.
1487168ae33SJames Morse  * - Our choices on how to configure each resource become progressively more
1497168ae33SJames Morse  *   limited as the number of resources grows.
1507168ae33SJames Morse  */
1517168ae33SJames Morse static unsigned long *closid_free_map;
1527168ae33SJames Morse 
1537168ae33SJames Morse static int closid_free_map_len;
1547168ae33SJames Morse 
closids_supported(void)1557168ae33SJames Morse int closids_supported(void)
1567168ae33SJames Morse {
1577168ae33SJames Morse 	return closid_free_map_len;
1587168ae33SJames Morse }
1597168ae33SJames Morse 
closid_init(void)1607168ae33SJames Morse static int closid_init(void)
1617168ae33SJames Morse {
1627168ae33SJames Morse 	struct resctrl_schema *s;
1637168ae33SJames Morse 	u32 rdt_min_closid = ~0;
1647168ae33SJames Morse 
1657168ae33SJames Morse 	/* Monitor only platforms still call closid_init() */
1667168ae33SJames Morse 	if (list_empty(&resctrl_schema_all))
1677168ae33SJames Morse 		return 0;
1687168ae33SJames Morse 
1697168ae33SJames Morse 	/* Compute rdt_min_closid across all resources */
1707168ae33SJames Morse 	list_for_each_entry(s, &resctrl_schema_all, list)
1717168ae33SJames Morse 		rdt_min_closid = min(rdt_min_closid, s->num_closid);
1727168ae33SJames Morse 
1737168ae33SJames Morse 	closid_free_map = bitmap_alloc(rdt_min_closid, GFP_KERNEL);
1747168ae33SJames Morse 	if (!closid_free_map)
1757168ae33SJames Morse 		return -ENOMEM;
1767168ae33SJames Morse 	bitmap_fill(closid_free_map, rdt_min_closid);
1777168ae33SJames Morse 
1787168ae33SJames Morse 	/* RESCTRL_RESERVED_CLOSID is always reserved for the default group */
1797168ae33SJames Morse 	__clear_bit(RESCTRL_RESERVED_CLOSID, closid_free_map);
1807168ae33SJames Morse 	closid_free_map_len = rdt_min_closid;
1817168ae33SJames Morse 
1827168ae33SJames Morse 	return 0;
1837168ae33SJames Morse }
1847168ae33SJames Morse 
closid_exit(void)1857168ae33SJames Morse static void closid_exit(void)
1867168ae33SJames Morse {
1877168ae33SJames Morse 	bitmap_free(closid_free_map);
1887168ae33SJames Morse 	closid_free_map = NULL;
1897168ae33SJames Morse }
1907168ae33SJames Morse 
closid_alloc(void)1917168ae33SJames Morse static int closid_alloc(void)
1927168ae33SJames Morse {
1937168ae33SJames Morse 	int cleanest_closid;
1947168ae33SJames Morse 	u32 closid;
1957168ae33SJames Morse 
1967168ae33SJames Morse 	lockdep_assert_held(&rdtgroup_mutex);
1977168ae33SJames Morse 
1987168ae33SJames Morse 	if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID) &&
1997168ae33SJames Morse 	    resctrl_arch_is_llc_occupancy_enabled()) {
2007168ae33SJames Morse 		cleanest_closid = resctrl_find_cleanest_closid();
2017168ae33SJames Morse 		if (cleanest_closid < 0)
2027168ae33SJames Morse 			return cleanest_closid;
2037168ae33SJames Morse 		closid = cleanest_closid;
2047168ae33SJames Morse 	} else {
2057168ae33SJames Morse 		closid = find_first_bit(closid_free_map, closid_free_map_len);
2067168ae33SJames Morse 		if (closid == closid_free_map_len)
2077168ae33SJames Morse 			return -ENOSPC;
2087168ae33SJames Morse 	}
2097168ae33SJames Morse 	__clear_bit(closid, closid_free_map);
2107168ae33SJames Morse 
2117168ae33SJames Morse 	return closid;
2127168ae33SJames Morse }
2137168ae33SJames Morse 
closid_free(int closid)2147168ae33SJames Morse void closid_free(int closid)
2157168ae33SJames Morse {
2167168ae33SJames Morse 	lockdep_assert_held(&rdtgroup_mutex);
2177168ae33SJames Morse 
2187168ae33SJames Morse 	__set_bit(closid, closid_free_map);
2197168ae33SJames Morse }
2207168ae33SJames Morse 
2217168ae33SJames Morse /**
2227168ae33SJames Morse  * closid_allocated - test if provided closid is in use
2237168ae33SJames Morse  * @closid: closid to be tested
2247168ae33SJames Morse  *
2257168ae33SJames Morse  * Return: true if @closid is currently associated with a resource group,
2267168ae33SJames Morse  * false if @closid is free
2277168ae33SJames Morse  */
closid_allocated(unsigned int closid)2287168ae33SJames Morse bool closid_allocated(unsigned int closid)
2297168ae33SJames Morse {
2307168ae33SJames Morse 	lockdep_assert_held(&rdtgroup_mutex);
2317168ae33SJames Morse 
2327168ae33SJames Morse 	return !test_bit(closid, closid_free_map);
2337168ae33SJames Morse }
2347168ae33SJames Morse 
2357168ae33SJames Morse /**
2367168ae33SJames Morse  * rdtgroup_mode_by_closid - Return mode of resource group with closid
2377168ae33SJames Morse  * @closid: closid if the resource group
2387168ae33SJames Morse  *
2397168ae33SJames Morse  * Each resource group is associated with a @closid. Here the mode
2407168ae33SJames Morse  * of a resource group can be queried by searching for it using its closid.
2417168ae33SJames Morse  *
2427168ae33SJames Morse  * Return: mode as &enum rdtgrp_mode of resource group with closid @closid
2437168ae33SJames Morse  */
rdtgroup_mode_by_closid(int closid)2447168ae33SJames Morse enum rdtgrp_mode rdtgroup_mode_by_closid(int closid)
2457168ae33SJames Morse {
2467168ae33SJames Morse 	struct rdtgroup *rdtgrp;
2477168ae33SJames Morse 
2487168ae33SJames Morse 	list_for_each_entry(rdtgrp, &rdt_all_groups, rdtgroup_list) {
2497168ae33SJames Morse 		if (rdtgrp->closid == closid)
2507168ae33SJames Morse 			return rdtgrp->mode;
2517168ae33SJames Morse 	}
2527168ae33SJames Morse 
2537168ae33SJames Morse 	return RDT_NUM_MODES;
2547168ae33SJames Morse }
2557168ae33SJames Morse 
2567168ae33SJames Morse static const char * const rdt_mode_str[] = {
2577168ae33SJames Morse 	[RDT_MODE_SHAREABLE]		= "shareable",
2587168ae33SJames Morse 	[RDT_MODE_EXCLUSIVE]		= "exclusive",
2597168ae33SJames Morse 	[RDT_MODE_PSEUDO_LOCKSETUP]	= "pseudo-locksetup",
2607168ae33SJames Morse 	[RDT_MODE_PSEUDO_LOCKED]	= "pseudo-locked",
2617168ae33SJames Morse };
2627168ae33SJames Morse 
2637168ae33SJames Morse /**
2647168ae33SJames Morse  * rdtgroup_mode_str - Return the string representation of mode
2657168ae33SJames Morse  * @mode: the resource group mode as &enum rdtgroup_mode
2667168ae33SJames Morse  *
2677168ae33SJames Morse  * Return: string representation of valid mode, "unknown" otherwise
2687168ae33SJames Morse  */
rdtgroup_mode_str(enum rdtgrp_mode mode)2697168ae33SJames Morse static const char *rdtgroup_mode_str(enum rdtgrp_mode mode)
2707168ae33SJames Morse {
2717168ae33SJames Morse 	if (mode < RDT_MODE_SHAREABLE || mode >= RDT_NUM_MODES)
2727168ae33SJames Morse 		return "unknown";
2737168ae33SJames Morse 
2747168ae33SJames Morse 	return rdt_mode_str[mode];
2757168ae33SJames Morse }
2767168ae33SJames Morse 
2777168ae33SJames Morse /* set uid and gid of rdtgroup dirs and files to that of the creator */
rdtgroup_kn_set_ugid(struct kernfs_node * kn)2787168ae33SJames Morse static int rdtgroup_kn_set_ugid(struct kernfs_node *kn)
2797168ae33SJames Morse {
2807168ae33SJames Morse 	struct iattr iattr = { .ia_valid = ATTR_UID | ATTR_GID,
2817168ae33SJames Morse 				.ia_uid = current_fsuid(),
2827168ae33SJames Morse 				.ia_gid = current_fsgid(), };
2837168ae33SJames Morse 
2847168ae33SJames Morse 	if (uid_eq(iattr.ia_uid, GLOBAL_ROOT_UID) &&
2857168ae33SJames Morse 	    gid_eq(iattr.ia_gid, GLOBAL_ROOT_GID))
2867168ae33SJames Morse 		return 0;
2877168ae33SJames Morse 
2887168ae33SJames Morse 	return kernfs_setattr(kn, &iattr);
2897168ae33SJames Morse }
2907168ae33SJames Morse 
rdtgroup_add_file(struct kernfs_node * parent_kn,struct rftype * rft)2917168ae33SJames Morse static int rdtgroup_add_file(struct kernfs_node *parent_kn, struct rftype *rft)
2927168ae33SJames Morse {
2937168ae33SJames Morse 	struct kernfs_node *kn;
2947168ae33SJames Morse 	int ret;
2957168ae33SJames Morse 
2967168ae33SJames Morse 	kn = __kernfs_create_file(parent_kn, rft->name, rft->mode,
2977168ae33SJames Morse 				  GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
2987168ae33SJames Morse 				  0, rft->kf_ops, rft, NULL, NULL);
2997168ae33SJames Morse 	if (IS_ERR(kn))
3007168ae33SJames Morse 		return PTR_ERR(kn);
3017168ae33SJames Morse 
3027168ae33SJames Morse 	ret = rdtgroup_kn_set_ugid(kn);
3037168ae33SJames Morse 	if (ret) {
3047168ae33SJames Morse 		kernfs_remove(kn);
3057168ae33SJames Morse 		return ret;
3067168ae33SJames Morse 	}
3077168ae33SJames Morse 
3087168ae33SJames Morse 	return 0;
3097168ae33SJames Morse }
3107168ae33SJames Morse 
rdtgroup_seqfile_show(struct seq_file * m,void * arg)3117168ae33SJames Morse static int rdtgroup_seqfile_show(struct seq_file *m, void *arg)
3127168ae33SJames Morse {
3137168ae33SJames Morse 	struct kernfs_open_file *of = m->private;
3147168ae33SJames Morse 	struct rftype *rft = of->kn->priv;
3157168ae33SJames Morse 
3167168ae33SJames Morse 	if (rft->seq_show)
3177168ae33SJames Morse 		return rft->seq_show(of, m, arg);
3187168ae33SJames Morse 	return 0;
3197168ae33SJames Morse }
3207168ae33SJames Morse 
rdtgroup_file_write(struct kernfs_open_file * of,char * buf,size_t nbytes,loff_t off)3217168ae33SJames Morse static ssize_t rdtgroup_file_write(struct kernfs_open_file *of, char *buf,
3227168ae33SJames Morse 				   size_t nbytes, loff_t off)
3237168ae33SJames Morse {
3247168ae33SJames Morse 	struct rftype *rft = of->kn->priv;
3257168ae33SJames Morse 
3267168ae33SJames Morse 	if (rft->write)
3277168ae33SJames Morse 		return rft->write(of, buf, nbytes, off);
3287168ae33SJames Morse 
3297168ae33SJames Morse 	return -EINVAL;
3307168ae33SJames Morse }
3317168ae33SJames Morse 
3327168ae33SJames Morse static const struct kernfs_ops rdtgroup_kf_single_ops = {
3337168ae33SJames Morse 	.atomic_write_len	= PAGE_SIZE,
3347168ae33SJames Morse 	.write			= rdtgroup_file_write,
3357168ae33SJames Morse 	.seq_show		= rdtgroup_seqfile_show,
3367168ae33SJames Morse };
3377168ae33SJames Morse 
3387168ae33SJames Morse static const struct kernfs_ops kf_mondata_ops = {
3397168ae33SJames Morse 	.atomic_write_len	= PAGE_SIZE,
3407168ae33SJames Morse 	.seq_show		= rdtgroup_mondata_show,
3417168ae33SJames Morse };
3427168ae33SJames Morse 
is_cpu_list(struct kernfs_open_file * of)3437168ae33SJames Morse static bool is_cpu_list(struct kernfs_open_file *of)
3447168ae33SJames Morse {
3457168ae33SJames Morse 	struct rftype *rft = of->kn->priv;
3467168ae33SJames Morse 
3477168ae33SJames Morse 	return rft->flags & RFTYPE_FLAGS_CPUS_LIST;
3487168ae33SJames Morse }
3497168ae33SJames Morse 
rdtgroup_cpus_show(struct kernfs_open_file * of,struct seq_file * s,void * v)3507168ae33SJames Morse static int rdtgroup_cpus_show(struct kernfs_open_file *of,
3517168ae33SJames Morse 			      struct seq_file *s, void *v)
3527168ae33SJames Morse {
3537168ae33SJames Morse 	struct rdtgroup *rdtgrp;
3547168ae33SJames Morse 	struct cpumask *mask;
3557168ae33SJames Morse 	int ret = 0;
3567168ae33SJames Morse 
3577168ae33SJames Morse 	rdtgrp = rdtgroup_kn_lock_live(of->kn);
3587168ae33SJames Morse 
3597168ae33SJames Morse 	if (rdtgrp) {
3607168ae33SJames Morse 		if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
3617168ae33SJames Morse 			if (!rdtgrp->plr->d) {
3627168ae33SJames Morse 				rdt_last_cmd_clear();
3637168ae33SJames Morse 				rdt_last_cmd_puts("Cache domain offline\n");
3647168ae33SJames Morse 				ret = -ENODEV;
3657168ae33SJames Morse 			} else {
3667168ae33SJames Morse 				mask = &rdtgrp->plr->d->hdr.cpu_mask;
3677168ae33SJames Morse 				seq_printf(s, is_cpu_list(of) ?
3687168ae33SJames Morse 					   "%*pbl\n" : "%*pb\n",
3697168ae33SJames Morse 					   cpumask_pr_args(mask));
3707168ae33SJames Morse 			}
3717168ae33SJames Morse 		} else {
3727168ae33SJames Morse 			seq_printf(s, is_cpu_list(of) ? "%*pbl\n" : "%*pb\n",
3737168ae33SJames Morse 				   cpumask_pr_args(&rdtgrp->cpu_mask));
3747168ae33SJames Morse 		}
3757168ae33SJames Morse 	} else {
3767168ae33SJames Morse 		ret = -ENOENT;
3777168ae33SJames Morse 	}
3787168ae33SJames Morse 	rdtgroup_kn_unlock(of->kn);
3797168ae33SJames Morse 
3807168ae33SJames Morse 	return ret;
3817168ae33SJames Morse }
3827168ae33SJames Morse 
3837168ae33SJames Morse /*
3847168ae33SJames Morse  * Update the PGR_ASSOC MSR on all cpus in @cpu_mask,
3857168ae33SJames Morse  *
3867168ae33SJames Morse  * Per task closids/rmids must have been set up before calling this function.
3877168ae33SJames Morse  * @r may be NULL.
3887168ae33SJames Morse  */
3897168ae33SJames Morse static void
update_closid_rmid(const struct cpumask * cpu_mask,struct rdtgroup * r)3907168ae33SJames Morse update_closid_rmid(const struct cpumask *cpu_mask, struct rdtgroup *r)
3917168ae33SJames Morse {
3927168ae33SJames Morse 	struct resctrl_cpu_defaults defaults, *p = NULL;
3937168ae33SJames Morse 
3947168ae33SJames Morse 	if (r) {
3957168ae33SJames Morse 		defaults.closid = r->closid;
3967168ae33SJames Morse 		defaults.rmid = r->mon.rmid;
3977168ae33SJames Morse 		p = &defaults;
3987168ae33SJames Morse 	}
3997168ae33SJames Morse 
4007168ae33SJames Morse 	on_each_cpu_mask(cpu_mask, resctrl_arch_sync_cpu_closid_rmid, p, 1);
4017168ae33SJames Morse }
4027168ae33SJames Morse 
cpus_mon_write(struct rdtgroup * rdtgrp,cpumask_var_t newmask,cpumask_var_t tmpmask)4037168ae33SJames Morse static int cpus_mon_write(struct rdtgroup *rdtgrp, cpumask_var_t newmask,
4047168ae33SJames Morse 			  cpumask_var_t tmpmask)
4057168ae33SJames Morse {
4067168ae33SJames Morse 	struct rdtgroup *prgrp = rdtgrp->mon.parent, *crgrp;
4077168ae33SJames Morse 	struct list_head *head;
4087168ae33SJames Morse 
4097168ae33SJames Morse 	/* Check whether cpus belong to parent ctrl group */
4107168ae33SJames Morse 	cpumask_andnot(tmpmask, newmask, &prgrp->cpu_mask);
4117168ae33SJames Morse 	if (!cpumask_empty(tmpmask)) {
4127168ae33SJames Morse 		rdt_last_cmd_puts("Can only add CPUs to mongroup that belong to parent\n");
4137168ae33SJames Morse 		return -EINVAL;
4147168ae33SJames Morse 	}
4157168ae33SJames Morse 
4167168ae33SJames Morse 	/* Check whether cpus are dropped from this group */
4177168ae33SJames Morse 	cpumask_andnot(tmpmask, &rdtgrp->cpu_mask, newmask);
4187168ae33SJames Morse 	if (!cpumask_empty(tmpmask)) {
4197168ae33SJames Morse 		/* Give any dropped cpus to parent rdtgroup */
4207168ae33SJames Morse 		cpumask_or(&prgrp->cpu_mask, &prgrp->cpu_mask, tmpmask);
4217168ae33SJames Morse 		update_closid_rmid(tmpmask, prgrp);
4227168ae33SJames Morse 	}
4237168ae33SJames Morse 
4247168ae33SJames Morse 	/*
4257168ae33SJames Morse 	 * If we added cpus, remove them from previous group that owned them
4267168ae33SJames Morse 	 * and update per-cpu rmid
4277168ae33SJames Morse 	 */
4287168ae33SJames Morse 	cpumask_andnot(tmpmask, newmask, &rdtgrp->cpu_mask);
4297168ae33SJames Morse 	if (!cpumask_empty(tmpmask)) {
4307168ae33SJames Morse 		head = &prgrp->mon.crdtgrp_list;
4317168ae33SJames Morse 		list_for_each_entry(crgrp, head, mon.crdtgrp_list) {
4327168ae33SJames Morse 			if (crgrp == rdtgrp)
4337168ae33SJames Morse 				continue;
4347168ae33SJames Morse 			cpumask_andnot(&crgrp->cpu_mask, &crgrp->cpu_mask,
4357168ae33SJames Morse 				       tmpmask);
4367168ae33SJames Morse 		}
4377168ae33SJames Morse 		update_closid_rmid(tmpmask, rdtgrp);
4387168ae33SJames Morse 	}
4397168ae33SJames Morse 
4407168ae33SJames Morse 	/* Done pushing/pulling - update this group with new mask */
4417168ae33SJames Morse 	cpumask_copy(&rdtgrp->cpu_mask, newmask);
4427168ae33SJames Morse 
4437168ae33SJames Morse 	return 0;
4447168ae33SJames Morse }
4457168ae33SJames Morse 
cpumask_rdtgrp_clear(struct rdtgroup * r,struct cpumask * m)4467168ae33SJames Morse static void cpumask_rdtgrp_clear(struct rdtgroup *r, struct cpumask *m)
4477168ae33SJames Morse {
4487168ae33SJames Morse 	struct rdtgroup *crgrp;
4497168ae33SJames Morse 
4507168ae33SJames Morse 	cpumask_andnot(&r->cpu_mask, &r->cpu_mask, m);
4517168ae33SJames Morse 	/* update the child mon group masks as well*/
4527168ae33SJames Morse 	list_for_each_entry(crgrp, &r->mon.crdtgrp_list, mon.crdtgrp_list)
4537168ae33SJames Morse 		cpumask_and(&crgrp->cpu_mask, &r->cpu_mask, &crgrp->cpu_mask);
4547168ae33SJames Morse }
4557168ae33SJames Morse 
cpus_ctrl_write(struct rdtgroup * rdtgrp,cpumask_var_t newmask,cpumask_var_t tmpmask,cpumask_var_t tmpmask1)4567168ae33SJames Morse static int cpus_ctrl_write(struct rdtgroup *rdtgrp, cpumask_var_t newmask,
4577168ae33SJames Morse 			   cpumask_var_t tmpmask, cpumask_var_t tmpmask1)
4587168ae33SJames Morse {
4597168ae33SJames Morse 	struct rdtgroup *r, *crgrp;
4607168ae33SJames Morse 	struct list_head *head;
4617168ae33SJames Morse 
4627168ae33SJames Morse 	/* Check whether cpus are dropped from this group */
4637168ae33SJames Morse 	cpumask_andnot(tmpmask, &rdtgrp->cpu_mask, newmask);
4647168ae33SJames Morse 	if (!cpumask_empty(tmpmask)) {
4657168ae33SJames Morse 		/* Can't drop from default group */
4667168ae33SJames Morse 		if (rdtgrp == &rdtgroup_default) {
4677168ae33SJames Morse 			rdt_last_cmd_puts("Can't drop CPUs from default group\n");
4687168ae33SJames Morse 			return -EINVAL;
4697168ae33SJames Morse 		}
4707168ae33SJames Morse 
4717168ae33SJames Morse 		/* Give any dropped cpus to rdtgroup_default */
4727168ae33SJames Morse 		cpumask_or(&rdtgroup_default.cpu_mask,
4737168ae33SJames Morse 			   &rdtgroup_default.cpu_mask, tmpmask);
4747168ae33SJames Morse 		update_closid_rmid(tmpmask, &rdtgroup_default);
4757168ae33SJames Morse 	}
4767168ae33SJames Morse 
4777168ae33SJames Morse 	/*
4787168ae33SJames Morse 	 * If we added cpus, remove them from previous group and
4797168ae33SJames Morse 	 * the prev group's child groups that owned them
4807168ae33SJames Morse 	 * and update per-cpu closid/rmid.
4817168ae33SJames Morse 	 */
4827168ae33SJames Morse 	cpumask_andnot(tmpmask, newmask, &rdtgrp->cpu_mask);
4837168ae33SJames Morse 	if (!cpumask_empty(tmpmask)) {
4847168ae33SJames Morse 		list_for_each_entry(r, &rdt_all_groups, rdtgroup_list) {
4857168ae33SJames Morse 			if (r == rdtgrp)
4867168ae33SJames Morse 				continue;
4877168ae33SJames Morse 			cpumask_and(tmpmask1, &r->cpu_mask, tmpmask);
4887168ae33SJames Morse 			if (!cpumask_empty(tmpmask1))
4897168ae33SJames Morse 				cpumask_rdtgrp_clear(r, tmpmask1);
4907168ae33SJames Morse 		}
4917168ae33SJames Morse 		update_closid_rmid(tmpmask, rdtgrp);
4927168ae33SJames Morse 	}
4937168ae33SJames Morse 
4947168ae33SJames Morse 	/* Done pushing/pulling - update this group with new mask */
4957168ae33SJames Morse 	cpumask_copy(&rdtgrp->cpu_mask, newmask);
4967168ae33SJames Morse 
4977168ae33SJames Morse 	/*
4987168ae33SJames Morse 	 * Clear child mon group masks since there is a new parent mask
4997168ae33SJames Morse 	 * now and update the rmid for the cpus the child lost.
5007168ae33SJames Morse 	 */
5017168ae33SJames Morse 	head = &rdtgrp->mon.crdtgrp_list;
5027168ae33SJames Morse 	list_for_each_entry(crgrp, head, mon.crdtgrp_list) {
5037168ae33SJames Morse 		cpumask_and(tmpmask, &rdtgrp->cpu_mask, &crgrp->cpu_mask);
5047168ae33SJames Morse 		update_closid_rmid(tmpmask, rdtgrp);
5057168ae33SJames Morse 		cpumask_clear(&crgrp->cpu_mask);
5067168ae33SJames Morse 	}
5077168ae33SJames Morse 
5087168ae33SJames Morse 	return 0;
5097168ae33SJames Morse }
5107168ae33SJames Morse 
rdtgroup_cpus_write(struct kernfs_open_file * of,char * buf,size_t nbytes,loff_t off)5117168ae33SJames Morse static ssize_t rdtgroup_cpus_write(struct kernfs_open_file *of,
5127168ae33SJames Morse 				   char *buf, size_t nbytes, loff_t off)
5137168ae33SJames Morse {
5147168ae33SJames Morse 	cpumask_var_t tmpmask, newmask, tmpmask1;
5157168ae33SJames Morse 	struct rdtgroup *rdtgrp;
5167168ae33SJames Morse 	int ret;
5177168ae33SJames Morse 
5187168ae33SJames Morse 	if (!buf)
5197168ae33SJames Morse 		return -EINVAL;
5207168ae33SJames Morse 
5217168ae33SJames Morse 	if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
5227168ae33SJames Morse 		return -ENOMEM;
5237168ae33SJames Morse 	if (!zalloc_cpumask_var(&newmask, GFP_KERNEL)) {
5247168ae33SJames Morse 		free_cpumask_var(tmpmask);
5257168ae33SJames Morse 		return -ENOMEM;
5267168ae33SJames Morse 	}
5277168ae33SJames Morse 	if (!zalloc_cpumask_var(&tmpmask1, GFP_KERNEL)) {
5287168ae33SJames Morse 		free_cpumask_var(tmpmask);
5297168ae33SJames Morse 		free_cpumask_var(newmask);
5307168ae33SJames Morse 		return -ENOMEM;
5317168ae33SJames Morse 	}
5327168ae33SJames Morse 
5337168ae33SJames Morse 	rdtgrp = rdtgroup_kn_lock_live(of->kn);
5347168ae33SJames Morse 	if (!rdtgrp) {
5357168ae33SJames Morse 		ret = -ENOENT;
5367168ae33SJames Morse 		goto unlock;
5377168ae33SJames Morse 	}
5387168ae33SJames Morse 
539dd2922dcSZeng Heng 	rdt_last_cmd_clear();
540dd2922dcSZeng Heng 
5417168ae33SJames Morse 	if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED ||
5427168ae33SJames Morse 	    rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
5437168ae33SJames Morse 		ret = -EINVAL;
5447168ae33SJames Morse 		rdt_last_cmd_puts("Pseudo-locking in progress\n");
5457168ae33SJames Morse 		goto unlock;
5467168ae33SJames Morse 	}
5477168ae33SJames Morse 
5487168ae33SJames Morse 	if (is_cpu_list(of))
5497168ae33SJames Morse 		ret = cpulist_parse(buf, newmask);
5507168ae33SJames Morse 	else
5517168ae33SJames Morse 		ret = cpumask_parse(buf, newmask);
5527168ae33SJames Morse 
5537168ae33SJames Morse 	if (ret) {
5547168ae33SJames Morse 		rdt_last_cmd_puts("Bad CPU list/mask\n");
5557168ae33SJames Morse 		goto unlock;
5567168ae33SJames Morse 	}
5577168ae33SJames Morse 
5587168ae33SJames Morse 	/* check that user didn't specify any offline cpus */
5597168ae33SJames Morse 	cpumask_andnot(tmpmask, newmask, cpu_online_mask);
5607168ae33SJames Morse 	if (!cpumask_empty(tmpmask)) {
5617168ae33SJames Morse 		ret = -EINVAL;
5627168ae33SJames Morse 		rdt_last_cmd_puts("Can only assign online CPUs\n");
5637168ae33SJames Morse 		goto unlock;
5647168ae33SJames Morse 	}
5657168ae33SJames Morse 
5667168ae33SJames Morse 	if (rdtgrp->type == RDTCTRL_GROUP)
5677168ae33SJames Morse 		ret = cpus_ctrl_write(rdtgrp, newmask, tmpmask, tmpmask1);
5687168ae33SJames Morse 	else if (rdtgrp->type == RDTMON_GROUP)
5697168ae33SJames Morse 		ret = cpus_mon_write(rdtgrp, newmask, tmpmask);
5707168ae33SJames Morse 	else
5717168ae33SJames Morse 		ret = -EINVAL;
5727168ae33SJames Morse 
5737168ae33SJames Morse unlock:
5747168ae33SJames Morse 	rdtgroup_kn_unlock(of->kn);
5757168ae33SJames Morse 	free_cpumask_var(tmpmask);
5767168ae33SJames Morse 	free_cpumask_var(newmask);
5777168ae33SJames Morse 	free_cpumask_var(tmpmask1);
5787168ae33SJames Morse 
5797168ae33SJames Morse 	return ret ?: nbytes;
5807168ae33SJames Morse }
5817168ae33SJames Morse 
5827168ae33SJames Morse /**
5837168ae33SJames Morse  * rdtgroup_remove - the helper to remove resource group safely
5847168ae33SJames Morse  * @rdtgrp: resource group to remove
5857168ae33SJames Morse  *
5867168ae33SJames Morse  * On resource group creation via a mkdir, an extra kernfs_node reference is
5877168ae33SJames Morse  * taken to ensure that the rdtgroup structure remains accessible for the
5887168ae33SJames Morse  * rdtgroup_kn_unlock() calls where it is removed.
5897168ae33SJames Morse  *
5907168ae33SJames Morse  * Drop the extra reference here, then free the rdtgroup structure.
5917168ae33SJames Morse  *
5927168ae33SJames Morse  * Return: void
5937168ae33SJames Morse  */
rdtgroup_remove(struct rdtgroup * rdtgrp)5947168ae33SJames Morse static void rdtgroup_remove(struct rdtgroup *rdtgrp)
5957168ae33SJames Morse {
5967168ae33SJames Morse 	kernfs_put(rdtgrp->kn);
5977168ae33SJames Morse 	kfree(rdtgrp);
5987168ae33SJames Morse }
5997168ae33SJames Morse 
_update_task_closid_rmid(void * task)6007168ae33SJames Morse static void _update_task_closid_rmid(void *task)
6017168ae33SJames Morse {
6027168ae33SJames Morse 	/*
6037168ae33SJames Morse 	 * If the task is still current on this CPU, update PQR_ASSOC MSR.
6047168ae33SJames Morse 	 * Otherwise, the MSR is updated when the task is scheduled in.
6057168ae33SJames Morse 	 */
6067168ae33SJames Morse 	if (task == current)
6077168ae33SJames Morse 		resctrl_arch_sched_in(task);
6087168ae33SJames Morse }
6097168ae33SJames Morse 
update_task_closid_rmid(struct task_struct * t)6107168ae33SJames Morse static void update_task_closid_rmid(struct task_struct *t)
6117168ae33SJames Morse {
6127168ae33SJames Morse 	if (IS_ENABLED(CONFIG_SMP) && task_curr(t))
6137168ae33SJames Morse 		smp_call_function_single(task_cpu(t), _update_task_closid_rmid, t, 1);
6147168ae33SJames Morse 	else
6157168ae33SJames Morse 		_update_task_closid_rmid(t);
6167168ae33SJames Morse }
6177168ae33SJames Morse 
task_in_rdtgroup(struct task_struct * tsk,struct rdtgroup * rdtgrp)6187168ae33SJames Morse static bool task_in_rdtgroup(struct task_struct *tsk, struct rdtgroup *rdtgrp)
6197168ae33SJames Morse {
6207168ae33SJames Morse 	u32 closid, rmid = rdtgrp->mon.rmid;
6217168ae33SJames Morse 
6227168ae33SJames Morse 	if (rdtgrp->type == RDTCTRL_GROUP)
6237168ae33SJames Morse 		closid = rdtgrp->closid;
6247168ae33SJames Morse 	else if (rdtgrp->type == RDTMON_GROUP)
6257168ae33SJames Morse 		closid = rdtgrp->mon.parent->closid;
6267168ae33SJames Morse 	else
6277168ae33SJames Morse 		return false;
6287168ae33SJames Morse 
6297168ae33SJames Morse 	return resctrl_arch_match_closid(tsk, closid) &&
6307168ae33SJames Morse 	       resctrl_arch_match_rmid(tsk, closid, rmid);
6317168ae33SJames Morse }
6327168ae33SJames Morse 
__rdtgroup_move_task(struct task_struct * tsk,struct rdtgroup * rdtgrp)6337168ae33SJames Morse static int __rdtgroup_move_task(struct task_struct *tsk,
6347168ae33SJames Morse 				struct rdtgroup *rdtgrp)
6357168ae33SJames Morse {
6367168ae33SJames Morse 	/* If the task is already in rdtgrp, no need to move the task. */
6377168ae33SJames Morse 	if (task_in_rdtgroup(tsk, rdtgrp))
6387168ae33SJames Morse 		return 0;
6397168ae33SJames Morse 
6407168ae33SJames Morse 	/*
6417168ae33SJames Morse 	 * Set the task's closid/rmid before the PQR_ASSOC MSR can be
6427168ae33SJames Morse 	 * updated by them.
6437168ae33SJames Morse 	 *
6447168ae33SJames Morse 	 * For ctrl_mon groups, move both closid and rmid.
6457168ae33SJames Morse 	 * For monitor groups, can move the tasks only from
6467168ae33SJames Morse 	 * their parent CTRL group.
6477168ae33SJames Morse 	 */
6487168ae33SJames Morse 	if (rdtgrp->type == RDTMON_GROUP &&
6497168ae33SJames Morse 	    !resctrl_arch_match_closid(tsk, rdtgrp->mon.parent->closid)) {
6507168ae33SJames Morse 		rdt_last_cmd_puts("Can't move task to different control group\n");
6517168ae33SJames Morse 		return -EINVAL;
6527168ae33SJames Morse 	}
6537168ae33SJames Morse 
6547168ae33SJames Morse 	if (rdtgrp->type == RDTMON_GROUP)
6557168ae33SJames Morse 		resctrl_arch_set_closid_rmid(tsk, rdtgrp->mon.parent->closid,
6567168ae33SJames Morse 					     rdtgrp->mon.rmid);
6577168ae33SJames Morse 	else
6587168ae33SJames Morse 		resctrl_arch_set_closid_rmid(tsk, rdtgrp->closid,
6597168ae33SJames Morse 					     rdtgrp->mon.rmid);
6607168ae33SJames Morse 
6617168ae33SJames Morse 	/*
6627168ae33SJames Morse 	 * Ensure the task's closid and rmid are written before determining if
6637168ae33SJames Morse 	 * the task is current that will decide if it will be interrupted.
6647168ae33SJames Morse 	 * This pairs with the full barrier between the rq->curr update and
6657168ae33SJames Morse 	 * resctrl_arch_sched_in() during context switch.
6667168ae33SJames Morse 	 */
6677168ae33SJames Morse 	smp_mb();
6687168ae33SJames Morse 
6697168ae33SJames Morse 	/*
6707168ae33SJames Morse 	 * By now, the task's closid and rmid are set. If the task is current
6717168ae33SJames Morse 	 * on a CPU, the PQR_ASSOC MSR needs to be updated to make the resource
6727168ae33SJames Morse 	 * group go into effect. If the task is not current, the MSR will be
6737168ae33SJames Morse 	 * updated when the task is scheduled in.
6747168ae33SJames Morse 	 */
6757168ae33SJames Morse 	update_task_closid_rmid(tsk);
6767168ae33SJames Morse 
6777168ae33SJames Morse 	return 0;
6787168ae33SJames Morse }
6797168ae33SJames Morse 
is_closid_match(struct task_struct * t,struct rdtgroup * r)6807168ae33SJames Morse static bool is_closid_match(struct task_struct *t, struct rdtgroup *r)
6817168ae33SJames Morse {
6827168ae33SJames Morse 	return (resctrl_arch_alloc_capable() && (r->type == RDTCTRL_GROUP) &&
6837168ae33SJames Morse 		resctrl_arch_match_closid(t, r->closid));
6847168ae33SJames Morse }
6857168ae33SJames Morse 
is_rmid_match(struct task_struct * t,struct rdtgroup * r)6867168ae33SJames Morse static bool is_rmid_match(struct task_struct *t, struct rdtgroup *r)
6877168ae33SJames Morse {
6887168ae33SJames Morse 	return (resctrl_arch_mon_capable() && (r->type == RDTMON_GROUP) &&
6897168ae33SJames Morse 		resctrl_arch_match_rmid(t, r->mon.parent->closid,
6907168ae33SJames Morse 					r->mon.rmid));
6917168ae33SJames Morse }
6927168ae33SJames Morse 
6937168ae33SJames Morse /**
6947168ae33SJames Morse  * rdtgroup_tasks_assigned - Test if tasks have been assigned to resource group
6957168ae33SJames Morse  * @r: Resource group
6967168ae33SJames Morse  *
6977168ae33SJames Morse  * Return: 1 if tasks have been assigned to @r, 0 otherwise
6987168ae33SJames Morse  */
rdtgroup_tasks_assigned(struct rdtgroup * r)6997168ae33SJames Morse int rdtgroup_tasks_assigned(struct rdtgroup *r)
7007168ae33SJames Morse {
7017168ae33SJames Morse 	struct task_struct *p, *t;
7027168ae33SJames Morse 	int ret = 0;
7037168ae33SJames Morse 
7047168ae33SJames Morse 	lockdep_assert_held(&rdtgroup_mutex);
7057168ae33SJames Morse 
7067168ae33SJames Morse 	rcu_read_lock();
7077168ae33SJames Morse 	for_each_process_thread(p, t) {
7087168ae33SJames Morse 		if (is_closid_match(t, r) || is_rmid_match(t, r)) {
7097168ae33SJames Morse 			ret = 1;
7107168ae33SJames Morse 			break;
7117168ae33SJames Morse 		}
7127168ae33SJames Morse 	}
7137168ae33SJames Morse 	rcu_read_unlock();
7147168ae33SJames Morse 
7157168ae33SJames Morse 	return ret;
7167168ae33SJames Morse }
7177168ae33SJames Morse 
rdtgroup_task_write_permission(struct task_struct * task,struct kernfs_open_file * of)7187168ae33SJames Morse static int rdtgroup_task_write_permission(struct task_struct *task,
7197168ae33SJames Morse 					  struct kernfs_open_file *of)
7207168ae33SJames Morse {
7217168ae33SJames Morse 	const struct cred *tcred = get_task_cred(task);
7227168ae33SJames Morse 	const struct cred *cred = current_cred();
7237168ae33SJames Morse 	int ret = 0;
7247168ae33SJames Morse 
7257168ae33SJames Morse 	/*
7267168ae33SJames Morse 	 * Even if we're attaching all tasks in the thread group, we only
7277168ae33SJames Morse 	 * need to check permissions on one of them.
7287168ae33SJames Morse 	 */
7297168ae33SJames Morse 	if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) &&
7307168ae33SJames Morse 	    !uid_eq(cred->euid, tcred->uid) &&
7317168ae33SJames Morse 	    !uid_eq(cred->euid, tcred->suid)) {
7327168ae33SJames Morse 		rdt_last_cmd_printf("No permission to move task %d\n", task->pid);
7337168ae33SJames Morse 		ret = -EPERM;
7347168ae33SJames Morse 	}
7357168ae33SJames Morse 
7367168ae33SJames Morse 	put_cred(tcred);
7377168ae33SJames Morse 	return ret;
7387168ae33SJames Morse }
7397168ae33SJames Morse 
rdtgroup_move_task(pid_t pid,struct rdtgroup * rdtgrp,struct kernfs_open_file * of)7407168ae33SJames Morse static int rdtgroup_move_task(pid_t pid, struct rdtgroup *rdtgrp,
7417168ae33SJames Morse 			      struct kernfs_open_file *of)
7427168ae33SJames Morse {
7437168ae33SJames Morse 	struct task_struct *tsk;
7447168ae33SJames Morse 	int ret;
7457168ae33SJames Morse 
7467168ae33SJames Morse 	rcu_read_lock();
7477168ae33SJames Morse 	if (pid) {
7487168ae33SJames Morse 		tsk = find_task_by_vpid(pid);
7497168ae33SJames Morse 		if (!tsk) {
7507168ae33SJames Morse 			rcu_read_unlock();
7517168ae33SJames Morse 			rdt_last_cmd_printf("No task %d\n", pid);
7527168ae33SJames Morse 			return -ESRCH;
7537168ae33SJames Morse 		}
7547168ae33SJames Morse 	} else {
7557168ae33SJames Morse 		tsk = current;
7567168ae33SJames Morse 	}
7577168ae33SJames Morse 
7587168ae33SJames Morse 	get_task_struct(tsk);
7597168ae33SJames Morse 	rcu_read_unlock();
7607168ae33SJames Morse 
7617168ae33SJames Morse 	ret = rdtgroup_task_write_permission(tsk, of);
7627168ae33SJames Morse 	if (!ret)
7637168ae33SJames Morse 		ret = __rdtgroup_move_task(tsk, rdtgrp);
7647168ae33SJames Morse 
7657168ae33SJames Morse 	put_task_struct(tsk);
7667168ae33SJames Morse 	return ret;
7677168ae33SJames Morse }
7687168ae33SJames Morse 
rdtgroup_tasks_write(struct kernfs_open_file * of,char * buf,size_t nbytes,loff_t off)7697168ae33SJames Morse static ssize_t rdtgroup_tasks_write(struct kernfs_open_file *of,
7707168ae33SJames Morse 				    char *buf, size_t nbytes, loff_t off)
7717168ae33SJames Morse {
7727168ae33SJames Morse 	struct rdtgroup *rdtgrp;
7737168ae33SJames Morse 	char *pid_str;
7747168ae33SJames Morse 	int ret = 0;
7757168ae33SJames Morse 	pid_t pid;
7767168ae33SJames Morse 
7777168ae33SJames Morse 	rdtgrp = rdtgroup_kn_lock_live(of->kn);
7787168ae33SJames Morse 	if (!rdtgrp) {
7797168ae33SJames Morse 		rdtgroup_kn_unlock(of->kn);
7807168ae33SJames Morse 		return -ENOENT;
7817168ae33SJames Morse 	}
7827168ae33SJames Morse 	rdt_last_cmd_clear();
7837168ae33SJames Morse 
7847168ae33SJames Morse 	if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED ||
7857168ae33SJames Morse 	    rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
7867168ae33SJames Morse 		ret = -EINVAL;
7877168ae33SJames Morse 		rdt_last_cmd_puts("Pseudo-locking in progress\n");
7887168ae33SJames Morse 		goto unlock;
7897168ae33SJames Morse 	}
7907168ae33SJames Morse 
7917168ae33SJames Morse 	while (buf && buf[0] != '\0' && buf[0] != '\n') {
7927168ae33SJames Morse 		pid_str = strim(strsep(&buf, ","));
7937168ae33SJames Morse 
7947168ae33SJames Morse 		if (kstrtoint(pid_str, 0, &pid)) {
7957168ae33SJames Morse 			rdt_last_cmd_printf("Task list parsing error pid %s\n", pid_str);
7967168ae33SJames Morse 			ret = -EINVAL;
7977168ae33SJames Morse 			break;
7987168ae33SJames Morse 		}
7997168ae33SJames Morse 
8007168ae33SJames Morse 		if (pid < 0) {
8017168ae33SJames Morse 			rdt_last_cmd_printf("Invalid pid %d\n", pid);
8027168ae33SJames Morse 			ret = -EINVAL;
8037168ae33SJames Morse 			break;
8047168ae33SJames Morse 		}
8057168ae33SJames Morse 
8067168ae33SJames Morse 		ret = rdtgroup_move_task(pid, rdtgrp, of);
8077168ae33SJames Morse 		if (ret) {
8087168ae33SJames Morse 			rdt_last_cmd_printf("Error while processing task %d\n", pid);
8097168ae33SJames Morse 			break;
8107168ae33SJames Morse 		}
8117168ae33SJames Morse 	}
8127168ae33SJames Morse 
8137168ae33SJames Morse unlock:
8147168ae33SJames Morse 	rdtgroup_kn_unlock(of->kn);
8157168ae33SJames Morse 
8167168ae33SJames Morse 	return ret ?: nbytes;
8177168ae33SJames Morse }
8187168ae33SJames Morse 
show_rdt_tasks(struct rdtgroup * r,struct seq_file * s)8197168ae33SJames Morse static void show_rdt_tasks(struct rdtgroup *r, struct seq_file *s)
8207168ae33SJames Morse {
8217168ae33SJames Morse 	struct task_struct *p, *t;
8227168ae33SJames Morse 	pid_t pid;
8237168ae33SJames Morse 
8247168ae33SJames Morse 	rcu_read_lock();
8257168ae33SJames Morse 	for_each_process_thread(p, t) {
8267168ae33SJames Morse 		if (is_closid_match(t, r) || is_rmid_match(t, r)) {
8277168ae33SJames Morse 			pid = task_pid_vnr(t);
8287168ae33SJames Morse 			if (pid)
8297168ae33SJames Morse 				seq_printf(s, "%d\n", pid);
8307168ae33SJames Morse 		}
8317168ae33SJames Morse 	}
8327168ae33SJames Morse 	rcu_read_unlock();
8337168ae33SJames Morse }
8347168ae33SJames Morse 
rdtgroup_tasks_show(struct kernfs_open_file * of,struct seq_file * s,void * v)8357168ae33SJames Morse static int rdtgroup_tasks_show(struct kernfs_open_file *of,
8367168ae33SJames Morse 			       struct seq_file *s, void *v)
8377168ae33SJames Morse {
8387168ae33SJames Morse 	struct rdtgroup *rdtgrp;
8397168ae33SJames Morse 	int ret = 0;
8407168ae33SJames Morse 
8417168ae33SJames Morse 	rdtgrp = rdtgroup_kn_lock_live(of->kn);
8427168ae33SJames Morse 	if (rdtgrp)
8437168ae33SJames Morse 		show_rdt_tasks(rdtgrp, s);
8447168ae33SJames Morse 	else
8457168ae33SJames Morse 		ret = -ENOENT;
8467168ae33SJames Morse 	rdtgroup_kn_unlock(of->kn);
8477168ae33SJames Morse 
8487168ae33SJames Morse 	return ret;
8497168ae33SJames Morse }
8507168ae33SJames Morse 
rdtgroup_closid_show(struct kernfs_open_file * of,struct seq_file * s,void * v)8517168ae33SJames Morse static int rdtgroup_closid_show(struct kernfs_open_file *of,
8527168ae33SJames Morse 				struct seq_file *s, void *v)
8537168ae33SJames Morse {
8547168ae33SJames Morse 	struct rdtgroup *rdtgrp;
8557168ae33SJames Morse 	int ret = 0;
8567168ae33SJames Morse 
8577168ae33SJames Morse 	rdtgrp = rdtgroup_kn_lock_live(of->kn);
8587168ae33SJames Morse 	if (rdtgrp)
8597168ae33SJames Morse 		seq_printf(s, "%u\n", rdtgrp->closid);
8607168ae33SJames Morse 	else
8617168ae33SJames Morse 		ret = -ENOENT;
8627168ae33SJames Morse 	rdtgroup_kn_unlock(of->kn);
8637168ae33SJames Morse 
8647168ae33SJames Morse 	return ret;
8657168ae33SJames Morse }
8667168ae33SJames Morse 
rdtgroup_rmid_show(struct kernfs_open_file * of,struct seq_file * s,void * v)8677168ae33SJames Morse static int rdtgroup_rmid_show(struct kernfs_open_file *of,
8687168ae33SJames Morse 			      struct seq_file *s, void *v)
8697168ae33SJames Morse {
8707168ae33SJames Morse 	struct rdtgroup *rdtgrp;
8717168ae33SJames Morse 	int ret = 0;
8727168ae33SJames Morse 
8737168ae33SJames Morse 	rdtgrp = rdtgroup_kn_lock_live(of->kn);
8747168ae33SJames Morse 	if (rdtgrp)
8757168ae33SJames Morse 		seq_printf(s, "%u\n", rdtgrp->mon.rmid);
8767168ae33SJames Morse 	else
8777168ae33SJames Morse 		ret = -ENOENT;
8787168ae33SJames Morse 	rdtgroup_kn_unlock(of->kn);
8797168ae33SJames Morse 
8807168ae33SJames Morse 	return ret;
8817168ae33SJames Morse }
8827168ae33SJames Morse 
8837168ae33SJames Morse #ifdef CONFIG_PROC_CPU_RESCTRL
8847168ae33SJames Morse /*
8857168ae33SJames Morse  * A task can only be part of one resctrl control group and of one monitor
8867168ae33SJames Morse  * group which is associated to that control group.
8877168ae33SJames Morse  *
8887168ae33SJames Morse  * 1)   res:
8897168ae33SJames Morse  *      mon:
8907168ae33SJames Morse  *
8917168ae33SJames Morse  *    resctrl is not available.
8927168ae33SJames Morse  *
8937168ae33SJames Morse  * 2)   res:/
8947168ae33SJames Morse  *      mon:
8957168ae33SJames Morse  *
8967168ae33SJames Morse  *    Task is part of the root resctrl control group, and it is not associated
8977168ae33SJames Morse  *    to any monitor group.
8987168ae33SJames Morse  *
8997168ae33SJames Morse  * 3)  res:/
9007168ae33SJames Morse  *     mon:mon0
9017168ae33SJames Morse  *
9027168ae33SJames Morse  *    Task is part of the root resctrl control group and monitor group mon0.
9037168ae33SJames Morse  *
9047168ae33SJames Morse  * 4)  res:group0
9057168ae33SJames Morse  *     mon:
9067168ae33SJames Morse  *
9077168ae33SJames Morse  *    Task is part of resctrl control group group0, and it is not associated
9087168ae33SJames Morse  *    to any monitor group.
9097168ae33SJames Morse  *
9107168ae33SJames Morse  * 5) res:group0
9117168ae33SJames Morse  *    mon:mon1
9127168ae33SJames Morse  *
9137168ae33SJames Morse  *    Task is part of resctrl control group group0 and monitor group mon1.
9147168ae33SJames Morse  */
proc_resctrl_show(struct seq_file * s,struct pid_namespace * ns,struct pid * pid,struct task_struct * tsk)9157168ae33SJames Morse int proc_resctrl_show(struct seq_file *s, struct pid_namespace *ns,
9167168ae33SJames Morse 		      struct pid *pid, struct task_struct *tsk)
9177168ae33SJames Morse {
9187168ae33SJames Morse 	struct rdtgroup *rdtg;
9197168ae33SJames Morse 	int ret = 0;
9207168ae33SJames Morse 
9217168ae33SJames Morse 	mutex_lock(&rdtgroup_mutex);
9227168ae33SJames Morse 
9237168ae33SJames Morse 	/* Return empty if resctrl has not been mounted. */
9247168ae33SJames Morse 	if (!resctrl_mounted) {
9257168ae33SJames Morse 		seq_puts(s, "res:\nmon:\n");
9267168ae33SJames Morse 		goto unlock;
9277168ae33SJames Morse 	}
9287168ae33SJames Morse 
9297168ae33SJames Morse 	list_for_each_entry(rdtg, &rdt_all_groups, rdtgroup_list) {
9307168ae33SJames Morse 		struct rdtgroup *crg;
9317168ae33SJames Morse 
9327168ae33SJames Morse 		/*
9337168ae33SJames Morse 		 * Task information is only relevant for shareable
9347168ae33SJames Morse 		 * and exclusive groups.
9357168ae33SJames Morse 		 */
9367168ae33SJames Morse 		if (rdtg->mode != RDT_MODE_SHAREABLE &&
9377168ae33SJames Morse 		    rdtg->mode != RDT_MODE_EXCLUSIVE)
9387168ae33SJames Morse 			continue;
9397168ae33SJames Morse 
9407168ae33SJames Morse 		if (!resctrl_arch_match_closid(tsk, rdtg->closid))
9417168ae33SJames Morse 			continue;
9427168ae33SJames Morse 
9437168ae33SJames Morse 		seq_printf(s, "res:%s%s\n", (rdtg == &rdtgroup_default) ? "/" : "",
9447168ae33SJames Morse 			   rdt_kn_name(rdtg->kn));
9457168ae33SJames Morse 		seq_puts(s, "mon:");
9467168ae33SJames Morse 		list_for_each_entry(crg, &rdtg->mon.crdtgrp_list,
9477168ae33SJames Morse 				    mon.crdtgrp_list) {
9487168ae33SJames Morse 			if (!resctrl_arch_match_rmid(tsk, crg->mon.parent->closid,
9497168ae33SJames Morse 						     crg->mon.rmid))
9507168ae33SJames Morse 				continue;
9517168ae33SJames Morse 			seq_printf(s, "%s", rdt_kn_name(crg->kn));
9527168ae33SJames Morse 			break;
9537168ae33SJames Morse 		}
9547168ae33SJames Morse 		seq_putc(s, '\n');
9557168ae33SJames Morse 		goto unlock;
9567168ae33SJames Morse 	}
9577168ae33SJames Morse 	/*
9587168ae33SJames Morse 	 * The above search should succeed. Otherwise return
9597168ae33SJames Morse 	 * with an error.
9607168ae33SJames Morse 	 */
9617168ae33SJames Morse 	ret = -ENOENT;
9627168ae33SJames Morse unlock:
9637168ae33SJames Morse 	mutex_unlock(&rdtgroup_mutex);
9647168ae33SJames Morse 
9657168ae33SJames Morse 	return ret;
9667168ae33SJames Morse }
9677168ae33SJames Morse #endif
9687168ae33SJames Morse 
rdt_last_cmd_status_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)9697168ae33SJames Morse static int rdt_last_cmd_status_show(struct kernfs_open_file *of,
9707168ae33SJames Morse 				    struct seq_file *seq, void *v)
9717168ae33SJames Morse {
9727168ae33SJames Morse 	int len;
9737168ae33SJames Morse 
9747168ae33SJames Morse 	mutex_lock(&rdtgroup_mutex);
9757168ae33SJames Morse 	len = seq_buf_used(&last_cmd_status);
9767168ae33SJames Morse 	if (len)
9777168ae33SJames Morse 		seq_printf(seq, "%.*s", len, last_cmd_status_buf);
9787168ae33SJames Morse 	else
9797168ae33SJames Morse 		seq_puts(seq, "ok\n");
9807168ae33SJames Morse 	mutex_unlock(&rdtgroup_mutex);
9817168ae33SJames Morse 	return 0;
9827168ae33SJames Morse }
9837168ae33SJames Morse 
rdt_kn_parent_priv(struct kernfs_node * kn)9847168ae33SJames Morse static void *rdt_kn_parent_priv(struct kernfs_node *kn)
9857168ae33SJames Morse {
9867168ae33SJames Morse 	/*
9877168ae33SJames Morse 	 * The parent pointer is only valid within RCU section since it can be
9887168ae33SJames Morse 	 * replaced.
9897168ae33SJames Morse 	 */
9907168ae33SJames Morse 	guard(rcu)();
9917168ae33SJames Morse 	return rcu_dereference(kn->__parent)->priv;
9927168ae33SJames Morse }
9937168ae33SJames Morse 
rdt_num_closids_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)9947168ae33SJames Morse static int rdt_num_closids_show(struct kernfs_open_file *of,
9957168ae33SJames Morse 				struct seq_file *seq, void *v)
9967168ae33SJames Morse {
9977168ae33SJames Morse 	struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
9987168ae33SJames Morse 
9997168ae33SJames Morse 	seq_printf(seq, "%u\n", s->num_closid);
10007168ae33SJames Morse 	return 0;
10017168ae33SJames Morse }
10027168ae33SJames Morse 
rdt_default_ctrl_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)10037168ae33SJames Morse static int rdt_default_ctrl_show(struct kernfs_open_file *of,
10047168ae33SJames Morse 				 struct seq_file *seq, void *v)
10057168ae33SJames Morse {
10067168ae33SJames Morse 	struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
10077168ae33SJames Morse 	struct rdt_resource *r = s->res;
10087168ae33SJames Morse 
10097168ae33SJames Morse 	seq_printf(seq, "%x\n", resctrl_get_default_ctrl(r));
10107168ae33SJames Morse 	return 0;
10117168ae33SJames Morse }
10127168ae33SJames Morse 
rdt_min_cbm_bits_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)10137168ae33SJames Morse static int rdt_min_cbm_bits_show(struct kernfs_open_file *of,
10147168ae33SJames Morse 				 struct seq_file *seq, void *v)
10157168ae33SJames Morse {
10167168ae33SJames Morse 	struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
10177168ae33SJames Morse 	struct rdt_resource *r = s->res;
10187168ae33SJames Morse 
10197168ae33SJames Morse 	seq_printf(seq, "%u\n", r->cache.min_cbm_bits);
10207168ae33SJames Morse 	return 0;
10217168ae33SJames Morse }
10227168ae33SJames Morse 
rdt_shareable_bits_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)10237168ae33SJames Morse static int rdt_shareable_bits_show(struct kernfs_open_file *of,
10247168ae33SJames Morse 				   struct seq_file *seq, void *v)
10257168ae33SJames Morse {
10267168ae33SJames Morse 	struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
10277168ae33SJames Morse 	struct rdt_resource *r = s->res;
10287168ae33SJames Morse 
10297168ae33SJames Morse 	seq_printf(seq, "%x\n", r->cache.shareable_bits);
10307168ae33SJames Morse 	return 0;
10317168ae33SJames Morse }
10327168ae33SJames Morse 
10337168ae33SJames Morse /*
10347168ae33SJames Morse  * rdt_bit_usage_show - Display current usage of resources
10357168ae33SJames Morse  *
10367168ae33SJames Morse  * A domain is a shared resource that can now be allocated differently. Here
10377168ae33SJames Morse  * we display the current regions of the domain as an annotated bitmask.
10387168ae33SJames Morse  * For each domain of this resource its allocation bitmask
10397168ae33SJames Morse  * is annotated as below to indicate the current usage of the corresponding bit:
10407168ae33SJames Morse  *   0 - currently unused
10417168ae33SJames Morse  *   X - currently available for sharing and used by software and hardware
10427168ae33SJames Morse  *   H - currently used by hardware only but available for software use
10437168ae33SJames Morse  *   S - currently used and shareable by software only
10447168ae33SJames Morse  *   E - currently used exclusively by one resource group
10457168ae33SJames Morse  *   P - currently pseudo-locked by one resource group
10467168ae33SJames Morse  */
rdt_bit_usage_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)10477168ae33SJames Morse static int rdt_bit_usage_show(struct kernfs_open_file *of,
10487168ae33SJames Morse 			      struct seq_file *seq, void *v)
10497168ae33SJames Morse {
10507168ae33SJames Morse 	struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
10517168ae33SJames Morse 	/*
10527168ae33SJames Morse 	 * Use unsigned long even though only 32 bits are used to ensure
10537168ae33SJames Morse 	 * test_bit() is used safely.
10547168ae33SJames Morse 	 */
10557168ae33SJames Morse 	unsigned long sw_shareable = 0, hw_shareable = 0;
10567168ae33SJames Morse 	unsigned long exclusive = 0, pseudo_locked = 0;
10577168ae33SJames Morse 	struct rdt_resource *r = s->res;
10587168ae33SJames Morse 	struct rdt_ctrl_domain *dom;
10597168ae33SJames Morse 	int i, hwb, swb, excl, psl;
10607168ae33SJames Morse 	enum rdtgrp_mode mode;
10617168ae33SJames Morse 	bool sep = false;
10627168ae33SJames Morse 	u32 ctrl_val;
10637168ae33SJames Morse 
10647168ae33SJames Morse 	cpus_read_lock();
10657168ae33SJames Morse 	mutex_lock(&rdtgroup_mutex);
10667168ae33SJames Morse 	hw_shareable = r->cache.shareable_bits;
10677168ae33SJames Morse 	list_for_each_entry(dom, &r->ctrl_domains, hdr.list) {
10687168ae33SJames Morse 		if (sep)
10697168ae33SJames Morse 			seq_putc(seq, ';');
10707168ae33SJames Morse 		sw_shareable = 0;
10717168ae33SJames Morse 		exclusive = 0;
10727168ae33SJames Morse 		seq_printf(seq, "%d=", dom->hdr.id);
10737168ae33SJames Morse 		for (i = 0; i < closids_supported(); i++) {
10747168ae33SJames Morse 			if (!closid_allocated(i))
10757168ae33SJames Morse 				continue;
10767168ae33SJames Morse 			ctrl_val = resctrl_arch_get_config(r, dom, i,
10777168ae33SJames Morse 							   s->conf_type);
10787168ae33SJames Morse 			mode = rdtgroup_mode_by_closid(i);
10797168ae33SJames Morse 			switch (mode) {
10807168ae33SJames Morse 			case RDT_MODE_SHAREABLE:
10817168ae33SJames Morse 				sw_shareable |= ctrl_val;
10827168ae33SJames Morse 				break;
10837168ae33SJames Morse 			case RDT_MODE_EXCLUSIVE:
10847168ae33SJames Morse 				exclusive |= ctrl_val;
10857168ae33SJames Morse 				break;
10867168ae33SJames Morse 			case RDT_MODE_PSEUDO_LOCKSETUP:
10877168ae33SJames Morse 			/*
10887168ae33SJames Morse 			 * RDT_MODE_PSEUDO_LOCKSETUP is possible
10897168ae33SJames Morse 			 * here but not included since the CBM
10907168ae33SJames Morse 			 * associated with this CLOSID in this mode
10917168ae33SJames Morse 			 * is not initialized and no task or cpu can be
10927168ae33SJames Morse 			 * assigned this CLOSID.
10937168ae33SJames Morse 			 */
10947168ae33SJames Morse 				break;
10957168ae33SJames Morse 			case RDT_MODE_PSEUDO_LOCKED:
10967168ae33SJames Morse 			case RDT_NUM_MODES:
10977168ae33SJames Morse 				WARN(1,
10987168ae33SJames Morse 				     "invalid mode for closid %d\n", i);
10997168ae33SJames Morse 				break;
11007168ae33SJames Morse 			}
11017168ae33SJames Morse 		}
11027168ae33SJames Morse 		for (i = r->cache.cbm_len - 1; i >= 0; i--) {
11037168ae33SJames Morse 			pseudo_locked = dom->plr ? dom->plr->cbm : 0;
11047168ae33SJames Morse 			hwb = test_bit(i, &hw_shareable);
11057168ae33SJames Morse 			swb = test_bit(i, &sw_shareable);
11067168ae33SJames Morse 			excl = test_bit(i, &exclusive);
11077168ae33SJames Morse 			psl = test_bit(i, &pseudo_locked);
11087168ae33SJames Morse 			if (hwb && swb)
11097168ae33SJames Morse 				seq_putc(seq, 'X');
11107168ae33SJames Morse 			else if (hwb && !swb)
11117168ae33SJames Morse 				seq_putc(seq, 'H');
11127168ae33SJames Morse 			else if (!hwb && swb)
11137168ae33SJames Morse 				seq_putc(seq, 'S');
11147168ae33SJames Morse 			else if (excl)
11157168ae33SJames Morse 				seq_putc(seq, 'E');
11167168ae33SJames Morse 			else if (psl)
11177168ae33SJames Morse 				seq_putc(seq, 'P');
11187168ae33SJames Morse 			else /* Unused bits remain */
11197168ae33SJames Morse 				seq_putc(seq, '0');
11207168ae33SJames Morse 		}
11217168ae33SJames Morse 		sep = true;
11227168ae33SJames Morse 	}
11237168ae33SJames Morse 	seq_putc(seq, '\n');
11247168ae33SJames Morse 	mutex_unlock(&rdtgroup_mutex);
11257168ae33SJames Morse 	cpus_read_unlock();
11267168ae33SJames Morse 	return 0;
11277168ae33SJames Morse }
11287168ae33SJames Morse 
rdt_min_bw_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)11297168ae33SJames Morse static int rdt_min_bw_show(struct kernfs_open_file *of,
11307168ae33SJames Morse 			   struct seq_file *seq, void *v)
11317168ae33SJames Morse {
11327168ae33SJames Morse 	struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
11337168ae33SJames Morse 	struct rdt_resource *r = s->res;
11347168ae33SJames Morse 
11357168ae33SJames Morse 	seq_printf(seq, "%u\n", r->membw.min_bw);
11367168ae33SJames Morse 	return 0;
11377168ae33SJames Morse }
11387168ae33SJames Morse 
rdt_num_rmids_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)11397168ae33SJames Morse static int rdt_num_rmids_show(struct kernfs_open_file *of,
11407168ae33SJames Morse 			      struct seq_file *seq, void *v)
11417168ae33SJames Morse {
11427168ae33SJames Morse 	struct rdt_resource *r = rdt_kn_parent_priv(of->kn);
11437168ae33SJames Morse 
11447168ae33SJames Morse 	seq_printf(seq, "%d\n", r->num_rmid);
11457168ae33SJames Morse 
11467168ae33SJames Morse 	return 0;
11477168ae33SJames Morse }
11487168ae33SJames Morse 
rdt_mon_features_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)11497168ae33SJames Morse static int rdt_mon_features_show(struct kernfs_open_file *of,
11507168ae33SJames Morse 				 struct seq_file *seq, void *v)
11517168ae33SJames Morse {
11527168ae33SJames Morse 	struct rdt_resource *r = rdt_kn_parent_priv(of->kn);
11537168ae33SJames Morse 	struct mon_evt *mevt;
11547168ae33SJames Morse 
11557168ae33SJames Morse 	list_for_each_entry(mevt, &r->evt_list, list) {
11567168ae33SJames Morse 		seq_printf(seq, "%s\n", mevt->name);
11577168ae33SJames Morse 		if (mevt->configurable)
11587168ae33SJames Morse 			seq_printf(seq, "%s_config\n", mevt->name);
11597168ae33SJames Morse 	}
11607168ae33SJames Morse 
11617168ae33SJames Morse 	return 0;
11627168ae33SJames Morse }
11637168ae33SJames Morse 
rdt_bw_gran_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)11647168ae33SJames Morse static int rdt_bw_gran_show(struct kernfs_open_file *of,
11657168ae33SJames Morse 			    struct seq_file *seq, void *v)
11667168ae33SJames Morse {
11677168ae33SJames Morse 	struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
11687168ae33SJames Morse 	struct rdt_resource *r = s->res;
11697168ae33SJames Morse 
11707168ae33SJames Morse 	seq_printf(seq, "%u\n", r->membw.bw_gran);
11717168ae33SJames Morse 	return 0;
11727168ae33SJames Morse }
11737168ae33SJames Morse 
rdt_delay_linear_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)11747168ae33SJames Morse static int rdt_delay_linear_show(struct kernfs_open_file *of,
11757168ae33SJames Morse 				 struct seq_file *seq, void *v)
11767168ae33SJames Morse {
11777168ae33SJames Morse 	struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
11787168ae33SJames Morse 	struct rdt_resource *r = s->res;
11797168ae33SJames Morse 
11807168ae33SJames Morse 	seq_printf(seq, "%u\n", r->membw.delay_linear);
11817168ae33SJames Morse 	return 0;
11827168ae33SJames Morse }
11837168ae33SJames Morse 
max_threshold_occ_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)11847168ae33SJames Morse static int max_threshold_occ_show(struct kernfs_open_file *of,
11857168ae33SJames Morse 				  struct seq_file *seq, void *v)
11867168ae33SJames Morse {
11877168ae33SJames Morse 	seq_printf(seq, "%u\n", resctrl_rmid_realloc_threshold);
11887168ae33SJames Morse 
11897168ae33SJames Morse 	return 0;
11907168ae33SJames Morse }
11917168ae33SJames Morse 
rdt_thread_throttle_mode_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)11927168ae33SJames Morse static int rdt_thread_throttle_mode_show(struct kernfs_open_file *of,
11937168ae33SJames Morse 					 struct seq_file *seq, void *v)
11947168ae33SJames Morse {
11957168ae33SJames Morse 	struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
11967168ae33SJames Morse 	struct rdt_resource *r = s->res;
11977168ae33SJames Morse 
11987168ae33SJames Morse 	switch (r->membw.throttle_mode) {
11997168ae33SJames Morse 	case THREAD_THROTTLE_PER_THREAD:
12007168ae33SJames Morse 		seq_puts(seq, "per-thread\n");
12017168ae33SJames Morse 		return 0;
12027168ae33SJames Morse 	case THREAD_THROTTLE_MAX:
12037168ae33SJames Morse 		seq_puts(seq, "max\n");
12047168ae33SJames Morse 		return 0;
12057168ae33SJames Morse 	case THREAD_THROTTLE_UNDEFINED:
12067168ae33SJames Morse 		seq_puts(seq, "undefined\n");
12077168ae33SJames Morse 		return 0;
12087168ae33SJames Morse 	}
12097168ae33SJames Morse 
12107168ae33SJames Morse 	WARN_ON_ONCE(1);
12117168ae33SJames Morse 
12127168ae33SJames Morse 	return 0;
12137168ae33SJames Morse }
12147168ae33SJames Morse 
max_threshold_occ_write(struct kernfs_open_file * of,char * buf,size_t nbytes,loff_t off)12157168ae33SJames Morse static ssize_t max_threshold_occ_write(struct kernfs_open_file *of,
12167168ae33SJames Morse 				       char *buf, size_t nbytes, loff_t off)
12177168ae33SJames Morse {
12187168ae33SJames Morse 	unsigned int bytes;
12197168ae33SJames Morse 	int ret;
12207168ae33SJames Morse 
12217168ae33SJames Morse 	ret = kstrtouint(buf, 0, &bytes);
12227168ae33SJames Morse 	if (ret)
12237168ae33SJames Morse 		return ret;
12247168ae33SJames Morse 
12257168ae33SJames Morse 	if (bytes > resctrl_rmid_realloc_limit)
12267168ae33SJames Morse 		return -EINVAL;
12277168ae33SJames Morse 
12287168ae33SJames Morse 	resctrl_rmid_realloc_threshold = resctrl_arch_round_mon_val(bytes);
12297168ae33SJames Morse 
12307168ae33SJames Morse 	return nbytes;
12317168ae33SJames Morse }
12327168ae33SJames Morse 
12337168ae33SJames Morse /*
12347168ae33SJames Morse  * rdtgroup_mode_show - Display mode of this resource group
12357168ae33SJames Morse  */
rdtgroup_mode_show(struct kernfs_open_file * of,struct seq_file * s,void * v)12367168ae33SJames Morse static int rdtgroup_mode_show(struct kernfs_open_file *of,
12377168ae33SJames Morse 			      struct seq_file *s, void *v)
12387168ae33SJames Morse {
12397168ae33SJames Morse 	struct rdtgroup *rdtgrp;
12407168ae33SJames Morse 
12417168ae33SJames Morse 	rdtgrp = rdtgroup_kn_lock_live(of->kn);
12427168ae33SJames Morse 	if (!rdtgrp) {
12437168ae33SJames Morse 		rdtgroup_kn_unlock(of->kn);
12447168ae33SJames Morse 		return -ENOENT;
12457168ae33SJames Morse 	}
12467168ae33SJames Morse 
12477168ae33SJames Morse 	seq_printf(s, "%s\n", rdtgroup_mode_str(rdtgrp->mode));
12487168ae33SJames Morse 
12497168ae33SJames Morse 	rdtgroup_kn_unlock(of->kn);
12507168ae33SJames Morse 	return 0;
12517168ae33SJames Morse }
12527168ae33SJames Morse 
resctrl_peer_type(enum resctrl_conf_type my_type)12537168ae33SJames Morse static enum resctrl_conf_type resctrl_peer_type(enum resctrl_conf_type my_type)
12547168ae33SJames Morse {
12557168ae33SJames Morse 	switch (my_type) {
12567168ae33SJames Morse 	case CDP_CODE:
12577168ae33SJames Morse 		return CDP_DATA;
12587168ae33SJames Morse 	case CDP_DATA:
12597168ae33SJames Morse 		return CDP_CODE;
12607168ae33SJames Morse 	default:
12617168ae33SJames Morse 	case CDP_NONE:
12627168ae33SJames Morse 		return CDP_NONE;
12637168ae33SJames Morse 	}
12647168ae33SJames Morse }
12657168ae33SJames Morse 
rdt_has_sparse_bitmasks_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)12667168ae33SJames Morse static int rdt_has_sparse_bitmasks_show(struct kernfs_open_file *of,
12677168ae33SJames Morse 					struct seq_file *seq, void *v)
12687168ae33SJames Morse {
12697168ae33SJames Morse 	struct resctrl_schema *s = rdt_kn_parent_priv(of->kn);
12707168ae33SJames Morse 	struct rdt_resource *r = s->res;
12717168ae33SJames Morse 
12727168ae33SJames Morse 	seq_printf(seq, "%u\n", r->cache.arch_has_sparse_bitmasks);
12737168ae33SJames Morse 
12747168ae33SJames Morse 	return 0;
12757168ae33SJames Morse }
12767168ae33SJames Morse 
12777168ae33SJames Morse /**
12787168ae33SJames Morse  * __rdtgroup_cbm_overlaps - Does CBM for intended closid overlap with other
12797168ae33SJames Morse  * @r: Resource to which domain instance @d belongs.
12807168ae33SJames Morse  * @d: The domain instance for which @closid is being tested.
12817168ae33SJames Morse  * @cbm: Capacity bitmask being tested.
12827168ae33SJames Morse  * @closid: Intended closid for @cbm.
12837168ae33SJames Morse  * @type: CDP type of @r.
12847168ae33SJames Morse  * @exclusive: Only check if overlaps with exclusive resource groups
12857168ae33SJames Morse  *
12867168ae33SJames Morse  * Checks if provided @cbm intended to be used for @closid on domain
12877168ae33SJames Morse  * @d overlaps with any other closids or other hardware usage associated
12887168ae33SJames Morse  * with this domain. If @exclusive is true then only overlaps with
12897168ae33SJames Morse  * resource groups in exclusive mode will be considered. If @exclusive
12907168ae33SJames Morse  * is false then overlaps with any resource group or hardware entities
12917168ae33SJames Morse  * will be considered.
12927168ae33SJames Morse  *
12937168ae33SJames Morse  * @cbm is unsigned long, even if only 32 bits are used, to make the
12947168ae33SJames Morse  * bitmap functions work correctly.
12957168ae33SJames Morse  *
12967168ae33SJames Morse  * Return: false if CBM does not overlap, true if it does.
12977168ae33SJames Morse  */
__rdtgroup_cbm_overlaps(struct rdt_resource * r,struct rdt_ctrl_domain * d,unsigned long cbm,int closid,enum resctrl_conf_type type,bool exclusive)12987168ae33SJames Morse static bool __rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_ctrl_domain *d,
12997168ae33SJames Morse 				    unsigned long cbm, int closid,
13007168ae33SJames Morse 				    enum resctrl_conf_type type, bool exclusive)
13017168ae33SJames Morse {
13027168ae33SJames Morse 	enum rdtgrp_mode mode;
13037168ae33SJames Morse 	unsigned long ctrl_b;
13047168ae33SJames Morse 	int i;
13057168ae33SJames Morse 
13067168ae33SJames Morse 	/* Check for any overlap with regions used by hardware directly */
13077168ae33SJames Morse 	if (!exclusive) {
13087168ae33SJames Morse 		ctrl_b = r->cache.shareable_bits;
13097168ae33SJames Morse 		if (bitmap_intersects(&cbm, &ctrl_b, r->cache.cbm_len))
13107168ae33SJames Morse 			return true;
13117168ae33SJames Morse 	}
13127168ae33SJames Morse 
13137168ae33SJames Morse 	/* Check for overlap with other resource groups */
13147168ae33SJames Morse 	for (i = 0; i < closids_supported(); i++) {
13157168ae33SJames Morse 		ctrl_b = resctrl_arch_get_config(r, d, i, type);
13167168ae33SJames Morse 		mode = rdtgroup_mode_by_closid(i);
13177168ae33SJames Morse 		if (closid_allocated(i) && i != closid &&
13187168ae33SJames Morse 		    mode != RDT_MODE_PSEUDO_LOCKSETUP) {
13197168ae33SJames Morse 			if (bitmap_intersects(&cbm, &ctrl_b, r->cache.cbm_len)) {
13207168ae33SJames Morse 				if (exclusive) {
13217168ae33SJames Morse 					if (mode == RDT_MODE_EXCLUSIVE)
13227168ae33SJames Morse 						return true;
13237168ae33SJames Morse 					continue;
13247168ae33SJames Morse 				}
13257168ae33SJames Morse 				return true;
13267168ae33SJames Morse 			}
13277168ae33SJames Morse 		}
13287168ae33SJames Morse 	}
13297168ae33SJames Morse 
13307168ae33SJames Morse 	return false;
13317168ae33SJames Morse }
13327168ae33SJames Morse 
13337168ae33SJames Morse /**
13347168ae33SJames Morse  * rdtgroup_cbm_overlaps - Does CBM overlap with other use of hardware
13357168ae33SJames Morse  * @s: Schema for the resource to which domain instance @d belongs.
13367168ae33SJames Morse  * @d: The domain instance for which @closid is being tested.
13377168ae33SJames Morse  * @cbm: Capacity bitmask being tested.
13387168ae33SJames Morse  * @closid: Intended closid for @cbm.
13397168ae33SJames Morse  * @exclusive: Only check if overlaps with exclusive resource groups
13407168ae33SJames Morse  *
13417168ae33SJames Morse  * Resources that can be allocated using a CBM can use the CBM to control
13427168ae33SJames Morse  * the overlap of these allocations. rdtgroup_cmb_overlaps() is the test
13437168ae33SJames Morse  * for overlap. Overlap test is not limited to the specific resource for
13447168ae33SJames Morse  * which the CBM is intended though - when dealing with CDP resources that
13457168ae33SJames Morse  * share the underlying hardware the overlap check should be performed on
13467168ae33SJames Morse  * the CDP resource sharing the hardware also.
13477168ae33SJames Morse  *
13487168ae33SJames Morse  * Refer to description of __rdtgroup_cbm_overlaps() for the details of the
13497168ae33SJames Morse  * overlap test.
13507168ae33SJames Morse  *
13517168ae33SJames Morse  * Return: true if CBM overlap detected, false if there is no overlap
13527168ae33SJames Morse  */
rdtgroup_cbm_overlaps(struct resctrl_schema * s,struct rdt_ctrl_domain * d,unsigned long cbm,int closid,bool exclusive)13537168ae33SJames Morse bool rdtgroup_cbm_overlaps(struct resctrl_schema *s, struct rdt_ctrl_domain *d,
13547168ae33SJames Morse 			   unsigned long cbm, int closid, bool exclusive)
13557168ae33SJames Morse {
13567168ae33SJames Morse 	enum resctrl_conf_type peer_type = resctrl_peer_type(s->conf_type);
13577168ae33SJames Morse 	struct rdt_resource *r = s->res;
13587168ae33SJames Morse 
13597168ae33SJames Morse 	if (__rdtgroup_cbm_overlaps(r, d, cbm, closid, s->conf_type,
13607168ae33SJames Morse 				    exclusive))
13617168ae33SJames Morse 		return true;
13627168ae33SJames Morse 
13637168ae33SJames Morse 	if (!resctrl_arch_get_cdp_enabled(r->rid))
13647168ae33SJames Morse 		return false;
13657168ae33SJames Morse 	return  __rdtgroup_cbm_overlaps(r, d, cbm, closid, peer_type, exclusive);
13667168ae33SJames Morse }
13677168ae33SJames Morse 
13687168ae33SJames Morse /**
13697168ae33SJames Morse  * rdtgroup_mode_test_exclusive - Test if this resource group can be exclusive
13707168ae33SJames Morse  * @rdtgrp: Resource group identified through its closid.
13717168ae33SJames Morse  *
13727168ae33SJames Morse  * An exclusive resource group implies that there should be no sharing of
13737168ae33SJames Morse  * its allocated resources. At the time this group is considered to be
13747168ae33SJames Morse  * exclusive this test can determine if its current schemata supports this
13757168ae33SJames Morse  * setting by testing for overlap with all other resource groups.
13767168ae33SJames Morse  *
13777168ae33SJames Morse  * Return: true if resource group can be exclusive, false if there is overlap
13787168ae33SJames Morse  * with allocations of other resource groups and thus this resource group
13797168ae33SJames Morse  * cannot be exclusive.
13807168ae33SJames Morse  */
rdtgroup_mode_test_exclusive(struct rdtgroup * rdtgrp)13817168ae33SJames Morse static bool rdtgroup_mode_test_exclusive(struct rdtgroup *rdtgrp)
13827168ae33SJames Morse {
13837168ae33SJames Morse 	int closid = rdtgrp->closid;
13847168ae33SJames Morse 	struct rdt_ctrl_domain *d;
13857168ae33SJames Morse 	struct resctrl_schema *s;
13867168ae33SJames Morse 	struct rdt_resource *r;
13877168ae33SJames Morse 	bool has_cache = false;
13887168ae33SJames Morse 	u32 ctrl;
13897168ae33SJames Morse 
13907168ae33SJames Morse 	/* Walking r->domains, ensure it can't race with cpuhp */
13917168ae33SJames Morse 	lockdep_assert_cpus_held();
13927168ae33SJames Morse 
13937168ae33SJames Morse 	list_for_each_entry(s, &resctrl_schema_all, list) {
13947168ae33SJames Morse 		r = s->res;
13957168ae33SJames Morse 		if (r->rid == RDT_RESOURCE_MBA || r->rid == RDT_RESOURCE_SMBA)
13967168ae33SJames Morse 			continue;
13977168ae33SJames Morse 		has_cache = true;
13987168ae33SJames Morse 		list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
13997168ae33SJames Morse 			ctrl = resctrl_arch_get_config(r, d, closid,
14007168ae33SJames Morse 						       s->conf_type);
14017168ae33SJames Morse 			if (rdtgroup_cbm_overlaps(s, d, ctrl, closid, false)) {
14027168ae33SJames Morse 				rdt_last_cmd_puts("Schemata overlaps\n");
14037168ae33SJames Morse 				return false;
14047168ae33SJames Morse 			}
14057168ae33SJames Morse 		}
14067168ae33SJames Morse 	}
14077168ae33SJames Morse 
14087168ae33SJames Morse 	if (!has_cache) {
14097168ae33SJames Morse 		rdt_last_cmd_puts("Cannot be exclusive without CAT/CDP\n");
14107168ae33SJames Morse 		return false;
14117168ae33SJames Morse 	}
14127168ae33SJames Morse 
14137168ae33SJames Morse 	return true;
14147168ae33SJames Morse }
14157168ae33SJames Morse 
14167168ae33SJames Morse /*
14177168ae33SJames Morse  * rdtgroup_mode_write - Modify the resource group's mode
14187168ae33SJames Morse  */
rdtgroup_mode_write(struct kernfs_open_file * of,char * buf,size_t nbytes,loff_t off)14197168ae33SJames Morse static ssize_t rdtgroup_mode_write(struct kernfs_open_file *of,
14207168ae33SJames Morse 				   char *buf, size_t nbytes, loff_t off)
14217168ae33SJames Morse {
14227168ae33SJames Morse 	struct rdtgroup *rdtgrp;
14237168ae33SJames Morse 	enum rdtgrp_mode mode;
14247168ae33SJames Morse 	int ret = 0;
14257168ae33SJames Morse 
14267168ae33SJames Morse 	/* Valid input requires a trailing newline */
14277168ae33SJames Morse 	if (nbytes == 0 || buf[nbytes - 1] != '\n')
14287168ae33SJames Morse 		return -EINVAL;
14297168ae33SJames Morse 	buf[nbytes - 1] = '\0';
14307168ae33SJames Morse 
14317168ae33SJames Morse 	rdtgrp = rdtgroup_kn_lock_live(of->kn);
14327168ae33SJames Morse 	if (!rdtgrp) {
14337168ae33SJames Morse 		rdtgroup_kn_unlock(of->kn);
14347168ae33SJames Morse 		return -ENOENT;
14357168ae33SJames Morse 	}
14367168ae33SJames Morse 
14377168ae33SJames Morse 	rdt_last_cmd_clear();
14387168ae33SJames Morse 
14397168ae33SJames Morse 	mode = rdtgrp->mode;
14407168ae33SJames Morse 
14417168ae33SJames Morse 	if ((!strcmp(buf, "shareable") && mode == RDT_MODE_SHAREABLE) ||
14427168ae33SJames Morse 	    (!strcmp(buf, "exclusive") && mode == RDT_MODE_EXCLUSIVE) ||
14437168ae33SJames Morse 	    (!strcmp(buf, "pseudo-locksetup") &&
14447168ae33SJames Morse 	     mode == RDT_MODE_PSEUDO_LOCKSETUP) ||
14457168ae33SJames Morse 	    (!strcmp(buf, "pseudo-locked") && mode == RDT_MODE_PSEUDO_LOCKED))
14467168ae33SJames Morse 		goto out;
14477168ae33SJames Morse 
14487168ae33SJames Morse 	if (mode == RDT_MODE_PSEUDO_LOCKED) {
14497168ae33SJames Morse 		rdt_last_cmd_puts("Cannot change pseudo-locked group\n");
14507168ae33SJames Morse 		ret = -EINVAL;
14517168ae33SJames Morse 		goto out;
14527168ae33SJames Morse 	}
14537168ae33SJames Morse 
14547168ae33SJames Morse 	if (!strcmp(buf, "shareable")) {
14557168ae33SJames Morse 		if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
14567168ae33SJames Morse 			ret = rdtgroup_locksetup_exit(rdtgrp);
14577168ae33SJames Morse 			if (ret)
14587168ae33SJames Morse 				goto out;
14597168ae33SJames Morse 		}
14607168ae33SJames Morse 		rdtgrp->mode = RDT_MODE_SHAREABLE;
14617168ae33SJames Morse 	} else if (!strcmp(buf, "exclusive")) {
14627168ae33SJames Morse 		if (!rdtgroup_mode_test_exclusive(rdtgrp)) {
14637168ae33SJames Morse 			ret = -EINVAL;
14647168ae33SJames Morse 			goto out;
14657168ae33SJames Morse 		}
14667168ae33SJames Morse 		if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
14677168ae33SJames Morse 			ret = rdtgroup_locksetup_exit(rdtgrp);
14687168ae33SJames Morse 			if (ret)
14697168ae33SJames Morse 				goto out;
14707168ae33SJames Morse 		}
14717168ae33SJames Morse 		rdtgrp->mode = RDT_MODE_EXCLUSIVE;
14727168ae33SJames Morse 	} else if (IS_ENABLED(CONFIG_RESCTRL_FS_PSEUDO_LOCK) &&
14737168ae33SJames Morse 		   !strcmp(buf, "pseudo-locksetup")) {
14747168ae33SJames Morse 		ret = rdtgroup_locksetup_enter(rdtgrp);
14757168ae33SJames Morse 		if (ret)
14767168ae33SJames Morse 			goto out;
14777168ae33SJames Morse 		rdtgrp->mode = RDT_MODE_PSEUDO_LOCKSETUP;
14787168ae33SJames Morse 	} else {
14797168ae33SJames Morse 		rdt_last_cmd_puts("Unknown or unsupported mode\n");
14807168ae33SJames Morse 		ret = -EINVAL;
14817168ae33SJames Morse 	}
14827168ae33SJames Morse 
14837168ae33SJames Morse out:
14847168ae33SJames Morse 	rdtgroup_kn_unlock(of->kn);
14857168ae33SJames Morse 	return ret ?: nbytes;
14867168ae33SJames Morse }
14877168ae33SJames Morse 
14887168ae33SJames Morse /**
14897168ae33SJames Morse  * rdtgroup_cbm_to_size - Translate CBM to size in bytes
14907168ae33SJames Morse  * @r: RDT resource to which @d belongs.
14917168ae33SJames Morse  * @d: RDT domain instance.
14927168ae33SJames Morse  * @cbm: bitmask for which the size should be computed.
14937168ae33SJames Morse  *
14947168ae33SJames Morse  * The bitmask provided associated with the RDT domain instance @d will be
14957168ae33SJames Morse  * translated into how many bytes it represents. The size in bytes is
14967168ae33SJames Morse  * computed by first dividing the total cache size by the CBM length to
14977168ae33SJames Morse  * determine how many bytes each bit in the bitmask represents. The result
14987168ae33SJames Morse  * is multiplied with the number of bits set in the bitmask.
14997168ae33SJames Morse  *
15007168ae33SJames Morse  * @cbm is unsigned long, even if only 32 bits are used to make the
15017168ae33SJames Morse  * bitmap functions work correctly.
15027168ae33SJames Morse  */
rdtgroup_cbm_to_size(struct rdt_resource * r,struct rdt_ctrl_domain * d,unsigned long cbm)15037168ae33SJames Morse unsigned int rdtgroup_cbm_to_size(struct rdt_resource *r,
15047168ae33SJames Morse 				  struct rdt_ctrl_domain *d, unsigned long cbm)
15057168ae33SJames Morse {
15067168ae33SJames Morse 	unsigned int size = 0;
15077168ae33SJames Morse 	struct cacheinfo *ci;
15087168ae33SJames Morse 	int num_b;
15097168ae33SJames Morse 
15107168ae33SJames Morse 	if (WARN_ON_ONCE(r->ctrl_scope != RESCTRL_L2_CACHE && r->ctrl_scope != RESCTRL_L3_CACHE))
15117168ae33SJames Morse 		return size;
15127168ae33SJames Morse 
15137168ae33SJames Morse 	num_b = bitmap_weight(&cbm, r->cache.cbm_len);
15147168ae33SJames Morse 	ci = get_cpu_cacheinfo_level(cpumask_any(&d->hdr.cpu_mask), r->ctrl_scope);
15157168ae33SJames Morse 	if (ci)
15167168ae33SJames Morse 		size = ci->size / r->cache.cbm_len * num_b;
15177168ae33SJames Morse 
15187168ae33SJames Morse 	return size;
15197168ae33SJames Morse }
15207168ae33SJames Morse 
is_mba_sc(struct rdt_resource * r)15217168ae33SJames Morse bool is_mba_sc(struct rdt_resource *r)
15227168ae33SJames Morse {
15237168ae33SJames Morse 	if (!r)
15247168ae33SJames Morse 		r = resctrl_arch_get_resource(RDT_RESOURCE_MBA);
15257168ae33SJames Morse 
15267168ae33SJames Morse 	/*
15277168ae33SJames Morse 	 * The software controller support is only applicable to MBA resource.
15287168ae33SJames Morse 	 * Make sure to check for resource type.
15297168ae33SJames Morse 	 */
15307168ae33SJames Morse 	if (r->rid != RDT_RESOURCE_MBA)
15317168ae33SJames Morse 		return false;
15327168ae33SJames Morse 
15337168ae33SJames Morse 	return r->membw.mba_sc;
15347168ae33SJames Morse }
15357168ae33SJames Morse 
15367168ae33SJames Morse /*
15377168ae33SJames Morse  * rdtgroup_size_show - Display size in bytes of allocated regions
15387168ae33SJames Morse  *
15397168ae33SJames Morse  * The "size" file mirrors the layout of the "schemata" file, printing the
15407168ae33SJames Morse  * size in bytes of each region instead of the capacity bitmask.
15417168ae33SJames Morse  */
rdtgroup_size_show(struct kernfs_open_file * of,struct seq_file * s,void * v)15427168ae33SJames Morse static int rdtgroup_size_show(struct kernfs_open_file *of,
15437168ae33SJames Morse 			      struct seq_file *s, void *v)
15447168ae33SJames Morse {
15457168ae33SJames Morse 	struct resctrl_schema *schema;
15467168ae33SJames Morse 	enum resctrl_conf_type type;
15477168ae33SJames Morse 	struct rdt_ctrl_domain *d;
15487168ae33SJames Morse 	struct rdtgroup *rdtgrp;
15497168ae33SJames Morse 	struct rdt_resource *r;
15507168ae33SJames Morse 	unsigned int size;
15517168ae33SJames Morse 	int ret = 0;
15527168ae33SJames Morse 	u32 closid;
15537168ae33SJames Morse 	bool sep;
15547168ae33SJames Morse 	u32 ctrl;
15557168ae33SJames Morse 
15567168ae33SJames Morse 	rdtgrp = rdtgroup_kn_lock_live(of->kn);
15577168ae33SJames Morse 	if (!rdtgrp) {
15587168ae33SJames Morse 		rdtgroup_kn_unlock(of->kn);
15597168ae33SJames Morse 		return -ENOENT;
15607168ae33SJames Morse 	}
15617168ae33SJames Morse 
15627168ae33SJames Morse 	if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
15637168ae33SJames Morse 		if (!rdtgrp->plr->d) {
15647168ae33SJames Morse 			rdt_last_cmd_clear();
15657168ae33SJames Morse 			rdt_last_cmd_puts("Cache domain offline\n");
15667168ae33SJames Morse 			ret = -ENODEV;
15677168ae33SJames Morse 		} else {
15687168ae33SJames Morse 			seq_printf(s, "%*s:", max_name_width,
15697168ae33SJames Morse 				   rdtgrp->plr->s->name);
15707168ae33SJames Morse 			size = rdtgroup_cbm_to_size(rdtgrp->plr->s->res,
15717168ae33SJames Morse 						    rdtgrp->plr->d,
15727168ae33SJames Morse 						    rdtgrp->plr->cbm);
15737168ae33SJames Morse 			seq_printf(s, "%d=%u\n", rdtgrp->plr->d->hdr.id, size);
15747168ae33SJames Morse 		}
15757168ae33SJames Morse 		goto out;
15767168ae33SJames Morse 	}
15777168ae33SJames Morse 
15787168ae33SJames Morse 	closid = rdtgrp->closid;
15797168ae33SJames Morse 
15807168ae33SJames Morse 	list_for_each_entry(schema, &resctrl_schema_all, list) {
15817168ae33SJames Morse 		r = schema->res;
15827168ae33SJames Morse 		type = schema->conf_type;
15837168ae33SJames Morse 		sep = false;
15847168ae33SJames Morse 		seq_printf(s, "%*s:", max_name_width, schema->name);
15857168ae33SJames Morse 		list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
15867168ae33SJames Morse 			if (sep)
15877168ae33SJames Morse 				seq_putc(s, ';');
15887168ae33SJames Morse 			if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
15897168ae33SJames Morse 				size = 0;
15907168ae33SJames Morse 			} else {
15917168ae33SJames Morse 				if (is_mba_sc(r))
15927168ae33SJames Morse 					ctrl = d->mbps_val[closid];
15937168ae33SJames Morse 				else
15947168ae33SJames Morse 					ctrl = resctrl_arch_get_config(r, d,
15957168ae33SJames Morse 								       closid,
15967168ae33SJames Morse 								       type);
15977168ae33SJames Morse 				if (r->rid == RDT_RESOURCE_MBA ||
15987168ae33SJames Morse 				    r->rid == RDT_RESOURCE_SMBA)
15997168ae33SJames Morse 					size = ctrl;
16007168ae33SJames Morse 				else
16017168ae33SJames Morse 					size = rdtgroup_cbm_to_size(r, d, ctrl);
16027168ae33SJames Morse 			}
16037168ae33SJames Morse 			seq_printf(s, "%d=%u", d->hdr.id, size);
16047168ae33SJames Morse 			sep = true;
16057168ae33SJames Morse 		}
16067168ae33SJames Morse 		seq_putc(s, '\n');
16077168ae33SJames Morse 	}
16087168ae33SJames Morse 
16097168ae33SJames Morse out:
16107168ae33SJames Morse 	rdtgroup_kn_unlock(of->kn);
16117168ae33SJames Morse 
16127168ae33SJames Morse 	return ret;
16137168ae33SJames Morse }
16147168ae33SJames Morse 
mondata_config_read(struct resctrl_mon_config_info * mon_info)16157168ae33SJames Morse static void mondata_config_read(struct resctrl_mon_config_info *mon_info)
16167168ae33SJames Morse {
16177168ae33SJames Morse 	smp_call_function_any(&mon_info->d->hdr.cpu_mask,
16187168ae33SJames Morse 			      resctrl_arch_mon_event_config_read, mon_info, 1);
16197168ae33SJames Morse }
16207168ae33SJames Morse 
mbm_config_show(struct seq_file * s,struct rdt_resource * r,u32 evtid)16217168ae33SJames Morse static int mbm_config_show(struct seq_file *s, struct rdt_resource *r, u32 evtid)
16227168ae33SJames Morse {
16237168ae33SJames Morse 	struct resctrl_mon_config_info mon_info;
16247168ae33SJames Morse 	struct rdt_mon_domain *dom;
16257168ae33SJames Morse 	bool sep = false;
16267168ae33SJames Morse 
16277168ae33SJames Morse 	cpus_read_lock();
16287168ae33SJames Morse 	mutex_lock(&rdtgroup_mutex);
16297168ae33SJames Morse 
16307168ae33SJames Morse 	list_for_each_entry(dom, &r->mon_domains, hdr.list) {
16317168ae33SJames Morse 		if (sep)
16327168ae33SJames Morse 			seq_puts(s, ";");
16337168ae33SJames Morse 
16347168ae33SJames Morse 		memset(&mon_info, 0, sizeof(struct resctrl_mon_config_info));
16357168ae33SJames Morse 		mon_info.r = r;
16367168ae33SJames Morse 		mon_info.d = dom;
16377168ae33SJames Morse 		mon_info.evtid = evtid;
16387168ae33SJames Morse 		mondata_config_read(&mon_info);
16397168ae33SJames Morse 
16407168ae33SJames Morse 		seq_printf(s, "%d=0x%02x", dom->hdr.id, mon_info.mon_config);
16417168ae33SJames Morse 		sep = true;
16427168ae33SJames Morse 	}
16437168ae33SJames Morse 	seq_puts(s, "\n");
16447168ae33SJames Morse 
16457168ae33SJames Morse 	mutex_unlock(&rdtgroup_mutex);
16467168ae33SJames Morse 	cpus_read_unlock();
16477168ae33SJames Morse 
16487168ae33SJames Morse 	return 0;
16497168ae33SJames Morse }
16507168ae33SJames Morse 
mbm_total_bytes_config_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)16517168ae33SJames Morse static int mbm_total_bytes_config_show(struct kernfs_open_file *of,
16527168ae33SJames Morse 				       struct seq_file *seq, void *v)
16537168ae33SJames Morse {
16547168ae33SJames Morse 	struct rdt_resource *r = rdt_kn_parent_priv(of->kn);
16557168ae33SJames Morse 
16567168ae33SJames Morse 	mbm_config_show(seq, r, QOS_L3_MBM_TOTAL_EVENT_ID);
16577168ae33SJames Morse 
16587168ae33SJames Morse 	return 0;
16597168ae33SJames Morse }
16607168ae33SJames Morse 
mbm_local_bytes_config_show(struct kernfs_open_file * of,struct seq_file * seq,void * v)16617168ae33SJames Morse static int mbm_local_bytes_config_show(struct kernfs_open_file *of,
16627168ae33SJames Morse 				       struct seq_file *seq, void *v)
16637168ae33SJames Morse {
16647168ae33SJames Morse 	struct rdt_resource *r = rdt_kn_parent_priv(of->kn);
16657168ae33SJames Morse 
16667168ae33SJames Morse 	mbm_config_show(seq, r, QOS_L3_MBM_LOCAL_EVENT_ID);
16677168ae33SJames Morse 
16687168ae33SJames Morse 	return 0;
16697168ae33SJames Morse }
16707168ae33SJames Morse 
mbm_config_write_domain(struct rdt_resource * r,struct rdt_mon_domain * d,u32 evtid,u32 val)16717168ae33SJames Morse static void mbm_config_write_domain(struct rdt_resource *r,
16727168ae33SJames Morse 				    struct rdt_mon_domain *d, u32 evtid, u32 val)
16737168ae33SJames Morse {
16747168ae33SJames Morse 	struct resctrl_mon_config_info mon_info = {0};
16757168ae33SJames Morse 
16767168ae33SJames Morse 	/*
16777168ae33SJames Morse 	 * Read the current config value first. If both are the same then
16787168ae33SJames Morse 	 * no need to write it again.
16797168ae33SJames Morse 	 */
16807168ae33SJames Morse 	mon_info.r = r;
16817168ae33SJames Morse 	mon_info.d = d;
16827168ae33SJames Morse 	mon_info.evtid = evtid;
16837168ae33SJames Morse 	mondata_config_read(&mon_info);
16847168ae33SJames Morse 	if (mon_info.mon_config == val)
16857168ae33SJames Morse 		return;
16867168ae33SJames Morse 
16877168ae33SJames Morse 	mon_info.mon_config = val;
16887168ae33SJames Morse 
16897168ae33SJames Morse 	/*
16907168ae33SJames Morse 	 * Update MSR_IA32_EVT_CFG_BASE MSR on one of the CPUs in the
16917168ae33SJames Morse 	 * domain. The MSRs offset from MSR MSR_IA32_EVT_CFG_BASE
16927168ae33SJames Morse 	 * are scoped at the domain level. Writing any of these MSRs
16937168ae33SJames Morse 	 * on one CPU is observed by all the CPUs in the domain.
16947168ae33SJames Morse 	 */
16957168ae33SJames Morse 	smp_call_function_any(&d->hdr.cpu_mask, resctrl_arch_mon_event_config_write,
16967168ae33SJames Morse 			      &mon_info, 1);
16977168ae33SJames Morse 
16987168ae33SJames Morse 	/*
16997168ae33SJames Morse 	 * When an Event Configuration is changed, the bandwidth counters
17007168ae33SJames Morse 	 * for all RMIDs and Events will be cleared by the hardware. The
17017168ae33SJames Morse 	 * hardware also sets MSR_IA32_QM_CTR.Unavailable (bit 62) for
17027168ae33SJames Morse 	 * every RMID on the next read to any event for every RMID.
17037168ae33SJames Morse 	 * Subsequent reads will have MSR_IA32_QM_CTR.Unavailable (bit 62)
17047168ae33SJames Morse 	 * cleared while it is tracked by the hardware. Clear the
17057168ae33SJames Morse 	 * mbm_local and mbm_total counts for all the RMIDs.
17067168ae33SJames Morse 	 */
17077168ae33SJames Morse 	resctrl_arch_reset_rmid_all(r, d);
17087168ae33SJames Morse }
17097168ae33SJames Morse 
mon_config_write(struct rdt_resource * r,char * tok,u32 evtid)17107168ae33SJames Morse static int mon_config_write(struct rdt_resource *r, char *tok, u32 evtid)
17117168ae33SJames Morse {
17127168ae33SJames Morse 	char *dom_str = NULL, *id_str;
17137168ae33SJames Morse 	unsigned long dom_id, val;
17147168ae33SJames Morse 	struct rdt_mon_domain *d;
17157168ae33SJames Morse 
17167168ae33SJames Morse 	/* Walking r->domains, ensure it can't race with cpuhp */
17177168ae33SJames Morse 	lockdep_assert_cpus_held();
17187168ae33SJames Morse 
17197168ae33SJames Morse next:
17207168ae33SJames Morse 	if (!tok || tok[0] == '\0')
17217168ae33SJames Morse 		return 0;
17227168ae33SJames Morse 
17237168ae33SJames Morse 	/* Start processing the strings for each domain */
17247168ae33SJames Morse 	dom_str = strim(strsep(&tok, ";"));
17257168ae33SJames Morse 	id_str = strsep(&dom_str, "=");
17267168ae33SJames Morse 
17277168ae33SJames Morse 	if (!id_str || kstrtoul(id_str, 10, &dom_id)) {
17287168ae33SJames Morse 		rdt_last_cmd_puts("Missing '=' or non-numeric domain id\n");
17297168ae33SJames Morse 		return -EINVAL;
17307168ae33SJames Morse 	}
17317168ae33SJames Morse 
17327168ae33SJames Morse 	if (!dom_str || kstrtoul(dom_str, 16, &val)) {
17337168ae33SJames Morse 		rdt_last_cmd_puts("Non-numeric event configuration value\n");
17347168ae33SJames Morse 		return -EINVAL;
17357168ae33SJames Morse 	}
17367168ae33SJames Morse 
17377168ae33SJames Morse 	/* Value from user cannot be more than the supported set of events */
17387168ae33SJames Morse 	if ((val & r->mbm_cfg_mask) != val) {
17397168ae33SJames Morse 		rdt_last_cmd_printf("Invalid event configuration: max valid mask is 0x%02x\n",
17407168ae33SJames Morse 				    r->mbm_cfg_mask);
17417168ae33SJames Morse 		return -EINVAL;
17427168ae33SJames Morse 	}
17437168ae33SJames Morse 
17447168ae33SJames Morse 	list_for_each_entry(d, &r->mon_domains, hdr.list) {
17457168ae33SJames Morse 		if (d->hdr.id == dom_id) {
17467168ae33SJames Morse 			mbm_config_write_domain(r, d, evtid, val);
17477168ae33SJames Morse 			goto next;
17487168ae33SJames Morse 		}
17497168ae33SJames Morse 	}
17507168ae33SJames Morse 
17517168ae33SJames Morse 	return -EINVAL;
17527168ae33SJames Morse }
17537168ae33SJames Morse 
mbm_total_bytes_config_write(struct kernfs_open_file * of,char * buf,size_t nbytes,loff_t off)17547168ae33SJames Morse static ssize_t mbm_total_bytes_config_write(struct kernfs_open_file *of,
17557168ae33SJames Morse 					    char *buf, size_t nbytes,
17567168ae33SJames Morse 					    loff_t off)
17577168ae33SJames Morse {
17587168ae33SJames Morse 	struct rdt_resource *r = rdt_kn_parent_priv(of->kn);
17597168ae33SJames Morse 	int ret;
17607168ae33SJames Morse 
17617168ae33SJames Morse 	/* Valid input requires a trailing newline */
17627168ae33SJames Morse 	if (nbytes == 0 || buf[nbytes - 1] != '\n')
17637168ae33SJames Morse 		return -EINVAL;
17647168ae33SJames Morse 
17657168ae33SJames Morse 	cpus_read_lock();
17667168ae33SJames Morse 	mutex_lock(&rdtgroup_mutex);
17677168ae33SJames Morse 
17687168ae33SJames Morse 	rdt_last_cmd_clear();
17697168ae33SJames Morse 
17707168ae33SJames Morse 	buf[nbytes - 1] = '\0';
17717168ae33SJames Morse 
17727168ae33SJames Morse 	ret = mon_config_write(r, buf, QOS_L3_MBM_TOTAL_EVENT_ID);
17737168ae33SJames Morse 
17747168ae33SJames Morse 	mutex_unlock(&rdtgroup_mutex);
17757168ae33SJames Morse 	cpus_read_unlock();
17767168ae33SJames Morse 
17777168ae33SJames Morse 	return ret ?: nbytes;
17787168ae33SJames Morse }
17797168ae33SJames Morse 
mbm_local_bytes_config_write(struct kernfs_open_file * of,char * buf,size_t nbytes,loff_t off)17807168ae33SJames Morse static ssize_t mbm_local_bytes_config_write(struct kernfs_open_file *of,
17817168ae33SJames Morse 					    char *buf, size_t nbytes,
17827168ae33SJames Morse 					    loff_t off)
17837168ae33SJames Morse {
17847168ae33SJames Morse 	struct rdt_resource *r = rdt_kn_parent_priv(of->kn);
17857168ae33SJames Morse 	int ret;
17867168ae33SJames Morse 
17877168ae33SJames Morse 	/* Valid input requires a trailing newline */
17887168ae33SJames Morse 	if (nbytes == 0 || buf[nbytes - 1] != '\n')
17897168ae33SJames Morse 		return -EINVAL;
17907168ae33SJames Morse 
17917168ae33SJames Morse 	cpus_read_lock();
17927168ae33SJames Morse 	mutex_lock(&rdtgroup_mutex);
17937168ae33SJames Morse 
17947168ae33SJames Morse 	rdt_last_cmd_clear();
17957168ae33SJames Morse 
17967168ae33SJames Morse 	buf[nbytes - 1] = '\0';
17977168ae33SJames Morse 
17987168ae33SJames Morse 	ret = mon_config_write(r, buf, QOS_L3_MBM_LOCAL_EVENT_ID);
17997168ae33SJames Morse 
18007168ae33SJames Morse 	mutex_unlock(&rdtgroup_mutex);
18017168ae33SJames Morse 	cpus_read_unlock();
18027168ae33SJames Morse 
18037168ae33SJames Morse 	return ret ?: nbytes;
18047168ae33SJames Morse }
18057168ae33SJames Morse 
18067168ae33SJames Morse /* rdtgroup information files for one cache resource. */
18077168ae33SJames Morse static struct rftype res_common_files[] = {
18087168ae33SJames Morse 	{
18097168ae33SJames Morse 		.name		= "last_cmd_status",
18107168ae33SJames Morse 		.mode		= 0444,
18117168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
18127168ae33SJames Morse 		.seq_show	= rdt_last_cmd_status_show,
18137168ae33SJames Morse 		.fflags		= RFTYPE_TOP_INFO,
18147168ae33SJames Morse 	},
18157168ae33SJames Morse 	{
18167168ae33SJames Morse 		.name		= "num_closids",
18177168ae33SJames Morse 		.mode		= 0444,
18187168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
18197168ae33SJames Morse 		.seq_show	= rdt_num_closids_show,
18207168ae33SJames Morse 		.fflags		= RFTYPE_CTRL_INFO,
18217168ae33SJames Morse 	},
18227168ae33SJames Morse 	{
18237168ae33SJames Morse 		.name		= "mon_features",
18247168ae33SJames Morse 		.mode		= 0444,
18257168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
18267168ae33SJames Morse 		.seq_show	= rdt_mon_features_show,
18277168ae33SJames Morse 		.fflags		= RFTYPE_MON_INFO,
18287168ae33SJames Morse 	},
18297168ae33SJames Morse 	{
18307168ae33SJames Morse 		.name		= "num_rmids",
18317168ae33SJames Morse 		.mode		= 0444,
18327168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
18337168ae33SJames Morse 		.seq_show	= rdt_num_rmids_show,
18347168ae33SJames Morse 		.fflags		= RFTYPE_MON_INFO,
18357168ae33SJames Morse 	},
18367168ae33SJames Morse 	{
18377168ae33SJames Morse 		.name		= "cbm_mask",
18387168ae33SJames Morse 		.mode		= 0444,
18397168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
18407168ae33SJames Morse 		.seq_show	= rdt_default_ctrl_show,
18417168ae33SJames Morse 		.fflags		= RFTYPE_CTRL_INFO | RFTYPE_RES_CACHE,
18427168ae33SJames Morse 	},
18437168ae33SJames Morse 	{
18447168ae33SJames Morse 		.name		= "min_cbm_bits",
18457168ae33SJames Morse 		.mode		= 0444,
18467168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
18477168ae33SJames Morse 		.seq_show	= rdt_min_cbm_bits_show,
18487168ae33SJames Morse 		.fflags		= RFTYPE_CTRL_INFO | RFTYPE_RES_CACHE,
18497168ae33SJames Morse 	},
18507168ae33SJames Morse 	{
18517168ae33SJames Morse 		.name		= "shareable_bits",
18527168ae33SJames Morse 		.mode		= 0444,
18537168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
18547168ae33SJames Morse 		.seq_show	= rdt_shareable_bits_show,
18557168ae33SJames Morse 		.fflags		= RFTYPE_CTRL_INFO | RFTYPE_RES_CACHE,
18567168ae33SJames Morse 	},
18577168ae33SJames Morse 	{
18587168ae33SJames Morse 		.name		= "bit_usage",
18597168ae33SJames Morse 		.mode		= 0444,
18607168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
18617168ae33SJames Morse 		.seq_show	= rdt_bit_usage_show,
18627168ae33SJames Morse 		.fflags		= RFTYPE_CTRL_INFO | RFTYPE_RES_CACHE,
18637168ae33SJames Morse 	},
18647168ae33SJames Morse 	{
18657168ae33SJames Morse 		.name		= "min_bandwidth",
18667168ae33SJames Morse 		.mode		= 0444,
18677168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
18687168ae33SJames Morse 		.seq_show	= rdt_min_bw_show,
18697168ae33SJames Morse 		.fflags		= RFTYPE_CTRL_INFO | RFTYPE_RES_MB,
18707168ae33SJames Morse 	},
18717168ae33SJames Morse 	{
18727168ae33SJames Morse 		.name		= "bandwidth_gran",
18737168ae33SJames Morse 		.mode		= 0444,
18747168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
18757168ae33SJames Morse 		.seq_show	= rdt_bw_gran_show,
18767168ae33SJames Morse 		.fflags		= RFTYPE_CTRL_INFO | RFTYPE_RES_MB,
18777168ae33SJames Morse 	},
18787168ae33SJames Morse 	{
18797168ae33SJames Morse 		.name		= "delay_linear",
18807168ae33SJames Morse 		.mode		= 0444,
18817168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
18827168ae33SJames Morse 		.seq_show	= rdt_delay_linear_show,
18837168ae33SJames Morse 		.fflags		= RFTYPE_CTRL_INFO | RFTYPE_RES_MB,
18847168ae33SJames Morse 	},
18857168ae33SJames Morse 	/*
18867168ae33SJames Morse 	 * Platform specific which (if any) capabilities are provided by
18877168ae33SJames Morse 	 * thread_throttle_mode. Defer "fflags" initialization to platform
18887168ae33SJames Morse 	 * discovery.
18897168ae33SJames Morse 	 */
18907168ae33SJames Morse 	{
18917168ae33SJames Morse 		.name		= "thread_throttle_mode",
18927168ae33SJames Morse 		.mode		= 0444,
18937168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
18947168ae33SJames Morse 		.seq_show	= rdt_thread_throttle_mode_show,
18957168ae33SJames Morse 	},
18967168ae33SJames Morse 	{
18977168ae33SJames Morse 		.name		= "max_threshold_occupancy",
18987168ae33SJames Morse 		.mode		= 0644,
18997168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
19007168ae33SJames Morse 		.write		= max_threshold_occ_write,
19017168ae33SJames Morse 		.seq_show	= max_threshold_occ_show,
19027168ae33SJames Morse 		.fflags		= RFTYPE_MON_INFO | RFTYPE_RES_CACHE,
19037168ae33SJames Morse 	},
19047168ae33SJames Morse 	{
19057168ae33SJames Morse 		.name		= "mbm_total_bytes_config",
19067168ae33SJames Morse 		.mode		= 0644,
19077168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
19087168ae33SJames Morse 		.seq_show	= mbm_total_bytes_config_show,
19097168ae33SJames Morse 		.write		= mbm_total_bytes_config_write,
19107168ae33SJames Morse 	},
19117168ae33SJames Morse 	{
19127168ae33SJames Morse 		.name		= "mbm_local_bytes_config",
19137168ae33SJames Morse 		.mode		= 0644,
19147168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
19157168ae33SJames Morse 		.seq_show	= mbm_local_bytes_config_show,
19167168ae33SJames Morse 		.write		= mbm_local_bytes_config_write,
19177168ae33SJames Morse 	},
19187168ae33SJames Morse 	{
19197168ae33SJames Morse 		.name		= "cpus",
19207168ae33SJames Morse 		.mode		= 0644,
19217168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
19227168ae33SJames Morse 		.write		= rdtgroup_cpus_write,
19237168ae33SJames Morse 		.seq_show	= rdtgroup_cpus_show,
19247168ae33SJames Morse 		.fflags		= RFTYPE_BASE,
19257168ae33SJames Morse 	},
19267168ae33SJames Morse 	{
19277168ae33SJames Morse 		.name		= "cpus_list",
19287168ae33SJames Morse 		.mode		= 0644,
19297168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
19307168ae33SJames Morse 		.write		= rdtgroup_cpus_write,
19317168ae33SJames Morse 		.seq_show	= rdtgroup_cpus_show,
19327168ae33SJames Morse 		.flags		= RFTYPE_FLAGS_CPUS_LIST,
19337168ae33SJames Morse 		.fflags		= RFTYPE_BASE,
19347168ae33SJames Morse 	},
19357168ae33SJames Morse 	{
19367168ae33SJames Morse 		.name		= "tasks",
19377168ae33SJames Morse 		.mode		= 0644,
19387168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
19397168ae33SJames Morse 		.write		= rdtgroup_tasks_write,
19407168ae33SJames Morse 		.seq_show	= rdtgroup_tasks_show,
19417168ae33SJames Morse 		.fflags		= RFTYPE_BASE,
19427168ae33SJames Morse 	},
19437168ae33SJames Morse 	{
19447168ae33SJames Morse 		.name		= "mon_hw_id",
19457168ae33SJames Morse 		.mode		= 0444,
19467168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
19477168ae33SJames Morse 		.seq_show	= rdtgroup_rmid_show,
19487168ae33SJames Morse 		.fflags		= RFTYPE_MON_BASE | RFTYPE_DEBUG,
19497168ae33SJames Morse 	},
19507168ae33SJames Morse 	{
19517168ae33SJames Morse 		.name		= "schemata",
19527168ae33SJames Morse 		.mode		= 0644,
19537168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
19547168ae33SJames Morse 		.write		= rdtgroup_schemata_write,
19557168ae33SJames Morse 		.seq_show	= rdtgroup_schemata_show,
19567168ae33SJames Morse 		.fflags		= RFTYPE_CTRL_BASE,
19577168ae33SJames Morse 	},
19587168ae33SJames Morse 	{
19597168ae33SJames Morse 		.name		= "mba_MBps_event",
19607168ae33SJames Morse 		.mode		= 0644,
19617168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
19627168ae33SJames Morse 		.write		= rdtgroup_mba_mbps_event_write,
19637168ae33SJames Morse 		.seq_show	= rdtgroup_mba_mbps_event_show,
19647168ae33SJames Morse 	},
19657168ae33SJames Morse 	{
19667168ae33SJames Morse 		.name		= "mode",
19677168ae33SJames Morse 		.mode		= 0644,
19687168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
19697168ae33SJames Morse 		.write		= rdtgroup_mode_write,
19707168ae33SJames Morse 		.seq_show	= rdtgroup_mode_show,
19717168ae33SJames Morse 		.fflags		= RFTYPE_CTRL_BASE,
19727168ae33SJames Morse 	},
19737168ae33SJames Morse 	{
19747168ae33SJames Morse 		.name		= "size",
19757168ae33SJames Morse 		.mode		= 0444,
19767168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
19777168ae33SJames Morse 		.seq_show	= rdtgroup_size_show,
19787168ae33SJames Morse 		.fflags		= RFTYPE_CTRL_BASE,
19797168ae33SJames Morse 	},
19807168ae33SJames Morse 	{
19817168ae33SJames Morse 		.name		= "sparse_masks",
19827168ae33SJames Morse 		.mode		= 0444,
19837168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
19847168ae33SJames Morse 		.seq_show	= rdt_has_sparse_bitmasks_show,
19857168ae33SJames Morse 		.fflags		= RFTYPE_CTRL_INFO | RFTYPE_RES_CACHE,
19867168ae33SJames Morse 	},
19877168ae33SJames Morse 	{
19887168ae33SJames Morse 		.name		= "ctrl_hw_id",
19897168ae33SJames Morse 		.mode		= 0444,
19907168ae33SJames Morse 		.kf_ops		= &rdtgroup_kf_single_ops,
19917168ae33SJames Morse 		.seq_show	= rdtgroup_closid_show,
19927168ae33SJames Morse 		.fflags		= RFTYPE_CTRL_BASE | RFTYPE_DEBUG,
19937168ae33SJames Morse 	},
19947168ae33SJames Morse };
19957168ae33SJames Morse 
rdtgroup_add_files(struct kernfs_node * kn,unsigned long fflags)19967168ae33SJames Morse static int rdtgroup_add_files(struct kernfs_node *kn, unsigned long fflags)
19977168ae33SJames Morse {
19987168ae33SJames Morse 	struct rftype *rfts, *rft;
19997168ae33SJames Morse 	int ret, len;
20007168ae33SJames Morse 
20017168ae33SJames Morse 	rfts = res_common_files;
20027168ae33SJames Morse 	len = ARRAY_SIZE(res_common_files);
20037168ae33SJames Morse 
20047168ae33SJames Morse 	lockdep_assert_held(&rdtgroup_mutex);
20057168ae33SJames Morse 
20067168ae33SJames Morse 	if (resctrl_debug)
20077168ae33SJames Morse 		fflags |= RFTYPE_DEBUG;
20087168ae33SJames Morse 
20097168ae33SJames Morse 	for (rft = rfts; rft < rfts + len; rft++) {
20107168ae33SJames Morse 		if (rft->fflags && ((fflags & rft->fflags) == rft->fflags)) {
20117168ae33SJames Morse 			ret = rdtgroup_add_file(kn, rft);
20127168ae33SJames Morse 			if (ret)
20137168ae33SJames Morse 				goto error;
20147168ae33SJames Morse 		}
20157168ae33SJames Morse 	}
20167168ae33SJames Morse 
20177168ae33SJames Morse 	return 0;
20187168ae33SJames Morse error:
20197168ae33SJames Morse 	pr_warn("Failed to add %s, err=%d\n", rft->name, ret);
20207168ae33SJames Morse 	while (--rft >= rfts) {
20217168ae33SJames Morse 		if ((fflags & rft->fflags) == rft->fflags)
20227168ae33SJames Morse 			kernfs_remove_by_name(kn, rft->name);
20237168ae33SJames Morse 	}
20247168ae33SJames Morse 	return ret;
20257168ae33SJames Morse }
20267168ae33SJames Morse 
rdtgroup_get_rftype_by_name(const char * name)20277168ae33SJames Morse static struct rftype *rdtgroup_get_rftype_by_name(const char *name)
20287168ae33SJames Morse {
20297168ae33SJames Morse 	struct rftype *rfts, *rft;
20307168ae33SJames Morse 	int len;
20317168ae33SJames Morse 
20327168ae33SJames Morse 	rfts = res_common_files;
20337168ae33SJames Morse 	len = ARRAY_SIZE(res_common_files);
20347168ae33SJames Morse 
20357168ae33SJames Morse 	for (rft = rfts; rft < rfts + len; rft++) {
20367168ae33SJames Morse 		if (!strcmp(rft->name, name))
20377168ae33SJames Morse 			return rft;
20387168ae33SJames Morse 	}
20397168ae33SJames Morse 
20407168ae33SJames Morse 	return NULL;
20417168ae33SJames Morse }
20427168ae33SJames Morse 
thread_throttle_mode_init(void)20437168ae33SJames Morse static void thread_throttle_mode_init(void)
20447168ae33SJames Morse {
20457168ae33SJames Morse 	enum membw_throttle_mode throttle_mode = THREAD_THROTTLE_UNDEFINED;
20467168ae33SJames Morse 	struct rdt_resource *r_mba, *r_smba;
20477168ae33SJames Morse 
20487168ae33SJames Morse 	r_mba = resctrl_arch_get_resource(RDT_RESOURCE_MBA);
20497168ae33SJames Morse 	if (r_mba->alloc_capable &&
20507168ae33SJames Morse 	    r_mba->membw.throttle_mode != THREAD_THROTTLE_UNDEFINED)
20517168ae33SJames Morse 		throttle_mode = r_mba->membw.throttle_mode;
20527168ae33SJames Morse 
20537168ae33SJames Morse 	r_smba = resctrl_arch_get_resource(RDT_RESOURCE_SMBA);
20547168ae33SJames Morse 	if (r_smba->alloc_capable &&
20557168ae33SJames Morse 	    r_smba->membw.throttle_mode != THREAD_THROTTLE_UNDEFINED)
20567168ae33SJames Morse 		throttle_mode = r_smba->membw.throttle_mode;
20577168ae33SJames Morse 
20587168ae33SJames Morse 	if (throttle_mode == THREAD_THROTTLE_UNDEFINED)
20597168ae33SJames Morse 		return;
20607168ae33SJames Morse 
20617168ae33SJames Morse 	resctrl_file_fflags_init("thread_throttle_mode",
20627168ae33SJames Morse 				 RFTYPE_CTRL_INFO | RFTYPE_RES_MB);
20637168ae33SJames Morse }
20647168ae33SJames Morse 
resctrl_file_fflags_init(const char * config,unsigned long fflags)20657168ae33SJames Morse void resctrl_file_fflags_init(const char *config, unsigned long fflags)
20667168ae33SJames Morse {
20677168ae33SJames Morse 	struct rftype *rft;
20687168ae33SJames Morse 
20697168ae33SJames Morse 	rft = rdtgroup_get_rftype_by_name(config);
20707168ae33SJames Morse 	if (rft)
20717168ae33SJames Morse 		rft->fflags = fflags;
20727168ae33SJames Morse }
20737168ae33SJames Morse 
20747168ae33SJames Morse /**
20757168ae33SJames Morse  * rdtgroup_kn_mode_restrict - Restrict user access to named resctrl file
20767168ae33SJames Morse  * @r: The resource group with which the file is associated.
20777168ae33SJames Morse  * @name: Name of the file
20787168ae33SJames Morse  *
20797168ae33SJames Morse  * The permissions of named resctrl file, directory, or link are modified
20807168ae33SJames Morse  * to not allow read, write, or execute by any user.
20817168ae33SJames Morse  *
20827168ae33SJames Morse  * WARNING: This function is intended to communicate to the user that the
20837168ae33SJames Morse  * resctrl file has been locked down - that it is not relevant to the
20847168ae33SJames Morse  * particular state the system finds itself in. It should not be relied
20857168ae33SJames Morse  * on to protect from user access because after the file's permissions
20867168ae33SJames Morse  * are restricted the user can still change the permissions using chmod
20877168ae33SJames Morse  * from the command line.
20887168ae33SJames Morse  *
20897168ae33SJames Morse  * Return: 0 on success, <0 on failure.
20907168ae33SJames Morse  */
rdtgroup_kn_mode_restrict(struct rdtgroup * r,const char * name)20917168ae33SJames Morse int rdtgroup_kn_mode_restrict(struct rdtgroup *r, const char *name)
20927168ae33SJames Morse {
20937168ae33SJames Morse 	struct iattr iattr = {.ia_valid = ATTR_MODE,};
20947168ae33SJames Morse 	struct kernfs_node *kn;
20957168ae33SJames Morse 	int ret = 0;
20967168ae33SJames Morse 
20977168ae33SJames Morse 	kn = kernfs_find_and_get_ns(r->kn, name, NULL);
20987168ae33SJames Morse 	if (!kn)
20997168ae33SJames Morse 		return -ENOENT;
21007168ae33SJames Morse 
21017168ae33SJames Morse 	switch (kernfs_type(kn)) {
21027168ae33SJames Morse 	case KERNFS_DIR:
21037168ae33SJames Morse 		iattr.ia_mode = S_IFDIR;
21047168ae33SJames Morse 		break;
21057168ae33SJames Morse 	case KERNFS_FILE:
21067168ae33SJames Morse 		iattr.ia_mode = S_IFREG;
21077168ae33SJames Morse 		break;
21087168ae33SJames Morse 	case KERNFS_LINK:
21097168ae33SJames Morse 		iattr.ia_mode = S_IFLNK;
21107168ae33SJames Morse 		break;
21117168ae33SJames Morse 	}
21127168ae33SJames Morse 
21137168ae33SJames Morse 	ret = kernfs_setattr(kn, &iattr);
21147168ae33SJames Morse 	kernfs_put(kn);
21157168ae33SJames Morse 	return ret;
21167168ae33SJames Morse }
21177168ae33SJames Morse 
21187168ae33SJames Morse /**
21197168ae33SJames Morse  * rdtgroup_kn_mode_restore - Restore user access to named resctrl file
21207168ae33SJames Morse  * @r: The resource group with which the file is associated.
21217168ae33SJames Morse  * @name: Name of the file
21227168ae33SJames Morse  * @mask: Mask of permissions that should be restored
21237168ae33SJames Morse  *
21247168ae33SJames Morse  * Restore the permissions of the named file. If @name is a directory the
21257168ae33SJames Morse  * permissions of its parent will be used.
21267168ae33SJames Morse  *
21277168ae33SJames Morse  * Return: 0 on success, <0 on failure.
21287168ae33SJames Morse  */
rdtgroup_kn_mode_restore(struct rdtgroup * r,const char * name,umode_t mask)21297168ae33SJames Morse int rdtgroup_kn_mode_restore(struct rdtgroup *r, const char *name,
21307168ae33SJames Morse 			     umode_t mask)
21317168ae33SJames Morse {
21327168ae33SJames Morse 	struct iattr iattr = {.ia_valid = ATTR_MODE,};
21337168ae33SJames Morse 	struct kernfs_node *kn, *parent;
21347168ae33SJames Morse 	struct rftype *rfts, *rft;
21357168ae33SJames Morse 	int ret, len;
21367168ae33SJames Morse 
21377168ae33SJames Morse 	rfts = res_common_files;
21387168ae33SJames Morse 	len = ARRAY_SIZE(res_common_files);
21397168ae33SJames Morse 
21407168ae33SJames Morse 	for (rft = rfts; rft < rfts + len; rft++) {
21417168ae33SJames Morse 		if (!strcmp(rft->name, name))
21427168ae33SJames Morse 			iattr.ia_mode = rft->mode & mask;
21437168ae33SJames Morse 	}
21447168ae33SJames Morse 
21457168ae33SJames Morse 	kn = kernfs_find_and_get_ns(r->kn, name, NULL);
21467168ae33SJames Morse 	if (!kn)
21477168ae33SJames Morse 		return -ENOENT;
21487168ae33SJames Morse 
21497168ae33SJames Morse 	switch (kernfs_type(kn)) {
21507168ae33SJames Morse 	case KERNFS_DIR:
21517168ae33SJames Morse 		parent = kernfs_get_parent(kn);
21527168ae33SJames Morse 		if (parent) {
21537168ae33SJames Morse 			iattr.ia_mode |= parent->mode;
21547168ae33SJames Morse 			kernfs_put(parent);
21557168ae33SJames Morse 		}
21567168ae33SJames Morse 		iattr.ia_mode |= S_IFDIR;
21577168ae33SJames Morse 		break;
21587168ae33SJames Morse 	case KERNFS_FILE:
21597168ae33SJames Morse 		iattr.ia_mode |= S_IFREG;
21607168ae33SJames Morse 		break;
21617168ae33SJames Morse 	case KERNFS_LINK:
21627168ae33SJames Morse 		iattr.ia_mode |= S_IFLNK;
21637168ae33SJames Morse 		break;
21647168ae33SJames Morse 	}
21657168ae33SJames Morse 
21667168ae33SJames Morse 	ret = kernfs_setattr(kn, &iattr);
21677168ae33SJames Morse 	kernfs_put(kn);
21687168ae33SJames Morse 	return ret;
21697168ae33SJames Morse }
21707168ae33SJames Morse 
rdtgroup_mkdir_info_resdir(void * priv,char * name,unsigned long fflags)21717168ae33SJames Morse static int rdtgroup_mkdir_info_resdir(void *priv, char *name,
21727168ae33SJames Morse 				      unsigned long fflags)
21737168ae33SJames Morse {
21747168ae33SJames Morse 	struct kernfs_node *kn_subdir;
21757168ae33SJames Morse 	int ret;
21767168ae33SJames Morse 
21777168ae33SJames Morse 	kn_subdir = kernfs_create_dir(kn_info, name,
21787168ae33SJames Morse 				      kn_info->mode, priv);
21797168ae33SJames Morse 	if (IS_ERR(kn_subdir))
21807168ae33SJames Morse 		return PTR_ERR(kn_subdir);
21817168ae33SJames Morse 
21827168ae33SJames Morse 	ret = rdtgroup_kn_set_ugid(kn_subdir);
21837168ae33SJames Morse 	if (ret)
21847168ae33SJames Morse 		return ret;
21857168ae33SJames Morse 
21867168ae33SJames Morse 	ret = rdtgroup_add_files(kn_subdir, fflags);
21877168ae33SJames Morse 	if (!ret)
21887168ae33SJames Morse 		kernfs_activate(kn_subdir);
21897168ae33SJames Morse 
21907168ae33SJames Morse 	return ret;
21917168ae33SJames Morse }
21927168ae33SJames Morse 
fflags_from_resource(struct rdt_resource * r)21937168ae33SJames Morse static unsigned long fflags_from_resource(struct rdt_resource *r)
21947168ae33SJames Morse {
21957168ae33SJames Morse 	switch (r->rid) {
21967168ae33SJames Morse 	case RDT_RESOURCE_L3:
21977168ae33SJames Morse 	case RDT_RESOURCE_L2:
21987168ae33SJames Morse 		return RFTYPE_RES_CACHE;
21997168ae33SJames Morse 	case RDT_RESOURCE_MBA:
22007168ae33SJames Morse 	case RDT_RESOURCE_SMBA:
22017168ae33SJames Morse 		return RFTYPE_RES_MB;
22027168ae33SJames Morse 	}
22037168ae33SJames Morse 
22047168ae33SJames Morse 	return WARN_ON_ONCE(1);
22057168ae33SJames Morse }
22067168ae33SJames Morse 
rdtgroup_create_info_dir(struct kernfs_node * parent_kn)22077168ae33SJames Morse static int rdtgroup_create_info_dir(struct kernfs_node *parent_kn)
22087168ae33SJames Morse {
22097168ae33SJames Morse 	struct resctrl_schema *s;
22107168ae33SJames Morse 	struct rdt_resource *r;
22117168ae33SJames Morse 	unsigned long fflags;
22127168ae33SJames Morse 	char name[32];
22137168ae33SJames Morse 	int ret;
22147168ae33SJames Morse 
22157168ae33SJames Morse 	/* create the directory */
22167168ae33SJames Morse 	kn_info = kernfs_create_dir(parent_kn, "info", parent_kn->mode, NULL);
22177168ae33SJames Morse 	if (IS_ERR(kn_info))
22187168ae33SJames Morse 		return PTR_ERR(kn_info);
22197168ae33SJames Morse 
22207168ae33SJames Morse 	ret = rdtgroup_add_files(kn_info, RFTYPE_TOP_INFO);
22217168ae33SJames Morse 	if (ret)
22227168ae33SJames Morse 		goto out_destroy;
22237168ae33SJames Morse 
22247168ae33SJames Morse 	/* loop over enabled controls, these are all alloc_capable */
22257168ae33SJames Morse 	list_for_each_entry(s, &resctrl_schema_all, list) {
22267168ae33SJames Morse 		r = s->res;
22277168ae33SJames Morse 		fflags = fflags_from_resource(r) | RFTYPE_CTRL_INFO;
22287168ae33SJames Morse 		ret = rdtgroup_mkdir_info_resdir(s, s->name, fflags);
22297168ae33SJames Morse 		if (ret)
22307168ae33SJames Morse 			goto out_destroy;
22317168ae33SJames Morse 	}
22327168ae33SJames Morse 
22337168ae33SJames Morse 	for_each_mon_capable_rdt_resource(r) {
22347168ae33SJames Morse 		fflags = fflags_from_resource(r) | RFTYPE_MON_INFO;
22357168ae33SJames Morse 		sprintf(name, "%s_MON", r->name);
22367168ae33SJames Morse 		ret = rdtgroup_mkdir_info_resdir(r, name, fflags);
22377168ae33SJames Morse 		if (ret)
22387168ae33SJames Morse 			goto out_destroy;
22397168ae33SJames Morse 	}
22407168ae33SJames Morse 
22417168ae33SJames Morse 	ret = rdtgroup_kn_set_ugid(kn_info);
22427168ae33SJames Morse 	if (ret)
22437168ae33SJames Morse 		goto out_destroy;
22447168ae33SJames Morse 
22457168ae33SJames Morse 	kernfs_activate(kn_info);
22467168ae33SJames Morse 
22477168ae33SJames Morse 	return 0;
22487168ae33SJames Morse 
22497168ae33SJames Morse out_destroy:
22507168ae33SJames Morse 	kernfs_remove(kn_info);
22517168ae33SJames Morse 	return ret;
22527168ae33SJames Morse }
22537168ae33SJames Morse 
22547168ae33SJames Morse static int
mongroup_create_dir(struct kernfs_node * parent_kn,struct rdtgroup * prgrp,char * name,struct kernfs_node ** dest_kn)22557168ae33SJames Morse mongroup_create_dir(struct kernfs_node *parent_kn, struct rdtgroup *prgrp,
22567168ae33SJames Morse 		    char *name, struct kernfs_node **dest_kn)
22577168ae33SJames Morse {
22587168ae33SJames Morse 	struct kernfs_node *kn;
22597168ae33SJames Morse 	int ret;
22607168ae33SJames Morse 
22617168ae33SJames Morse 	/* create the directory */
22627168ae33SJames Morse 	kn = kernfs_create_dir(parent_kn, name, parent_kn->mode, prgrp);
22637168ae33SJames Morse 	if (IS_ERR(kn))
22647168ae33SJames Morse 		return PTR_ERR(kn);
22657168ae33SJames Morse 
22667168ae33SJames Morse 	if (dest_kn)
22677168ae33SJames Morse 		*dest_kn = kn;
22687168ae33SJames Morse 
22697168ae33SJames Morse 	ret = rdtgroup_kn_set_ugid(kn);
22707168ae33SJames Morse 	if (ret)
22717168ae33SJames Morse 		goto out_destroy;
22727168ae33SJames Morse 
22737168ae33SJames Morse 	kernfs_activate(kn);
22747168ae33SJames Morse 
22757168ae33SJames Morse 	return 0;
22767168ae33SJames Morse 
22777168ae33SJames Morse out_destroy:
22787168ae33SJames Morse 	kernfs_remove(kn);
22797168ae33SJames Morse 	return ret;
22807168ae33SJames Morse }
22817168ae33SJames Morse 
is_mba_linear(void)22827168ae33SJames Morse static inline bool is_mba_linear(void)
22837168ae33SJames Morse {
22847168ae33SJames Morse 	return resctrl_arch_get_resource(RDT_RESOURCE_MBA)->membw.delay_linear;
22857168ae33SJames Morse }
22867168ae33SJames Morse 
mba_sc_domain_allocate(struct rdt_resource * r,struct rdt_ctrl_domain * d)22877168ae33SJames Morse static int mba_sc_domain_allocate(struct rdt_resource *r, struct rdt_ctrl_domain *d)
22887168ae33SJames Morse {
22897168ae33SJames Morse 	u32 num_closid = resctrl_arch_get_num_closid(r);
22907168ae33SJames Morse 	int cpu = cpumask_any(&d->hdr.cpu_mask);
22917168ae33SJames Morse 	int i;
22927168ae33SJames Morse 
22937168ae33SJames Morse 	d->mbps_val = kcalloc_node(num_closid, sizeof(*d->mbps_val),
22947168ae33SJames Morse 				   GFP_KERNEL, cpu_to_node(cpu));
22957168ae33SJames Morse 	if (!d->mbps_val)
22967168ae33SJames Morse 		return -ENOMEM;
22977168ae33SJames Morse 
22987168ae33SJames Morse 	for (i = 0; i < num_closid; i++)
22997168ae33SJames Morse 		d->mbps_val[i] = MBA_MAX_MBPS;
23007168ae33SJames Morse 
23017168ae33SJames Morse 	return 0;
23027168ae33SJames Morse }
23037168ae33SJames Morse 
mba_sc_domain_destroy(struct rdt_resource * r,struct rdt_ctrl_domain * d)23047168ae33SJames Morse static void mba_sc_domain_destroy(struct rdt_resource *r,
23057168ae33SJames Morse 				  struct rdt_ctrl_domain *d)
23067168ae33SJames Morse {
23077168ae33SJames Morse 	kfree(d->mbps_val);
23087168ae33SJames Morse 	d->mbps_val = NULL;
23097168ae33SJames Morse }
23107168ae33SJames Morse 
23117168ae33SJames Morse /*
23127168ae33SJames Morse  * MBA software controller is supported only if
23137168ae33SJames Morse  * MBM is supported and MBA is in linear scale,
23147168ae33SJames Morse  * and the MBM monitor scope is the same as MBA
23157168ae33SJames Morse  * control scope.
23167168ae33SJames Morse  */
supports_mba_mbps(void)23177168ae33SJames Morse static bool supports_mba_mbps(void)
23187168ae33SJames Morse {
23197168ae33SJames Morse 	struct rdt_resource *rmbm = resctrl_arch_get_resource(RDT_RESOURCE_L3);
23207168ae33SJames Morse 	struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_MBA);
23217168ae33SJames Morse 
23227168ae33SJames Morse 	return (resctrl_is_mbm_enabled() &&
23237168ae33SJames Morse 		r->alloc_capable && is_mba_linear() &&
23247168ae33SJames Morse 		r->ctrl_scope == rmbm->mon_scope);
23257168ae33SJames Morse }
23267168ae33SJames Morse 
23277168ae33SJames Morse /*
23287168ae33SJames Morse  * Enable or disable the MBA software controller
23297168ae33SJames Morse  * which helps user specify bandwidth in MBps.
23307168ae33SJames Morse  */
set_mba_sc(bool mba_sc)23317168ae33SJames Morse static int set_mba_sc(bool mba_sc)
23327168ae33SJames Morse {
23337168ae33SJames Morse 	struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_MBA);
23347168ae33SJames Morse 	u32 num_closid = resctrl_arch_get_num_closid(r);
23357168ae33SJames Morse 	struct rdt_ctrl_domain *d;
23367168ae33SJames Morse 	unsigned long fflags;
23377168ae33SJames Morse 	int i;
23387168ae33SJames Morse 
23397168ae33SJames Morse 	if (!supports_mba_mbps() || mba_sc == is_mba_sc(r))
23407168ae33SJames Morse 		return -EINVAL;
23417168ae33SJames Morse 
23427168ae33SJames Morse 	r->membw.mba_sc = mba_sc;
23437168ae33SJames Morse 
23447168ae33SJames Morse 	rdtgroup_default.mba_mbps_event = mba_mbps_default_event;
23457168ae33SJames Morse 
23467168ae33SJames Morse 	list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
23477168ae33SJames Morse 		for (i = 0; i < num_closid; i++)
23487168ae33SJames Morse 			d->mbps_val[i] = MBA_MAX_MBPS;
23497168ae33SJames Morse 	}
23507168ae33SJames Morse 
23517168ae33SJames Morse 	fflags = mba_sc ? RFTYPE_CTRL_BASE | RFTYPE_MON_BASE : 0;
23527168ae33SJames Morse 	resctrl_file_fflags_init("mba_MBps_event", fflags);
23537168ae33SJames Morse 
23547168ae33SJames Morse 	return 0;
23557168ae33SJames Morse }
23567168ae33SJames Morse 
23577168ae33SJames Morse /*
23587168ae33SJames Morse  * We don't allow rdtgroup directories to be created anywhere
23597168ae33SJames Morse  * except the root directory. Thus when looking for the rdtgroup
23607168ae33SJames Morse  * structure for a kernfs node we are either looking at a directory,
23617168ae33SJames Morse  * in which case the rdtgroup structure is pointed at by the "priv"
23627168ae33SJames Morse  * field, otherwise we have a file, and need only look to the parent
23637168ae33SJames Morse  * to find the rdtgroup.
23647168ae33SJames Morse  */
kernfs_to_rdtgroup(struct kernfs_node * kn)23657168ae33SJames Morse static struct rdtgroup *kernfs_to_rdtgroup(struct kernfs_node *kn)
23667168ae33SJames Morse {
23677168ae33SJames Morse 	if (kernfs_type(kn) == KERNFS_DIR) {
23687168ae33SJames Morse 		/*
23697168ae33SJames Morse 		 * All the resource directories use "kn->priv"
23707168ae33SJames Morse 		 * to point to the "struct rdtgroup" for the
23717168ae33SJames Morse 		 * resource. "info" and its subdirectories don't
23727168ae33SJames Morse 		 * have rdtgroup structures, so return NULL here.
23737168ae33SJames Morse 		 */
23747168ae33SJames Morse 		if (kn == kn_info ||
23757168ae33SJames Morse 		    rcu_access_pointer(kn->__parent) == kn_info)
23767168ae33SJames Morse 			return NULL;
23777168ae33SJames Morse 		else
23787168ae33SJames Morse 			return kn->priv;
23797168ae33SJames Morse 	} else {
23807168ae33SJames Morse 		return rdt_kn_parent_priv(kn);
23817168ae33SJames Morse 	}
23827168ae33SJames Morse }
23837168ae33SJames Morse 
rdtgroup_kn_get(struct rdtgroup * rdtgrp,struct kernfs_node * kn)23847168ae33SJames Morse static void rdtgroup_kn_get(struct rdtgroup *rdtgrp, struct kernfs_node *kn)
23857168ae33SJames Morse {
23867168ae33SJames Morse 	atomic_inc(&rdtgrp->waitcount);
23877168ae33SJames Morse 	kernfs_break_active_protection(kn);
23887168ae33SJames Morse }
23897168ae33SJames Morse 
rdtgroup_kn_put(struct rdtgroup * rdtgrp,struct kernfs_node * kn)23907168ae33SJames Morse static void rdtgroup_kn_put(struct rdtgroup *rdtgrp, struct kernfs_node *kn)
23917168ae33SJames Morse {
23927168ae33SJames Morse 	if (atomic_dec_and_test(&rdtgrp->waitcount) &&
23937168ae33SJames Morse 	    (rdtgrp->flags & RDT_DELETED)) {
23947168ae33SJames Morse 		if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP ||
23957168ae33SJames Morse 		    rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED)
23967168ae33SJames Morse 			rdtgroup_pseudo_lock_remove(rdtgrp);
23977168ae33SJames Morse 		kernfs_unbreak_active_protection(kn);
23987168ae33SJames Morse 		rdtgroup_remove(rdtgrp);
23997168ae33SJames Morse 	} else {
24007168ae33SJames Morse 		kernfs_unbreak_active_protection(kn);
24017168ae33SJames Morse 	}
24027168ae33SJames Morse }
24037168ae33SJames Morse 
rdtgroup_kn_lock_live(struct kernfs_node * kn)24047168ae33SJames Morse struct rdtgroup *rdtgroup_kn_lock_live(struct kernfs_node *kn)
24057168ae33SJames Morse {
24067168ae33SJames Morse 	struct rdtgroup *rdtgrp = kernfs_to_rdtgroup(kn);
24077168ae33SJames Morse 
24087168ae33SJames Morse 	if (!rdtgrp)
24097168ae33SJames Morse 		return NULL;
24107168ae33SJames Morse 
24117168ae33SJames Morse 	rdtgroup_kn_get(rdtgrp, kn);
24127168ae33SJames Morse 
24137168ae33SJames Morse 	cpus_read_lock();
24147168ae33SJames Morse 	mutex_lock(&rdtgroup_mutex);
24157168ae33SJames Morse 
24167168ae33SJames Morse 	/* Was this group deleted while we waited? */
24177168ae33SJames Morse 	if (rdtgrp->flags & RDT_DELETED)
24187168ae33SJames Morse 		return NULL;
24197168ae33SJames Morse 
24207168ae33SJames Morse 	return rdtgrp;
24217168ae33SJames Morse }
24227168ae33SJames Morse 
rdtgroup_kn_unlock(struct kernfs_node * kn)24237168ae33SJames Morse void rdtgroup_kn_unlock(struct kernfs_node *kn)
24247168ae33SJames Morse {
24257168ae33SJames Morse 	struct rdtgroup *rdtgrp = kernfs_to_rdtgroup(kn);
24267168ae33SJames Morse 
24277168ae33SJames Morse 	if (!rdtgrp)
24287168ae33SJames Morse 		return;
24297168ae33SJames Morse 
24307168ae33SJames Morse 	mutex_unlock(&rdtgroup_mutex);
24317168ae33SJames Morse 	cpus_read_unlock();
24327168ae33SJames Morse 
24337168ae33SJames Morse 	rdtgroup_kn_put(rdtgrp, kn);
24347168ae33SJames Morse }
24357168ae33SJames Morse 
24367168ae33SJames Morse static int mkdir_mondata_all(struct kernfs_node *parent_kn,
24377168ae33SJames Morse 			     struct rdtgroup *prgrp,
24387168ae33SJames Morse 			     struct kernfs_node **mon_data_kn);
24397168ae33SJames Morse 
rdt_disable_ctx(void)24407168ae33SJames Morse static void rdt_disable_ctx(void)
24417168ae33SJames Morse {
24427168ae33SJames Morse 	resctrl_arch_set_cdp_enabled(RDT_RESOURCE_L3, false);
24437168ae33SJames Morse 	resctrl_arch_set_cdp_enabled(RDT_RESOURCE_L2, false);
24447168ae33SJames Morse 	set_mba_sc(false);
24457168ae33SJames Morse 
24467168ae33SJames Morse 	resctrl_debug = false;
24477168ae33SJames Morse }
24487168ae33SJames Morse 
rdt_enable_ctx(struct rdt_fs_context * ctx)24497168ae33SJames Morse static int rdt_enable_ctx(struct rdt_fs_context *ctx)
24507168ae33SJames Morse {
24517168ae33SJames Morse 	int ret = 0;
24527168ae33SJames Morse 
24537168ae33SJames Morse 	if (ctx->enable_cdpl2) {
24547168ae33SJames Morse 		ret = resctrl_arch_set_cdp_enabled(RDT_RESOURCE_L2, true);
24557168ae33SJames Morse 		if (ret)
24567168ae33SJames Morse 			goto out_done;
24577168ae33SJames Morse 	}
24587168ae33SJames Morse 
24597168ae33SJames Morse 	if (ctx->enable_cdpl3) {
24607168ae33SJames Morse 		ret = resctrl_arch_set_cdp_enabled(RDT_RESOURCE_L3, true);
24617168ae33SJames Morse 		if (ret)
24627168ae33SJames Morse 			goto out_cdpl2;
24637168ae33SJames Morse 	}
24647168ae33SJames Morse 
24657168ae33SJames Morse 	if (ctx->enable_mba_mbps) {
24667168ae33SJames Morse 		ret = set_mba_sc(true);
24677168ae33SJames Morse 		if (ret)
24687168ae33SJames Morse 			goto out_cdpl3;
24697168ae33SJames Morse 	}
24707168ae33SJames Morse 
24717168ae33SJames Morse 	if (ctx->enable_debug)
24727168ae33SJames Morse 		resctrl_debug = true;
24737168ae33SJames Morse 
24747168ae33SJames Morse 	return 0;
24757168ae33SJames Morse 
24767168ae33SJames Morse out_cdpl3:
24777168ae33SJames Morse 	resctrl_arch_set_cdp_enabled(RDT_RESOURCE_L3, false);
24787168ae33SJames Morse out_cdpl2:
24797168ae33SJames Morse 	resctrl_arch_set_cdp_enabled(RDT_RESOURCE_L2, false);
24807168ae33SJames Morse out_done:
24817168ae33SJames Morse 	return ret;
24827168ae33SJames Morse }
24837168ae33SJames Morse 
schemata_list_add(struct rdt_resource * r,enum resctrl_conf_type type)24847168ae33SJames Morse static int schemata_list_add(struct rdt_resource *r, enum resctrl_conf_type type)
24857168ae33SJames Morse {
24867168ae33SJames Morse 	struct resctrl_schema *s;
24877168ae33SJames Morse 	const char *suffix = "";
24887168ae33SJames Morse 	int ret, cl;
24897168ae33SJames Morse 
24907168ae33SJames Morse 	s = kzalloc(sizeof(*s), GFP_KERNEL);
24917168ae33SJames Morse 	if (!s)
24927168ae33SJames Morse 		return -ENOMEM;
24937168ae33SJames Morse 
24947168ae33SJames Morse 	s->res = r;
24957168ae33SJames Morse 	s->num_closid = resctrl_arch_get_num_closid(r);
24967168ae33SJames Morse 	if (resctrl_arch_get_cdp_enabled(r->rid))
24977168ae33SJames Morse 		s->num_closid /= 2;
24987168ae33SJames Morse 
24997168ae33SJames Morse 	s->conf_type = type;
25007168ae33SJames Morse 	switch (type) {
25017168ae33SJames Morse 	case CDP_CODE:
25027168ae33SJames Morse 		suffix = "CODE";
25037168ae33SJames Morse 		break;
25047168ae33SJames Morse 	case CDP_DATA:
25057168ae33SJames Morse 		suffix = "DATA";
25067168ae33SJames Morse 		break;
25077168ae33SJames Morse 	case CDP_NONE:
25087168ae33SJames Morse 		suffix = "";
25097168ae33SJames Morse 		break;
25107168ae33SJames Morse 	}
25117168ae33SJames Morse 
25127168ae33SJames Morse 	ret = snprintf(s->name, sizeof(s->name), "%s%s", r->name, suffix);
25137168ae33SJames Morse 	if (ret >= sizeof(s->name)) {
25147168ae33SJames Morse 		kfree(s);
25157168ae33SJames Morse 		return -EINVAL;
25167168ae33SJames Morse 	}
25177168ae33SJames Morse 
25187168ae33SJames Morse 	cl = strlen(s->name);
25197168ae33SJames Morse 
25207168ae33SJames Morse 	/*
25217168ae33SJames Morse 	 * If CDP is supported by this resource, but not enabled,
25227168ae33SJames Morse 	 * include the suffix. This ensures the tabular format of the
25237168ae33SJames Morse 	 * schemata file does not change between mounts of the filesystem.
25247168ae33SJames Morse 	 */
25257168ae33SJames Morse 	if (r->cdp_capable && !resctrl_arch_get_cdp_enabled(r->rid))
25267168ae33SJames Morse 		cl += 4;
25277168ae33SJames Morse 
25287168ae33SJames Morse 	if (cl > max_name_width)
25297168ae33SJames Morse 		max_name_width = cl;
25307168ae33SJames Morse 
25317168ae33SJames Morse 	switch (r->schema_fmt) {
25327168ae33SJames Morse 	case RESCTRL_SCHEMA_BITMAP:
25337168ae33SJames Morse 		s->fmt_str = "%d=%x";
25347168ae33SJames Morse 		break;
25357168ae33SJames Morse 	case RESCTRL_SCHEMA_RANGE:
25367168ae33SJames Morse 		s->fmt_str = "%d=%u";
25377168ae33SJames Morse 		break;
25387168ae33SJames Morse 	}
25397168ae33SJames Morse 
25407168ae33SJames Morse 	if (WARN_ON_ONCE(!s->fmt_str)) {
25417168ae33SJames Morse 		kfree(s);
25427168ae33SJames Morse 		return -EINVAL;
25437168ae33SJames Morse 	}
25447168ae33SJames Morse 
25457168ae33SJames Morse 	INIT_LIST_HEAD(&s->list);
25467168ae33SJames Morse 	list_add(&s->list, &resctrl_schema_all);
25477168ae33SJames Morse 
25487168ae33SJames Morse 	return 0;
25497168ae33SJames Morse }
25507168ae33SJames Morse 
schemata_list_create(void)25517168ae33SJames Morse static int schemata_list_create(void)
25527168ae33SJames Morse {
25537168ae33SJames Morse 	struct rdt_resource *r;
25547168ae33SJames Morse 	int ret = 0;
25557168ae33SJames Morse 
25567168ae33SJames Morse 	for_each_alloc_capable_rdt_resource(r) {
25577168ae33SJames Morse 		if (resctrl_arch_get_cdp_enabled(r->rid)) {
25587168ae33SJames Morse 			ret = schemata_list_add(r, CDP_CODE);
25597168ae33SJames Morse 			if (ret)
25607168ae33SJames Morse 				break;
25617168ae33SJames Morse 
25627168ae33SJames Morse 			ret = schemata_list_add(r, CDP_DATA);
25637168ae33SJames Morse 		} else {
25647168ae33SJames Morse 			ret = schemata_list_add(r, CDP_NONE);
25657168ae33SJames Morse 		}
25667168ae33SJames Morse 
25677168ae33SJames Morse 		if (ret)
25687168ae33SJames Morse 			break;
25697168ae33SJames Morse 	}
25707168ae33SJames Morse 
25717168ae33SJames Morse 	return ret;
25727168ae33SJames Morse }
25737168ae33SJames Morse 
schemata_list_destroy(void)25747168ae33SJames Morse static void schemata_list_destroy(void)
25757168ae33SJames Morse {
25767168ae33SJames Morse 	struct resctrl_schema *s, *tmp;
25777168ae33SJames Morse 
25787168ae33SJames Morse 	list_for_each_entry_safe(s, tmp, &resctrl_schema_all, list) {
25797168ae33SJames Morse 		list_del(&s->list);
25807168ae33SJames Morse 		kfree(s);
25817168ae33SJames Morse 	}
25827168ae33SJames Morse }
25837168ae33SJames Morse 
rdt_get_tree(struct fs_context * fc)25847168ae33SJames Morse static int rdt_get_tree(struct fs_context *fc)
25857168ae33SJames Morse {
25867168ae33SJames Morse 	struct rdt_fs_context *ctx = rdt_fc2context(fc);
25877168ae33SJames Morse 	unsigned long flags = RFTYPE_CTRL_BASE;
25887168ae33SJames Morse 	struct rdt_mon_domain *dom;
25897168ae33SJames Morse 	struct rdt_resource *r;
25907168ae33SJames Morse 	int ret;
25917168ae33SJames Morse 
25927168ae33SJames Morse 	cpus_read_lock();
25937168ae33SJames Morse 	mutex_lock(&rdtgroup_mutex);
25947168ae33SJames Morse 	/*
25957168ae33SJames Morse 	 * resctrl file system can only be mounted once.
25967168ae33SJames Morse 	 */
25977168ae33SJames Morse 	if (resctrl_mounted) {
25987168ae33SJames Morse 		ret = -EBUSY;
25997168ae33SJames Morse 		goto out;
26007168ae33SJames Morse 	}
26017168ae33SJames Morse 
26027168ae33SJames Morse 	ret = rdtgroup_setup_root(ctx);
26037168ae33SJames Morse 	if (ret)
26047168ae33SJames Morse 		goto out;
26057168ae33SJames Morse 
26067168ae33SJames Morse 	ret = rdt_enable_ctx(ctx);
26077168ae33SJames Morse 	if (ret)
26087168ae33SJames Morse 		goto out_root;
26097168ae33SJames Morse 
26107168ae33SJames Morse 	ret = schemata_list_create();
26117168ae33SJames Morse 	if (ret) {
26127168ae33SJames Morse 		schemata_list_destroy();
26137168ae33SJames Morse 		goto out_ctx;
26147168ae33SJames Morse 	}
26157168ae33SJames Morse 
26167168ae33SJames Morse 	ret = closid_init();
26177168ae33SJames Morse 	if (ret)
26187168ae33SJames Morse 		goto out_schemata_free;
26197168ae33SJames Morse 
26207168ae33SJames Morse 	if (resctrl_arch_mon_capable())
26217168ae33SJames Morse 		flags |= RFTYPE_MON;
26227168ae33SJames Morse 
26237168ae33SJames Morse 	ret = rdtgroup_add_files(rdtgroup_default.kn, flags);
26247168ae33SJames Morse 	if (ret)
26257168ae33SJames Morse 		goto out_closid_exit;
26267168ae33SJames Morse 
26277168ae33SJames Morse 	kernfs_activate(rdtgroup_default.kn);
26287168ae33SJames Morse 
26297168ae33SJames Morse 	ret = rdtgroup_create_info_dir(rdtgroup_default.kn);
26307168ae33SJames Morse 	if (ret < 0)
26317168ae33SJames Morse 		goto out_closid_exit;
26327168ae33SJames Morse 
26337168ae33SJames Morse 	if (resctrl_arch_mon_capable()) {
26347168ae33SJames Morse 		ret = mongroup_create_dir(rdtgroup_default.kn,
26357168ae33SJames Morse 					  &rdtgroup_default, "mon_groups",
26367168ae33SJames Morse 					  &kn_mongrp);
26377168ae33SJames Morse 		if (ret < 0)
26387168ae33SJames Morse 			goto out_info;
26397168ae33SJames Morse 
26407168ae33SJames Morse 		ret = mkdir_mondata_all(rdtgroup_default.kn,
26417168ae33SJames Morse 					&rdtgroup_default, &kn_mondata);
26427168ae33SJames Morse 		if (ret < 0)
26437168ae33SJames Morse 			goto out_mongrp;
26447168ae33SJames Morse 		rdtgroup_default.mon.mon_data_kn = kn_mondata;
26457168ae33SJames Morse 	}
26467168ae33SJames Morse 
26477168ae33SJames Morse 	ret = rdt_pseudo_lock_init();
26487168ae33SJames Morse 	if (ret)
26497168ae33SJames Morse 		goto out_mondata;
26507168ae33SJames Morse 
26517168ae33SJames Morse 	ret = kernfs_get_tree(fc);
26527168ae33SJames Morse 	if (ret < 0)
26537168ae33SJames Morse 		goto out_psl;
26547168ae33SJames Morse 
26557168ae33SJames Morse 	if (resctrl_arch_alloc_capable())
26567168ae33SJames Morse 		resctrl_arch_enable_alloc();
26577168ae33SJames Morse 	if (resctrl_arch_mon_capable())
26587168ae33SJames Morse 		resctrl_arch_enable_mon();
26597168ae33SJames Morse 
26607168ae33SJames Morse 	if (resctrl_arch_alloc_capable() || resctrl_arch_mon_capable())
26617168ae33SJames Morse 		resctrl_mounted = true;
26627168ae33SJames Morse 
26637168ae33SJames Morse 	if (resctrl_is_mbm_enabled()) {
26647168ae33SJames Morse 		r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
26657168ae33SJames Morse 		list_for_each_entry(dom, &r->mon_domains, hdr.list)
26667168ae33SJames Morse 			mbm_setup_overflow_handler(dom, MBM_OVERFLOW_INTERVAL,
26677168ae33SJames Morse 						   RESCTRL_PICK_ANY_CPU);
26687168ae33SJames Morse 	}
26697168ae33SJames Morse 
26707168ae33SJames Morse 	goto out;
26717168ae33SJames Morse 
26727168ae33SJames Morse out_psl:
26737168ae33SJames Morse 	rdt_pseudo_lock_release();
26747168ae33SJames Morse out_mondata:
26757168ae33SJames Morse 	if (resctrl_arch_mon_capable())
26767168ae33SJames Morse 		kernfs_remove(kn_mondata);
26777168ae33SJames Morse out_mongrp:
26787168ae33SJames Morse 	if (resctrl_arch_mon_capable())
26797168ae33SJames Morse 		kernfs_remove(kn_mongrp);
26807168ae33SJames Morse out_info:
26817168ae33SJames Morse 	kernfs_remove(kn_info);
26827168ae33SJames Morse out_closid_exit:
26837168ae33SJames Morse 	closid_exit();
26847168ae33SJames Morse out_schemata_free:
26857168ae33SJames Morse 	schemata_list_destroy();
26867168ae33SJames Morse out_ctx:
26877168ae33SJames Morse 	rdt_disable_ctx();
26887168ae33SJames Morse out_root:
26897168ae33SJames Morse 	rdtgroup_destroy_root();
26907168ae33SJames Morse out:
26917168ae33SJames Morse 	rdt_last_cmd_clear();
26927168ae33SJames Morse 	mutex_unlock(&rdtgroup_mutex);
26937168ae33SJames Morse 	cpus_read_unlock();
26947168ae33SJames Morse 	return ret;
26957168ae33SJames Morse }
26967168ae33SJames Morse 
26977168ae33SJames Morse enum rdt_param {
26987168ae33SJames Morse 	Opt_cdp,
26997168ae33SJames Morse 	Opt_cdpl2,
27007168ae33SJames Morse 	Opt_mba_mbps,
27017168ae33SJames Morse 	Opt_debug,
27027168ae33SJames Morse 	nr__rdt_params
27037168ae33SJames Morse };
27047168ae33SJames Morse 
27057168ae33SJames Morse static const struct fs_parameter_spec rdt_fs_parameters[] = {
27067168ae33SJames Morse 	fsparam_flag("cdp",		Opt_cdp),
27077168ae33SJames Morse 	fsparam_flag("cdpl2",		Opt_cdpl2),
27087168ae33SJames Morse 	fsparam_flag("mba_MBps",	Opt_mba_mbps),
27097168ae33SJames Morse 	fsparam_flag("debug",		Opt_debug),
27107168ae33SJames Morse 	{}
27117168ae33SJames Morse };
27127168ae33SJames Morse 
rdt_parse_param(struct fs_context * fc,struct fs_parameter * param)27137168ae33SJames Morse static int rdt_parse_param(struct fs_context *fc, struct fs_parameter *param)
27147168ae33SJames Morse {
27157168ae33SJames Morse 	struct rdt_fs_context *ctx = rdt_fc2context(fc);
27167168ae33SJames Morse 	struct fs_parse_result result;
27177168ae33SJames Morse 	const char *msg;
27187168ae33SJames Morse 	int opt;
27197168ae33SJames Morse 
27207168ae33SJames Morse 	opt = fs_parse(fc, rdt_fs_parameters, param, &result);
27217168ae33SJames Morse 	if (opt < 0)
27227168ae33SJames Morse 		return opt;
27237168ae33SJames Morse 
27247168ae33SJames Morse 	switch (opt) {
27257168ae33SJames Morse 	case Opt_cdp:
27267168ae33SJames Morse 		ctx->enable_cdpl3 = true;
27277168ae33SJames Morse 		return 0;
27287168ae33SJames Morse 	case Opt_cdpl2:
27297168ae33SJames Morse 		ctx->enable_cdpl2 = true;
27307168ae33SJames Morse 		return 0;
27317168ae33SJames Morse 	case Opt_mba_mbps:
27327168ae33SJames Morse 		msg = "mba_MBps requires MBM and linear scale MBA at L3 scope";
27337168ae33SJames Morse 		if (!supports_mba_mbps())
27347168ae33SJames Morse 			return invalfc(fc, msg);
27357168ae33SJames Morse 		ctx->enable_mba_mbps = true;
27367168ae33SJames Morse 		return 0;
27377168ae33SJames Morse 	case Opt_debug:
27387168ae33SJames Morse 		ctx->enable_debug = true;
27397168ae33SJames Morse 		return 0;
27407168ae33SJames Morse 	}
27417168ae33SJames Morse 
27427168ae33SJames Morse 	return -EINVAL;
27437168ae33SJames Morse }
27447168ae33SJames Morse 
rdt_fs_context_free(struct fs_context * fc)27457168ae33SJames Morse static void rdt_fs_context_free(struct fs_context *fc)
27467168ae33SJames Morse {
27477168ae33SJames Morse 	struct rdt_fs_context *ctx = rdt_fc2context(fc);
27487168ae33SJames Morse 
27497168ae33SJames Morse 	kernfs_free_fs_context(fc);
27507168ae33SJames Morse 	kfree(ctx);
27517168ae33SJames Morse }
27527168ae33SJames Morse 
27537168ae33SJames Morse static const struct fs_context_operations rdt_fs_context_ops = {
27547168ae33SJames Morse 	.free		= rdt_fs_context_free,
27557168ae33SJames Morse 	.parse_param	= rdt_parse_param,
27567168ae33SJames Morse 	.get_tree	= rdt_get_tree,
27577168ae33SJames Morse };
27587168ae33SJames Morse 
rdt_init_fs_context(struct fs_context * fc)27597168ae33SJames Morse static int rdt_init_fs_context(struct fs_context *fc)
27607168ae33SJames Morse {
27617168ae33SJames Morse 	struct rdt_fs_context *ctx;
27627168ae33SJames Morse 
27637168ae33SJames Morse 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
27647168ae33SJames Morse 	if (!ctx)
27657168ae33SJames Morse 		return -ENOMEM;
27667168ae33SJames Morse 
27677168ae33SJames Morse 	ctx->kfc.magic = RDTGROUP_SUPER_MAGIC;
27687168ae33SJames Morse 	fc->fs_private = &ctx->kfc;
27697168ae33SJames Morse 	fc->ops = &rdt_fs_context_ops;
27707168ae33SJames Morse 	put_user_ns(fc->user_ns);
27717168ae33SJames Morse 	fc->user_ns = get_user_ns(&init_user_ns);
27727168ae33SJames Morse 	fc->global = true;
27737168ae33SJames Morse 	return 0;
27747168ae33SJames Morse }
27757168ae33SJames Morse 
27767168ae33SJames Morse /*
27777168ae33SJames Morse  * Move tasks from one to the other group. If @from is NULL, then all tasks
27787168ae33SJames Morse  * in the systems are moved unconditionally (used for teardown).
27797168ae33SJames Morse  *
27807168ae33SJames Morse  * If @mask is not NULL the cpus on which moved tasks are running are set
27817168ae33SJames Morse  * in that mask so the update smp function call is restricted to affected
27827168ae33SJames Morse  * cpus.
27837168ae33SJames Morse  */
rdt_move_group_tasks(struct rdtgroup * from,struct rdtgroup * to,struct cpumask * mask)27847168ae33SJames Morse static void rdt_move_group_tasks(struct rdtgroup *from, struct rdtgroup *to,
27857168ae33SJames Morse 				 struct cpumask *mask)
27867168ae33SJames Morse {
27877168ae33SJames Morse 	struct task_struct *p, *t;
27887168ae33SJames Morse 
27897168ae33SJames Morse 	read_lock(&tasklist_lock);
27907168ae33SJames Morse 	for_each_process_thread(p, t) {
27917168ae33SJames Morse 		if (!from || is_closid_match(t, from) ||
27927168ae33SJames Morse 		    is_rmid_match(t, from)) {
27937168ae33SJames Morse 			resctrl_arch_set_closid_rmid(t, to->closid,
27947168ae33SJames Morse 						     to->mon.rmid);
27957168ae33SJames Morse 
27967168ae33SJames Morse 			/*
27977168ae33SJames Morse 			 * Order the closid/rmid stores above before the loads
27987168ae33SJames Morse 			 * in task_curr(). This pairs with the full barrier
27997168ae33SJames Morse 			 * between the rq->curr update and
28007168ae33SJames Morse 			 * resctrl_arch_sched_in() during context switch.
28017168ae33SJames Morse 			 */
28027168ae33SJames Morse 			smp_mb();
28037168ae33SJames Morse 
28047168ae33SJames Morse 			/*
28057168ae33SJames Morse 			 * If the task is on a CPU, set the CPU in the mask.
28067168ae33SJames Morse 			 * The detection is inaccurate as tasks might move or
28077168ae33SJames Morse 			 * schedule before the smp function call takes place.
28087168ae33SJames Morse 			 * In such a case the function call is pointless, but
28097168ae33SJames Morse 			 * there is no other side effect.
28107168ae33SJames Morse 			 */
28117168ae33SJames Morse 			if (IS_ENABLED(CONFIG_SMP) && mask && task_curr(t))
28127168ae33SJames Morse 				cpumask_set_cpu(task_cpu(t), mask);
28137168ae33SJames Morse 		}
28147168ae33SJames Morse 	}
28157168ae33SJames Morse 	read_unlock(&tasklist_lock);
28167168ae33SJames Morse }
28177168ae33SJames Morse 
free_all_child_rdtgrp(struct rdtgroup * rdtgrp)28187168ae33SJames Morse static void free_all_child_rdtgrp(struct rdtgroup *rdtgrp)
28197168ae33SJames Morse {
28207168ae33SJames Morse 	struct rdtgroup *sentry, *stmp;
28217168ae33SJames Morse 	struct list_head *head;
28227168ae33SJames Morse 
28237168ae33SJames Morse 	head = &rdtgrp->mon.crdtgrp_list;
28247168ae33SJames Morse 	list_for_each_entry_safe(sentry, stmp, head, mon.crdtgrp_list) {
28257168ae33SJames Morse 		free_rmid(sentry->closid, sentry->mon.rmid);
28267168ae33SJames Morse 		list_del(&sentry->mon.crdtgrp_list);
28277168ae33SJames Morse 
28287168ae33SJames Morse 		if (atomic_read(&sentry->waitcount) != 0)
28297168ae33SJames Morse 			sentry->flags = RDT_DELETED;
28307168ae33SJames Morse 		else
28317168ae33SJames Morse 			rdtgroup_remove(sentry);
28327168ae33SJames Morse 	}
28337168ae33SJames Morse }
28347168ae33SJames Morse 
28357168ae33SJames Morse /*
28367168ae33SJames Morse  * Forcibly remove all of subdirectories under root.
28377168ae33SJames Morse  */
rmdir_all_sub(void)28387168ae33SJames Morse static void rmdir_all_sub(void)
28397168ae33SJames Morse {
28407168ae33SJames Morse 	struct rdtgroup *rdtgrp, *tmp;
28417168ae33SJames Morse 
28427168ae33SJames Morse 	/* Move all tasks to the default resource group */
28437168ae33SJames Morse 	rdt_move_group_tasks(NULL, &rdtgroup_default, NULL);
28447168ae33SJames Morse 
28457168ae33SJames Morse 	list_for_each_entry_safe(rdtgrp, tmp, &rdt_all_groups, rdtgroup_list) {
28467168ae33SJames Morse 		/* Free any child rmids */
28477168ae33SJames Morse 		free_all_child_rdtgrp(rdtgrp);
28487168ae33SJames Morse 
28497168ae33SJames Morse 		/* Remove each rdtgroup other than root */
28507168ae33SJames Morse 		if (rdtgrp == &rdtgroup_default)
28517168ae33SJames Morse 			continue;
28527168ae33SJames Morse 
28537168ae33SJames Morse 		if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP ||
28547168ae33SJames Morse 		    rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED)
28557168ae33SJames Morse 			rdtgroup_pseudo_lock_remove(rdtgrp);
28567168ae33SJames Morse 
28577168ae33SJames Morse 		/*
28587168ae33SJames Morse 		 * Give any CPUs back to the default group. We cannot copy
28597168ae33SJames Morse 		 * cpu_online_mask because a CPU might have executed the
28607168ae33SJames Morse 		 * offline callback already, but is still marked online.
28617168ae33SJames Morse 		 */
28627168ae33SJames Morse 		cpumask_or(&rdtgroup_default.cpu_mask,
28637168ae33SJames Morse 			   &rdtgroup_default.cpu_mask, &rdtgrp->cpu_mask);
28647168ae33SJames Morse 
28657168ae33SJames Morse 		free_rmid(rdtgrp->closid, rdtgrp->mon.rmid);
28667168ae33SJames Morse 
28677168ae33SJames Morse 		kernfs_remove(rdtgrp->kn);
28687168ae33SJames Morse 		list_del(&rdtgrp->rdtgroup_list);
28697168ae33SJames Morse 
28707168ae33SJames Morse 		if (atomic_read(&rdtgrp->waitcount) != 0)
28717168ae33SJames Morse 			rdtgrp->flags = RDT_DELETED;
28727168ae33SJames Morse 		else
28737168ae33SJames Morse 			rdtgroup_remove(rdtgrp);
28747168ae33SJames Morse 	}
28757168ae33SJames Morse 	/* Notify online CPUs to update per cpu storage and PQR_ASSOC MSR */
28767168ae33SJames Morse 	update_closid_rmid(cpu_online_mask, &rdtgroup_default);
28777168ae33SJames Morse 
28787168ae33SJames Morse 	kernfs_remove(kn_info);
28797168ae33SJames Morse 	kernfs_remove(kn_mongrp);
28807168ae33SJames Morse 	kernfs_remove(kn_mondata);
28817168ae33SJames Morse }
28827168ae33SJames Morse 
28837168ae33SJames Morse /**
28847168ae33SJames Morse  * mon_get_kn_priv() - Get the mon_data priv data for this event.
28857168ae33SJames Morse  *
28867168ae33SJames Morse  * The same values are used across the mon_data directories of all control and
28877168ae33SJames Morse  * monitor groups for the same event in the same domain. Keep a list of
28887168ae33SJames Morse  * allocated structures and re-use an existing one with the same values for
28897168ae33SJames Morse  * @rid, @domid, etc.
28907168ae33SJames Morse  *
28917168ae33SJames Morse  * @rid:    The resource id for the event file being created.
28927168ae33SJames Morse  * @domid:  The domain id for the event file being created.
28937168ae33SJames Morse  * @mevt:   The type of event file being created.
28947168ae33SJames Morse  * @do_sum: Whether SNC summing monitors are being created.
28957168ae33SJames Morse  */
mon_get_kn_priv(enum resctrl_res_level rid,int domid,struct mon_evt * mevt,bool do_sum)28967168ae33SJames Morse static struct mon_data *mon_get_kn_priv(enum resctrl_res_level rid, int domid,
28977168ae33SJames Morse 					struct mon_evt *mevt,
28987168ae33SJames Morse 					bool do_sum)
28997168ae33SJames Morse {
29007168ae33SJames Morse 	struct mon_data *priv;
29017168ae33SJames Morse 
29027168ae33SJames Morse 	lockdep_assert_held(&rdtgroup_mutex);
29037168ae33SJames Morse 
29047168ae33SJames Morse 	list_for_each_entry(priv, &mon_data_kn_priv_list, list) {
29057168ae33SJames Morse 		if (priv->rid == rid && priv->domid == domid &&
29067168ae33SJames Morse 		    priv->sum == do_sum && priv->evtid == mevt->evtid)
29077168ae33SJames Morse 			return priv;
29087168ae33SJames Morse 	}
29097168ae33SJames Morse 
29107168ae33SJames Morse 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
29117168ae33SJames Morse 	if (!priv)
29127168ae33SJames Morse 		return NULL;
29137168ae33SJames Morse 
29147168ae33SJames Morse 	priv->rid = rid;
29157168ae33SJames Morse 	priv->domid = domid;
29167168ae33SJames Morse 	priv->sum = do_sum;
29177168ae33SJames Morse 	priv->evtid = mevt->evtid;
29187168ae33SJames Morse 	list_add_tail(&priv->list, &mon_data_kn_priv_list);
29197168ae33SJames Morse 
29207168ae33SJames Morse 	return priv;
29217168ae33SJames Morse }
29227168ae33SJames Morse 
29237168ae33SJames Morse /**
29247168ae33SJames Morse  * mon_put_kn_priv() - Free all allocated mon_data structures.
29257168ae33SJames Morse  *
29267168ae33SJames Morse  * Called when resctrl file system is unmounted.
29277168ae33SJames Morse  */
mon_put_kn_priv(void)29287168ae33SJames Morse static void mon_put_kn_priv(void)
29297168ae33SJames Morse {
29307168ae33SJames Morse 	struct mon_data *priv, *tmp;
29317168ae33SJames Morse 
29327168ae33SJames Morse 	lockdep_assert_held(&rdtgroup_mutex);
29337168ae33SJames Morse 
29347168ae33SJames Morse 	list_for_each_entry_safe(priv, tmp, &mon_data_kn_priv_list, list) {
29357168ae33SJames Morse 		list_del(&priv->list);
29367168ae33SJames Morse 		kfree(priv);
29377168ae33SJames Morse 	}
29387168ae33SJames Morse }
29397168ae33SJames Morse 
resctrl_fs_teardown(void)29407168ae33SJames Morse static void resctrl_fs_teardown(void)
29417168ae33SJames Morse {
29427168ae33SJames Morse 	lockdep_assert_held(&rdtgroup_mutex);
29437168ae33SJames Morse 
29447168ae33SJames Morse 	/* Cleared by rdtgroup_destroy_root() */
29457168ae33SJames Morse 	if (!rdtgroup_default.kn)
29467168ae33SJames Morse 		return;
29477168ae33SJames Morse 
29487168ae33SJames Morse 	rmdir_all_sub();
29497168ae33SJames Morse 	mon_put_kn_priv();
29507168ae33SJames Morse 	rdt_pseudo_lock_release();
29517168ae33SJames Morse 	rdtgroup_default.mode = RDT_MODE_SHAREABLE;
29527168ae33SJames Morse 	closid_exit();
29537168ae33SJames Morse 	schemata_list_destroy();
29547168ae33SJames Morse 	rdtgroup_destroy_root();
29557168ae33SJames Morse }
29567168ae33SJames Morse 
rdt_kill_sb(struct super_block * sb)29577168ae33SJames Morse static void rdt_kill_sb(struct super_block *sb)
29587168ae33SJames Morse {
29597168ae33SJames Morse 	struct rdt_resource *r;
29607168ae33SJames Morse 
29617168ae33SJames Morse 	cpus_read_lock();
29627168ae33SJames Morse 	mutex_lock(&rdtgroup_mutex);
29637168ae33SJames Morse 
29647168ae33SJames Morse 	rdt_disable_ctx();
29657168ae33SJames Morse 
29667168ae33SJames Morse 	/* Put everything back to default values. */
29677168ae33SJames Morse 	for_each_alloc_capable_rdt_resource(r)
29687168ae33SJames Morse 		resctrl_arch_reset_all_ctrls(r);
29697168ae33SJames Morse 
29707168ae33SJames Morse 	resctrl_fs_teardown();
29717168ae33SJames Morse 	if (resctrl_arch_alloc_capable())
29727168ae33SJames Morse 		resctrl_arch_disable_alloc();
29737168ae33SJames Morse 	if (resctrl_arch_mon_capable())
29747168ae33SJames Morse 		resctrl_arch_disable_mon();
29757168ae33SJames Morse 	resctrl_mounted = false;
29767168ae33SJames Morse 	kernfs_kill_sb(sb);
29777168ae33SJames Morse 	mutex_unlock(&rdtgroup_mutex);
29787168ae33SJames Morse 	cpus_read_unlock();
29797168ae33SJames Morse }
29807168ae33SJames Morse 
29817168ae33SJames Morse static struct file_system_type rdt_fs_type = {
29827168ae33SJames Morse 	.name			= "resctrl",
29837168ae33SJames Morse 	.init_fs_context	= rdt_init_fs_context,
29847168ae33SJames Morse 	.parameters		= rdt_fs_parameters,
29857168ae33SJames Morse 	.kill_sb		= rdt_kill_sb,
29867168ae33SJames Morse };
29877168ae33SJames Morse 
mon_addfile(struct kernfs_node * parent_kn,const char * name,void * priv)29887168ae33SJames Morse static int mon_addfile(struct kernfs_node *parent_kn, const char *name,
29897168ae33SJames Morse 		       void *priv)
29907168ae33SJames Morse {
29917168ae33SJames Morse 	struct kernfs_node *kn;
29927168ae33SJames Morse 	int ret = 0;
29937168ae33SJames Morse 
29947168ae33SJames Morse 	kn = __kernfs_create_file(parent_kn, name, 0444,
29957168ae33SJames Morse 				  GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, 0,
29967168ae33SJames Morse 				  &kf_mondata_ops, priv, NULL, NULL);
29977168ae33SJames Morse 	if (IS_ERR(kn))
29987168ae33SJames Morse 		return PTR_ERR(kn);
29997168ae33SJames Morse 
30007168ae33SJames Morse 	ret = rdtgroup_kn_set_ugid(kn);
30017168ae33SJames Morse 	if (ret) {
30027168ae33SJames Morse 		kernfs_remove(kn);
30037168ae33SJames Morse 		return ret;
30047168ae33SJames Morse 	}
30057168ae33SJames Morse 
30067168ae33SJames Morse 	return ret;
30077168ae33SJames Morse }
30087168ae33SJames Morse 
mon_rmdir_one_subdir(struct kernfs_node * pkn,char * name,char * subname)30097168ae33SJames Morse static void mon_rmdir_one_subdir(struct kernfs_node *pkn, char *name, char *subname)
30107168ae33SJames Morse {
30117168ae33SJames Morse 	struct kernfs_node *kn;
30127168ae33SJames Morse 
30137168ae33SJames Morse 	kn = kernfs_find_and_get(pkn, name);
30147168ae33SJames Morse 	if (!kn)
30157168ae33SJames Morse 		return;
30167168ae33SJames Morse 	kernfs_put(kn);
30177168ae33SJames Morse 
30187168ae33SJames Morse 	if (kn->dir.subdirs <= 1)
30197168ae33SJames Morse 		kernfs_remove(kn);
30207168ae33SJames Morse 	else
30217168ae33SJames Morse 		kernfs_remove_by_name(kn, subname);
30227168ae33SJames Morse }
30237168ae33SJames Morse 
30247168ae33SJames Morse /*
30257168ae33SJames Morse  * Remove all subdirectories of mon_data of ctrl_mon groups
30267168ae33SJames Morse  * and monitor groups for the given domain.
30277168ae33SJames Morse  * Remove files and directories containing "sum" of domain data
30287168ae33SJames Morse  * when last domain being summed is removed.
30297168ae33SJames Morse  */
rmdir_mondata_subdir_allrdtgrp(struct rdt_resource * r,struct rdt_mon_domain * d)30307168ae33SJames Morse static void rmdir_mondata_subdir_allrdtgrp(struct rdt_resource *r,
30317168ae33SJames Morse 					   struct rdt_mon_domain *d)
30327168ae33SJames Morse {
30337168ae33SJames Morse 	struct rdtgroup *prgrp, *crgrp;
30347168ae33SJames Morse 	char subname[32];
30357168ae33SJames Morse 	bool snc_mode;
30367168ae33SJames Morse 	char name[32];
30377168ae33SJames Morse 
30387168ae33SJames Morse 	snc_mode = r->mon_scope == RESCTRL_L3_NODE;
3039*594902c9SQinyun Tan 	sprintf(name, "mon_%s_%02d", r->name, snc_mode ? d->ci_id : d->hdr.id);
30407168ae33SJames Morse 	if (snc_mode)
30417168ae33SJames Morse 		sprintf(subname, "mon_sub_%s_%02d", r->name, d->hdr.id);
30427168ae33SJames Morse 
30437168ae33SJames Morse 	list_for_each_entry(prgrp, &rdt_all_groups, rdtgroup_list) {
30447168ae33SJames Morse 		mon_rmdir_one_subdir(prgrp->mon.mon_data_kn, name, subname);
30457168ae33SJames Morse 
30467168ae33SJames Morse 		list_for_each_entry(crgrp, &prgrp->mon.crdtgrp_list, mon.crdtgrp_list)
30477168ae33SJames Morse 			mon_rmdir_one_subdir(crgrp->mon.mon_data_kn, name, subname);
30487168ae33SJames Morse 	}
30497168ae33SJames Morse }
30507168ae33SJames Morse 
mon_add_all_files(struct kernfs_node * kn,struct rdt_mon_domain * d,struct rdt_resource * r,struct rdtgroup * prgrp,bool do_sum)30517168ae33SJames Morse static int mon_add_all_files(struct kernfs_node *kn, struct rdt_mon_domain *d,
30527168ae33SJames Morse 			     struct rdt_resource *r, struct rdtgroup *prgrp,
30537168ae33SJames Morse 			     bool do_sum)
30547168ae33SJames Morse {
30557168ae33SJames Morse 	struct rmid_read rr = {0};
30567168ae33SJames Morse 	struct mon_data *priv;
30577168ae33SJames Morse 	struct mon_evt *mevt;
30587168ae33SJames Morse 	int ret, domid;
30597168ae33SJames Morse 
30607168ae33SJames Morse 	if (WARN_ON(list_empty(&r->evt_list)))
30617168ae33SJames Morse 		return -EPERM;
30627168ae33SJames Morse 
30637168ae33SJames Morse 	list_for_each_entry(mevt, &r->evt_list, list) {
3064*594902c9SQinyun Tan 		domid = do_sum ? d->ci_id : d->hdr.id;
30657168ae33SJames Morse 		priv = mon_get_kn_priv(r->rid, domid, mevt, do_sum);
30667168ae33SJames Morse 		if (WARN_ON_ONCE(!priv))
30677168ae33SJames Morse 			return -EINVAL;
30687168ae33SJames Morse 
30697168ae33SJames Morse 		ret = mon_addfile(kn, mevt->name, priv);
30707168ae33SJames Morse 		if (ret)
30717168ae33SJames Morse 			return ret;
30727168ae33SJames Morse 
30737168ae33SJames Morse 		if (!do_sum && resctrl_is_mbm_event(mevt->evtid))
30747168ae33SJames Morse 			mon_event_read(&rr, r, d, prgrp, &d->hdr.cpu_mask, mevt->evtid, true);
30757168ae33SJames Morse 	}
30767168ae33SJames Morse 
30777168ae33SJames Morse 	return 0;
30787168ae33SJames Morse }
30797168ae33SJames Morse 
mkdir_mondata_subdir(struct kernfs_node * parent_kn,struct rdt_mon_domain * d,struct rdt_resource * r,struct rdtgroup * prgrp)30807168ae33SJames Morse static int mkdir_mondata_subdir(struct kernfs_node *parent_kn,
30817168ae33SJames Morse 				struct rdt_mon_domain *d,
30827168ae33SJames Morse 				struct rdt_resource *r, struct rdtgroup *prgrp)
30837168ae33SJames Morse {
30847168ae33SJames Morse 	struct kernfs_node *kn, *ckn;
30857168ae33SJames Morse 	char name[32];
30867168ae33SJames Morse 	bool snc_mode;
30877168ae33SJames Morse 	int ret = 0;
30887168ae33SJames Morse 
30897168ae33SJames Morse 	lockdep_assert_held(&rdtgroup_mutex);
30907168ae33SJames Morse 
30917168ae33SJames Morse 	snc_mode = r->mon_scope == RESCTRL_L3_NODE;
3092*594902c9SQinyun Tan 	sprintf(name, "mon_%s_%02d", r->name, snc_mode ? d->ci_id : d->hdr.id);
30937168ae33SJames Morse 	kn = kernfs_find_and_get(parent_kn, name);
30947168ae33SJames Morse 	if (kn) {
30957168ae33SJames Morse 		/*
30967168ae33SJames Morse 		 * rdtgroup_mutex will prevent this directory from being
30977168ae33SJames Morse 		 * removed. No need to keep this hold.
30987168ae33SJames Morse 		 */
30997168ae33SJames Morse 		kernfs_put(kn);
31007168ae33SJames Morse 	} else {
31017168ae33SJames Morse 		kn = kernfs_create_dir(parent_kn, name, parent_kn->mode, prgrp);
31027168ae33SJames Morse 		if (IS_ERR(kn))
31037168ae33SJames Morse 			return PTR_ERR(kn);
31047168ae33SJames Morse 
31057168ae33SJames Morse 		ret = rdtgroup_kn_set_ugid(kn);
31067168ae33SJames Morse 		if (ret)
31077168ae33SJames Morse 			goto out_destroy;
31087168ae33SJames Morse 		ret = mon_add_all_files(kn, d, r, prgrp, snc_mode);
31097168ae33SJames Morse 		if (ret)
31107168ae33SJames Morse 			goto out_destroy;
31117168ae33SJames Morse 	}
31127168ae33SJames Morse 
31137168ae33SJames Morse 	if (snc_mode) {
31147168ae33SJames Morse 		sprintf(name, "mon_sub_%s_%02d", r->name, d->hdr.id);
31157168ae33SJames Morse 		ckn = kernfs_create_dir(kn, name, parent_kn->mode, prgrp);
31167168ae33SJames Morse 		if (IS_ERR(ckn)) {
31177168ae33SJames Morse 			ret = -EINVAL;
31187168ae33SJames Morse 			goto out_destroy;
31197168ae33SJames Morse 		}
31207168ae33SJames Morse 
31217168ae33SJames Morse 		ret = rdtgroup_kn_set_ugid(ckn);
31227168ae33SJames Morse 		if (ret)
31237168ae33SJames Morse 			goto out_destroy;
31247168ae33SJames Morse 
31257168ae33SJames Morse 		ret = mon_add_all_files(ckn, d, r, prgrp, false);
31267168ae33SJames Morse 		if (ret)
31277168ae33SJames Morse 			goto out_destroy;
31287168ae33SJames Morse 	}
31297168ae33SJames Morse 
31307168ae33SJames Morse 	kernfs_activate(kn);
31317168ae33SJames Morse 	return 0;
31327168ae33SJames Morse 
31337168ae33SJames Morse out_destroy:
31347168ae33SJames Morse 	kernfs_remove(kn);
31357168ae33SJames Morse 	return ret;
31367168ae33SJames Morse }
31377168ae33SJames Morse 
31387168ae33SJames Morse /*
31397168ae33SJames Morse  * Add all subdirectories of mon_data for "ctrl_mon" groups
31407168ae33SJames Morse  * and "monitor" groups with given domain id.
31417168ae33SJames Morse  */
mkdir_mondata_subdir_allrdtgrp(struct rdt_resource * r,struct rdt_mon_domain * d)31427168ae33SJames Morse static void mkdir_mondata_subdir_allrdtgrp(struct rdt_resource *r,
31437168ae33SJames Morse 					   struct rdt_mon_domain *d)
31447168ae33SJames Morse {
31457168ae33SJames Morse 	struct kernfs_node *parent_kn;
31467168ae33SJames Morse 	struct rdtgroup *prgrp, *crgrp;
31477168ae33SJames Morse 	struct list_head *head;
31487168ae33SJames Morse 
31497168ae33SJames Morse 	list_for_each_entry(prgrp, &rdt_all_groups, rdtgroup_list) {
31507168ae33SJames Morse 		parent_kn = prgrp->mon.mon_data_kn;
31517168ae33SJames Morse 		mkdir_mondata_subdir(parent_kn, d, r, prgrp);
31527168ae33SJames Morse 
31537168ae33SJames Morse 		head = &prgrp->mon.crdtgrp_list;
31547168ae33SJames Morse 		list_for_each_entry(crgrp, head, mon.crdtgrp_list) {
31557168ae33SJames Morse 			parent_kn = crgrp->mon.mon_data_kn;
31567168ae33SJames Morse 			mkdir_mondata_subdir(parent_kn, d, r, crgrp);
31577168ae33SJames Morse 		}
31587168ae33SJames Morse 	}
31597168ae33SJames Morse }
31607168ae33SJames Morse 
mkdir_mondata_subdir_alldom(struct kernfs_node * parent_kn,struct rdt_resource * r,struct rdtgroup * prgrp)31617168ae33SJames Morse static int mkdir_mondata_subdir_alldom(struct kernfs_node *parent_kn,
31627168ae33SJames Morse 				       struct rdt_resource *r,
31637168ae33SJames Morse 				       struct rdtgroup *prgrp)
31647168ae33SJames Morse {
31657168ae33SJames Morse 	struct rdt_mon_domain *dom;
31667168ae33SJames Morse 	int ret;
31677168ae33SJames Morse 
31687168ae33SJames Morse 	/* Walking r->domains, ensure it can't race with cpuhp */
31697168ae33SJames Morse 	lockdep_assert_cpus_held();
31707168ae33SJames Morse 
31717168ae33SJames Morse 	list_for_each_entry(dom, &r->mon_domains, hdr.list) {
31727168ae33SJames Morse 		ret = mkdir_mondata_subdir(parent_kn, dom, r, prgrp);
31737168ae33SJames Morse 		if (ret)
31747168ae33SJames Morse 			return ret;
31757168ae33SJames Morse 	}
31767168ae33SJames Morse 
31777168ae33SJames Morse 	return 0;
31787168ae33SJames Morse }
31797168ae33SJames Morse 
31807168ae33SJames Morse /*
31817168ae33SJames Morse  * This creates a directory mon_data which contains the monitored data.
31827168ae33SJames Morse  *
31837168ae33SJames Morse  * mon_data has one directory for each domain which are named
31847168ae33SJames Morse  * in the format mon_<domain_name>_<domain_id>. For ex: A mon_data
31857168ae33SJames Morse  * with L3 domain looks as below:
31867168ae33SJames Morse  * ./mon_data:
31877168ae33SJames Morse  * mon_L3_00
31887168ae33SJames Morse  * mon_L3_01
31897168ae33SJames Morse  * mon_L3_02
31907168ae33SJames Morse  * ...
31917168ae33SJames Morse  *
31927168ae33SJames Morse  * Each domain directory has one file per event:
31937168ae33SJames Morse  * ./mon_L3_00/:
31947168ae33SJames Morse  * llc_occupancy
31957168ae33SJames Morse  *
31967168ae33SJames Morse  */
mkdir_mondata_all(struct kernfs_node * parent_kn,struct rdtgroup * prgrp,struct kernfs_node ** dest_kn)31977168ae33SJames Morse static int mkdir_mondata_all(struct kernfs_node *parent_kn,
31987168ae33SJames Morse 			     struct rdtgroup *prgrp,
31997168ae33SJames Morse 			     struct kernfs_node **dest_kn)
32007168ae33SJames Morse {
32017168ae33SJames Morse 	struct rdt_resource *r;
32027168ae33SJames Morse 	struct kernfs_node *kn;
32037168ae33SJames Morse 	int ret;
32047168ae33SJames Morse 
32057168ae33SJames Morse 	/*
32067168ae33SJames Morse 	 * Create the mon_data directory first.
32077168ae33SJames Morse 	 */
32087168ae33SJames Morse 	ret = mongroup_create_dir(parent_kn, prgrp, "mon_data", &kn);
32097168ae33SJames Morse 	if (ret)
32107168ae33SJames Morse 		return ret;
32117168ae33SJames Morse 
32127168ae33SJames Morse 	if (dest_kn)
32137168ae33SJames Morse 		*dest_kn = kn;
32147168ae33SJames Morse 
32157168ae33SJames Morse 	/*
32167168ae33SJames Morse 	 * Create the subdirectories for each domain. Note that all events
32177168ae33SJames Morse 	 * in a domain like L3 are grouped into a resource whose domain is L3
32187168ae33SJames Morse 	 */
32197168ae33SJames Morse 	for_each_mon_capable_rdt_resource(r) {
32207168ae33SJames Morse 		ret = mkdir_mondata_subdir_alldom(kn, r, prgrp);
32217168ae33SJames Morse 		if (ret)
32227168ae33SJames Morse 			goto out_destroy;
32237168ae33SJames Morse 	}
32247168ae33SJames Morse 
32257168ae33SJames Morse 	return 0;
32267168ae33SJames Morse 
32277168ae33SJames Morse out_destroy:
32287168ae33SJames Morse 	kernfs_remove(kn);
32297168ae33SJames Morse 	return ret;
32307168ae33SJames Morse }
32317168ae33SJames Morse 
32327168ae33SJames Morse /**
32337168ae33SJames Morse  * cbm_ensure_valid - Enforce validity on provided CBM
32347168ae33SJames Morse  * @_val:	Candidate CBM
32357168ae33SJames Morse  * @r:		RDT resource to which the CBM belongs
32367168ae33SJames Morse  *
32377168ae33SJames Morse  * The provided CBM represents all cache portions available for use. This
32387168ae33SJames Morse  * may be represented by a bitmap that does not consist of contiguous ones
32397168ae33SJames Morse  * and thus be an invalid CBM.
32407168ae33SJames Morse  * Here the provided CBM is forced to be a valid CBM by only considering
32417168ae33SJames Morse  * the first set of contiguous bits as valid and clearing all bits.
32427168ae33SJames Morse  * The intention here is to provide a valid default CBM with which a new
32437168ae33SJames Morse  * resource group is initialized. The user can follow this with a
32447168ae33SJames Morse  * modification to the CBM if the default does not satisfy the
32457168ae33SJames Morse  * requirements.
32467168ae33SJames Morse  */
cbm_ensure_valid(u32 _val,struct rdt_resource * r)32477168ae33SJames Morse static u32 cbm_ensure_valid(u32 _val, struct rdt_resource *r)
32487168ae33SJames Morse {
32497168ae33SJames Morse 	unsigned int cbm_len = r->cache.cbm_len;
32507168ae33SJames Morse 	unsigned long first_bit, zero_bit;
32517168ae33SJames Morse 	unsigned long val = _val;
32527168ae33SJames Morse 
32537168ae33SJames Morse 	if (!val)
32547168ae33SJames Morse 		return 0;
32557168ae33SJames Morse 
32567168ae33SJames Morse 	first_bit = find_first_bit(&val, cbm_len);
32577168ae33SJames Morse 	zero_bit = find_next_zero_bit(&val, cbm_len, first_bit);
32587168ae33SJames Morse 
32597168ae33SJames Morse 	/* Clear any remaining bits to ensure contiguous region */
32607168ae33SJames Morse 	bitmap_clear(&val, zero_bit, cbm_len - zero_bit);
32617168ae33SJames Morse 	return (u32)val;
32627168ae33SJames Morse }
32637168ae33SJames Morse 
32647168ae33SJames Morse /*
32657168ae33SJames Morse  * Initialize cache resources per RDT domain
32667168ae33SJames Morse  *
32677168ae33SJames Morse  * Set the RDT domain up to start off with all usable allocations. That is,
32687168ae33SJames Morse  * all shareable and unused bits. All-zero CBM is invalid.
32697168ae33SJames Morse  */
__init_one_rdt_domain(struct rdt_ctrl_domain * d,struct resctrl_schema * s,u32 closid)32707168ae33SJames Morse static int __init_one_rdt_domain(struct rdt_ctrl_domain *d, struct resctrl_schema *s,
32717168ae33SJames Morse 				 u32 closid)
32727168ae33SJames Morse {
32737168ae33SJames Morse 	enum resctrl_conf_type peer_type = resctrl_peer_type(s->conf_type);
32747168ae33SJames Morse 	enum resctrl_conf_type t = s->conf_type;
32757168ae33SJames Morse 	struct resctrl_staged_config *cfg;
32767168ae33SJames Morse 	struct rdt_resource *r = s->res;
32777168ae33SJames Morse 	u32 used_b = 0, unused_b = 0;
32787168ae33SJames Morse 	unsigned long tmp_cbm;
32797168ae33SJames Morse 	enum rdtgrp_mode mode;
32807168ae33SJames Morse 	u32 peer_ctl, ctrl_val;
32817168ae33SJames Morse 	int i;
32827168ae33SJames Morse 
32837168ae33SJames Morse 	cfg = &d->staged_config[t];
32847168ae33SJames Morse 	cfg->have_new_ctrl = false;
32857168ae33SJames Morse 	cfg->new_ctrl = r->cache.shareable_bits;
32867168ae33SJames Morse 	used_b = r->cache.shareable_bits;
32877168ae33SJames Morse 	for (i = 0; i < closids_supported(); i++) {
32887168ae33SJames Morse 		if (closid_allocated(i) && i != closid) {
32897168ae33SJames Morse 			mode = rdtgroup_mode_by_closid(i);
32907168ae33SJames Morse 			if (mode == RDT_MODE_PSEUDO_LOCKSETUP)
32917168ae33SJames Morse 				/*
32927168ae33SJames Morse 				 * ctrl values for locksetup aren't relevant
32937168ae33SJames Morse 				 * until the schemata is written, and the mode
32947168ae33SJames Morse 				 * becomes RDT_MODE_PSEUDO_LOCKED.
32957168ae33SJames Morse 				 */
32967168ae33SJames Morse 				continue;
32977168ae33SJames Morse 			/*
32987168ae33SJames Morse 			 * If CDP is active include peer domain's
32997168ae33SJames Morse 			 * usage to ensure there is no overlap
33007168ae33SJames Morse 			 * with an exclusive group.
33017168ae33SJames Morse 			 */
33027168ae33SJames Morse 			if (resctrl_arch_get_cdp_enabled(r->rid))
33037168ae33SJames Morse 				peer_ctl = resctrl_arch_get_config(r, d, i,
33047168ae33SJames Morse 								   peer_type);
33057168ae33SJames Morse 			else
33067168ae33SJames Morse 				peer_ctl = 0;
33077168ae33SJames Morse 			ctrl_val = resctrl_arch_get_config(r, d, i,
33087168ae33SJames Morse 							   s->conf_type);
33097168ae33SJames Morse 			used_b |= ctrl_val | peer_ctl;
33107168ae33SJames Morse 			if (mode == RDT_MODE_SHAREABLE)
33117168ae33SJames Morse 				cfg->new_ctrl |= ctrl_val | peer_ctl;
33127168ae33SJames Morse 		}
33137168ae33SJames Morse 	}
33147168ae33SJames Morse 	if (d->plr && d->plr->cbm > 0)
33157168ae33SJames Morse 		used_b |= d->plr->cbm;
33167168ae33SJames Morse 	unused_b = used_b ^ (BIT_MASK(r->cache.cbm_len) - 1);
33177168ae33SJames Morse 	unused_b &= BIT_MASK(r->cache.cbm_len) - 1;
33187168ae33SJames Morse 	cfg->new_ctrl |= unused_b;
33197168ae33SJames Morse 	/*
33207168ae33SJames Morse 	 * Force the initial CBM to be valid, user can
33217168ae33SJames Morse 	 * modify the CBM based on system availability.
33227168ae33SJames Morse 	 */
33237168ae33SJames Morse 	cfg->new_ctrl = cbm_ensure_valid(cfg->new_ctrl, r);
33247168ae33SJames Morse 	/*
33257168ae33SJames Morse 	 * Assign the u32 CBM to an unsigned long to ensure that
33267168ae33SJames Morse 	 * bitmap_weight() does not access out-of-bound memory.
33277168ae33SJames Morse 	 */
33287168ae33SJames Morse 	tmp_cbm = cfg->new_ctrl;
33297168ae33SJames Morse 	if (bitmap_weight(&tmp_cbm, r->cache.cbm_len) < r->cache.min_cbm_bits) {
33307168ae33SJames Morse 		rdt_last_cmd_printf("No space on %s:%d\n", s->name, d->hdr.id);
33317168ae33SJames Morse 		return -ENOSPC;
33327168ae33SJames Morse 	}
33337168ae33SJames Morse 	cfg->have_new_ctrl = true;
33347168ae33SJames Morse 
33357168ae33SJames Morse 	return 0;
33367168ae33SJames Morse }
33377168ae33SJames Morse 
33387168ae33SJames Morse /*
33397168ae33SJames Morse  * Initialize cache resources with default values.
33407168ae33SJames Morse  *
33417168ae33SJames Morse  * A new RDT group is being created on an allocation capable (CAT)
33427168ae33SJames Morse  * supporting system. Set this group up to start off with all usable
33437168ae33SJames Morse  * allocations.
33447168ae33SJames Morse  *
33457168ae33SJames Morse  * If there are no more shareable bits available on any domain then
33467168ae33SJames Morse  * the entire allocation will fail.
33477168ae33SJames Morse  */
rdtgroup_init_cat(struct resctrl_schema * s,u32 closid)33487168ae33SJames Morse static int rdtgroup_init_cat(struct resctrl_schema *s, u32 closid)
33497168ae33SJames Morse {
33507168ae33SJames Morse 	struct rdt_ctrl_domain *d;
33517168ae33SJames Morse 	int ret;
33527168ae33SJames Morse 
33537168ae33SJames Morse 	list_for_each_entry(d, &s->res->ctrl_domains, hdr.list) {
33547168ae33SJames Morse 		ret = __init_one_rdt_domain(d, s, closid);
33557168ae33SJames Morse 		if (ret < 0)
33567168ae33SJames Morse 			return ret;
33577168ae33SJames Morse 	}
33587168ae33SJames Morse 
33597168ae33SJames Morse 	return 0;
33607168ae33SJames Morse }
33617168ae33SJames Morse 
33627168ae33SJames Morse /* Initialize MBA resource with default values. */
rdtgroup_init_mba(struct rdt_resource * r,u32 closid)33637168ae33SJames Morse static void rdtgroup_init_mba(struct rdt_resource *r, u32 closid)
33647168ae33SJames Morse {
33657168ae33SJames Morse 	struct resctrl_staged_config *cfg;
33667168ae33SJames Morse 	struct rdt_ctrl_domain *d;
33677168ae33SJames Morse 
33687168ae33SJames Morse 	list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
33697168ae33SJames Morse 		if (is_mba_sc(r)) {
33707168ae33SJames Morse 			d->mbps_val[closid] = MBA_MAX_MBPS;
33717168ae33SJames Morse 			continue;
33727168ae33SJames Morse 		}
33737168ae33SJames Morse 
33747168ae33SJames Morse 		cfg = &d->staged_config[CDP_NONE];
33757168ae33SJames Morse 		cfg->new_ctrl = resctrl_get_default_ctrl(r);
33767168ae33SJames Morse 		cfg->have_new_ctrl = true;
33777168ae33SJames Morse 	}
33787168ae33SJames Morse }
33797168ae33SJames Morse 
33807168ae33SJames Morse /* Initialize the RDT group's allocations. */
rdtgroup_init_alloc(struct rdtgroup * rdtgrp)33817168ae33SJames Morse static int rdtgroup_init_alloc(struct rdtgroup *rdtgrp)
33827168ae33SJames Morse {
33837168ae33SJames Morse 	struct resctrl_schema *s;
33847168ae33SJames Morse 	struct rdt_resource *r;
33857168ae33SJames Morse 	int ret = 0;
33867168ae33SJames Morse 
33877168ae33SJames Morse 	rdt_staged_configs_clear();
33887168ae33SJames Morse 
33897168ae33SJames Morse 	list_for_each_entry(s, &resctrl_schema_all, list) {
33907168ae33SJames Morse 		r = s->res;
33917168ae33SJames Morse 		if (r->rid == RDT_RESOURCE_MBA ||
33927168ae33SJames Morse 		    r->rid == RDT_RESOURCE_SMBA) {
33937168ae33SJames Morse 			rdtgroup_init_mba(r, rdtgrp->closid);
33947168ae33SJames Morse 			if (is_mba_sc(r))
33957168ae33SJames Morse 				continue;
33967168ae33SJames Morse 		} else {
33977168ae33SJames Morse 			ret = rdtgroup_init_cat(s, rdtgrp->closid);
33987168ae33SJames Morse 			if (ret < 0)
33997168ae33SJames Morse 				goto out;
34007168ae33SJames Morse 		}
34017168ae33SJames Morse 
34027168ae33SJames Morse 		ret = resctrl_arch_update_domains(r, rdtgrp->closid);
34037168ae33SJames Morse 		if (ret < 0) {
34047168ae33SJames Morse 			rdt_last_cmd_puts("Failed to initialize allocations\n");
34057168ae33SJames Morse 			goto out;
34067168ae33SJames Morse 		}
34077168ae33SJames Morse 	}
34087168ae33SJames Morse 
34097168ae33SJames Morse 	rdtgrp->mode = RDT_MODE_SHAREABLE;
34107168ae33SJames Morse 
34117168ae33SJames Morse out:
34127168ae33SJames Morse 	rdt_staged_configs_clear();
34137168ae33SJames Morse 	return ret;
34147168ae33SJames Morse }
34157168ae33SJames Morse 
mkdir_rdt_prepare_rmid_alloc(struct rdtgroup * rdtgrp)34167168ae33SJames Morse static int mkdir_rdt_prepare_rmid_alloc(struct rdtgroup *rdtgrp)
34177168ae33SJames Morse {
34187168ae33SJames Morse 	int ret;
34197168ae33SJames Morse 
34207168ae33SJames Morse 	if (!resctrl_arch_mon_capable())
34217168ae33SJames Morse 		return 0;
34227168ae33SJames Morse 
34237168ae33SJames Morse 	ret = alloc_rmid(rdtgrp->closid);
34247168ae33SJames Morse 	if (ret < 0) {
34257168ae33SJames Morse 		rdt_last_cmd_puts("Out of RMIDs\n");
34267168ae33SJames Morse 		return ret;
34277168ae33SJames Morse 	}
34287168ae33SJames Morse 	rdtgrp->mon.rmid = ret;
34297168ae33SJames Morse 
34307168ae33SJames Morse 	ret = mkdir_mondata_all(rdtgrp->kn, rdtgrp, &rdtgrp->mon.mon_data_kn);
34317168ae33SJames Morse 	if (ret) {
34327168ae33SJames Morse 		rdt_last_cmd_puts("kernfs subdir error\n");
34337168ae33SJames Morse 		free_rmid(rdtgrp->closid, rdtgrp->mon.rmid);
34347168ae33SJames Morse 		return ret;
34357168ae33SJames Morse 	}
34367168ae33SJames Morse 
34377168ae33SJames Morse 	return 0;
34387168ae33SJames Morse }
34397168ae33SJames Morse 
mkdir_rdt_prepare_rmid_free(struct rdtgroup * rgrp)34407168ae33SJames Morse static void mkdir_rdt_prepare_rmid_free(struct rdtgroup *rgrp)
34417168ae33SJames Morse {
34427168ae33SJames Morse 	if (resctrl_arch_mon_capable())
34437168ae33SJames Morse 		free_rmid(rgrp->closid, rgrp->mon.rmid);
34447168ae33SJames Morse }
34457168ae33SJames Morse 
34467168ae33SJames Morse /*
34477168ae33SJames Morse  * We allow creating mon groups only with in a directory called "mon_groups"
34487168ae33SJames Morse  * which is present in every ctrl_mon group. Check if this is a valid
34497168ae33SJames Morse  * "mon_groups" directory.
34507168ae33SJames Morse  *
34517168ae33SJames Morse  * 1. The directory should be named "mon_groups".
34527168ae33SJames Morse  * 2. The mon group itself should "not" be named "mon_groups".
34537168ae33SJames Morse  *   This makes sure "mon_groups" directory always has a ctrl_mon group
34547168ae33SJames Morse  *   as parent.
34557168ae33SJames Morse  */
is_mon_groups(struct kernfs_node * kn,const char * name)34567168ae33SJames Morse static bool is_mon_groups(struct kernfs_node *kn, const char *name)
34577168ae33SJames Morse {
34587168ae33SJames Morse 	return (!strcmp(rdt_kn_name(kn), "mon_groups") &&
34597168ae33SJames Morse 		strcmp(name, "mon_groups"));
34607168ae33SJames Morse }
34617168ae33SJames Morse 
mkdir_rdt_prepare(struct kernfs_node * parent_kn,const char * name,umode_t mode,enum rdt_group_type rtype,struct rdtgroup ** r)34627168ae33SJames Morse static int mkdir_rdt_prepare(struct kernfs_node *parent_kn,
34637168ae33SJames Morse 			     const char *name, umode_t mode,
34647168ae33SJames Morse 			     enum rdt_group_type rtype, struct rdtgroup **r)
34657168ae33SJames Morse {
34667168ae33SJames Morse 	struct rdtgroup *prdtgrp, *rdtgrp;
34677168ae33SJames Morse 	unsigned long files = 0;
34687168ae33SJames Morse 	struct kernfs_node *kn;
34697168ae33SJames Morse 	int ret;
34707168ae33SJames Morse 
34717168ae33SJames Morse 	prdtgrp = rdtgroup_kn_lock_live(parent_kn);
34727168ae33SJames Morse 	if (!prdtgrp) {
34737168ae33SJames Morse 		ret = -ENODEV;
34747168ae33SJames Morse 		goto out_unlock;
34757168ae33SJames Morse 	}
34767168ae33SJames Morse 
3477dd2922dcSZeng Heng 	rdt_last_cmd_clear();
3478dd2922dcSZeng Heng 
34797168ae33SJames Morse 	/*
34807168ae33SJames Morse 	 * Check that the parent directory for a monitor group is a "mon_groups"
34817168ae33SJames Morse 	 * directory.
34827168ae33SJames Morse 	 */
34837168ae33SJames Morse 	if (rtype == RDTMON_GROUP && !is_mon_groups(parent_kn, name)) {
34847168ae33SJames Morse 		ret = -EPERM;
34857168ae33SJames Morse 		goto out_unlock;
34867168ae33SJames Morse 	}
34877168ae33SJames Morse 
34887168ae33SJames Morse 	if (rtype == RDTMON_GROUP &&
34897168ae33SJames Morse 	    (prdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP ||
34907168ae33SJames Morse 	     prdtgrp->mode == RDT_MODE_PSEUDO_LOCKED)) {
34917168ae33SJames Morse 		ret = -EINVAL;
34927168ae33SJames Morse 		rdt_last_cmd_puts("Pseudo-locking in progress\n");
34937168ae33SJames Morse 		goto out_unlock;
34947168ae33SJames Morse 	}
34957168ae33SJames Morse 
34967168ae33SJames Morse 	/* allocate the rdtgroup. */
34977168ae33SJames Morse 	rdtgrp = kzalloc(sizeof(*rdtgrp), GFP_KERNEL);
34987168ae33SJames Morse 	if (!rdtgrp) {
34997168ae33SJames Morse 		ret = -ENOSPC;
35007168ae33SJames Morse 		rdt_last_cmd_puts("Kernel out of memory\n");
35017168ae33SJames Morse 		goto out_unlock;
35027168ae33SJames Morse 	}
35037168ae33SJames Morse 	*r = rdtgrp;
35047168ae33SJames Morse 	rdtgrp->mon.parent = prdtgrp;
35057168ae33SJames Morse 	rdtgrp->type = rtype;
35067168ae33SJames Morse 	INIT_LIST_HEAD(&rdtgrp->mon.crdtgrp_list);
35077168ae33SJames Morse 
35087168ae33SJames Morse 	/* kernfs creates the directory for rdtgrp */
35097168ae33SJames Morse 	kn = kernfs_create_dir(parent_kn, name, mode, rdtgrp);
35107168ae33SJames Morse 	if (IS_ERR(kn)) {
35117168ae33SJames Morse 		ret = PTR_ERR(kn);
35127168ae33SJames Morse 		rdt_last_cmd_puts("kernfs create error\n");
35137168ae33SJames Morse 		goto out_free_rgrp;
35147168ae33SJames Morse 	}
35157168ae33SJames Morse 	rdtgrp->kn = kn;
35167168ae33SJames Morse 
35177168ae33SJames Morse 	/*
35187168ae33SJames Morse 	 * kernfs_remove() will drop the reference count on "kn" which
35197168ae33SJames Morse 	 * will free it. But we still need it to stick around for the
35207168ae33SJames Morse 	 * rdtgroup_kn_unlock(kn) call. Take one extra reference here,
35217168ae33SJames Morse 	 * which will be dropped by kernfs_put() in rdtgroup_remove().
35227168ae33SJames Morse 	 */
35237168ae33SJames Morse 	kernfs_get(kn);
35247168ae33SJames Morse 
35257168ae33SJames Morse 	ret = rdtgroup_kn_set_ugid(kn);
35267168ae33SJames Morse 	if (ret) {
35277168ae33SJames Morse 		rdt_last_cmd_puts("kernfs perm error\n");
35287168ae33SJames Morse 		goto out_destroy;
35297168ae33SJames Morse 	}
35307168ae33SJames Morse 
35317168ae33SJames Morse 	if (rtype == RDTCTRL_GROUP) {
35327168ae33SJames Morse 		files = RFTYPE_BASE | RFTYPE_CTRL;
35337168ae33SJames Morse 		if (resctrl_arch_mon_capable())
35347168ae33SJames Morse 			files |= RFTYPE_MON;
35357168ae33SJames Morse 	} else {
35367168ae33SJames Morse 		files = RFTYPE_BASE | RFTYPE_MON;
35377168ae33SJames Morse 	}
35387168ae33SJames Morse 
35397168ae33SJames Morse 	ret = rdtgroup_add_files(kn, files);
35407168ae33SJames Morse 	if (ret) {
35417168ae33SJames Morse 		rdt_last_cmd_puts("kernfs fill error\n");
35427168ae33SJames Morse 		goto out_destroy;
35437168ae33SJames Morse 	}
35447168ae33SJames Morse 
35457168ae33SJames Morse 	/*
35467168ae33SJames Morse 	 * The caller unlocks the parent_kn upon success.
35477168ae33SJames Morse 	 */
35487168ae33SJames Morse 	return 0;
35497168ae33SJames Morse 
35507168ae33SJames Morse out_destroy:
35517168ae33SJames Morse 	kernfs_put(rdtgrp->kn);
35527168ae33SJames Morse 	kernfs_remove(rdtgrp->kn);
35537168ae33SJames Morse out_free_rgrp:
35547168ae33SJames Morse 	kfree(rdtgrp);
35557168ae33SJames Morse out_unlock:
35567168ae33SJames Morse 	rdtgroup_kn_unlock(parent_kn);
35577168ae33SJames Morse 	return ret;
35587168ae33SJames Morse }
35597168ae33SJames Morse 
mkdir_rdt_prepare_clean(struct rdtgroup * rgrp)35607168ae33SJames Morse static void mkdir_rdt_prepare_clean(struct rdtgroup *rgrp)
35617168ae33SJames Morse {
35627168ae33SJames Morse 	kernfs_remove(rgrp->kn);
35637168ae33SJames Morse 	rdtgroup_remove(rgrp);
35647168ae33SJames Morse }
35657168ae33SJames Morse 
35667168ae33SJames Morse /*
35677168ae33SJames Morse  * Create a monitor group under "mon_groups" directory of a control
35687168ae33SJames Morse  * and monitor group(ctrl_mon). This is a resource group
35697168ae33SJames Morse  * to monitor a subset of tasks and cpus in its parent ctrl_mon group.
35707168ae33SJames Morse  */
rdtgroup_mkdir_mon(struct kernfs_node * parent_kn,const char * name,umode_t mode)35717168ae33SJames Morse static int rdtgroup_mkdir_mon(struct kernfs_node *parent_kn,
35727168ae33SJames Morse 			      const char *name, umode_t mode)
35737168ae33SJames Morse {
35747168ae33SJames Morse 	struct rdtgroup *rdtgrp, *prgrp;
35757168ae33SJames Morse 	int ret;
35767168ae33SJames Morse 
35777168ae33SJames Morse 	ret = mkdir_rdt_prepare(parent_kn, name, mode, RDTMON_GROUP, &rdtgrp);
35787168ae33SJames Morse 	if (ret)
35797168ae33SJames Morse 		return ret;
35807168ae33SJames Morse 
35817168ae33SJames Morse 	prgrp = rdtgrp->mon.parent;
35827168ae33SJames Morse 	rdtgrp->closid = prgrp->closid;
35837168ae33SJames Morse 
35847168ae33SJames Morse 	ret = mkdir_rdt_prepare_rmid_alloc(rdtgrp);
35857168ae33SJames Morse 	if (ret) {
35867168ae33SJames Morse 		mkdir_rdt_prepare_clean(rdtgrp);
35877168ae33SJames Morse 		goto out_unlock;
35887168ae33SJames Morse 	}
35897168ae33SJames Morse 
35907168ae33SJames Morse 	kernfs_activate(rdtgrp->kn);
35917168ae33SJames Morse 
35927168ae33SJames Morse 	/*
35937168ae33SJames Morse 	 * Add the rdtgrp to the list of rdtgrps the parent
35947168ae33SJames Morse 	 * ctrl_mon group has to track.
35957168ae33SJames Morse 	 */
35967168ae33SJames Morse 	list_add_tail(&rdtgrp->mon.crdtgrp_list, &prgrp->mon.crdtgrp_list);
35977168ae33SJames Morse 
35987168ae33SJames Morse out_unlock:
35997168ae33SJames Morse 	rdtgroup_kn_unlock(parent_kn);
36007168ae33SJames Morse 	return ret;
36017168ae33SJames Morse }
36027168ae33SJames Morse 
36037168ae33SJames Morse /*
36047168ae33SJames Morse  * These are rdtgroups created under the root directory. Can be used
36057168ae33SJames Morse  * to allocate and monitor resources.
36067168ae33SJames Morse  */
rdtgroup_mkdir_ctrl_mon(struct kernfs_node * parent_kn,const char * name,umode_t mode)36077168ae33SJames Morse static int rdtgroup_mkdir_ctrl_mon(struct kernfs_node *parent_kn,
36087168ae33SJames Morse 				   const char *name, umode_t mode)
36097168ae33SJames Morse {
36107168ae33SJames Morse 	struct rdtgroup *rdtgrp;
36117168ae33SJames Morse 	struct kernfs_node *kn;
36127168ae33SJames Morse 	u32 closid;
36137168ae33SJames Morse 	int ret;
36147168ae33SJames Morse 
36157168ae33SJames Morse 	ret = mkdir_rdt_prepare(parent_kn, name, mode, RDTCTRL_GROUP, &rdtgrp);
36167168ae33SJames Morse 	if (ret)
36177168ae33SJames Morse 		return ret;
36187168ae33SJames Morse 
36197168ae33SJames Morse 	kn = rdtgrp->kn;
36207168ae33SJames Morse 	ret = closid_alloc();
36217168ae33SJames Morse 	if (ret < 0) {
36227168ae33SJames Morse 		rdt_last_cmd_puts("Out of CLOSIDs\n");
36237168ae33SJames Morse 		goto out_common_fail;
36247168ae33SJames Morse 	}
36257168ae33SJames Morse 	closid = ret;
36267168ae33SJames Morse 	ret = 0;
36277168ae33SJames Morse 
36287168ae33SJames Morse 	rdtgrp->closid = closid;
36297168ae33SJames Morse 
36307168ae33SJames Morse 	ret = mkdir_rdt_prepare_rmid_alloc(rdtgrp);
36317168ae33SJames Morse 	if (ret)
36327168ae33SJames Morse 		goto out_closid_free;
36337168ae33SJames Morse 
36347168ae33SJames Morse 	kernfs_activate(rdtgrp->kn);
36357168ae33SJames Morse 
36367168ae33SJames Morse 	ret = rdtgroup_init_alloc(rdtgrp);
36377168ae33SJames Morse 	if (ret < 0)
36387168ae33SJames Morse 		goto out_rmid_free;
36397168ae33SJames Morse 
36407168ae33SJames Morse 	list_add(&rdtgrp->rdtgroup_list, &rdt_all_groups);
36417168ae33SJames Morse 
36427168ae33SJames Morse 	if (resctrl_arch_mon_capable()) {
36437168ae33SJames Morse 		/*
36447168ae33SJames Morse 		 * Create an empty mon_groups directory to hold the subset
36457168ae33SJames Morse 		 * of tasks and cpus to monitor.
36467168ae33SJames Morse 		 */
36477168ae33SJames Morse 		ret = mongroup_create_dir(kn, rdtgrp, "mon_groups", NULL);
36487168ae33SJames Morse 		if (ret) {
36497168ae33SJames Morse 			rdt_last_cmd_puts("kernfs subdir error\n");
36507168ae33SJames Morse 			goto out_del_list;
36517168ae33SJames Morse 		}
36527168ae33SJames Morse 		if (is_mba_sc(NULL))
36537168ae33SJames Morse 			rdtgrp->mba_mbps_event = mba_mbps_default_event;
36547168ae33SJames Morse 	}
36557168ae33SJames Morse 
36567168ae33SJames Morse 	goto out_unlock;
36577168ae33SJames Morse 
36587168ae33SJames Morse out_del_list:
36597168ae33SJames Morse 	list_del(&rdtgrp->rdtgroup_list);
36607168ae33SJames Morse out_rmid_free:
36617168ae33SJames Morse 	mkdir_rdt_prepare_rmid_free(rdtgrp);
36627168ae33SJames Morse out_closid_free:
36637168ae33SJames Morse 	closid_free(closid);
36647168ae33SJames Morse out_common_fail:
36657168ae33SJames Morse 	mkdir_rdt_prepare_clean(rdtgrp);
36667168ae33SJames Morse out_unlock:
36677168ae33SJames Morse 	rdtgroup_kn_unlock(parent_kn);
36687168ae33SJames Morse 	return ret;
36697168ae33SJames Morse }
36707168ae33SJames Morse 
rdtgroup_mkdir(struct kernfs_node * parent_kn,const char * name,umode_t mode)36717168ae33SJames Morse static int rdtgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
36727168ae33SJames Morse 			  umode_t mode)
36737168ae33SJames Morse {
36747168ae33SJames Morse 	/* Do not accept '\n' to avoid unparsable situation. */
36757168ae33SJames Morse 	if (strchr(name, '\n'))
36767168ae33SJames Morse 		return -EINVAL;
36777168ae33SJames Morse 
36787168ae33SJames Morse 	/*
36797168ae33SJames Morse 	 * If the parent directory is the root directory and RDT
36807168ae33SJames Morse 	 * allocation is supported, add a control and monitoring
36817168ae33SJames Morse 	 * subdirectory
36827168ae33SJames Morse 	 */
36837168ae33SJames Morse 	if (resctrl_arch_alloc_capable() && parent_kn == rdtgroup_default.kn)
36847168ae33SJames Morse 		return rdtgroup_mkdir_ctrl_mon(parent_kn, name, mode);
36857168ae33SJames Morse 
36867168ae33SJames Morse 	/* Else, attempt to add a monitoring subdirectory. */
36877168ae33SJames Morse 	if (resctrl_arch_mon_capable())
36887168ae33SJames Morse 		return rdtgroup_mkdir_mon(parent_kn, name, mode);
36897168ae33SJames Morse 
36907168ae33SJames Morse 	return -EPERM;
36917168ae33SJames Morse }
36927168ae33SJames Morse 
rdtgroup_rmdir_mon(struct rdtgroup * rdtgrp,cpumask_var_t tmpmask)36937168ae33SJames Morse static int rdtgroup_rmdir_mon(struct rdtgroup *rdtgrp, cpumask_var_t tmpmask)
36947168ae33SJames Morse {
36957168ae33SJames Morse 	struct rdtgroup *prdtgrp = rdtgrp->mon.parent;
36967168ae33SJames Morse 	u32 closid, rmid;
36977168ae33SJames Morse 	int cpu;
36987168ae33SJames Morse 
36997168ae33SJames Morse 	/* Give any tasks back to the parent group */
37007168ae33SJames Morse 	rdt_move_group_tasks(rdtgrp, prdtgrp, tmpmask);
37017168ae33SJames Morse 
37027168ae33SJames Morse 	/*
37037168ae33SJames Morse 	 * Update per cpu closid/rmid of the moved CPUs first.
37047168ae33SJames Morse 	 * Note: the closid will not change, but the arch code still needs it.
37057168ae33SJames Morse 	 */
37067168ae33SJames Morse 	closid = prdtgrp->closid;
37077168ae33SJames Morse 	rmid = prdtgrp->mon.rmid;
37087168ae33SJames Morse 	for_each_cpu(cpu, &rdtgrp->cpu_mask)
37097168ae33SJames Morse 		resctrl_arch_set_cpu_default_closid_rmid(cpu, closid, rmid);
37107168ae33SJames Morse 
37117168ae33SJames Morse 	/*
37127168ae33SJames Morse 	 * Update the MSR on moved CPUs and CPUs which have moved
37137168ae33SJames Morse 	 * task running on them.
37147168ae33SJames Morse 	 */
37157168ae33SJames Morse 	cpumask_or(tmpmask, tmpmask, &rdtgrp->cpu_mask);
37167168ae33SJames Morse 	update_closid_rmid(tmpmask, NULL);
37177168ae33SJames Morse 
37187168ae33SJames Morse 	rdtgrp->flags = RDT_DELETED;
37197168ae33SJames Morse 	free_rmid(rdtgrp->closid, rdtgrp->mon.rmid);
37207168ae33SJames Morse 
37217168ae33SJames Morse 	/*
37227168ae33SJames Morse 	 * Remove the rdtgrp from the parent ctrl_mon group's list
37237168ae33SJames Morse 	 */
37247168ae33SJames Morse 	WARN_ON(list_empty(&prdtgrp->mon.crdtgrp_list));
37257168ae33SJames Morse 	list_del(&rdtgrp->mon.crdtgrp_list);
37267168ae33SJames Morse 
37277168ae33SJames Morse 	kernfs_remove(rdtgrp->kn);
37287168ae33SJames Morse 
37297168ae33SJames Morse 	return 0;
37307168ae33SJames Morse }
37317168ae33SJames Morse 
rdtgroup_ctrl_remove(struct rdtgroup * rdtgrp)37327168ae33SJames Morse static int rdtgroup_ctrl_remove(struct rdtgroup *rdtgrp)
37337168ae33SJames Morse {
37347168ae33SJames Morse 	rdtgrp->flags = RDT_DELETED;
37357168ae33SJames Morse 	list_del(&rdtgrp->rdtgroup_list);
37367168ae33SJames Morse 
37377168ae33SJames Morse 	kernfs_remove(rdtgrp->kn);
37387168ae33SJames Morse 	return 0;
37397168ae33SJames Morse }
37407168ae33SJames Morse 
rdtgroup_rmdir_ctrl(struct rdtgroup * rdtgrp,cpumask_var_t tmpmask)37417168ae33SJames Morse static int rdtgroup_rmdir_ctrl(struct rdtgroup *rdtgrp, cpumask_var_t tmpmask)
37427168ae33SJames Morse {
37437168ae33SJames Morse 	u32 closid, rmid;
37447168ae33SJames Morse 	int cpu;
37457168ae33SJames Morse 
37467168ae33SJames Morse 	/* Give any tasks back to the default group */
37477168ae33SJames Morse 	rdt_move_group_tasks(rdtgrp, &rdtgroup_default, tmpmask);
37487168ae33SJames Morse 
37497168ae33SJames Morse 	/* Give any CPUs back to the default group */
37507168ae33SJames Morse 	cpumask_or(&rdtgroup_default.cpu_mask,
37517168ae33SJames Morse 		   &rdtgroup_default.cpu_mask, &rdtgrp->cpu_mask);
37527168ae33SJames Morse 
37537168ae33SJames Morse 	/* Update per cpu closid and rmid of the moved CPUs first */
37547168ae33SJames Morse 	closid = rdtgroup_default.closid;
37557168ae33SJames Morse 	rmid = rdtgroup_default.mon.rmid;
37567168ae33SJames Morse 	for_each_cpu(cpu, &rdtgrp->cpu_mask)
37577168ae33SJames Morse 		resctrl_arch_set_cpu_default_closid_rmid(cpu, closid, rmid);
37587168ae33SJames Morse 
37597168ae33SJames Morse 	/*
37607168ae33SJames Morse 	 * Update the MSR on moved CPUs and CPUs which have moved
37617168ae33SJames Morse 	 * task running on them.
37627168ae33SJames Morse 	 */
37637168ae33SJames Morse 	cpumask_or(tmpmask, tmpmask, &rdtgrp->cpu_mask);
37647168ae33SJames Morse 	update_closid_rmid(tmpmask, NULL);
37657168ae33SJames Morse 
37667168ae33SJames Morse 	free_rmid(rdtgrp->closid, rdtgrp->mon.rmid);
37677168ae33SJames Morse 	closid_free(rdtgrp->closid);
37687168ae33SJames Morse 
37697168ae33SJames Morse 	rdtgroup_ctrl_remove(rdtgrp);
37707168ae33SJames Morse 
37717168ae33SJames Morse 	/*
37727168ae33SJames Morse 	 * Free all the child monitor group rmids.
37737168ae33SJames Morse 	 */
37747168ae33SJames Morse 	free_all_child_rdtgrp(rdtgrp);
37757168ae33SJames Morse 
37767168ae33SJames Morse 	return 0;
37777168ae33SJames Morse }
37787168ae33SJames Morse 
rdt_kn_parent(struct kernfs_node * kn)37797168ae33SJames Morse static struct kernfs_node *rdt_kn_parent(struct kernfs_node *kn)
37807168ae33SJames Morse {
37817168ae33SJames Morse 	/*
37827168ae33SJames Morse 	 * Valid within the RCU section it was obtained or while rdtgroup_mutex
37837168ae33SJames Morse 	 * is held.
37847168ae33SJames Morse 	 */
37857168ae33SJames Morse 	return rcu_dereference_check(kn->__parent, lockdep_is_held(&rdtgroup_mutex));
37867168ae33SJames Morse }
37877168ae33SJames Morse 
rdtgroup_rmdir(struct kernfs_node * kn)37887168ae33SJames Morse static int rdtgroup_rmdir(struct kernfs_node *kn)
37897168ae33SJames Morse {
37907168ae33SJames Morse 	struct kernfs_node *parent_kn;
37917168ae33SJames Morse 	struct rdtgroup *rdtgrp;
37927168ae33SJames Morse 	cpumask_var_t tmpmask;
37937168ae33SJames Morse 	int ret = 0;
37947168ae33SJames Morse 
37957168ae33SJames Morse 	if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
37967168ae33SJames Morse 		return -ENOMEM;
37977168ae33SJames Morse 
37987168ae33SJames Morse 	rdtgrp = rdtgroup_kn_lock_live(kn);
37997168ae33SJames Morse 	if (!rdtgrp) {
38007168ae33SJames Morse 		ret = -EPERM;
38017168ae33SJames Morse 		goto out;
38027168ae33SJames Morse 	}
38037168ae33SJames Morse 	parent_kn = rdt_kn_parent(kn);
38047168ae33SJames Morse 
38057168ae33SJames Morse 	/*
38067168ae33SJames Morse 	 * If the rdtgroup is a ctrl_mon group and parent directory
38077168ae33SJames Morse 	 * is the root directory, remove the ctrl_mon group.
38087168ae33SJames Morse 	 *
38097168ae33SJames Morse 	 * If the rdtgroup is a mon group and parent directory
38107168ae33SJames Morse 	 * is a valid "mon_groups" directory, remove the mon group.
38117168ae33SJames Morse 	 */
38127168ae33SJames Morse 	if (rdtgrp->type == RDTCTRL_GROUP && parent_kn == rdtgroup_default.kn &&
38137168ae33SJames Morse 	    rdtgrp != &rdtgroup_default) {
38147168ae33SJames Morse 		if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP ||
38157168ae33SJames Morse 		    rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
38167168ae33SJames Morse 			ret = rdtgroup_ctrl_remove(rdtgrp);
38177168ae33SJames Morse 		} else {
38187168ae33SJames Morse 			ret = rdtgroup_rmdir_ctrl(rdtgrp, tmpmask);
38197168ae33SJames Morse 		}
38207168ae33SJames Morse 	} else if (rdtgrp->type == RDTMON_GROUP &&
38217168ae33SJames Morse 		 is_mon_groups(parent_kn, rdt_kn_name(kn))) {
38227168ae33SJames Morse 		ret = rdtgroup_rmdir_mon(rdtgrp, tmpmask);
38237168ae33SJames Morse 	} else {
38247168ae33SJames Morse 		ret = -EPERM;
38257168ae33SJames Morse 	}
38267168ae33SJames Morse 
38277168ae33SJames Morse out:
38287168ae33SJames Morse 	rdtgroup_kn_unlock(kn);
38297168ae33SJames Morse 	free_cpumask_var(tmpmask);
38307168ae33SJames Morse 	return ret;
38317168ae33SJames Morse }
38327168ae33SJames Morse 
38337168ae33SJames Morse /**
38347168ae33SJames Morse  * mongrp_reparent() - replace parent CTRL_MON group of a MON group
38357168ae33SJames Morse  * @rdtgrp:		the MON group whose parent should be replaced
38367168ae33SJames Morse  * @new_prdtgrp:	replacement parent CTRL_MON group for @rdtgrp
38377168ae33SJames Morse  * @cpus:		cpumask provided by the caller for use during this call
38387168ae33SJames Morse  *
38397168ae33SJames Morse  * Replaces the parent CTRL_MON group for a MON group, resulting in all member
38407168ae33SJames Morse  * tasks' CLOSID immediately changing to that of the new parent group.
38417168ae33SJames Morse  * Monitoring data for the group is unaffected by this operation.
38427168ae33SJames Morse  */
mongrp_reparent(struct rdtgroup * rdtgrp,struct rdtgroup * new_prdtgrp,cpumask_var_t cpus)38437168ae33SJames Morse static void mongrp_reparent(struct rdtgroup *rdtgrp,
38447168ae33SJames Morse 			    struct rdtgroup *new_prdtgrp,
38457168ae33SJames Morse 			    cpumask_var_t cpus)
38467168ae33SJames Morse {
38477168ae33SJames Morse 	struct rdtgroup *prdtgrp = rdtgrp->mon.parent;
38487168ae33SJames Morse 
38497168ae33SJames Morse 	WARN_ON(rdtgrp->type != RDTMON_GROUP);
38507168ae33SJames Morse 	WARN_ON(new_prdtgrp->type != RDTCTRL_GROUP);
38517168ae33SJames Morse 
38527168ae33SJames Morse 	/* Nothing to do when simply renaming a MON group. */
38537168ae33SJames Morse 	if (prdtgrp == new_prdtgrp)
38547168ae33SJames Morse 		return;
38557168ae33SJames Morse 
38567168ae33SJames Morse 	WARN_ON(list_empty(&prdtgrp->mon.crdtgrp_list));
38577168ae33SJames Morse 	list_move_tail(&rdtgrp->mon.crdtgrp_list,
38587168ae33SJames Morse 		       &new_prdtgrp->mon.crdtgrp_list);
38597168ae33SJames Morse 
38607168ae33SJames Morse 	rdtgrp->mon.parent = new_prdtgrp;
38617168ae33SJames Morse 	rdtgrp->closid = new_prdtgrp->closid;
38627168ae33SJames Morse 
38637168ae33SJames Morse 	/* Propagate updated closid to all tasks in this group. */
38647168ae33SJames Morse 	rdt_move_group_tasks(rdtgrp, rdtgrp, cpus);
38657168ae33SJames Morse 
38667168ae33SJames Morse 	update_closid_rmid(cpus, NULL);
38677168ae33SJames Morse }
38687168ae33SJames Morse 
rdtgroup_rename(struct kernfs_node * kn,struct kernfs_node * new_parent,const char * new_name)38697168ae33SJames Morse static int rdtgroup_rename(struct kernfs_node *kn,
38707168ae33SJames Morse 			   struct kernfs_node *new_parent, const char *new_name)
38717168ae33SJames Morse {
38727168ae33SJames Morse 	struct kernfs_node *kn_parent;
38737168ae33SJames Morse 	struct rdtgroup *new_prdtgrp;
38747168ae33SJames Morse 	struct rdtgroup *rdtgrp;
38757168ae33SJames Morse 	cpumask_var_t tmpmask;
38767168ae33SJames Morse 	int ret;
38777168ae33SJames Morse 
38787168ae33SJames Morse 	rdtgrp = kernfs_to_rdtgroup(kn);
38797168ae33SJames Morse 	new_prdtgrp = kernfs_to_rdtgroup(new_parent);
38807168ae33SJames Morse 	if (!rdtgrp || !new_prdtgrp)
38817168ae33SJames Morse 		return -ENOENT;
38827168ae33SJames Morse 
38837168ae33SJames Morse 	/* Release both kernfs active_refs before obtaining rdtgroup mutex. */
38847168ae33SJames Morse 	rdtgroup_kn_get(rdtgrp, kn);
38857168ae33SJames Morse 	rdtgroup_kn_get(new_prdtgrp, new_parent);
38867168ae33SJames Morse 
38877168ae33SJames Morse 	mutex_lock(&rdtgroup_mutex);
38887168ae33SJames Morse 
38897168ae33SJames Morse 	rdt_last_cmd_clear();
38907168ae33SJames Morse 
38917168ae33SJames Morse 	/*
38927168ae33SJames Morse 	 * Don't allow kernfs_to_rdtgroup() to return a parent rdtgroup if
38937168ae33SJames Morse 	 * either kernfs_node is a file.
38947168ae33SJames Morse 	 */
38957168ae33SJames Morse 	if (kernfs_type(kn) != KERNFS_DIR ||
38967168ae33SJames Morse 	    kernfs_type(new_parent) != KERNFS_DIR) {
38977168ae33SJames Morse 		rdt_last_cmd_puts("Source and destination must be directories");
38987168ae33SJames Morse 		ret = -EPERM;
38997168ae33SJames Morse 		goto out;
39007168ae33SJames Morse 	}
39017168ae33SJames Morse 
39027168ae33SJames Morse 	if ((rdtgrp->flags & RDT_DELETED) || (new_prdtgrp->flags & RDT_DELETED)) {
39037168ae33SJames Morse 		ret = -ENOENT;
39047168ae33SJames Morse 		goto out;
39057168ae33SJames Morse 	}
39067168ae33SJames Morse 
39077168ae33SJames Morse 	kn_parent = rdt_kn_parent(kn);
39087168ae33SJames Morse 	if (rdtgrp->type != RDTMON_GROUP || !kn_parent ||
39097168ae33SJames Morse 	    !is_mon_groups(kn_parent, rdt_kn_name(kn))) {
39107168ae33SJames Morse 		rdt_last_cmd_puts("Source must be a MON group\n");
39117168ae33SJames Morse 		ret = -EPERM;
39127168ae33SJames Morse 		goto out;
39137168ae33SJames Morse 	}
39147168ae33SJames Morse 
39157168ae33SJames Morse 	if (!is_mon_groups(new_parent, new_name)) {
39167168ae33SJames Morse 		rdt_last_cmd_puts("Destination must be a mon_groups subdirectory\n");
39177168ae33SJames Morse 		ret = -EPERM;
39187168ae33SJames Morse 		goto out;
39197168ae33SJames Morse 	}
39207168ae33SJames Morse 
39217168ae33SJames Morse 	/*
39227168ae33SJames Morse 	 * If the MON group is monitoring CPUs, the CPUs must be assigned to the
39237168ae33SJames Morse 	 * current parent CTRL_MON group and therefore cannot be assigned to
39247168ae33SJames Morse 	 * the new parent, making the move illegal.
39257168ae33SJames Morse 	 */
39267168ae33SJames Morse 	if (!cpumask_empty(&rdtgrp->cpu_mask) &&
39277168ae33SJames Morse 	    rdtgrp->mon.parent != new_prdtgrp) {
39287168ae33SJames Morse 		rdt_last_cmd_puts("Cannot move a MON group that monitors CPUs\n");
39297168ae33SJames Morse 		ret = -EPERM;
39307168ae33SJames Morse 		goto out;
39317168ae33SJames Morse 	}
39327168ae33SJames Morse 
39337168ae33SJames Morse 	/*
39347168ae33SJames Morse 	 * Allocate the cpumask for use in mongrp_reparent() to avoid the
39357168ae33SJames Morse 	 * possibility of failing to allocate it after kernfs_rename() has
39367168ae33SJames Morse 	 * succeeded.
39377168ae33SJames Morse 	 */
39387168ae33SJames Morse 	if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL)) {
39397168ae33SJames Morse 		ret = -ENOMEM;
39407168ae33SJames Morse 		goto out;
39417168ae33SJames Morse 	}
39427168ae33SJames Morse 
39437168ae33SJames Morse 	/*
39447168ae33SJames Morse 	 * Perform all input validation and allocations needed to ensure
39457168ae33SJames Morse 	 * mongrp_reparent() will succeed before calling kernfs_rename(),
39467168ae33SJames Morse 	 * otherwise it would be necessary to revert this call if
39477168ae33SJames Morse 	 * mongrp_reparent() failed.
39487168ae33SJames Morse 	 */
39497168ae33SJames Morse 	ret = kernfs_rename(kn, new_parent, new_name);
39507168ae33SJames Morse 	if (!ret)
39517168ae33SJames Morse 		mongrp_reparent(rdtgrp, new_prdtgrp, tmpmask);
39527168ae33SJames Morse 
39537168ae33SJames Morse 	free_cpumask_var(tmpmask);
39547168ae33SJames Morse 
39557168ae33SJames Morse out:
39567168ae33SJames Morse 	mutex_unlock(&rdtgroup_mutex);
39577168ae33SJames Morse 	rdtgroup_kn_put(rdtgrp, kn);
39587168ae33SJames Morse 	rdtgroup_kn_put(new_prdtgrp, new_parent);
39597168ae33SJames Morse 	return ret;
39607168ae33SJames Morse }
39617168ae33SJames Morse 
rdtgroup_show_options(struct seq_file * seq,struct kernfs_root * kf)39627168ae33SJames Morse static int rdtgroup_show_options(struct seq_file *seq, struct kernfs_root *kf)
39637168ae33SJames Morse {
39647168ae33SJames Morse 	if (resctrl_arch_get_cdp_enabled(RDT_RESOURCE_L3))
39657168ae33SJames Morse 		seq_puts(seq, ",cdp");
39667168ae33SJames Morse 
39677168ae33SJames Morse 	if (resctrl_arch_get_cdp_enabled(RDT_RESOURCE_L2))
39687168ae33SJames Morse 		seq_puts(seq, ",cdpl2");
39697168ae33SJames Morse 
39707168ae33SJames Morse 	if (is_mba_sc(resctrl_arch_get_resource(RDT_RESOURCE_MBA)))
39717168ae33SJames Morse 		seq_puts(seq, ",mba_MBps");
39727168ae33SJames Morse 
39737168ae33SJames Morse 	if (resctrl_debug)
39747168ae33SJames Morse 		seq_puts(seq, ",debug");
39757168ae33SJames Morse 
39767168ae33SJames Morse 	return 0;
39777168ae33SJames Morse }
39787168ae33SJames Morse 
39797168ae33SJames Morse static struct kernfs_syscall_ops rdtgroup_kf_syscall_ops = {
39807168ae33SJames Morse 	.mkdir		= rdtgroup_mkdir,
39817168ae33SJames Morse 	.rmdir		= rdtgroup_rmdir,
39827168ae33SJames Morse 	.rename		= rdtgroup_rename,
39837168ae33SJames Morse 	.show_options	= rdtgroup_show_options,
39847168ae33SJames Morse };
39857168ae33SJames Morse 
rdtgroup_setup_root(struct rdt_fs_context * ctx)39867168ae33SJames Morse static int rdtgroup_setup_root(struct rdt_fs_context *ctx)
39877168ae33SJames Morse {
39887168ae33SJames Morse 	rdt_root = kernfs_create_root(&rdtgroup_kf_syscall_ops,
39897168ae33SJames Morse 				      KERNFS_ROOT_CREATE_DEACTIVATED |
39907168ae33SJames Morse 				      KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK,
39917168ae33SJames Morse 				      &rdtgroup_default);
39927168ae33SJames Morse 	if (IS_ERR(rdt_root))
39937168ae33SJames Morse 		return PTR_ERR(rdt_root);
39947168ae33SJames Morse 
39957168ae33SJames Morse 	ctx->kfc.root = rdt_root;
39967168ae33SJames Morse 	rdtgroup_default.kn = kernfs_root_to_node(rdt_root);
39977168ae33SJames Morse 
39987168ae33SJames Morse 	return 0;
39997168ae33SJames Morse }
40007168ae33SJames Morse 
rdtgroup_destroy_root(void)40017168ae33SJames Morse static void rdtgroup_destroy_root(void)
40027168ae33SJames Morse {
40037168ae33SJames Morse 	lockdep_assert_held(&rdtgroup_mutex);
40047168ae33SJames Morse 
40057168ae33SJames Morse 	kernfs_destroy_root(rdt_root);
40067168ae33SJames Morse 	rdtgroup_default.kn = NULL;
40077168ae33SJames Morse }
40087168ae33SJames Morse 
rdtgroup_setup_default(void)40097168ae33SJames Morse static void rdtgroup_setup_default(void)
40107168ae33SJames Morse {
40117168ae33SJames Morse 	mutex_lock(&rdtgroup_mutex);
40127168ae33SJames Morse 
40137168ae33SJames Morse 	rdtgroup_default.closid = RESCTRL_RESERVED_CLOSID;
40147168ae33SJames Morse 	rdtgroup_default.mon.rmid = RESCTRL_RESERVED_RMID;
40157168ae33SJames Morse 	rdtgroup_default.type = RDTCTRL_GROUP;
40167168ae33SJames Morse 	INIT_LIST_HEAD(&rdtgroup_default.mon.crdtgrp_list);
40177168ae33SJames Morse 
40187168ae33SJames Morse 	list_add(&rdtgroup_default.rdtgroup_list, &rdt_all_groups);
40197168ae33SJames Morse 
40207168ae33SJames Morse 	mutex_unlock(&rdtgroup_mutex);
40217168ae33SJames Morse }
40227168ae33SJames Morse 
domain_destroy_mon_state(struct rdt_mon_domain * d)40237168ae33SJames Morse static void domain_destroy_mon_state(struct rdt_mon_domain *d)
40247168ae33SJames Morse {
40257168ae33SJames Morse 	bitmap_free(d->rmid_busy_llc);
40267168ae33SJames Morse 	kfree(d->mbm_total);
40277168ae33SJames Morse 	kfree(d->mbm_local);
40287168ae33SJames Morse }
40297168ae33SJames Morse 
resctrl_offline_ctrl_domain(struct rdt_resource * r,struct rdt_ctrl_domain * d)40307168ae33SJames Morse void resctrl_offline_ctrl_domain(struct rdt_resource *r, struct rdt_ctrl_domain *d)
40317168ae33SJames Morse {
40327168ae33SJames Morse 	mutex_lock(&rdtgroup_mutex);
40337168ae33SJames Morse 
40347168ae33SJames Morse 	if (supports_mba_mbps() && r->rid == RDT_RESOURCE_MBA)
40357168ae33SJames Morse 		mba_sc_domain_destroy(r, d);
40367168ae33SJames Morse 
40377168ae33SJames Morse 	mutex_unlock(&rdtgroup_mutex);
40387168ae33SJames Morse }
40397168ae33SJames Morse 
resctrl_offline_mon_domain(struct rdt_resource * r,struct rdt_mon_domain * d)40407168ae33SJames Morse void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_mon_domain *d)
40417168ae33SJames Morse {
40427168ae33SJames Morse 	mutex_lock(&rdtgroup_mutex);
40437168ae33SJames Morse 
40447168ae33SJames Morse 	/*
40457168ae33SJames Morse 	 * If resctrl is mounted, remove all the
40467168ae33SJames Morse 	 * per domain monitor data directories.
40477168ae33SJames Morse 	 */
40487168ae33SJames Morse 	if (resctrl_mounted && resctrl_arch_mon_capable())
40497168ae33SJames Morse 		rmdir_mondata_subdir_allrdtgrp(r, d);
40507168ae33SJames Morse 
40517168ae33SJames Morse 	if (resctrl_is_mbm_enabled())
40527168ae33SJames Morse 		cancel_delayed_work(&d->mbm_over);
40537168ae33SJames Morse 	if (resctrl_arch_is_llc_occupancy_enabled() && has_busy_rmid(d)) {
40547168ae33SJames Morse 		/*
40557168ae33SJames Morse 		 * When a package is going down, forcefully
40567168ae33SJames Morse 		 * decrement rmid->ebusy. There is no way to know
40577168ae33SJames Morse 		 * that the L3 was flushed and hence may lead to
40587168ae33SJames Morse 		 * incorrect counts in rare scenarios, but leaving
40597168ae33SJames Morse 		 * the RMID as busy creates RMID leaks if the
40607168ae33SJames Morse 		 * package never comes back.
40617168ae33SJames Morse 		 */
40627168ae33SJames Morse 		__check_limbo(d, true);
40637168ae33SJames Morse 		cancel_delayed_work(&d->cqm_limbo);
40647168ae33SJames Morse 	}
40657168ae33SJames Morse 
40667168ae33SJames Morse 	domain_destroy_mon_state(d);
40677168ae33SJames Morse 
40687168ae33SJames Morse 	mutex_unlock(&rdtgroup_mutex);
40697168ae33SJames Morse }
40707168ae33SJames Morse 
40717168ae33SJames Morse /**
40727168ae33SJames Morse  * domain_setup_mon_state() -  Initialise domain monitoring structures.
40737168ae33SJames Morse  * @r:	The resource for the newly online domain.
40747168ae33SJames Morse  * @d:	The newly online domain.
40757168ae33SJames Morse  *
40767168ae33SJames Morse  * Allocate monitor resources that belong to this domain.
40777168ae33SJames Morse  * Called when the first CPU of a domain comes online, regardless of whether
40787168ae33SJames Morse  * the filesystem is mounted.
40797168ae33SJames Morse  * During boot this may be called before global allocations have been made by
40807168ae33SJames Morse  * resctrl_mon_resource_init().
40817168ae33SJames Morse  *
40827168ae33SJames Morse  * Returns 0 for success, or -ENOMEM.
40837168ae33SJames Morse  */
domain_setup_mon_state(struct rdt_resource * r,struct rdt_mon_domain * d)40847168ae33SJames Morse static int domain_setup_mon_state(struct rdt_resource *r, struct rdt_mon_domain *d)
40857168ae33SJames Morse {
40867168ae33SJames Morse 	u32 idx_limit = resctrl_arch_system_num_rmid_idx();
40877168ae33SJames Morse 	size_t tsize;
40887168ae33SJames Morse 
40897168ae33SJames Morse 	if (resctrl_arch_is_llc_occupancy_enabled()) {
40907168ae33SJames Morse 		d->rmid_busy_llc = bitmap_zalloc(idx_limit, GFP_KERNEL);
40917168ae33SJames Morse 		if (!d->rmid_busy_llc)
40927168ae33SJames Morse 			return -ENOMEM;
40937168ae33SJames Morse 	}
40947168ae33SJames Morse 	if (resctrl_arch_is_mbm_total_enabled()) {
40957168ae33SJames Morse 		tsize = sizeof(*d->mbm_total);
40967168ae33SJames Morse 		d->mbm_total = kcalloc(idx_limit, tsize, GFP_KERNEL);
40977168ae33SJames Morse 		if (!d->mbm_total) {
40987168ae33SJames Morse 			bitmap_free(d->rmid_busy_llc);
40997168ae33SJames Morse 			return -ENOMEM;
41007168ae33SJames Morse 		}
41017168ae33SJames Morse 	}
41027168ae33SJames Morse 	if (resctrl_arch_is_mbm_local_enabled()) {
41037168ae33SJames Morse 		tsize = sizeof(*d->mbm_local);
41047168ae33SJames Morse 		d->mbm_local = kcalloc(idx_limit, tsize, GFP_KERNEL);
41057168ae33SJames Morse 		if (!d->mbm_local) {
41067168ae33SJames Morse 			bitmap_free(d->rmid_busy_llc);
41077168ae33SJames Morse 			kfree(d->mbm_total);
41087168ae33SJames Morse 			return -ENOMEM;
41097168ae33SJames Morse 		}
41107168ae33SJames Morse 	}
41117168ae33SJames Morse 
41127168ae33SJames Morse 	return 0;
41137168ae33SJames Morse }
41147168ae33SJames Morse 
resctrl_online_ctrl_domain(struct rdt_resource * r,struct rdt_ctrl_domain * d)41157168ae33SJames Morse int resctrl_online_ctrl_domain(struct rdt_resource *r, struct rdt_ctrl_domain *d)
41167168ae33SJames Morse {
41177168ae33SJames Morse 	int err = 0;
41187168ae33SJames Morse 
41197168ae33SJames Morse 	mutex_lock(&rdtgroup_mutex);
41207168ae33SJames Morse 
41217168ae33SJames Morse 	if (supports_mba_mbps() && r->rid == RDT_RESOURCE_MBA) {
41227168ae33SJames Morse 		/* RDT_RESOURCE_MBA is never mon_capable */
41237168ae33SJames Morse 		err = mba_sc_domain_allocate(r, d);
41247168ae33SJames Morse 	}
41257168ae33SJames Morse 
41267168ae33SJames Morse 	mutex_unlock(&rdtgroup_mutex);
41277168ae33SJames Morse 
41287168ae33SJames Morse 	return err;
41297168ae33SJames Morse }
41307168ae33SJames Morse 
resctrl_online_mon_domain(struct rdt_resource * r,struct rdt_mon_domain * d)41317168ae33SJames Morse int resctrl_online_mon_domain(struct rdt_resource *r, struct rdt_mon_domain *d)
41327168ae33SJames Morse {
41337168ae33SJames Morse 	int err;
41347168ae33SJames Morse 
41357168ae33SJames Morse 	mutex_lock(&rdtgroup_mutex);
41367168ae33SJames Morse 
41377168ae33SJames Morse 	err = domain_setup_mon_state(r, d);
41387168ae33SJames Morse 	if (err)
41397168ae33SJames Morse 		goto out_unlock;
41407168ae33SJames Morse 
41417168ae33SJames Morse 	if (resctrl_is_mbm_enabled()) {
41427168ae33SJames Morse 		INIT_DELAYED_WORK(&d->mbm_over, mbm_handle_overflow);
41437168ae33SJames Morse 		mbm_setup_overflow_handler(d, MBM_OVERFLOW_INTERVAL,
41447168ae33SJames Morse 					   RESCTRL_PICK_ANY_CPU);
41457168ae33SJames Morse 	}
41467168ae33SJames Morse 
41477168ae33SJames Morse 	if (resctrl_arch_is_llc_occupancy_enabled())
41487168ae33SJames Morse 		INIT_DELAYED_WORK(&d->cqm_limbo, cqm_handle_limbo);
41497168ae33SJames Morse 
41507168ae33SJames Morse 	/*
41517168ae33SJames Morse 	 * If the filesystem is not mounted then only the default resource group
41527168ae33SJames Morse 	 * exists. Creation of its directories is deferred until mount time
41537168ae33SJames Morse 	 * by rdt_get_tree() calling mkdir_mondata_all().
41547168ae33SJames Morse 	 * If resctrl is mounted, add per domain monitor data directories.
41557168ae33SJames Morse 	 */
41567168ae33SJames Morse 	if (resctrl_mounted && resctrl_arch_mon_capable())
41577168ae33SJames Morse 		mkdir_mondata_subdir_allrdtgrp(r, d);
41587168ae33SJames Morse 
41597168ae33SJames Morse out_unlock:
41607168ae33SJames Morse 	mutex_unlock(&rdtgroup_mutex);
41617168ae33SJames Morse 
41627168ae33SJames Morse 	return err;
41637168ae33SJames Morse }
41647168ae33SJames Morse 
resctrl_online_cpu(unsigned int cpu)41657168ae33SJames Morse void resctrl_online_cpu(unsigned int cpu)
41667168ae33SJames Morse {
41677168ae33SJames Morse 	mutex_lock(&rdtgroup_mutex);
41687168ae33SJames Morse 	/* The CPU is set in default rdtgroup after online. */
41697168ae33SJames Morse 	cpumask_set_cpu(cpu, &rdtgroup_default.cpu_mask);
41707168ae33SJames Morse 	mutex_unlock(&rdtgroup_mutex);
41717168ae33SJames Morse }
41727168ae33SJames Morse 
clear_childcpus(struct rdtgroup * r,unsigned int cpu)41737168ae33SJames Morse static void clear_childcpus(struct rdtgroup *r, unsigned int cpu)
41747168ae33SJames Morse {
41757168ae33SJames Morse 	struct rdtgroup *cr;
41767168ae33SJames Morse 
41777168ae33SJames Morse 	list_for_each_entry(cr, &r->mon.crdtgrp_list, mon.crdtgrp_list) {
41787168ae33SJames Morse 		if (cpumask_test_and_clear_cpu(cpu, &cr->cpu_mask))
41797168ae33SJames Morse 			break;
41807168ae33SJames Morse 	}
41817168ae33SJames Morse }
41827168ae33SJames Morse 
get_mon_domain_from_cpu(int cpu,struct rdt_resource * r)41837168ae33SJames Morse static struct rdt_mon_domain *get_mon_domain_from_cpu(int cpu,
41847168ae33SJames Morse 						      struct rdt_resource *r)
41857168ae33SJames Morse {
41867168ae33SJames Morse 	struct rdt_mon_domain *d;
41877168ae33SJames Morse 
41887168ae33SJames Morse 	lockdep_assert_cpus_held();
41897168ae33SJames Morse 
41907168ae33SJames Morse 	list_for_each_entry(d, &r->mon_domains, hdr.list) {
41917168ae33SJames Morse 		/* Find the domain that contains this CPU */
41927168ae33SJames Morse 		if (cpumask_test_cpu(cpu, &d->hdr.cpu_mask))
41937168ae33SJames Morse 			return d;
41947168ae33SJames Morse 	}
41957168ae33SJames Morse 
41967168ae33SJames Morse 	return NULL;
41977168ae33SJames Morse }
41987168ae33SJames Morse 
resctrl_offline_cpu(unsigned int cpu)41997168ae33SJames Morse void resctrl_offline_cpu(unsigned int cpu)
42007168ae33SJames Morse {
42017168ae33SJames Morse 	struct rdt_resource *l3 = resctrl_arch_get_resource(RDT_RESOURCE_L3);
42027168ae33SJames Morse 	struct rdt_mon_domain *d;
42037168ae33SJames Morse 	struct rdtgroup *rdtgrp;
42047168ae33SJames Morse 
42057168ae33SJames Morse 	mutex_lock(&rdtgroup_mutex);
42067168ae33SJames Morse 	list_for_each_entry(rdtgrp, &rdt_all_groups, rdtgroup_list) {
42077168ae33SJames Morse 		if (cpumask_test_and_clear_cpu(cpu, &rdtgrp->cpu_mask)) {
42087168ae33SJames Morse 			clear_childcpus(rdtgrp, cpu);
42097168ae33SJames Morse 			break;
42107168ae33SJames Morse 		}
42117168ae33SJames Morse 	}
42127168ae33SJames Morse 
42137168ae33SJames Morse 	if (!l3->mon_capable)
42147168ae33SJames Morse 		goto out_unlock;
42157168ae33SJames Morse 
42167168ae33SJames Morse 	d = get_mon_domain_from_cpu(cpu, l3);
42177168ae33SJames Morse 	if (d) {
42187168ae33SJames Morse 		if (resctrl_is_mbm_enabled() && cpu == d->mbm_work_cpu) {
42197168ae33SJames Morse 			cancel_delayed_work(&d->mbm_over);
42207168ae33SJames Morse 			mbm_setup_overflow_handler(d, 0, cpu);
42217168ae33SJames Morse 		}
42227168ae33SJames Morse 		if (resctrl_arch_is_llc_occupancy_enabled() &&
42237168ae33SJames Morse 		    cpu == d->cqm_work_cpu && has_busy_rmid(d)) {
42247168ae33SJames Morse 			cancel_delayed_work(&d->cqm_limbo);
42257168ae33SJames Morse 			cqm_setup_limbo_handler(d, 0, cpu);
42267168ae33SJames Morse 		}
42277168ae33SJames Morse 	}
42287168ae33SJames Morse 
42297168ae33SJames Morse out_unlock:
42307168ae33SJames Morse 	mutex_unlock(&rdtgroup_mutex);
42317168ae33SJames Morse }
42327168ae33SJames Morse 
42337168ae33SJames Morse /*
42347168ae33SJames Morse  * resctrl_init - resctrl filesystem initialization
42357168ae33SJames Morse  *
42367168ae33SJames Morse  * Setup resctrl file system including set up root, create mount point,
42377168ae33SJames Morse  * register resctrl filesystem, and initialize files under root directory.
42387168ae33SJames Morse  *
42397168ae33SJames Morse  * Return: 0 on success or -errno
42407168ae33SJames Morse  */
resctrl_init(void)42417168ae33SJames Morse int resctrl_init(void)
42427168ae33SJames Morse {
42437168ae33SJames Morse 	int ret = 0;
42447168ae33SJames Morse 
42457168ae33SJames Morse 	seq_buf_init(&last_cmd_status, last_cmd_status_buf,
42467168ae33SJames Morse 		     sizeof(last_cmd_status_buf));
42477168ae33SJames Morse 
42487168ae33SJames Morse 	rdtgroup_setup_default();
42497168ae33SJames Morse 
42507168ae33SJames Morse 	thread_throttle_mode_init();
42517168ae33SJames Morse 
42527168ae33SJames Morse 	ret = resctrl_mon_resource_init();
42537168ae33SJames Morse 	if (ret)
42547168ae33SJames Morse 		return ret;
42557168ae33SJames Morse 
42567168ae33SJames Morse 	ret = sysfs_create_mount_point(fs_kobj, "resctrl");
42577168ae33SJames Morse 	if (ret) {
42587168ae33SJames Morse 		resctrl_mon_resource_exit();
42597168ae33SJames Morse 		return ret;
42607168ae33SJames Morse 	}
42617168ae33SJames Morse 
42627168ae33SJames Morse 	ret = register_filesystem(&rdt_fs_type);
42637168ae33SJames Morse 	if (ret)
42647168ae33SJames Morse 		goto cleanup_mountpoint;
42657168ae33SJames Morse 
42667168ae33SJames Morse 	/*
42677168ae33SJames Morse 	 * Adding the resctrl debugfs directory here may not be ideal since
42687168ae33SJames Morse 	 * it would let the resctrl debugfs directory appear on the debugfs
42697168ae33SJames Morse 	 * filesystem before the resctrl filesystem is mounted.
42707168ae33SJames Morse 	 * It may also be ok since that would enable debugging of RDT before
42717168ae33SJames Morse 	 * resctrl is mounted.
42727168ae33SJames Morse 	 * The reason why the debugfs directory is created here and not in
42737168ae33SJames Morse 	 * rdt_get_tree() is because rdt_get_tree() takes rdtgroup_mutex and
42747168ae33SJames Morse 	 * during the debugfs directory creation also &sb->s_type->i_mutex_key
42757168ae33SJames Morse 	 * (the lockdep class of inode->i_rwsem). Other filesystem
42767168ae33SJames Morse 	 * interactions (eg. SyS_getdents) have the lock ordering:
42777168ae33SJames Morse 	 * &sb->s_type->i_mutex_key --> &mm->mmap_lock
42787168ae33SJames Morse 	 * During mmap(), called with &mm->mmap_lock, the rdtgroup_mutex
42797168ae33SJames Morse 	 * is taken, thus creating dependency:
42807168ae33SJames Morse 	 * &mm->mmap_lock --> rdtgroup_mutex for the latter that can cause
42817168ae33SJames Morse 	 * issues considering the other two lock dependencies.
42827168ae33SJames Morse 	 * By creating the debugfs directory here we avoid a dependency
42837168ae33SJames Morse 	 * that may cause deadlock (even though file operations cannot
42847168ae33SJames Morse 	 * occur until the filesystem is mounted, but I do not know how to
42857168ae33SJames Morse 	 * tell lockdep that).
42867168ae33SJames Morse 	 */
42877168ae33SJames Morse 	debugfs_resctrl = debugfs_create_dir("resctrl", NULL);
42887168ae33SJames Morse 
42897168ae33SJames Morse 	return 0;
42907168ae33SJames Morse 
42917168ae33SJames Morse cleanup_mountpoint:
42927168ae33SJames Morse 	sysfs_remove_mount_point(fs_kobj, "resctrl");
42937168ae33SJames Morse 	resctrl_mon_resource_exit();
42947168ae33SJames Morse 
42957168ae33SJames Morse 	return ret;
42967168ae33SJames Morse }
42977168ae33SJames Morse 
resctrl_online_domains_exist(void)42987168ae33SJames Morse static bool resctrl_online_domains_exist(void)
42997168ae33SJames Morse {
43007168ae33SJames Morse 	struct rdt_resource *r;
43017168ae33SJames Morse 
43027168ae33SJames Morse 	/*
43037168ae33SJames Morse 	 * Only walk capable resources to allow resctrl_arch_get_resource()
43047168ae33SJames Morse 	 * to return dummy 'not capable' resources.
43057168ae33SJames Morse 	 */
43067168ae33SJames Morse 	for_each_alloc_capable_rdt_resource(r) {
43077168ae33SJames Morse 		if (!list_empty(&r->ctrl_domains))
43087168ae33SJames Morse 			return true;
43097168ae33SJames Morse 	}
43107168ae33SJames Morse 
43117168ae33SJames Morse 	for_each_mon_capable_rdt_resource(r) {
43127168ae33SJames Morse 		if (!list_empty(&r->mon_domains))
43137168ae33SJames Morse 			return true;
43147168ae33SJames Morse 	}
43157168ae33SJames Morse 
43167168ae33SJames Morse 	return false;
43177168ae33SJames Morse }
43187168ae33SJames Morse 
43197168ae33SJames Morse /**
43207168ae33SJames Morse  * resctrl_exit() - Remove the resctrl filesystem and free resources.
43217168ae33SJames Morse  *
43227168ae33SJames Morse  * Called by the architecture code in response to a fatal error.
43237168ae33SJames Morse  * Removes resctrl files and structures from kernfs to prevent further
43247168ae33SJames Morse  * configuration.
43257168ae33SJames Morse  *
43267168ae33SJames Morse  * When called by the architecture code, all CPUs and resctrl domains must be
43277168ae33SJames Morse  * offline. This ensures the limbo and overflow handlers are not scheduled to
43287168ae33SJames Morse  * run, meaning the data structures they access can be freed by
43297168ae33SJames Morse  * resctrl_mon_resource_exit().
43307168ae33SJames Morse  *
43317168ae33SJames Morse  * After resctrl_exit() returns, the architecture code should return an
43327168ae33SJames Morse  * error from all resctrl_arch_ functions that can do this.
43337168ae33SJames Morse  * resctrl_arch_get_resource() must continue to return struct rdt_resources
43347168ae33SJames Morse  * with the correct rid field to ensure the filesystem can be unmounted.
43357168ae33SJames Morse  */
resctrl_exit(void)43367168ae33SJames Morse void resctrl_exit(void)
43377168ae33SJames Morse {
43387168ae33SJames Morse 	cpus_read_lock();
43397168ae33SJames Morse 	WARN_ON_ONCE(resctrl_online_domains_exist());
43407168ae33SJames Morse 
43417168ae33SJames Morse 	mutex_lock(&rdtgroup_mutex);
43427168ae33SJames Morse 	resctrl_fs_teardown();
43437168ae33SJames Morse 	mutex_unlock(&rdtgroup_mutex);
43447168ae33SJames Morse 
43457168ae33SJames Morse 	cpus_read_unlock();
43467168ae33SJames Morse 
43477168ae33SJames Morse 	debugfs_remove_recursive(debugfs_resctrl);
43487168ae33SJames Morse 	debugfs_resctrl = NULL;
43497168ae33SJames Morse 	unregister_filesystem(&rdt_fs_type);
43507168ae33SJames Morse 
43517168ae33SJames Morse 	/*
43527168ae33SJames Morse 	 * Do not remove the sysfs mount point added by resctrl_init() so that
43537168ae33SJames Morse 	 * it can be used to umount resctrl.
43547168ae33SJames Morse 	 */
43557168ae33SJames Morse 
43567168ae33SJames Morse 	resctrl_mon_resource_exit();
43577168ae33SJames Morse }
4358