xref: /openbmc/linux/arch/x86/kernel/cpu/resctrl/rdtgroup.c (revision fa7d949337ccad32c76740c88e0e0351c349053b)
1*fa7d9493SBabu Moger /*
2*fa7d9493SBabu Moger  * User interface for Resource Alloction in Resource Director Technology(RDT)
3*fa7d9493SBabu Moger  *
4*fa7d9493SBabu Moger  * Copyright (C) 2016 Intel Corporation
5*fa7d9493SBabu Moger  *
6*fa7d9493SBabu Moger  * Author: Fenghua Yu <fenghua.yu@intel.com>
7*fa7d9493SBabu Moger  *
8*fa7d9493SBabu Moger  * This program is free software; you can redistribute it and/or modify it
9*fa7d9493SBabu Moger  * under the terms and conditions of the GNU General Public License,
10*fa7d9493SBabu Moger  * version 2, as published by the Free Software Foundation.
11*fa7d9493SBabu Moger  *
12*fa7d9493SBabu Moger  * This program is distributed in the hope it will be useful, but WITHOUT
13*fa7d9493SBabu Moger  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14*fa7d9493SBabu Moger  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15*fa7d9493SBabu Moger  * more details.
16*fa7d9493SBabu Moger  *
17*fa7d9493SBabu Moger  * More information about RDT be found in the Intel (R) x86 Architecture
18*fa7d9493SBabu Moger  * Software Developer Manual.
19*fa7d9493SBabu Moger  */
20*fa7d9493SBabu Moger 
21*fa7d9493SBabu Moger #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
22*fa7d9493SBabu Moger 
23*fa7d9493SBabu Moger #include <linux/cacheinfo.h>
24*fa7d9493SBabu Moger #include <linux/cpu.h>
25*fa7d9493SBabu Moger #include <linux/debugfs.h>
26*fa7d9493SBabu Moger #include <linux/fs.h>
27*fa7d9493SBabu Moger #include <linux/sysfs.h>
28*fa7d9493SBabu Moger #include <linux/kernfs.h>
29*fa7d9493SBabu Moger #include <linux/seq_buf.h>
30*fa7d9493SBabu Moger #include <linux/seq_file.h>
31*fa7d9493SBabu Moger #include <linux/sched/signal.h>
32*fa7d9493SBabu Moger #include <linux/sched/task.h>
33*fa7d9493SBabu Moger #include <linux/slab.h>
34*fa7d9493SBabu Moger #include <linux/task_work.h>
35*fa7d9493SBabu Moger 
36*fa7d9493SBabu Moger #include <uapi/linux/magic.h>
37*fa7d9493SBabu Moger 
38*fa7d9493SBabu Moger #include <asm/resctrl_sched.h>
39*fa7d9493SBabu Moger #include "internal.h"
40*fa7d9493SBabu Moger 
41*fa7d9493SBabu Moger DEFINE_STATIC_KEY_FALSE(rdt_enable_key);
42*fa7d9493SBabu Moger DEFINE_STATIC_KEY_FALSE(rdt_mon_enable_key);
43*fa7d9493SBabu Moger DEFINE_STATIC_KEY_FALSE(rdt_alloc_enable_key);
44*fa7d9493SBabu Moger static struct kernfs_root *rdt_root;
45*fa7d9493SBabu Moger struct rdtgroup rdtgroup_default;
46*fa7d9493SBabu Moger LIST_HEAD(rdt_all_groups);
47*fa7d9493SBabu Moger 
48*fa7d9493SBabu Moger /* Kernel fs node for "info" directory under root */
49*fa7d9493SBabu Moger static struct kernfs_node *kn_info;
50*fa7d9493SBabu Moger 
51*fa7d9493SBabu Moger /* Kernel fs node for "mon_groups" directory under root */
52*fa7d9493SBabu Moger static struct kernfs_node *kn_mongrp;
53*fa7d9493SBabu Moger 
54*fa7d9493SBabu Moger /* Kernel fs node for "mon_data" directory under root */
55*fa7d9493SBabu Moger static struct kernfs_node *kn_mondata;
56*fa7d9493SBabu Moger 
57*fa7d9493SBabu Moger static struct seq_buf last_cmd_status;
58*fa7d9493SBabu Moger static char last_cmd_status_buf[512];
59*fa7d9493SBabu Moger 
60*fa7d9493SBabu Moger struct dentry *debugfs_resctrl;
61*fa7d9493SBabu Moger 
62*fa7d9493SBabu Moger void rdt_last_cmd_clear(void)
63*fa7d9493SBabu Moger {
64*fa7d9493SBabu Moger 	lockdep_assert_held(&rdtgroup_mutex);
65*fa7d9493SBabu Moger 	seq_buf_clear(&last_cmd_status);
66*fa7d9493SBabu Moger }
67*fa7d9493SBabu Moger 
68*fa7d9493SBabu Moger void rdt_last_cmd_puts(const char *s)
69*fa7d9493SBabu Moger {
70*fa7d9493SBabu Moger 	lockdep_assert_held(&rdtgroup_mutex);
71*fa7d9493SBabu Moger 	seq_buf_puts(&last_cmd_status, s);
72*fa7d9493SBabu Moger }
73*fa7d9493SBabu Moger 
74*fa7d9493SBabu Moger void rdt_last_cmd_printf(const char *fmt, ...)
75*fa7d9493SBabu Moger {
76*fa7d9493SBabu Moger 	va_list ap;
77*fa7d9493SBabu Moger 
78*fa7d9493SBabu Moger 	va_start(ap, fmt);
79*fa7d9493SBabu Moger 	lockdep_assert_held(&rdtgroup_mutex);
80*fa7d9493SBabu Moger 	seq_buf_vprintf(&last_cmd_status, fmt, ap);
81*fa7d9493SBabu Moger 	va_end(ap);
82*fa7d9493SBabu Moger }
83*fa7d9493SBabu Moger 
84*fa7d9493SBabu Moger /*
85*fa7d9493SBabu Moger  * Trivial allocator for CLOSIDs. Since h/w only supports a small number,
86*fa7d9493SBabu Moger  * we can keep a bitmap of free CLOSIDs in a single integer.
87*fa7d9493SBabu Moger  *
88*fa7d9493SBabu Moger  * Using a global CLOSID across all resources has some advantages and
89*fa7d9493SBabu Moger  * some drawbacks:
90*fa7d9493SBabu Moger  * + We can simply set "current->closid" to assign a task to a resource
91*fa7d9493SBabu Moger  *   group.
92*fa7d9493SBabu Moger  * + Context switch code can avoid extra memory references deciding which
93*fa7d9493SBabu Moger  *   CLOSID to load into the PQR_ASSOC MSR
94*fa7d9493SBabu Moger  * - We give up some options in configuring resource groups across multi-socket
95*fa7d9493SBabu Moger  *   systems.
96*fa7d9493SBabu Moger  * - Our choices on how to configure each resource become progressively more
97*fa7d9493SBabu Moger  *   limited as the number of resources grows.
98*fa7d9493SBabu Moger  */
99*fa7d9493SBabu Moger static int closid_free_map;
100*fa7d9493SBabu Moger static int closid_free_map_len;
101*fa7d9493SBabu Moger 
102*fa7d9493SBabu Moger int closids_supported(void)
103*fa7d9493SBabu Moger {
104*fa7d9493SBabu Moger 	return closid_free_map_len;
105*fa7d9493SBabu Moger }
106*fa7d9493SBabu Moger 
107*fa7d9493SBabu Moger static void closid_init(void)
108*fa7d9493SBabu Moger {
109*fa7d9493SBabu Moger 	struct rdt_resource *r;
110*fa7d9493SBabu Moger 	int rdt_min_closid = 32;
111*fa7d9493SBabu Moger 
112*fa7d9493SBabu Moger 	/* Compute rdt_min_closid across all resources */
113*fa7d9493SBabu Moger 	for_each_alloc_enabled_rdt_resource(r)
114*fa7d9493SBabu Moger 		rdt_min_closid = min(rdt_min_closid, r->num_closid);
115*fa7d9493SBabu Moger 
116*fa7d9493SBabu Moger 	closid_free_map = BIT_MASK(rdt_min_closid) - 1;
117*fa7d9493SBabu Moger 
118*fa7d9493SBabu Moger 	/* CLOSID 0 is always reserved for the default group */
119*fa7d9493SBabu Moger 	closid_free_map &= ~1;
120*fa7d9493SBabu Moger 	closid_free_map_len = rdt_min_closid;
121*fa7d9493SBabu Moger }
122*fa7d9493SBabu Moger 
123*fa7d9493SBabu Moger static int closid_alloc(void)
124*fa7d9493SBabu Moger {
125*fa7d9493SBabu Moger 	u32 closid = ffs(closid_free_map);
126*fa7d9493SBabu Moger 
127*fa7d9493SBabu Moger 	if (closid == 0)
128*fa7d9493SBabu Moger 		return -ENOSPC;
129*fa7d9493SBabu Moger 	closid--;
130*fa7d9493SBabu Moger 	closid_free_map &= ~(1 << closid);
131*fa7d9493SBabu Moger 
132*fa7d9493SBabu Moger 	return closid;
133*fa7d9493SBabu Moger }
134*fa7d9493SBabu Moger 
135*fa7d9493SBabu Moger void closid_free(int closid)
136*fa7d9493SBabu Moger {
137*fa7d9493SBabu Moger 	closid_free_map |= 1 << closid;
138*fa7d9493SBabu Moger }
139*fa7d9493SBabu Moger 
140*fa7d9493SBabu Moger /**
141*fa7d9493SBabu Moger  * closid_allocated - test if provided closid is in use
142*fa7d9493SBabu Moger  * @closid: closid to be tested
143*fa7d9493SBabu Moger  *
144*fa7d9493SBabu Moger  * Return: true if @closid is currently associated with a resource group,
145*fa7d9493SBabu Moger  * false if @closid is free
146*fa7d9493SBabu Moger  */
147*fa7d9493SBabu Moger static bool closid_allocated(unsigned int closid)
148*fa7d9493SBabu Moger {
149*fa7d9493SBabu Moger 	return (closid_free_map & (1 << closid)) == 0;
150*fa7d9493SBabu Moger }
151*fa7d9493SBabu Moger 
152*fa7d9493SBabu Moger /**
153*fa7d9493SBabu Moger  * rdtgroup_mode_by_closid - Return mode of resource group with closid
154*fa7d9493SBabu Moger  * @closid: closid if the resource group
155*fa7d9493SBabu Moger  *
156*fa7d9493SBabu Moger  * Each resource group is associated with a @closid. Here the mode
157*fa7d9493SBabu Moger  * of a resource group can be queried by searching for it using its closid.
158*fa7d9493SBabu Moger  *
159*fa7d9493SBabu Moger  * Return: mode as &enum rdtgrp_mode of resource group with closid @closid
160*fa7d9493SBabu Moger  */
161*fa7d9493SBabu Moger enum rdtgrp_mode rdtgroup_mode_by_closid(int closid)
162*fa7d9493SBabu Moger {
163*fa7d9493SBabu Moger 	struct rdtgroup *rdtgrp;
164*fa7d9493SBabu Moger 
165*fa7d9493SBabu Moger 	list_for_each_entry(rdtgrp, &rdt_all_groups, rdtgroup_list) {
166*fa7d9493SBabu Moger 		if (rdtgrp->closid == closid)
167*fa7d9493SBabu Moger 			return rdtgrp->mode;
168*fa7d9493SBabu Moger 	}
169*fa7d9493SBabu Moger 
170*fa7d9493SBabu Moger 	return RDT_NUM_MODES;
171*fa7d9493SBabu Moger }
172*fa7d9493SBabu Moger 
173*fa7d9493SBabu Moger static const char * const rdt_mode_str[] = {
174*fa7d9493SBabu Moger 	[RDT_MODE_SHAREABLE]		= "shareable",
175*fa7d9493SBabu Moger 	[RDT_MODE_EXCLUSIVE]		= "exclusive",
176*fa7d9493SBabu Moger 	[RDT_MODE_PSEUDO_LOCKSETUP]	= "pseudo-locksetup",
177*fa7d9493SBabu Moger 	[RDT_MODE_PSEUDO_LOCKED]	= "pseudo-locked",
178*fa7d9493SBabu Moger };
179*fa7d9493SBabu Moger 
180*fa7d9493SBabu Moger /**
181*fa7d9493SBabu Moger  * rdtgroup_mode_str - Return the string representation of mode
182*fa7d9493SBabu Moger  * @mode: the resource group mode as &enum rdtgroup_mode
183*fa7d9493SBabu Moger  *
184*fa7d9493SBabu Moger  * Return: string representation of valid mode, "unknown" otherwise
185*fa7d9493SBabu Moger  */
186*fa7d9493SBabu Moger static const char *rdtgroup_mode_str(enum rdtgrp_mode mode)
187*fa7d9493SBabu Moger {
188*fa7d9493SBabu Moger 	if (mode < RDT_MODE_SHAREABLE || mode >= RDT_NUM_MODES)
189*fa7d9493SBabu Moger 		return "unknown";
190*fa7d9493SBabu Moger 
191*fa7d9493SBabu Moger 	return rdt_mode_str[mode];
192*fa7d9493SBabu Moger }
193*fa7d9493SBabu Moger 
194*fa7d9493SBabu Moger /* set uid and gid of rdtgroup dirs and files to that of the creator */
195*fa7d9493SBabu Moger static int rdtgroup_kn_set_ugid(struct kernfs_node *kn)
196*fa7d9493SBabu Moger {
197*fa7d9493SBabu Moger 	struct iattr iattr = { .ia_valid = ATTR_UID | ATTR_GID,
198*fa7d9493SBabu Moger 				.ia_uid = current_fsuid(),
199*fa7d9493SBabu Moger 				.ia_gid = current_fsgid(), };
200*fa7d9493SBabu Moger 
201*fa7d9493SBabu Moger 	if (uid_eq(iattr.ia_uid, GLOBAL_ROOT_UID) &&
202*fa7d9493SBabu Moger 	    gid_eq(iattr.ia_gid, GLOBAL_ROOT_GID))
203*fa7d9493SBabu Moger 		return 0;
204*fa7d9493SBabu Moger 
205*fa7d9493SBabu Moger 	return kernfs_setattr(kn, &iattr);
206*fa7d9493SBabu Moger }
207*fa7d9493SBabu Moger 
208*fa7d9493SBabu Moger static int rdtgroup_add_file(struct kernfs_node *parent_kn, struct rftype *rft)
209*fa7d9493SBabu Moger {
210*fa7d9493SBabu Moger 	struct kernfs_node *kn;
211*fa7d9493SBabu Moger 	int ret;
212*fa7d9493SBabu Moger 
213*fa7d9493SBabu Moger 	kn = __kernfs_create_file(parent_kn, rft->name, rft->mode,
214*fa7d9493SBabu Moger 				  GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
215*fa7d9493SBabu Moger 				  0, rft->kf_ops, rft, NULL, NULL);
216*fa7d9493SBabu Moger 	if (IS_ERR(kn))
217*fa7d9493SBabu Moger 		return PTR_ERR(kn);
218*fa7d9493SBabu Moger 
219*fa7d9493SBabu Moger 	ret = rdtgroup_kn_set_ugid(kn);
220*fa7d9493SBabu Moger 	if (ret) {
221*fa7d9493SBabu Moger 		kernfs_remove(kn);
222*fa7d9493SBabu Moger 		return ret;
223*fa7d9493SBabu Moger 	}
224*fa7d9493SBabu Moger 
225*fa7d9493SBabu Moger 	return 0;
226*fa7d9493SBabu Moger }
227*fa7d9493SBabu Moger 
228*fa7d9493SBabu Moger static int rdtgroup_seqfile_show(struct seq_file *m, void *arg)
229*fa7d9493SBabu Moger {
230*fa7d9493SBabu Moger 	struct kernfs_open_file *of = m->private;
231*fa7d9493SBabu Moger 	struct rftype *rft = of->kn->priv;
232*fa7d9493SBabu Moger 
233*fa7d9493SBabu Moger 	if (rft->seq_show)
234*fa7d9493SBabu Moger 		return rft->seq_show(of, m, arg);
235*fa7d9493SBabu Moger 	return 0;
236*fa7d9493SBabu Moger }
237*fa7d9493SBabu Moger 
238*fa7d9493SBabu Moger static ssize_t rdtgroup_file_write(struct kernfs_open_file *of, char *buf,
239*fa7d9493SBabu Moger 				   size_t nbytes, loff_t off)
240*fa7d9493SBabu Moger {
241*fa7d9493SBabu Moger 	struct rftype *rft = of->kn->priv;
242*fa7d9493SBabu Moger 
243*fa7d9493SBabu Moger 	if (rft->write)
244*fa7d9493SBabu Moger 		return rft->write(of, buf, nbytes, off);
245*fa7d9493SBabu Moger 
246*fa7d9493SBabu Moger 	return -EINVAL;
247*fa7d9493SBabu Moger }
248*fa7d9493SBabu Moger 
249*fa7d9493SBabu Moger static struct kernfs_ops rdtgroup_kf_single_ops = {
250*fa7d9493SBabu Moger 	.atomic_write_len	= PAGE_SIZE,
251*fa7d9493SBabu Moger 	.write			= rdtgroup_file_write,
252*fa7d9493SBabu Moger 	.seq_show		= rdtgroup_seqfile_show,
253*fa7d9493SBabu Moger };
254*fa7d9493SBabu Moger 
255*fa7d9493SBabu Moger static struct kernfs_ops kf_mondata_ops = {
256*fa7d9493SBabu Moger 	.atomic_write_len	= PAGE_SIZE,
257*fa7d9493SBabu Moger 	.seq_show		= rdtgroup_mondata_show,
258*fa7d9493SBabu Moger };
259*fa7d9493SBabu Moger 
260*fa7d9493SBabu Moger static bool is_cpu_list(struct kernfs_open_file *of)
261*fa7d9493SBabu Moger {
262*fa7d9493SBabu Moger 	struct rftype *rft = of->kn->priv;
263*fa7d9493SBabu Moger 
264*fa7d9493SBabu Moger 	return rft->flags & RFTYPE_FLAGS_CPUS_LIST;
265*fa7d9493SBabu Moger }
266*fa7d9493SBabu Moger 
267*fa7d9493SBabu Moger static int rdtgroup_cpus_show(struct kernfs_open_file *of,
268*fa7d9493SBabu Moger 			      struct seq_file *s, void *v)
269*fa7d9493SBabu Moger {
270*fa7d9493SBabu Moger 	struct rdtgroup *rdtgrp;
271*fa7d9493SBabu Moger 	struct cpumask *mask;
272*fa7d9493SBabu Moger 	int ret = 0;
273*fa7d9493SBabu Moger 
274*fa7d9493SBabu Moger 	rdtgrp = rdtgroup_kn_lock_live(of->kn);
275*fa7d9493SBabu Moger 
276*fa7d9493SBabu Moger 	if (rdtgrp) {
277*fa7d9493SBabu Moger 		if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
278*fa7d9493SBabu Moger 			if (!rdtgrp->plr->d) {
279*fa7d9493SBabu Moger 				rdt_last_cmd_clear();
280*fa7d9493SBabu Moger 				rdt_last_cmd_puts("Cache domain offline\n");
281*fa7d9493SBabu Moger 				ret = -ENODEV;
282*fa7d9493SBabu Moger 			} else {
283*fa7d9493SBabu Moger 				mask = &rdtgrp->plr->d->cpu_mask;
284*fa7d9493SBabu Moger 				seq_printf(s, is_cpu_list(of) ?
285*fa7d9493SBabu Moger 					   "%*pbl\n" : "%*pb\n",
286*fa7d9493SBabu Moger 					   cpumask_pr_args(mask));
287*fa7d9493SBabu Moger 			}
288*fa7d9493SBabu Moger 		} else {
289*fa7d9493SBabu Moger 			seq_printf(s, is_cpu_list(of) ? "%*pbl\n" : "%*pb\n",
290*fa7d9493SBabu Moger 				   cpumask_pr_args(&rdtgrp->cpu_mask));
291*fa7d9493SBabu Moger 		}
292*fa7d9493SBabu Moger 	} else {
293*fa7d9493SBabu Moger 		ret = -ENOENT;
294*fa7d9493SBabu Moger 	}
295*fa7d9493SBabu Moger 	rdtgroup_kn_unlock(of->kn);
296*fa7d9493SBabu Moger 
297*fa7d9493SBabu Moger 	return ret;
298*fa7d9493SBabu Moger }
299*fa7d9493SBabu Moger 
300*fa7d9493SBabu Moger /*
301*fa7d9493SBabu Moger  * This is safe against intel_rdt_sched_in() called from __switch_to()
302*fa7d9493SBabu Moger  * because __switch_to() is executed with interrupts disabled. A local call
303*fa7d9493SBabu Moger  * from update_closid_rmid() is proteced against __switch_to() because
304*fa7d9493SBabu Moger  * preemption is disabled.
305*fa7d9493SBabu Moger  */
306*fa7d9493SBabu Moger static void update_cpu_closid_rmid(void *info)
307*fa7d9493SBabu Moger {
308*fa7d9493SBabu Moger 	struct rdtgroup *r = info;
309*fa7d9493SBabu Moger 
310*fa7d9493SBabu Moger 	if (r) {
311*fa7d9493SBabu Moger 		this_cpu_write(pqr_state.default_closid, r->closid);
312*fa7d9493SBabu Moger 		this_cpu_write(pqr_state.default_rmid, r->mon.rmid);
313*fa7d9493SBabu Moger 	}
314*fa7d9493SBabu Moger 
315*fa7d9493SBabu Moger 	/*
316*fa7d9493SBabu Moger 	 * We cannot unconditionally write the MSR because the current
317*fa7d9493SBabu Moger 	 * executing task might have its own closid selected. Just reuse
318*fa7d9493SBabu Moger 	 * the context switch code.
319*fa7d9493SBabu Moger 	 */
320*fa7d9493SBabu Moger 	intel_rdt_sched_in();
321*fa7d9493SBabu Moger }
322*fa7d9493SBabu Moger 
323*fa7d9493SBabu Moger /*
324*fa7d9493SBabu Moger  * Update the PGR_ASSOC MSR on all cpus in @cpu_mask,
325*fa7d9493SBabu Moger  *
326*fa7d9493SBabu Moger  * Per task closids/rmids must have been set up before calling this function.
327*fa7d9493SBabu Moger  */
328*fa7d9493SBabu Moger static void
329*fa7d9493SBabu Moger update_closid_rmid(const struct cpumask *cpu_mask, struct rdtgroup *r)
330*fa7d9493SBabu Moger {
331*fa7d9493SBabu Moger 	int cpu = get_cpu();
332*fa7d9493SBabu Moger 
333*fa7d9493SBabu Moger 	if (cpumask_test_cpu(cpu, cpu_mask))
334*fa7d9493SBabu Moger 		update_cpu_closid_rmid(r);
335*fa7d9493SBabu Moger 	smp_call_function_many(cpu_mask, update_cpu_closid_rmid, r, 1);
336*fa7d9493SBabu Moger 	put_cpu();
337*fa7d9493SBabu Moger }
338*fa7d9493SBabu Moger 
339*fa7d9493SBabu Moger static int cpus_mon_write(struct rdtgroup *rdtgrp, cpumask_var_t newmask,
340*fa7d9493SBabu Moger 			  cpumask_var_t tmpmask)
341*fa7d9493SBabu Moger {
342*fa7d9493SBabu Moger 	struct rdtgroup *prgrp = rdtgrp->mon.parent, *crgrp;
343*fa7d9493SBabu Moger 	struct list_head *head;
344*fa7d9493SBabu Moger 
345*fa7d9493SBabu Moger 	/* Check whether cpus belong to parent ctrl group */
346*fa7d9493SBabu Moger 	cpumask_andnot(tmpmask, newmask, &prgrp->cpu_mask);
347*fa7d9493SBabu Moger 	if (cpumask_weight(tmpmask)) {
348*fa7d9493SBabu Moger 		rdt_last_cmd_puts("can only add CPUs to mongroup that belong to parent\n");
349*fa7d9493SBabu Moger 		return -EINVAL;
350*fa7d9493SBabu Moger 	}
351*fa7d9493SBabu Moger 
352*fa7d9493SBabu Moger 	/* Check whether cpus are dropped from this group */
353*fa7d9493SBabu Moger 	cpumask_andnot(tmpmask, &rdtgrp->cpu_mask, newmask);
354*fa7d9493SBabu Moger 	if (cpumask_weight(tmpmask)) {
355*fa7d9493SBabu Moger 		/* Give any dropped cpus to parent rdtgroup */
356*fa7d9493SBabu Moger 		cpumask_or(&prgrp->cpu_mask, &prgrp->cpu_mask, tmpmask);
357*fa7d9493SBabu Moger 		update_closid_rmid(tmpmask, prgrp);
358*fa7d9493SBabu Moger 	}
359*fa7d9493SBabu Moger 
360*fa7d9493SBabu Moger 	/*
361*fa7d9493SBabu Moger 	 * If we added cpus, remove them from previous group that owned them
362*fa7d9493SBabu Moger 	 * and update per-cpu rmid
363*fa7d9493SBabu Moger 	 */
364*fa7d9493SBabu Moger 	cpumask_andnot(tmpmask, newmask, &rdtgrp->cpu_mask);
365*fa7d9493SBabu Moger 	if (cpumask_weight(tmpmask)) {
366*fa7d9493SBabu Moger 		head = &prgrp->mon.crdtgrp_list;
367*fa7d9493SBabu Moger 		list_for_each_entry(crgrp, head, mon.crdtgrp_list) {
368*fa7d9493SBabu Moger 			if (crgrp == rdtgrp)
369*fa7d9493SBabu Moger 				continue;
370*fa7d9493SBabu Moger 			cpumask_andnot(&crgrp->cpu_mask, &crgrp->cpu_mask,
371*fa7d9493SBabu Moger 				       tmpmask);
372*fa7d9493SBabu Moger 		}
373*fa7d9493SBabu Moger 		update_closid_rmid(tmpmask, rdtgrp);
374*fa7d9493SBabu Moger 	}
375*fa7d9493SBabu Moger 
376*fa7d9493SBabu Moger 	/* Done pushing/pulling - update this group with new mask */
377*fa7d9493SBabu Moger 	cpumask_copy(&rdtgrp->cpu_mask, newmask);
378*fa7d9493SBabu Moger 
379*fa7d9493SBabu Moger 	return 0;
380*fa7d9493SBabu Moger }
381*fa7d9493SBabu Moger 
382*fa7d9493SBabu Moger static void cpumask_rdtgrp_clear(struct rdtgroup *r, struct cpumask *m)
383*fa7d9493SBabu Moger {
384*fa7d9493SBabu Moger 	struct rdtgroup *crgrp;
385*fa7d9493SBabu Moger 
386*fa7d9493SBabu Moger 	cpumask_andnot(&r->cpu_mask, &r->cpu_mask, m);
387*fa7d9493SBabu Moger 	/* update the child mon group masks as well*/
388*fa7d9493SBabu Moger 	list_for_each_entry(crgrp, &r->mon.crdtgrp_list, mon.crdtgrp_list)
389*fa7d9493SBabu Moger 		cpumask_and(&crgrp->cpu_mask, &r->cpu_mask, &crgrp->cpu_mask);
390*fa7d9493SBabu Moger }
391*fa7d9493SBabu Moger 
392*fa7d9493SBabu Moger static int cpus_ctrl_write(struct rdtgroup *rdtgrp, cpumask_var_t newmask,
393*fa7d9493SBabu Moger 			   cpumask_var_t tmpmask, cpumask_var_t tmpmask1)
394*fa7d9493SBabu Moger {
395*fa7d9493SBabu Moger 	struct rdtgroup *r, *crgrp;
396*fa7d9493SBabu Moger 	struct list_head *head;
397*fa7d9493SBabu Moger 
398*fa7d9493SBabu Moger 	/* Check whether cpus are dropped from this group */
399*fa7d9493SBabu Moger 	cpumask_andnot(tmpmask, &rdtgrp->cpu_mask, newmask);
400*fa7d9493SBabu Moger 	if (cpumask_weight(tmpmask)) {
401*fa7d9493SBabu Moger 		/* Can't drop from default group */
402*fa7d9493SBabu Moger 		if (rdtgrp == &rdtgroup_default) {
403*fa7d9493SBabu Moger 			rdt_last_cmd_puts("Can't drop CPUs from default group\n");
404*fa7d9493SBabu Moger 			return -EINVAL;
405*fa7d9493SBabu Moger 		}
406*fa7d9493SBabu Moger 
407*fa7d9493SBabu Moger 		/* Give any dropped cpus to rdtgroup_default */
408*fa7d9493SBabu Moger 		cpumask_or(&rdtgroup_default.cpu_mask,
409*fa7d9493SBabu Moger 			   &rdtgroup_default.cpu_mask, tmpmask);
410*fa7d9493SBabu Moger 		update_closid_rmid(tmpmask, &rdtgroup_default);
411*fa7d9493SBabu Moger 	}
412*fa7d9493SBabu Moger 
413*fa7d9493SBabu Moger 	/*
414*fa7d9493SBabu Moger 	 * If we added cpus, remove them from previous group and
415*fa7d9493SBabu Moger 	 * the prev group's child groups that owned them
416*fa7d9493SBabu Moger 	 * and update per-cpu closid/rmid.
417*fa7d9493SBabu Moger 	 */
418*fa7d9493SBabu Moger 	cpumask_andnot(tmpmask, newmask, &rdtgrp->cpu_mask);
419*fa7d9493SBabu Moger 	if (cpumask_weight(tmpmask)) {
420*fa7d9493SBabu Moger 		list_for_each_entry(r, &rdt_all_groups, rdtgroup_list) {
421*fa7d9493SBabu Moger 			if (r == rdtgrp)
422*fa7d9493SBabu Moger 				continue;
423*fa7d9493SBabu Moger 			cpumask_and(tmpmask1, &r->cpu_mask, tmpmask);
424*fa7d9493SBabu Moger 			if (cpumask_weight(tmpmask1))
425*fa7d9493SBabu Moger 				cpumask_rdtgrp_clear(r, tmpmask1);
426*fa7d9493SBabu Moger 		}
427*fa7d9493SBabu Moger 		update_closid_rmid(tmpmask, rdtgrp);
428*fa7d9493SBabu Moger 	}
429*fa7d9493SBabu Moger 
430*fa7d9493SBabu Moger 	/* Done pushing/pulling - update this group with new mask */
431*fa7d9493SBabu Moger 	cpumask_copy(&rdtgrp->cpu_mask, newmask);
432*fa7d9493SBabu Moger 
433*fa7d9493SBabu Moger 	/*
434*fa7d9493SBabu Moger 	 * Clear child mon group masks since there is a new parent mask
435*fa7d9493SBabu Moger 	 * now and update the rmid for the cpus the child lost.
436*fa7d9493SBabu Moger 	 */
437*fa7d9493SBabu Moger 	head = &rdtgrp->mon.crdtgrp_list;
438*fa7d9493SBabu Moger 	list_for_each_entry(crgrp, head, mon.crdtgrp_list) {
439*fa7d9493SBabu Moger 		cpumask_and(tmpmask, &rdtgrp->cpu_mask, &crgrp->cpu_mask);
440*fa7d9493SBabu Moger 		update_closid_rmid(tmpmask, rdtgrp);
441*fa7d9493SBabu Moger 		cpumask_clear(&crgrp->cpu_mask);
442*fa7d9493SBabu Moger 	}
443*fa7d9493SBabu Moger 
444*fa7d9493SBabu Moger 	return 0;
445*fa7d9493SBabu Moger }
446*fa7d9493SBabu Moger 
447*fa7d9493SBabu Moger static ssize_t rdtgroup_cpus_write(struct kernfs_open_file *of,
448*fa7d9493SBabu Moger 				   char *buf, size_t nbytes, loff_t off)
449*fa7d9493SBabu Moger {
450*fa7d9493SBabu Moger 	cpumask_var_t tmpmask, newmask, tmpmask1;
451*fa7d9493SBabu Moger 	struct rdtgroup *rdtgrp;
452*fa7d9493SBabu Moger 	int ret;
453*fa7d9493SBabu Moger 
454*fa7d9493SBabu Moger 	if (!buf)
455*fa7d9493SBabu Moger 		return -EINVAL;
456*fa7d9493SBabu Moger 
457*fa7d9493SBabu Moger 	if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
458*fa7d9493SBabu Moger 		return -ENOMEM;
459*fa7d9493SBabu Moger 	if (!zalloc_cpumask_var(&newmask, GFP_KERNEL)) {
460*fa7d9493SBabu Moger 		free_cpumask_var(tmpmask);
461*fa7d9493SBabu Moger 		return -ENOMEM;
462*fa7d9493SBabu Moger 	}
463*fa7d9493SBabu Moger 	if (!zalloc_cpumask_var(&tmpmask1, GFP_KERNEL)) {
464*fa7d9493SBabu Moger 		free_cpumask_var(tmpmask);
465*fa7d9493SBabu Moger 		free_cpumask_var(newmask);
466*fa7d9493SBabu Moger 		return -ENOMEM;
467*fa7d9493SBabu Moger 	}
468*fa7d9493SBabu Moger 
469*fa7d9493SBabu Moger 	rdtgrp = rdtgroup_kn_lock_live(of->kn);
470*fa7d9493SBabu Moger 	rdt_last_cmd_clear();
471*fa7d9493SBabu Moger 	if (!rdtgrp) {
472*fa7d9493SBabu Moger 		ret = -ENOENT;
473*fa7d9493SBabu Moger 		rdt_last_cmd_puts("directory was removed\n");
474*fa7d9493SBabu Moger 		goto unlock;
475*fa7d9493SBabu Moger 	}
476*fa7d9493SBabu Moger 
477*fa7d9493SBabu Moger 	if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED ||
478*fa7d9493SBabu Moger 	    rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
479*fa7d9493SBabu Moger 		ret = -EINVAL;
480*fa7d9493SBabu Moger 		rdt_last_cmd_puts("pseudo-locking in progress\n");
481*fa7d9493SBabu Moger 		goto unlock;
482*fa7d9493SBabu Moger 	}
483*fa7d9493SBabu Moger 
484*fa7d9493SBabu Moger 	if (is_cpu_list(of))
485*fa7d9493SBabu Moger 		ret = cpulist_parse(buf, newmask);
486*fa7d9493SBabu Moger 	else
487*fa7d9493SBabu Moger 		ret = cpumask_parse(buf, newmask);
488*fa7d9493SBabu Moger 
489*fa7d9493SBabu Moger 	if (ret) {
490*fa7d9493SBabu Moger 		rdt_last_cmd_puts("bad cpu list/mask\n");
491*fa7d9493SBabu Moger 		goto unlock;
492*fa7d9493SBabu Moger 	}
493*fa7d9493SBabu Moger 
494*fa7d9493SBabu Moger 	/* check that user didn't specify any offline cpus */
495*fa7d9493SBabu Moger 	cpumask_andnot(tmpmask, newmask, cpu_online_mask);
496*fa7d9493SBabu Moger 	if (cpumask_weight(tmpmask)) {
497*fa7d9493SBabu Moger 		ret = -EINVAL;
498*fa7d9493SBabu Moger 		rdt_last_cmd_puts("can only assign online cpus\n");
499*fa7d9493SBabu Moger 		goto unlock;
500*fa7d9493SBabu Moger 	}
501*fa7d9493SBabu Moger 
502*fa7d9493SBabu Moger 	if (rdtgrp->type == RDTCTRL_GROUP)
503*fa7d9493SBabu Moger 		ret = cpus_ctrl_write(rdtgrp, newmask, tmpmask, tmpmask1);
504*fa7d9493SBabu Moger 	else if (rdtgrp->type == RDTMON_GROUP)
505*fa7d9493SBabu Moger 		ret = cpus_mon_write(rdtgrp, newmask, tmpmask);
506*fa7d9493SBabu Moger 	else
507*fa7d9493SBabu Moger 		ret = -EINVAL;
508*fa7d9493SBabu Moger 
509*fa7d9493SBabu Moger unlock:
510*fa7d9493SBabu Moger 	rdtgroup_kn_unlock(of->kn);
511*fa7d9493SBabu Moger 	free_cpumask_var(tmpmask);
512*fa7d9493SBabu Moger 	free_cpumask_var(newmask);
513*fa7d9493SBabu Moger 	free_cpumask_var(tmpmask1);
514*fa7d9493SBabu Moger 
515*fa7d9493SBabu Moger 	return ret ?: nbytes;
516*fa7d9493SBabu Moger }
517*fa7d9493SBabu Moger 
518*fa7d9493SBabu Moger struct task_move_callback {
519*fa7d9493SBabu Moger 	struct callback_head	work;
520*fa7d9493SBabu Moger 	struct rdtgroup		*rdtgrp;
521*fa7d9493SBabu Moger };
522*fa7d9493SBabu Moger 
523*fa7d9493SBabu Moger static void move_myself(struct callback_head *head)
524*fa7d9493SBabu Moger {
525*fa7d9493SBabu Moger 	struct task_move_callback *callback;
526*fa7d9493SBabu Moger 	struct rdtgroup *rdtgrp;
527*fa7d9493SBabu Moger 
528*fa7d9493SBabu Moger 	callback = container_of(head, struct task_move_callback, work);
529*fa7d9493SBabu Moger 	rdtgrp = callback->rdtgrp;
530*fa7d9493SBabu Moger 
531*fa7d9493SBabu Moger 	/*
532*fa7d9493SBabu Moger 	 * If resource group was deleted before this task work callback
533*fa7d9493SBabu Moger 	 * was invoked, then assign the task to root group and free the
534*fa7d9493SBabu Moger 	 * resource group.
535*fa7d9493SBabu Moger 	 */
536*fa7d9493SBabu Moger 	if (atomic_dec_and_test(&rdtgrp->waitcount) &&
537*fa7d9493SBabu Moger 	    (rdtgrp->flags & RDT_DELETED)) {
538*fa7d9493SBabu Moger 		current->closid = 0;
539*fa7d9493SBabu Moger 		current->rmid = 0;
540*fa7d9493SBabu Moger 		kfree(rdtgrp);
541*fa7d9493SBabu Moger 	}
542*fa7d9493SBabu Moger 
543*fa7d9493SBabu Moger 	preempt_disable();
544*fa7d9493SBabu Moger 	/* update PQR_ASSOC MSR to make resource group go into effect */
545*fa7d9493SBabu Moger 	intel_rdt_sched_in();
546*fa7d9493SBabu Moger 	preempt_enable();
547*fa7d9493SBabu Moger 
548*fa7d9493SBabu Moger 	kfree(callback);
549*fa7d9493SBabu Moger }
550*fa7d9493SBabu Moger 
551*fa7d9493SBabu Moger static int __rdtgroup_move_task(struct task_struct *tsk,
552*fa7d9493SBabu Moger 				struct rdtgroup *rdtgrp)
553*fa7d9493SBabu Moger {
554*fa7d9493SBabu Moger 	struct task_move_callback *callback;
555*fa7d9493SBabu Moger 	int ret;
556*fa7d9493SBabu Moger 
557*fa7d9493SBabu Moger 	callback = kzalloc(sizeof(*callback), GFP_KERNEL);
558*fa7d9493SBabu Moger 	if (!callback)
559*fa7d9493SBabu Moger 		return -ENOMEM;
560*fa7d9493SBabu Moger 	callback->work.func = move_myself;
561*fa7d9493SBabu Moger 	callback->rdtgrp = rdtgrp;
562*fa7d9493SBabu Moger 
563*fa7d9493SBabu Moger 	/*
564*fa7d9493SBabu Moger 	 * Take a refcount, so rdtgrp cannot be freed before the
565*fa7d9493SBabu Moger 	 * callback has been invoked.
566*fa7d9493SBabu Moger 	 */
567*fa7d9493SBabu Moger 	atomic_inc(&rdtgrp->waitcount);
568*fa7d9493SBabu Moger 	ret = task_work_add(tsk, &callback->work, true);
569*fa7d9493SBabu Moger 	if (ret) {
570*fa7d9493SBabu Moger 		/*
571*fa7d9493SBabu Moger 		 * Task is exiting. Drop the refcount and free the callback.
572*fa7d9493SBabu Moger 		 * No need to check the refcount as the group cannot be
573*fa7d9493SBabu Moger 		 * deleted before the write function unlocks rdtgroup_mutex.
574*fa7d9493SBabu Moger 		 */
575*fa7d9493SBabu Moger 		atomic_dec(&rdtgrp->waitcount);
576*fa7d9493SBabu Moger 		kfree(callback);
577*fa7d9493SBabu Moger 		rdt_last_cmd_puts("task exited\n");
578*fa7d9493SBabu Moger 	} else {
579*fa7d9493SBabu Moger 		/*
580*fa7d9493SBabu Moger 		 * For ctrl_mon groups move both closid and rmid.
581*fa7d9493SBabu Moger 		 * For monitor groups, can move the tasks only from
582*fa7d9493SBabu Moger 		 * their parent CTRL group.
583*fa7d9493SBabu Moger 		 */
584*fa7d9493SBabu Moger 		if (rdtgrp->type == RDTCTRL_GROUP) {
585*fa7d9493SBabu Moger 			tsk->closid = rdtgrp->closid;
586*fa7d9493SBabu Moger 			tsk->rmid = rdtgrp->mon.rmid;
587*fa7d9493SBabu Moger 		} else if (rdtgrp->type == RDTMON_GROUP) {
588*fa7d9493SBabu Moger 			if (rdtgrp->mon.parent->closid == tsk->closid) {
589*fa7d9493SBabu Moger 				tsk->rmid = rdtgrp->mon.rmid;
590*fa7d9493SBabu Moger 			} else {
591*fa7d9493SBabu Moger 				rdt_last_cmd_puts("Can't move task to different control group\n");
592*fa7d9493SBabu Moger 				ret = -EINVAL;
593*fa7d9493SBabu Moger 			}
594*fa7d9493SBabu Moger 		}
595*fa7d9493SBabu Moger 	}
596*fa7d9493SBabu Moger 	return ret;
597*fa7d9493SBabu Moger }
598*fa7d9493SBabu Moger 
599*fa7d9493SBabu Moger /**
600*fa7d9493SBabu Moger  * rdtgroup_tasks_assigned - Test if tasks have been assigned to resource group
601*fa7d9493SBabu Moger  * @r: Resource group
602*fa7d9493SBabu Moger  *
603*fa7d9493SBabu Moger  * Return: 1 if tasks have been assigned to @r, 0 otherwise
604*fa7d9493SBabu Moger  */
605*fa7d9493SBabu Moger int rdtgroup_tasks_assigned(struct rdtgroup *r)
606*fa7d9493SBabu Moger {
607*fa7d9493SBabu Moger 	struct task_struct *p, *t;
608*fa7d9493SBabu Moger 	int ret = 0;
609*fa7d9493SBabu Moger 
610*fa7d9493SBabu Moger 	lockdep_assert_held(&rdtgroup_mutex);
611*fa7d9493SBabu Moger 
612*fa7d9493SBabu Moger 	rcu_read_lock();
613*fa7d9493SBabu Moger 	for_each_process_thread(p, t) {
614*fa7d9493SBabu Moger 		if ((r->type == RDTCTRL_GROUP && t->closid == r->closid) ||
615*fa7d9493SBabu Moger 		    (r->type == RDTMON_GROUP && t->rmid == r->mon.rmid)) {
616*fa7d9493SBabu Moger 			ret = 1;
617*fa7d9493SBabu Moger 			break;
618*fa7d9493SBabu Moger 		}
619*fa7d9493SBabu Moger 	}
620*fa7d9493SBabu Moger 	rcu_read_unlock();
621*fa7d9493SBabu Moger 
622*fa7d9493SBabu Moger 	return ret;
623*fa7d9493SBabu Moger }
624*fa7d9493SBabu Moger 
625*fa7d9493SBabu Moger static int rdtgroup_task_write_permission(struct task_struct *task,
626*fa7d9493SBabu Moger 					  struct kernfs_open_file *of)
627*fa7d9493SBabu Moger {
628*fa7d9493SBabu Moger 	const struct cred *tcred = get_task_cred(task);
629*fa7d9493SBabu Moger 	const struct cred *cred = current_cred();
630*fa7d9493SBabu Moger 	int ret = 0;
631*fa7d9493SBabu Moger 
632*fa7d9493SBabu Moger 	/*
633*fa7d9493SBabu Moger 	 * Even if we're attaching all tasks in the thread group, we only
634*fa7d9493SBabu Moger 	 * need to check permissions on one of them.
635*fa7d9493SBabu Moger 	 */
636*fa7d9493SBabu Moger 	if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) &&
637*fa7d9493SBabu Moger 	    !uid_eq(cred->euid, tcred->uid) &&
638*fa7d9493SBabu Moger 	    !uid_eq(cred->euid, tcred->suid)) {
639*fa7d9493SBabu Moger 		rdt_last_cmd_printf("No permission to move task %d\n", task->pid);
640*fa7d9493SBabu Moger 		ret = -EPERM;
641*fa7d9493SBabu Moger 	}
642*fa7d9493SBabu Moger 
643*fa7d9493SBabu Moger 	put_cred(tcred);
644*fa7d9493SBabu Moger 	return ret;
645*fa7d9493SBabu Moger }
646*fa7d9493SBabu Moger 
647*fa7d9493SBabu Moger static int rdtgroup_move_task(pid_t pid, struct rdtgroup *rdtgrp,
648*fa7d9493SBabu Moger 			      struct kernfs_open_file *of)
649*fa7d9493SBabu Moger {
650*fa7d9493SBabu Moger 	struct task_struct *tsk;
651*fa7d9493SBabu Moger 	int ret;
652*fa7d9493SBabu Moger 
653*fa7d9493SBabu Moger 	rcu_read_lock();
654*fa7d9493SBabu Moger 	if (pid) {
655*fa7d9493SBabu Moger 		tsk = find_task_by_vpid(pid);
656*fa7d9493SBabu Moger 		if (!tsk) {
657*fa7d9493SBabu Moger 			rcu_read_unlock();
658*fa7d9493SBabu Moger 			rdt_last_cmd_printf("No task %d\n", pid);
659*fa7d9493SBabu Moger 			return -ESRCH;
660*fa7d9493SBabu Moger 		}
661*fa7d9493SBabu Moger 	} else {
662*fa7d9493SBabu Moger 		tsk = current;
663*fa7d9493SBabu Moger 	}
664*fa7d9493SBabu Moger 
665*fa7d9493SBabu Moger 	get_task_struct(tsk);
666*fa7d9493SBabu Moger 	rcu_read_unlock();
667*fa7d9493SBabu Moger 
668*fa7d9493SBabu Moger 	ret = rdtgroup_task_write_permission(tsk, of);
669*fa7d9493SBabu Moger 	if (!ret)
670*fa7d9493SBabu Moger 		ret = __rdtgroup_move_task(tsk, rdtgrp);
671*fa7d9493SBabu Moger 
672*fa7d9493SBabu Moger 	put_task_struct(tsk);
673*fa7d9493SBabu Moger 	return ret;
674*fa7d9493SBabu Moger }
675*fa7d9493SBabu Moger 
676*fa7d9493SBabu Moger static ssize_t rdtgroup_tasks_write(struct kernfs_open_file *of,
677*fa7d9493SBabu Moger 				    char *buf, size_t nbytes, loff_t off)
678*fa7d9493SBabu Moger {
679*fa7d9493SBabu Moger 	struct rdtgroup *rdtgrp;
680*fa7d9493SBabu Moger 	int ret = 0;
681*fa7d9493SBabu Moger 	pid_t pid;
682*fa7d9493SBabu Moger 
683*fa7d9493SBabu Moger 	if (kstrtoint(strstrip(buf), 0, &pid) || pid < 0)
684*fa7d9493SBabu Moger 		return -EINVAL;
685*fa7d9493SBabu Moger 	rdtgrp = rdtgroup_kn_lock_live(of->kn);
686*fa7d9493SBabu Moger 	if (!rdtgrp) {
687*fa7d9493SBabu Moger 		rdtgroup_kn_unlock(of->kn);
688*fa7d9493SBabu Moger 		return -ENOENT;
689*fa7d9493SBabu Moger 	}
690*fa7d9493SBabu Moger 	rdt_last_cmd_clear();
691*fa7d9493SBabu Moger 
692*fa7d9493SBabu Moger 	if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED ||
693*fa7d9493SBabu Moger 	    rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
694*fa7d9493SBabu Moger 		ret = -EINVAL;
695*fa7d9493SBabu Moger 		rdt_last_cmd_puts("pseudo-locking in progress\n");
696*fa7d9493SBabu Moger 		goto unlock;
697*fa7d9493SBabu Moger 	}
698*fa7d9493SBabu Moger 
699*fa7d9493SBabu Moger 	ret = rdtgroup_move_task(pid, rdtgrp, of);
700*fa7d9493SBabu Moger 
701*fa7d9493SBabu Moger unlock:
702*fa7d9493SBabu Moger 	rdtgroup_kn_unlock(of->kn);
703*fa7d9493SBabu Moger 
704*fa7d9493SBabu Moger 	return ret ?: nbytes;
705*fa7d9493SBabu Moger }
706*fa7d9493SBabu Moger 
707*fa7d9493SBabu Moger static void show_rdt_tasks(struct rdtgroup *r, struct seq_file *s)
708*fa7d9493SBabu Moger {
709*fa7d9493SBabu Moger 	struct task_struct *p, *t;
710*fa7d9493SBabu Moger 
711*fa7d9493SBabu Moger 	rcu_read_lock();
712*fa7d9493SBabu Moger 	for_each_process_thread(p, t) {
713*fa7d9493SBabu Moger 		if ((r->type == RDTCTRL_GROUP && t->closid == r->closid) ||
714*fa7d9493SBabu Moger 		    (r->type == RDTMON_GROUP && t->rmid == r->mon.rmid))
715*fa7d9493SBabu Moger 			seq_printf(s, "%d\n", t->pid);
716*fa7d9493SBabu Moger 	}
717*fa7d9493SBabu Moger 	rcu_read_unlock();
718*fa7d9493SBabu Moger }
719*fa7d9493SBabu Moger 
720*fa7d9493SBabu Moger static int rdtgroup_tasks_show(struct kernfs_open_file *of,
721*fa7d9493SBabu Moger 			       struct seq_file *s, void *v)
722*fa7d9493SBabu Moger {
723*fa7d9493SBabu Moger 	struct rdtgroup *rdtgrp;
724*fa7d9493SBabu Moger 	int ret = 0;
725*fa7d9493SBabu Moger 
726*fa7d9493SBabu Moger 	rdtgrp = rdtgroup_kn_lock_live(of->kn);
727*fa7d9493SBabu Moger 	if (rdtgrp)
728*fa7d9493SBabu Moger 		show_rdt_tasks(rdtgrp, s);
729*fa7d9493SBabu Moger 	else
730*fa7d9493SBabu Moger 		ret = -ENOENT;
731*fa7d9493SBabu Moger 	rdtgroup_kn_unlock(of->kn);
732*fa7d9493SBabu Moger 
733*fa7d9493SBabu Moger 	return ret;
734*fa7d9493SBabu Moger }
735*fa7d9493SBabu Moger 
736*fa7d9493SBabu Moger static int rdt_last_cmd_status_show(struct kernfs_open_file *of,
737*fa7d9493SBabu Moger 				    struct seq_file *seq, void *v)
738*fa7d9493SBabu Moger {
739*fa7d9493SBabu Moger 	int len;
740*fa7d9493SBabu Moger 
741*fa7d9493SBabu Moger 	mutex_lock(&rdtgroup_mutex);
742*fa7d9493SBabu Moger 	len = seq_buf_used(&last_cmd_status);
743*fa7d9493SBabu Moger 	if (len)
744*fa7d9493SBabu Moger 		seq_printf(seq, "%.*s", len, last_cmd_status_buf);
745*fa7d9493SBabu Moger 	else
746*fa7d9493SBabu Moger 		seq_puts(seq, "ok\n");
747*fa7d9493SBabu Moger 	mutex_unlock(&rdtgroup_mutex);
748*fa7d9493SBabu Moger 	return 0;
749*fa7d9493SBabu Moger }
750*fa7d9493SBabu Moger 
751*fa7d9493SBabu Moger static int rdt_num_closids_show(struct kernfs_open_file *of,
752*fa7d9493SBabu Moger 				struct seq_file *seq, void *v)
753*fa7d9493SBabu Moger {
754*fa7d9493SBabu Moger 	struct rdt_resource *r = of->kn->parent->priv;
755*fa7d9493SBabu Moger 
756*fa7d9493SBabu Moger 	seq_printf(seq, "%d\n", r->num_closid);
757*fa7d9493SBabu Moger 	return 0;
758*fa7d9493SBabu Moger }
759*fa7d9493SBabu Moger 
760*fa7d9493SBabu Moger static int rdt_default_ctrl_show(struct kernfs_open_file *of,
761*fa7d9493SBabu Moger 			     struct seq_file *seq, void *v)
762*fa7d9493SBabu Moger {
763*fa7d9493SBabu Moger 	struct rdt_resource *r = of->kn->parent->priv;
764*fa7d9493SBabu Moger 
765*fa7d9493SBabu Moger 	seq_printf(seq, "%x\n", r->default_ctrl);
766*fa7d9493SBabu Moger 	return 0;
767*fa7d9493SBabu Moger }
768*fa7d9493SBabu Moger 
769*fa7d9493SBabu Moger static int rdt_min_cbm_bits_show(struct kernfs_open_file *of,
770*fa7d9493SBabu Moger 			     struct seq_file *seq, void *v)
771*fa7d9493SBabu Moger {
772*fa7d9493SBabu Moger 	struct rdt_resource *r = of->kn->parent->priv;
773*fa7d9493SBabu Moger 
774*fa7d9493SBabu Moger 	seq_printf(seq, "%u\n", r->cache.min_cbm_bits);
775*fa7d9493SBabu Moger 	return 0;
776*fa7d9493SBabu Moger }
777*fa7d9493SBabu Moger 
778*fa7d9493SBabu Moger static int rdt_shareable_bits_show(struct kernfs_open_file *of,
779*fa7d9493SBabu Moger 				   struct seq_file *seq, void *v)
780*fa7d9493SBabu Moger {
781*fa7d9493SBabu Moger 	struct rdt_resource *r = of->kn->parent->priv;
782*fa7d9493SBabu Moger 
783*fa7d9493SBabu Moger 	seq_printf(seq, "%x\n", r->cache.shareable_bits);
784*fa7d9493SBabu Moger 	return 0;
785*fa7d9493SBabu Moger }
786*fa7d9493SBabu Moger 
787*fa7d9493SBabu Moger /**
788*fa7d9493SBabu Moger  * rdt_bit_usage_show - Display current usage of resources
789*fa7d9493SBabu Moger  *
790*fa7d9493SBabu Moger  * A domain is a shared resource that can now be allocated differently. Here
791*fa7d9493SBabu Moger  * we display the current regions of the domain as an annotated bitmask.
792*fa7d9493SBabu Moger  * For each domain of this resource its allocation bitmask
793*fa7d9493SBabu Moger  * is annotated as below to indicate the current usage of the corresponding bit:
794*fa7d9493SBabu Moger  *   0 - currently unused
795*fa7d9493SBabu Moger  *   X - currently available for sharing and used by software and hardware
796*fa7d9493SBabu Moger  *   H - currently used by hardware only but available for software use
797*fa7d9493SBabu Moger  *   S - currently used and shareable by software only
798*fa7d9493SBabu Moger  *   E - currently used exclusively by one resource group
799*fa7d9493SBabu Moger  *   P - currently pseudo-locked by one resource group
800*fa7d9493SBabu Moger  */
801*fa7d9493SBabu Moger static int rdt_bit_usage_show(struct kernfs_open_file *of,
802*fa7d9493SBabu Moger 			      struct seq_file *seq, void *v)
803*fa7d9493SBabu Moger {
804*fa7d9493SBabu Moger 	struct rdt_resource *r = of->kn->parent->priv;
805*fa7d9493SBabu Moger 	u32 sw_shareable = 0, hw_shareable = 0;
806*fa7d9493SBabu Moger 	u32 exclusive = 0, pseudo_locked = 0;
807*fa7d9493SBabu Moger 	struct rdt_domain *dom;
808*fa7d9493SBabu Moger 	int i, hwb, swb, excl, psl;
809*fa7d9493SBabu Moger 	enum rdtgrp_mode mode;
810*fa7d9493SBabu Moger 	bool sep = false;
811*fa7d9493SBabu Moger 	u32 *ctrl;
812*fa7d9493SBabu Moger 
813*fa7d9493SBabu Moger 	mutex_lock(&rdtgroup_mutex);
814*fa7d9493SBabu Moger 	hw_shareable = r->cache.shareable_bits;
815*fa7d9493SBabu Moger 	list_for_each_entry(dom, &r->domains, list) {
816*fa7d9493SBabu Moger 		if (sep)
817*fa7d9493SBabu Moger 			seq_putc(seq, ';');
818*fa7d9493SBabu Moger 		ctrl = dom->ctrl_val;
819*fa7d9493SBabu Moger 		sw_shareable = 0;
820*fa7d9493SBabu Moger 		exclusive = 0;
821*fa7d9493SBabu Moger 		seq_printf(seq, "%d=", dom->id);
822*fa7d9493SBabu Moger 		for (i = 0; i < closids_supported(); i++, ctrl++) {
823*fa7d9493SBabu Moger 			if (!closid_allocated(i))
824*fa7d9493SBabu Moger 				continue;
825*fa7d9493SBabu Moger 			mode = rdtgroup_mode_by_closid(i);
826*fa7d9493SBabu Moger 			switch (mode) {
827*fa7d9493SBabu Moger 			case RDT_MODE_SHAREABLE:
828*fa7d9493SBabu Moger 				sw_shareable |= *ctrl;
829*fa7d9493SBabu Moger 				break;
830*fa7d9493SBabu Moger 			case RDT_MODE_EXCLUSIVE:
831*fa7d9493SBabu Moger 				exclusive |= *ctrl;
832*fa7d9493SBabu Moger 				break;
833*fa7d9493SBabu Moger 			case RDT_MODE_PSEUDO_LOCKSETUP:
834*fa7d9493SBabu Moger 			/*
835*fa7d9493SBabu Moger 			 * RDT_MODE_PSEUDO_LOCKSETUP is possible
836*fa7d9493SBabu Moger 			 * here but not included since the CBM
837*fa7d9493SBabu Moger 			 * associated with this CLOSID in this mode
838*fa7d9493SBabu Moger 			 * is not initialized and no task or cpu can be
839*fa7d9493SBabu Moger 			 * assigned this CLOSID.
840*fa7d9493SBabu Moger 			 */
841*fa7d9493SBabu Moger 				break;
842*fa7d9493SBabu Moger 			case RDT_MODE_PSEUDO_LOCKED:
843*fa7d9493SBabu Moger 			case RDT_NUM_MODES:
844*fa7d9493SBabu Moger 				WARN(1,
845*fa7d9493SBabu Moger 				     "invalid mode for closid %d\n", i);
846*fa7d9493SBabu Moger 				break;
847*fa7d9493SBabu Moger 			}
848*fa7d9493SBabu Moger 		}
849*fa7d9493SBabu Moger 		for (i = r->cache.cbm_len - 1; i >= 0; i--) {
850*fa7d9493SBabu Moger 			pseudo_locked = dom->plr ? dom->plr->cbm : 0;
851*fa7d9493SBabu Moger 			hwb = test_bit(i, (unsigned long *)&hw_shareable);
852*fa7d9493SBabu Moger 			swb = test_bit(i, (unsigned long *)&sw_shareable);
853*fa7d9493SBabu Moger 			excl = test_bit(i, (unsigned long *)&exclusive);
854*fa7d9493SBabu Moger 			psl = test_bit(i, (unsigned long *)&pseudo_locked);
855*fa7d9493SBabu Moger 			if (hwb && swb)
856*fa7d9493SBabu Moger 				seq_putc(seq, 'X');
857*fa7d9493SBabu Moger 			else if (hwb && !swb)
858*fa7d9493SBabu Moger 				seq_putc(seq, 'H');
859*fa7d9493SBabu Moger 			else if (!hwb && swb)
860*fa7d9493SBabu Moger 				seq_putc(seq, 'S');
861*fa7d9493SBabu Moger 			else if (excl)
862*fa7d9493SBabu Moger 				seq_putc(seq, 'E');
863*fa7d9493SBabu Moger 			else if (psl)
864*fa7d9493SBabu Moger 				seq_putc(seq, 'P');
865*fa7d9493SBabu Moger 			else /* Unused bits remain */
866*fa7d9493SBabu Moger 				seq_putc(seq, '0');
867*fa7d9493SBabu Moger 		}
868*fa7d9493SBabu Moger 		sep = true;
869*fa7d9493SBabu Moger 	}
870*fa7d9493SBabu Moger 	seq_putc(seq, '\n');
871*fa7d9493SBabu Moger 	mutex_unlock(&rdtgroup_mutex);
872*fa7d9493SBabu Moger 	return 0;
873*fa7d9493SBabu Moger }
874*fa7d9493SBabu Moger 
875*fa7d9493SBabu Moger static int rdt_min_bw_show(struct kernfs_open_file *of,
876*fa7d9493SBabu Moger 			     struct seq_file *seq, void *v)
877*fa7d9493SBabu Moger {
878*fa7d9493SBabu Moger 	struct rdt_resource *r = of->kn->parent->priv;
879*fa7d9493SBabu Moger 
880*fa7d9493SBabu Moger 	seq_printf(seq, "%u\n", r->membw.min_bw);
881*fa7d9493SBabu Moger 	return 0;
882*fa7d9493SBabu Moger }
883*fa7d9493SBabu Moger 
884*fa7d9493SBabu Moger static int rdt_num_rmids_show(struct kernfs_open_file *of,
885*fa7d9493SBabu Moger 			      struct seq_file *seq, void *v)
886*fa7d9493SBabu Moger {
887*fa7d9493SBabu Moger 	struct rdt_resource *r = of->kn->parent->priv;
888*fa7d9493SBabu Moger 
889*fa7d9493SBabu Moger 	seq_printf(seq, "%d\n", r->num_rmid);
890*fa7d9493SBabu Moger 
891*fa7d9493SBabu Moger 	return 0;
892*fa7d9493SBabu Moger }
893*fa7d9493SBabu Moger 
894*fa7d9493SBabu Moger static int rdt_mon_features_show(struct kernfs_open_file *of,
895*fa7d9493SBabu Moger 				 struct seq_file *seq, void *v)
896*fa7d9493SBabu Moger {
897*fa7d9493SBabu Moger 	struct rdt_resource *r = of->kn->parent->priv;
898*fa7d9493SBabu Moger 	struct mon_evt *mevt;
899*fa7d9493SBabu Moger 
900*fa7d9493SBabu Moger 	list_for_each_entry(mevt, &r->evt_list, list)
901*fa7d9493SBabu Moger 		seq_printf(seq, "%s\n", mevt->name);
902*fa7d9493SBabu Moger 
903*fa7d9493SBabu Moger 	return 0;
904*fa7d9493SBabu Moger }
905*fa7d9493SBabu Moger 
906*fa7d9493SBabu Moger static int rdt_bw_gran_show(struct kernfs_open_file *of,
907*fa7d9493SBabu Moger 			     struct seq_file *seq, void *v)
908*fa7d9493SBabu Moger {
909*fa7d9493SBabu Moger 	struct rdt_resource *r = of->kn->parent->priv;
910*fa7d9493SBabu Moger 
911*fa7d9493SBabu Moger 	seq_printf(seq, "%u\n", r->membw.bw_gran);
912*fa7d9493SBabu Moger 	return 0;
913*fa7d9493SBabu Moger }
914*fa7d9493SBabu Moger 
915*fa7d9493SBabu Moger static int rdt_delay_linear_show(struct kernfs_open_file *of,
916*fa7d9493SBabu Moger 			     struct seq_file *seq, void *v)
917*fa7d9493SBabu Moger {
918*fa7d9493SBabu Moger 	struct rdt_resource *r = of->kn->parent->priv;
919*fa7d9493SBabu Moger 
920*fa7d9493SBabu Moger 	seq_printf(seq, "%u\n", r->membw.delay_linear);
921*fa7d9493SBabu Moger 	return 0;
922*fa7d9493SBabu Moger }
923*fa7d9493SBabu Moger 
924*fa7d9493SBabu Moger static int max_threshold_occ_show(struct kernfs_open_file *of,
925*fa7d9493SBabu Moger 				  struct seq_file *seq, void *v)
926*fa7d9493SBabu Moger {
927*fa7d9493SBabu Moger 	struct rdt_resource *r = of->kn->parent->priv;
928*fa7d9493SBabu Moger 
929*fa7d9493SBabu Moger 	seq_printf(seq, "%u\n", intel_cqm_threshold * r->mon_scale);
930*fa7d9493SBabu Moger 
931*fa7d9493SBabu Moger 	return 0;
932*fa7d9493SBabu Moger }
933*fa7d9493SBabu Moger 
934*fa7d9493SBabu Moger static ssize_t max_threshold_occ_write(struct kernfs_open_file *of,
935*fa7d9493SBabu Moger 				       char *buf, size_t nbytes, loff_t off)
936*fa7d9493SBabu Moger {
937*fa7d9493SBabu Moger 	struct rdt_resource *r = of->kn->parent->priv;
938*fa7d9493SBabu Moger 	unsigned int bytes;
939*fa7d9493SBabu Moger 	int ret;
940*fa7d9493SBabu Moger 
941*fa7d9493SBabu Moger 	ret = kstrtouint(buf, 0, &bytes);
942*fa7d9493SBabu Moger 	if (ret)
943*fa7d9493SBabu Moger 		return ret;
944*fa7d9493SBabu Moger 
945*fa7d9493SBabu Moger 	if (bytes > (boot_cpu_data.x86_cache_size * 1024))
946*fa7d9493SBabu Moger 		return -EINVAL;
947*fa7d9493SBabu Moger 
948*fa7d9493SBabu Moger 	intel_cqm_threshold = bytes / r->mon_scale;
949*fa7d9493SBabu Moger 
950*fa7d9493SBabu Moger 	return nbytes;
951*fa7d9493SBabu Moger }
952*fa7d9493SBabu Moger 
953*fa7d9493SBabu Moger /*
954*fa7d9493SBabu Moger  * rdtgroup_mode_show - Display mode of this resource group
955*fa7d9493SBabu Moger  */
956*fa7d9493SBabu Moger static int rdtgroup_mode_show(struct kernfs_open_file *of,
957*fa7d9493SBabu Moger 			      struct seq_file *s, void *v)
958*fa7d9493SBabu Moger {
959*fa7d9493SBabu Moger 	struct rdtgroup *rdtgrp;
960*fa7d9493SBabu Moger 
961*fa7d9493SBabu Moger 	rdtgrp = rdtgroup_kn_lock_live(of->kn);
962*fa7d9493SBabu Moger 	if (!rdtgrp) {
963*fa7d9493SBabu Moger 		rdtgroup_kn_unlock(of->kn);
964*fa7d9493SBabu Moger 		return -ENOENT;
965*fa7d9493SBabu Moger 	}
966*fa7d9493SBabu Moger 
967*fa7d9493SBabu Moger 	seq_printf(s, "%s\n", rdtgroup_mode_str(rdtgrp->mode));
968*fa7d9493SBabu Moger 
969*fa7d9493SBabu Moger 	rdtgroup_kn_unlock(of->kn);
970*fa7d9493SBabu Moger 	return 0;
971*fa7d9493SBabu Moger }
972*fa7d9493SBabu Moger 
973*fa7d9493SBabu Moger /**
974*fa7d9493SBabu Moger  * rdt_cdp_peer_get - Retrieve CDP peer if it exists
975*fa7d9493SBabu Moger  * @r: RDT resource to which RDT domain @d belongs
976*fa7d9493SBabu Moger  * @d: Cache instance for which a CDP peer is requested
977*fa7d9493SBabu Moger  * @r_cdp: RDT resource that shares hardware with @r (RDT resource peer)
978*fa7d9493SBabu Moger  *         Used to return the result.
979*fa7d9493SBabu Moger  * @d_cdp: RDT domain that shares hardware with @d (RDT domain peer)
980*fa7d9493SBabu Moger  *         Used to return the result.
981*fa7d9493SBabu Moger  *
982*fa7d9493SBabu Moger  * RDT resources are managed independently and by extension the RDT domains
983*fa7d9493SBabu Moger  * (RDT resource instances) are managed independently also. The Code and
984*fa7d9493SBabu Moger  * Data Prioritization (CDP) RDT resources, while managed independently,
985*fa7d9493SBabu Moger  * could refer to the same underlying hardware. For example,
986*fa7d9493SBabu Moger  * RDT_RESOURCE_L2CODE and RDT_RESOURCE_L2DATA both refer to the L2 cache.
987*fa7d9493SBabu Moger  *
988*fa7d9493SBabu Moger  * When provided with an RDT resource @r and an instance of that RDT
989*fa7d9493SBabu Moger  * resource @d rdt_cdp_peer_get() will return if there is a peer RDT
990*fa7d9493SBabu Moger  * resource and the exact instance that shares the same hardware.
991*fa7d9493SBabu Moger  *
992*fa7d9493SBabu Moger  * Return: 0 if a CDP peer was found, <0 on error or if no CDP peer exists.
993*fa7d9493SBabu Moger  *         If a CDP peer was found, @r_cdp will point to the peer RDT resource
994*fa7d9493SBabu Moger  *         and @d_cdp will point to the peer RDT domain.
995*fa7d9493SBabu Moger  */
996*fa7d9493SBabu Moger static int rdt_cdp_peer_get(struct rdt_resource *r, struct rdt_domain *d,
997*fa7d9493SBabu Moger 			    struct rdt_resource **r_cdp,
998*fa7d9493SBabu Moger 			    struct rdt_domain **d_cdp)
999*fa7d9493SBabu Moger {
1000*fa7d9493SBabu Moger 	struct rdt_resource *_r_cdp = NULL;
1001*fa7d9493SBabu Moger 	struct rdt_domain *_d_cdp = NULL;
1002*fa7d9493SBabu Moger 	int ret = 0;
1003*fa7d9493SBabu Moger 
1004*fa7d9493SBabu Moger 	switch (r->rid) {
1005*fa7d9493SBabu Moger 	case RDT_RESOURCE_L3DATA:
1006*fa7d9493SBabu Moger 		_r_cdp = &rdt_resources_all[RDT_RESOURCE_L3CODE];
1007*fa7d9493SBabu Moger 		break;
1008*fa7d9493SBabu Moger 	case RDT_RESOURCE_L3CODE:
1009*fa7d9493SBabu Moger 		_r_cdp =  &rdt_resources_all[RDT_RESOURCE_L3DATA];
1010*fa7d9493SBabu Moger 		break;
1011*fa7d9493SBabu Moger 	case RDT_RESOURCE_L2DATA:
1012*fa7d9493SBabu Moger 		_r_cdp =  &rdt_resources_all[RDT_RESOURCE_L2CODE];
1013*fa7d9493SBabu Moger 		break;
1014*fa7d9493SBabu Moger 	case RDT_RESOURCE_L2CODE:
1015*fa7d9493SBabu Moger 		_r_cdp =  &rdt_resources_all[RDT_RESOURCE_L2DATA];
1016*fa7d9493SBabu Moger 		break;
1017*fa7d9493SBabu Moger 	default:
1018*fa7d9493SBabu Moger 		ret = -ENOENT;
1019*fa7d9493SBabu Moger 		goto out;
1020*fa7d9493SBabu Moger 	}
1021*fa7d9493SBabu Moger 
1022*fa7d9493SBabu Moger 	/*
1023*fa7d9493SBabu Moger 	 * When a new CPU comes online and CDP is enabled then the new
1024*fa7d9493SBabu Moger 	 * RDT domains (if any) associated with both CDP RDT resources
1025*fa7d9493SBabu Moger 	 * are added in the same CPU online routine while the
1026*fa7d9493SBabu Moger 	 * rdtgroup_mutex is held. It should thus not happen for one
1027*fa7d9493SBabu Moger 	 * RDT domain to exist and be associated with its RDT CDP
1028*fa7d9493SBabu Moger 	 * resource but there is no RDT domain associated with the
1029*fa7d9493SBabu Moger 	 * peer RDT CDP resource. Hence the WARN.
1030*fa7d9493SBabu Moger 	 */
1031*fa7d9493SBabu Moger 	_d_cdp = rdt_find_domain(_r_cdp, d->id, NULL);
1032*fa7d9493SBabu Moger 	if (WARN_ON(!_d_cdp)) {
1033*fa7d9493SBabu Moger 		_r_cdp = NULL;
1034*fa7d9493SBabu Moger 		ret = -EINVAL;
1035*fa7d9493SBabu Moger 	}
1036*fa7d9493SBabu Moger 
1037*fa7d9493SBabu Moger out:
1038*fa7d9493SBabu Moger 	*r_cdp = _r_cdp;
1039*fa7d9493SBabu Moger 	*d_cdp = _d_cdp;
1040*fa7d9493SBabu Moger 
1041*fa7d9493SBabu Moger 	return ret;
1042*fa7d9493SBabu Moger }
1043*fa7d9493SBabu Moger 
1044*fa7d9493SBabu Moger /**
1045*fa7d9493SBabu Moger  * __rdtgroup_cbm_overlaps - Does CBM for intended closid overlap with other
1046*fa7d9493SBabu Moger  * @r: Resource to which domain instance @d belongs.
1047*fa7d9493SBabu Moger  * @d: The domain instance for which @closid is being tested.
1048*fa7d9493SBabu Moger  * @cbm: Capacity bitmask being tested.
1049*fa7d9493SBabu Moger  * @closid: Intended closid for @cbm.
1050*fa7d9493SBabu Moger  * @exclusive: Only check if overlaps with exclusive resource groups
1051*fa7d9493SBabu Moger  *
1052*fa7d9493SBabu Moger  * Checks if provided @cbm intended to be used for @closid on domain
1053*fa7d9493SBabu Moger  * @d overlaps with any other closids or other hardware usage associated
1054*fa7d9493SBabu Moger  * with this domain. If @exclusive is true then only overlaps with
1055*fa7d9493SBabu Moger  * resource groups in exclusive mode will be considered. If @exclusive
1056*fa7d9493SBabu Moger  * is false then overlaps with any resource group or hardware entities
1057*fa7d9493SBabu Moger  * will be considered.
1058*fa7d9493SBabu Moger  *
1059*fa7d9493SBabu Moger  * @cbm is unsigned long, even if only 32 bits are used, to make the
1060*fa7d9493SBabu Moger  * bitmap functions work correctly.
1061*fa7d9493SBabu Moger  *
1062*fa7d9493SBabu Moger  * Return: false if CBM does not overlap, true if it does.
1063*fa7d9493SBabu Moger  */
1064*fa7d9493SBabu Moger static bool __rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_domain *d,
1065*fa7d9493SBabu Moger 				    unsigned long cbm, int closid, bool exclusive)
1066*fa7d9493SBabu Moger {
1067*fa7d9493SBabu Moger 	enum rdtgrp_mode mode;
1068*fa7d9493SBabu Moger 	unsigned long ctrl_b;
1069*fa7d9493SBabu Moger 	u32 *ctrl;
1070*fa7d9493SBabu Moger 	int i;
1071*fa7d9493SBabu Moger 
1072*fa7d9493SBabu Moger 	/* Check for any overlap with regions used by hardware directly */
1073*fa7d9493SBabu Moger 	if (!exclusive) {
1074*fa7d9493SBabu Moger 		ctrl_b = r->cache.shareable_bits;
1075*fa7d9493SBabu Moger 		if (bitmap_intersects(&cbm, &ctrl_b, r->cache.cbm_len))
1076*fa7d9493SBabu Moger 			return true;
1077*fa7d9493SBabu Moger 	}
1078*fa7d9493SBabu Moger 
1079*fa7d9493SBabu Moger 	/* Check for overlap with other resource groups */
1080*fa7d9493SBabu Moger 	ctrl = d->ctrl_val;
1081*fa7d9493SBabu Moger 	for (i = 0; i < closids_supported(); i++, ctrl++) {
1082*fa7d9493SBabu Moger 		ctrl_b = *ctrl;
1083*fa7d9493SBabu Moger 		mode = rdtgroup_mode_by_closid(i);
1084*fa7d9493SBabu Moger 		if (closid_allocated(i) && i != closid &&
1085*fa7d9493SBabu Moger 		    mode != RDT_MODE_PSEUDO_LOCKSETUP) {
1086*fa7d9493SBabu Moger 			if (bitmap_intersects(&cbm, &ctrl_b, r->cache.cbm_len)) {
1087*fa7d9493SBabu Moger 				if (exclusive) {
1088*fa7d9493SBabu Moger 					if (mode == RDT_MODE_EXCLUSIVE)
1089*fa7d9493SBabu Moger 						return true;
1090*fa7d9493SBabu Moger 					continue;
1091*fa7d9493SBabu Moger 				}
1092*fa7d9493SBabu Moger 				return true;
1093*fa7d9493SBabu Moger 			}
1094*fa7d9493SBabu Moger 		}
1095*fa7d9493SBabu Moger 	}
1096*fa7d9493SBabu Moger 
1097*fa7d9493SBabu Moger 	return false;
1098*fa7d9493SBabu Moger }
1099*fa7d9493SBabu Moger 
1100*fa7d9493SBabu Moger /**
1101*fa7d9493SBabu Moger  * rdtgroup_cbm_overlaps - Does CBM overlap with other use of hardware
1102*fa7d9493SBabu Moger  * @r: Resource to which domain instance @d belongs.
1103*fa7d9493SBabu Moger  * @d: The domain instance for which @closid is being tested.
1104*fa7d9493SBabu Moger  * @cbm: Capacity bitmask being tested.
1105*fa7d9493SBabu Moger  * @closid: Intended closid for @cbm.
1106*fa7d9493SBabu Moger  * @exclusive: Only check if overlaps with exclusive resource groups
1107*fa7d9493SBabu Moger  *
1108*fa7d9493SBabu Moger  * Resources that can be allocated using a CBM can use the CBM to control
1109*fa7d9493SBabu Moger  * the overlap of these allocations. rdtgroup_cmb_overlaps() is the test
1110*fa7d9493SBabu Moger  * for overlap. Overlap test is not limited to the specific resource for
1111*fa7d9493SBabu Moger  * which the CBM is intended though - when dealing with CDP resources that
1112*fa7d9493SBabu Moger  * share the underlying hardware the overlap check should be performed on
1113*fa7d9493SBabu Moger  * the CDP resource sharing the hardware also.
1114*fa7d9493SBabu Moger  *
1115*fa7d9493SBabu Moger  * Refer to description of __rdtgroup_cbm_overlaps() for the details of the
1116*fa7d9493SBabu Moger  * overlap test.
1117*fa7d9493SBabu Moger  *
1118*fa7d9493SBabu Moger  * Return: true if CBM overlap detected, false if there is no overlap
1119*fa7d9493SBabu Moger  */
1120*fa7d9493SBabu Moger bool rdtgroup_cbm_overlaps(struct rdt_resource *r, struct rdt_domain *d,
1121*fa7d9493SBabu Moger 			   unsigned long cbm, int closid, bool exclusive)
1122*fa7d9493SBabu Moger {
1123*fa7d9493SBabu Moger 	struct rdt_resource *r_cdp;
1124*fa7d9493SBabu Moger 	struct rdt_domain *d_cdp;
1125*fa7d9493SBabu Moger 
1126*fa7d9493SBabu Moger 	if (__rdtgroup_cbm_overlaps(r, d, cbm, closid, exclusive))
1127*fa7d9493SBabu Moger 		return true;
1128*fa7d9493SBabu Moger 
1129*fa7d9493SBabu Moger 	if (rdt_cdp_peer_get(r, d, &r_cdp, &d_cdp) < 0)
1130*fa7d9493SBabu Moger 		return false;
1131*fa7d9493SBabu Moger 
1132*fa7d9493SBabu Moger 	return  __rdtgroup_cbm_overlaps(r_cdp, d_cdp, cbm, closid, exclusive);
1133*fa7d9493SBabu Moger }
1134*fa7d9493SBabu Moger 
1135*fa7d9493SBabu Moger /**
1136*fa7d9493SBabu Moger  * rdtgroup_mode_test_exclusive - Test if this resource group can be exclusive
1137*fa7d9493SBabu Moger  *
1138*fa7d9493SBabu Moger  * An exclusive resource group implies that there should be no sharing of
1139*fa7d9493SBabu Moger  * its allocated resources. At the time this group is considered to be
1140*fa7d9493SBabu Moger  * exclusive this test can determine if its current schemata supports this
1141*fa7d9493SBabu Moger  * setting by testing for overlap with all other resource groups.
1142*fa7d9493SBabu Moger  *
1143*fa7d9493SBabu Moger  * Return: true if resource group can be exclusive, false if there is overlap
1144*fa7d9493SBabu Moger  * with allocations of other resource groups and thus this resource group
1145*fa7d9493SBabu Moger  * cannot be exclusive.
1146*fa7d9493SBabu Moger  */
1147*fa7d9493SBabu Moger static bool rdtgroup_mode_test_exclusive(struct rdtgroup *rdtgrp)
1148*fa7d9493SBabu Moger {
1149*fa7d9493SBabu Moger 	int closid = rdtgrp->closid;
1150*fa7d9493SBabu Moger 	struct rdt_resource *r;
1151*fa7d9493SBabu Moger 	bool has_cache = false;
1152*fa7d9493SBabu Moger 	struct rdt_domain *d;
1153*fa7d9493SBabu Moger 
1154*fa7d9493SBabu Moger 	for_each_alloc_enabled_rdt_resource(r) {
1155*fa7d9493SBabu Moger 		if (r->rid == RDT_RESOURCE_MBA)
1156*fa7d9493SBabu Moger 			continue;
1157*fa7d9493SBabu Moger 		has_cache = true;
1158*fa7d9493SBabu Moger 		list_for_each_entry(d, &r->domains, list) {
1159*fa7d9493SBabu Moger 			if (rdtgroup_cbm_overlaps(r, d, d->ctrl_val[closid],
1160*fa7d9493SBabu Moger 						  rdtgrp->closid, false)) {
1161*fa7d9493SBabu Moger 				rdt_last_cmd_puts("schemata overlaps\n");
1162*fa7d9493SBabu Moger 				return false;
1163*fa7d9493SBabu Moger 			}
1164*fa7d9493SBabu Moger 		}
1165*fa7d9493SBabu Moger 	}
1166*fa7d9493SBabu Moger 
1167*fa7d9493SBabu Moger 	if (!has_cache) {
1168*fa7d9493SBabu Moger 		rdt_last_cmd_puts("cannot be exclusive without CAT/CDP\n");
1169*fa7d9493SBabu Moger 		return false;
1170*fa7d9493SBabu Moger 	}
1171*fa7d9493SBabu Moger 
1172*fa7d9493SBabu Moger 	return true;
1173*fa7d9493SBabu Moger }
1174*fa7d9493SBabu Moger 
1175*fa7d9493SBabu Moger /**
1176*fa7d9493SBabu Moger  * rdtgroup_mode_write - Modify the resource group's mode
1177*fa7d9493SBabu Moger  *
1178*fa7d9493SBabu Moger  */
1179*fa7d9493SBabu Moger static ssize_t rdtgroup_mode_write(struct kernfs_open_file *of,
1180*fa7d9493SBabu Moger 				   char *buf, size_t nbytes, loff_t off)
1181*fa7d9493SBabu Moger {
1182*fa7d9493SBabu Moger 	struct rdtgroup *rdtgrp;
1183*fa7d9493SBabu Moger 	enum rdtgrp_mode mode;
1184*fa7d9493SBabu Moger 	int ret = 0;
1185*fa7d9493SBabu Moger 
1186*fa7d9493SBabu Moger 	/* Valid input requires a trailing newline */
1187*fa7d9493SBabu Moger 	if (nbytes == 0 || buf[nbytes - 1] != '\n')
1188*fa7d9493SBabu Moger 		return -EINVAL;
1189*fa7d9493SBabu Moger 	buf[nbytes - 1] = '\0';
1190*fa7d9493SBabu Moger 
1191*fa7d9493SBabu Moger 	rdtgrp = rdtgroup_kn_lock_live(of->kn);
1192*fa7d9493SBabu Moger 	if (!rdtgrp) {
1193*fa7d9493SBabu Moger 		rdtgroup_kn_unlock(of->kn);
1194*fa7d9493SBabu Moger 		return -ENOENT;
1195*fa7d9493SBabu Moger 	}
1196*fa7d9493SBabu Moger 
1197*fa7d9493SBabu Moger 	rdt_last_cmd_clear();
1198*fa7d9493SBabu Moger 
1199*fa7d9493SBabu Moger 	mode = rdtgrp->mode;
1200*fa7d9493SBabu Moger 
1201*fa7d9493SBabu Moger 	if ((!strcmp(buf, "shareable") && mode == RDT_MODE_SHAREABLE) ||
1202*fa7d9493SBabu Moger 	    (!strcmp(buf, "exclusive") && mode == RDT_MODE_EXCLUSIVE) ||
1203*fa7d9493SBabu Moger 	    (!strcmp(buf, "pseudo-locksetup") &&
1204*fa7d9493SBabu Moger 	     mode == RDT_MODE_PSEUDO_LOCKSETUP) ||
1205*fa7d9493SBabu Moger 	    (!strcmp(buf, "pseudo-locked") && mode == RDT_MODE_PSEUDO_LOCKED))
1206*fa7d9493SBabu Moger 		goto out;
1207*fa7d9493SBabu Moger 
1208*fa7d9493SBabu Moger 	if (mode == RDT_MODE_PSEUDO_LOCKED) {
1209*fa7d9493SBabu Moger 		rdt_last_cmd_printf("cannot change pseudo-locked group\n");
1210*fa7d9493SBabu Moger 		ret = -EINVAL;
1211*fa7d9493SBabu Moger 		goto out;
1212*fa7d9493SBabu Moger 	}
1213*fa7d9493SBabu Moger 
1214*fa7d9493SBabu Moger 	if (!strcmp(buf, "shareable")) {
1215*fa7d9493SBabu Moger 		if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
1216*fa7d9493SBabu Moger 			ret = rdtgroup_locksetup_exit(rdtgrp);
1217*fa7d9493SBabu Moger 			if (ret)
1218*fa7d9493SBabu Moger 				goto out;
1219*fa7d9493SBabu Moger 		}
1220*fa7d9493SBabu Moger 		rdtgrp->mode = RDT_MODE_SHAREABLE;
1221*fa7d9493SBabu Moger 	} else if (!strcmp(buf, "exclusive")) {
1222*fa7d9493SBabu Moger 		if (!rdtgroup_mode_test_exclusive(rdtgrp)) {
1223*fa7d9493SBabu Moger 			ret = -EINVAL;
1224*fa7d9493SBabu Moger 			goto out;
1225*fa7d9493SBabu Moger 		}
1226*fa7d9493SBabu Moger 		if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
1227*fa7d9493SBabu Moger 			ret = rdtgroup_locksetup_exit(rdtgrp);
1228*fa7d9493SBabu Moger 			if (ret)
1229*fa7d9493SBabu Moger 				goto out;
1230*fa7d9493SBabu Moger 		}
1231*fa7d9493SBabu Moger 		rdtgrp->mode = RDT_MODE_EXCLUSIVE;
1232*fa7d9493SBabu Moger 	} else if (!strcmp(buf, "pseudo-locksetup")) {
1233*fa7d9493SBabu Moger 		ret = rdtgroup_locksetup_enter(rdtgrp);
1234*fa7d9493SBabu Moger 		if (ret)
1235*fa7d9493SBabu Moger 			goto out;
1236*fa7d9493SBabu Moger 		rdtgrp->mode = RDT_MODE_PSEUDO_LOCKSETUP;
1237*fa7d9493SBabu Moger 	} else {
1238*fa7d9493SBabu Moger 		rdt_last_cmd_printf("unknown/unsupported mode\n");
1239*fa7d9493SBabu Moger 		ret = -EINVAL;
1240*fa7d9493SBabu Moger 	}
1241*fa7d9493SBabu Moger 
1242*fa7d9493SBabu Moger out:
1243*fa7d9493SBabu Moger 	rdtgroup_kn_unlock(of->kn);
1244*fa7d9493SBabu Moger 	return ret ?: nbytes;
1245*fa7d9493SBabu Moger }
1246*fa7d9493SBabu Moger 
1247*fa7d9493SBabu Moger /**
1248*fa7d9493SBabu Moger  * rdtgroup_cbm_to_size - Translate CBM to size in bytes
1249*fa7d9493SBabu Moger  * @r: RDT resource to which @d belongs.
1250*fa7d9493SBabu Moger  * @d: RDT domain instance.
1251*fa7d9493SBabu Moger  * @cbm: bitmask for which the size should be computed.
1252*fa7d9493SBabu Moger  *
1253*fa7d9493SBabu Moger  * The bitmask provided associated with the RDT domain instance @d will be
1254*fa7d9493SBabu Moger  * translated into how many bytes it represents. The size in bytes is
1255*fa7d9493SBabu Moger  * computed by first dividing the total cache size by the CBM length to
1256*fa7d9493SBabu Moger  * determine how many bytes each bit in the bitmask represents. The result
1257*fa7d9493SBabu Moger  * is multiplied with the number of bits set in the bitmask.
1258*fa7d9493SBabu Moger  *
1259*fa7d9493SBabu Moger  * @cbm is unsigned long, even if only 32 bits are used to make the
1260*fa7d9493SBabu Moger  * bitmap functions work correctly.
1261*fa7d9493SBabu Moger  */
1262*fa7d9493SBabu Moger unsigned int rdtgroup_cbm_to_size(struct rdt_resource *r,
1263*fa7d9493SBabu Moger 				  struct rdt_domain *d, unsigned long cbm)
1264*fa7d9493SBabu Moger {
1265*fa7d9493SBabu Moger 	struct cpu_cacheinfo *ci;
1266*fa7d9493SBabu Moger 	unsigned int size = 0;
1267*fa7d9493SBabu Moger 	int num_b, i;
1268*fa7d9493SBabu Moger 
1269*fa7d9493SBabu Moger 	num_b = bitmap_weight(&cbm, r->cache.cbm_len);
1270*fa7d9493SBabu Moger 	ci = get_cpu_cacheinfo(cpumask_any(&d->cpu_mask));
1271*fa7d9493SBabu Moger 	for (i = 0; i < ci->num_leaves; i++) {
1272*fa7d9493SBabu Moger 		if (ci->info_list[i].level == r->cache_level) {
1273*fa7d9493SBabu Moger 			size = ci->info_list[i].size / r->cache.cbm_len * num_b;
1274*fa7d9493SBabu Moger 			break;
1275*fa7d9493SBabu Moger 		}
1276*fa7d9493SBabu Moger 	}
1277*fa7d9493SBabu Moger 
1278*fa7d9493SBabu Moger 	return size;
1279*fa7d9493SBabu Moger }
1280*fa7d9493SBabu Moger 
1281*fa7d9493SBabu Moger /**
1282*fa7d9493SBabu Moger  * rdtgroup_size_show - Display size in bytes of allocated regions
1283*fa7d9493SBabu Moger  *
1284*fa7d9493SBabu Moger  * The "size" file mirrors the layout of the "schemata" file, printing the
1285*fa7d9493SBabu Moger  * size in bytes of each region instead of the capacity bitmask.
1286*fa7d9493SBabu Moger  *
1287*fa7d9493SBabu Moger  */
1288*fa7d9493SBabu Moger static int rdtgroup_size_show(struct kernfs_open_file *of,
1289*fa7d9493SBabu Moger 			      struct seq_file *s, void *v)
1290*fa7d9493SBabu Moger {
1291*fa7d9493SBabu Moger 	struct rdtgroup *rdtgrp;
1292*fa7d9493SBabu Moger 	struct rdt_resource *r;
1293*fa7d9493SBabu Moger 	struct rdt_domain *d;
1294*fa7d9493SBabu Moger 	unsigned int size;
1295*fa7d9493SBabu Moger 	int ret = 0;
1296*fa7d9493SBabu Moger 	bool sep;
1297*fa7d9493SBabu Moger 	u32 ctrl;
1298*fa7d9493SBabu Moger 
1299*fa7d9493SBabu Moger 	rdtgrp = rdtgroup_kn_lock_live(of->kn);
1300*fa7d9493SBabu Moger 	if (!rdtgrp) {
1301*fa7d9493SBabu Moger 		rdtgroup_kn_unlock(of->kn);
1302*fa7d9493SBabu Moger 		return -ENOENT;
1303*fa7d9493SBabu Moger 	}
1304*fa7d9493SBabu Moger 
1305*fa7d9493SBabu Moger 	if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
1306*fa7d9493SBabu Moger 		if (!rdtgrp->plr->d) {
1307*fa7d9493SBabu Moger 			rdt_last_cmd_clear();
1308*fa7d9493SBabu Moger 			rdt_last_cmd_puts("Cache domain offline\n");
1309*fa7d9493SBabu Moger 			ret = -ENODEV;
1310*fa7d9493SBabu Moger 		} else {
1311*fa7d9493SBabu Moger 			seq_printf(s, "%*s:", max_name_width,
1312*fa7d9493SBabu Moger 				   rdtgrp->plr->r->name);
1313*fa7d9493SBabu Moger 			size = rdtgroup_cbm_to_size(rdtgrp->plr->r,
1314*fa7d9493SBabu Moger 						    rdtgrp->plr->d,
1315*fa7d9493SBabu Moger 						    rdtgrp->plr->cbm);
1316*fa7d9493SBabu Moger 			seq_printf(s, "%d=%u\n", rdtgrp->plr->d->id, size);
1317*fa7d9493SBabu Moger 		}
1318*fa7d9493SBabu Moger 		goto out;
1319*fa7d9493SBabu Moger 	}
1320*fa7d9493SBabu Moger 
1321*fa7d9493SBabu Moger 	for_each_alloc_enabled_rdt_resource(r) {
1322*fa7d9493SBabu Moger 		sep = false;
1323*fa7d9493SBabu Moger 		seq_printf(s, "%*s:", max_name_width, r->name);
1324*fa7d9493SBabu Moger 		list_for_each_entry(d, &r->domains, list) {
1325*fa7d9493SBabu Moger 			if (sep)
1326*fa7d9493SBabu Moger 				seq_putc(s, ';');
1327*fa7d9493SBabu Moger 			if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
1328*fa7d9493SBabu Moger 				size = 0;
1329*fa7d9493SBabu Moger 			} else {
1330*fa7d9493SBabu Moger 				ctrl = (!is_mba_sc(r) ?
1331*fa7d9493SBabu Moger 						d->ctrl_val[rdtgrp->closid] :
1332*fa7d9493SBabu Moger 						d->mbps_val[rdtgrp->closid]);
1333*fa7d9493SBabu Moger 				if (r->rid == RDT_RESOURCE_MBA)
1334*fa7d9493SBabu Moger 					size = ctrl;
1335*fa7d9493SBabu Moger 				else
1336*fa7d9493SBabu Moger 					size = rdtgroup_cbm_to_size(r, d, ctrl);
1337*fa7d9493SBabu Moger 			}
1338*fa7d9493SBabu Moger 			seq_printf(s, "%d=%u", d->id, size);
1339*fa7d9493SBabu Moger 			sep = true;
1340*fa7d9493SBabu Moger 		}
1341*fa7d9493SBabu Moger 		seq_putc(s, '\n');
1342*fa7d9493SBabu Moger 	}
1343*fa7d9493SBabu Moger 
1344*fa7d9493SBabu Moger out:
1345*fa7d9493SBabu Moger 	rdtgroup_kn_unlock(of->kn);
1346*fa7d9493SBabu Moger 
1347*fa7d9493SBabu Moger 	return ret;
1348*fa7d9493SBabu Moger }
1349*fa7d9493SBabu Moger 
1350*fa7d9493SBabu Moger /* rdtgroup information files for one cache resource. */
1351*fa7d9493SBabu Moger static struct rftype res_common_files[] = {
1352*fa7d9493SBabu Moger 	{
1353*fa7d9493SBabu Moger 		.name		= "last_cmd_status",
1354*fa7d9493SBabu Moger 		.mode		= 0444,
1355*fa7d9493SBabu Moger 		.kf_ops		= &rdtgroup_kf_single_ops,
1356*fa7d9493SBabu Moger 		.seq_show	= rdt_last_cmd_status_show,
1357*fa7d9493SBabu Moger 		.fflags		= RF_TOP_INFO,
1358*fa7d9493SBabu Moger 	},
1359*fa7d9493SBabu Moger 	{
1360*fa7d9493SBabu Moger 		.name		= "num_closids",
1361*fa7d9493SBabu Moger 		.mode		= 0444,
1362*fa7d9493SBabu Moger 		.kf_ops		= &rdtgroup_kf_single_ops,
1363*fa7d9493SBabu Moger 		.seq_show	= rdt_num_closids_show,
1364*fa7d9493SBabu Moger 		.fflags		= RF_CTRL_INFO,
1365*fa7d9493SBabu Moger 	},
1366*fa7d9493SBabu Moger 	{
1367*fa7d9493SBabu Moger 		.name		= "mon_features",
1368*fa7d9493SBabu Moger 		.mode		= 0444,
1369*fa7d9493SBabu Moger 		.kf_ops		= &rdtgroup_kf_single_ops,
1370*fa7d9493SBabu Moger 		.seq_show	= rdt_mon_features_show,
1371*fa7d9493SBabu Moger 		.fflags		= RF_MON_INFO,
1372*fa7d9493SBabu Moger 	},
1373*fa7d9493SBabu Moger 	{
1374*fa7d9493SBabu Moger 		.name		= "num_rmids",
1375*fa7d9493SBabu Moger 		.mode		= 0444,
1376*fa7d9493SBabu Moger 		.kf_ops		= &rdtgroup_kf_single_ops,
1377*fa7d9493SBabu Moger 		.seq_show	= rdt_num_rmids_show,
1378*fa7d9493SBabu Moger 		.fflags		= RF_MON_INFO,
1379*fa7d9493SBabu Moger 	},
1380*fa7d9493SBabu Moger 	{
1381*fa7d9493SBabu Moger 		.name		= "cbm_mask",
1382*fa7d9493SBabu Moger 		.mode		= 0444,
1383*fa7d9493SBabu Moger 		.kf_ops		= &rdtgroup_kf_single_ops,
1384*fa7d9493SBabu Moger 		.seq_show	= rdt_default_ctrl_show,
1385*fa7d9493SBabu Moger 		.fflags		= RF_CTRL_INFO | RFTYPE_RES_CACHE,
1386*fa7d9493SBabu Moger 	},
1387*fa7d9493SBabu Moger 	{
1388*fa7d9493SBabu Moger 		.name		= "min_cbm_bits",
1389*fa7d9493SBabu Moger 		.mode		= 0444,
1390*fa7d9493SBabu Moger 		.kf_ops		= &rdtgroup_kf_single_ops,
1391*fa7d9493SBabu Moger 		.seq_show	= rdt_min_cbm_bits_show,
1392*fa7d9493SBabu Moger 		.fflags		= RF_CTRL_INFO | RFTYPE_RES_CACHE,
1393*fa7d9493SBabu Moger 	},
1394*fa7d9493SBabu Moger 	{
1395*fa7d9493SBabu Moger 		.name		= "shareable_bits",
1396*fa7d9493SBabu Moger 		.mode		= 0444,
1397*fa7d9493SBabu Moger 		.kf_ops		= &rdtgroup_kf_single_ops,
1398*fa7d9493SBabu Moger 		.seq_show	= rdt_shareable_bits_show,
1399*fa7d9493SBabu Moger 		.fflags		= RF_CTRL_INFO | RFTYPE_RES_CACHE,
1400*fa7d9493SBabu Moger 	},
1401*fa7d9493SBabu Moger 	{
1402*fa7d9493SBabu Moger 		.name		= "bit_usage",
1403*fa7d9493SBabu Moger 		.mode		= 0444,
1404*fa7d9493SBabu Moger 		.kf_ops		= &rdtgroup_kf_single_ops,
1405*fa7d9493SBabu Moger 		.seq_show	= rdt_bit_usage_show,
1406*fa7d9493SBabu Moger 		.fflags		= RF_CTRL_INFO | RFTYPE_RES_CACHE,
1407*fa7d9493SBabu Moger 	},
1408*fa7d9493SBabu Moger 	{
1409*fa7d9493SBabu Moger 		.name		= "min_bandwidth",
1410*fa7d9493SBabu Moger 		.mode		= 0444,
1411*fa7d9493SBabu Moger 		.kf_ops		= &rdtgroup_kf_single_ops,
1412*fa7d9493SBabu Moger 		.seq_show	= rdt_min_bw_show,
1413*fa7d9493SBabu Moger 		.fflags		= RF_CTRL_INFO | RFTYPE_RES_MB,
1414*fa7d9493SBabu Moger 	},
1415*fa7d9493SBabu Moger 	{
1416*fa7d9493SBabu Moger 		.name		= "bandwidth_gran",
1417*fa7d9493SBabu Moger 		.mode		= 0444,
1418*fa7d9493SBabu Moger 		.kf_ops		= &rdtgroup_kf_single_ops,
1419*fa7d9493SBabu Moger 		.seq_show	= rdt_bw_gran_show,
1420*fa7d9493SBabu Moger 		.fflags		= RF_CTRL_INFO | RFTYPE_RES_MB,
1421*fa7d9493SBabu Moger 	},
1422*fa7d9493SBabu Moger 	{
1423*fa7d9493SBabu Moger 		.name		= "delay_linear",
1424*fa7d9493SBabu Moger 		.mode		= 0444,
1425*fa7d9493SBabu Moger 		.kf_ops		= &rdtgroup_kf_single_ops,
1426*fa7d9493SBabu Moger 		.seq_show	= rdt_delay_linear_show,
1427*fa7d9493SBabu Moger 		.fflags		= RF_CTRL_INFO | RFTYPE_RES_MB,
1428*fa7d9493SBabu Moger 	},
1429*fa7d9493SBabu Moger 	{
1430*fa7d9493SBabu Moger 		.name		= "max_threshold_occupancy",
1431*fa7d9493SBabu Moger 		.mode		= 0644,
1432*fa7d9493SBabu Moger 		.kf_ops		= &rdtgroup_kf_single_ops,
1433*fa7d9493SBabu Moger 		.write		= max_threshold_occ_write,
1434*fa7d9493SBabu Moger 		.seq_show	= max_threshold_occ_show,
1435*fa7d9493SBabu Moger 		.fflags		= RF_MON_INFO | RFTYPE_RES_CACHE,
1436*fa7d9493SBabu Moger 	},
1437*fa7d9493SBabu Moger 	{
1438*fa7d9493SBabu Moger 		.name		= "cpus",
1439*fa7d9493SBabu Moger 		.mode		= 0644,
1440*fa7d9493SBabu Moger 		.kf_ops		= &rdtgroup_kf_single_ops,
1441*fa7d9493SBabu Moger 		.write		= rdtgroup_cpus_write,
1442*fa7d9493SBabu Moger 		.seq_show	= rdtgroup_cpus_show,
1443*fa7d9493SBabu Moger 		.fflags		= RFTYPE_BASE,
1444*fa7d9493SBabu Moger 	},
1445*fa7d9493SBabu Moger 	{
1446*fa7d9493SBabu Moger 		.name		= "cpus_list",
1447*fa7d9493SBabu Moger 		.mode		= 0644,
1448*fa7d9493SBabu Moger 		.kf_ops		= &rdtgroup_kf_single_ops,
1449*fa7d9493SBabu Moger 		.write		= rdtgroup_cpus_write,
1450*fa7d9493SBabu Moger 		.seq_show	= rdtgroup_cpus_show,
1451*fa7d9493SBabu Moger 		.flags		= RFTYPE_FLAGS_CPUS_LIST,
1452*fa7d9493SBabu Moger 		.fflags		= RFTYPE_BASE,
1453*fa7d9493SBabu Moger 	},
1454*fa7d9493SBabu Moger 	{
1455*fa7d9493SBabu Moger 		.name		= "tasks",
1456*fa7d9493SBabu Moger 		.mode		= 0644,
1457*fa7d9493SBabu Moger 		.kf_ops		= &rdtgroup_kf_single_ops,
1458*fa7d9493SBabu Moger 		.write		= rdtgroup_tasks_write,
1459*fa7d9493SBabu Moger 		.seq_show	= rdtgroup_tasks_show,
1460*fa7d9493SBabu Moger 		.fflags		= RFTYPE_BASE,
1461*fa7d9493SBabu Moger 	},
1462*fa7d9493SBabu Moger 	{
1463*fa7d9493SBabu Moger 		.name		= "schemata",
1464*fa7d9493SBabu Moger 		.mode		= 0644,
1465*fa7d9493SBabu Moger 		.kf_ops		= &rdtgroup_kf_single_ops,
1466*fa7d9493SBabu Moger 		.write		= rdtgroup_schemata_write,
1467*fa7d9493SBabu Moger 		.seq_show	= rdtgroup_schemata_show,
1468*fa7d9493SBabu Moger 		.fflags		= RF_CTRL_BASE,
1469*fa7d9493SBabu Moger 	},
1470*fa7d9493SBabu Moger 	{
1471*fa7d9493SBabu Moger 		.name		= "mode",
1472*fa7d9493SBabu Moger 		.mode		= 0644,
1473*fa7d9493SBabu Moger 		.kf_ops		= &rdtgroup_kf_single_ops,
1474*fa7d9493SBabu Moger 		.write		= rdtgroup_mode_write,
1475*fa7d9493SBabu Moger 		.seq_show	= rdtgroup_mode_show,
1476*fa7d9493SBabu Moger 		.fflags		= RF_CTRL_BASE,
1477*fa7d9493SBabu Moger 	},
1478*fa7d9493SBabu Moger 	{
1479*fa7d9493SBabu Moger 		.name		= "size",
1480*fa7d9493SBabu Moger 		.mode		= 0444,
1481*fa7d9493SBabu Moger 		.kf_ops		= &rdtgroup_kf_single_ops,
1482*fa7d9493SBabu Moger 		.seq_show	= rdtgroup_size_show,
1483*fa7d9493SBabu Moger 		.fflags		= RF_CTRL_BASE,
1484*fa7d9493SBabu Moger 	},
1485*fa7d9493SBabu Moger 
1486*fa7d9493SBabu Moger };
1487*fa7d9493SBabu Moger 
1488*fa7d9493SBabu Moger static int rdtgroup_add_files(struct kernfs_node *kn, unsigned long fflags)
1489*fa7d9493SBabu Moger {
1490*fa7d9493SBabu Moger 	struct rftype *rfts, *rft;
1491*fa7d9493SBabu Moger 	int ret, len;
1492*fa7d9493SBabu Moger 
1493*fa7d9493SBabu Moger 	rfts = res_common_files;
1494*fa7d9493SBabu Moger 	len = ARRAY_SIZE(res_common_files);
1495*fa7d9493SBabu Moger 
1496*fa7d9493SBabu Moger 	lockdep_assert_held(&rdtgroup_mutex);
1497*fa7d9493SBabu Moger 
1498*fa7d9493SBabu Moger 	for (rft = rfts; rft < rfts + len; rft++) {
1499*fa7d9493SBabu Moger 		if ((fflags & rft->fflags) == rft->fflags) {
1500*fa7d9493SBabu Moger 			ret = rdtgroup_add_file(kn, rft);
1501*fa7d9493SBabu Moger 			if (ret)
1502*fa7d9493SBabu Moger 				goto error;
1503*fa7d9493SBabu Moger 		}
1504*fa7d9493SBabu Moger 	}
1505*fa7d9493SBabu Moger 
1506*fa7d9493SBabu Moger 	return 0;
1507*fa7d9493SBabu Moger error:
1508*fa7d9493SBabu Moger 	pr_warn("Failed to add %s, err=%d\n", rft->name, ret);
1509*fa7d9493SBabu Moger 	while (--rft >= rfts) {
1510*fa7d9493SBabu Moger 		if ((fflags & rft->fflags) == rft->fflags)
1511*fa7d9493SBabu Moger 			kernfs_remove_by_name(kn, rft->name);
1512*fa7d9493SBabu Moger 	}
1513*fa7d9493SBabu Moger 	return ret;
1514*fa7d9493SBabu Moger }
1515*fa7d9493SBabu Moger 
1516*fa7d9493SBabu Moger /**
1517*fa7d9493SBabu Moger  * rdtgroup_kn_mode_restrict - Restrict user access to named resctrl file
1518*fa7d9493SBabu Moger  * @r: The resource group with which the file is associated.
1519*fa7d9493SBabu Moger  * @name: Name of the file
1520*fa7d9493SBabu Moger  *
1521*fa7d9493SBabu Moger  * The permissions of named resctrl file, directory, or link are modified
1522*fa7d9493SBabu Moger  * to not allow read, write, or execute by any user.
1523*fa7d9493SBabu Moger  *
1524*fa7d9493SBabu Moger  * WARNING: This function is intended to communicate to the user that the
1525*fa7d9493SBabu Moger  * resctrl file has been locked down - that it is not relevant to the
1526*fa7d9493SBabu Moger  * particular state the system finds itself in. It should not be relied
1527*fa7d9493SBabu Moger  * on to protect from user access because after the file's permissions
1528*fa7d9493SBabu Moger  * are restricted the user can still change the permissions using chmod
1529*fa7d9493SBabu Moger  * from the command line.
1530*fa7d9493SBabu Moger  *
1531*fa7d9493SBabu Moger  * Return: 0 on success, <0 on failure.
1532*fa7d9493SBabu Moger  */
1533*fa7d9493SBabu Moger int rdtgroup_kn_mode_restrict(struct rdtgroup *r, const char *name)
1534*fa7d9493SBabu Moger {
1535*fa7d9493SBabu Moger 	struct iattr iattr = {.ia_valid = ATTR_MODE,};
1536*fa7d9493SBabu Moger 	struct kernfs_node *kn;
1537*fa7d9493SBabu Moger 	int ret = 0;
1538*fa7d9493SBabu Moger 
1539*fa7d9493SBabu Moger 	kn = kernfs_find_and_get_ns(r->kn, name, NULL);
1540*fa7d9493SBabu Moger 	if (!kn)
1541*fa7d9493SBabu Moger 		return -ENOENT;
1542*fa7d9493SBabu Moger 
1543*fa7d9493SBabu Moger 	switch (kernfs_type(kn)) {
1544*fa7d9493SBabu Moger 	case KERNFS_DIR:
1545*fa7d9493SBabu Moger 		iattr.ia_mode = S_IFDIR;
1546*fa7d9493SBabu Moger 		break;
1547*fa7d9493SBabu Moger 	case KERNFS_FILE:
1548*fa7d9493SBabu Moger 		iattr.ia_mode = S_IFREG;
1549*fa7d9493SBabu Moger 		break;
1550*fa7d9493SBabu Moger 	case KERNFS_LINK:
1551*fa7d9493SBabu Moger 		iattr.ia_mode = S_IFLNK;
1552*fa7d9493SBabu Moger 		break;
1553*fa7d9493SBabu Moger 	}
1554*fa7d9493SBabu Moger 
1555*fa7d9493SBabu Moger 	ret = kernfs_setattr(kn, &iattr);
1556*fa7d9493SBabu Moger 	kernfs_put(kn);
1557*fa7d9493SBabu Moger 	return ret;
1558*fa7d9493SBabu Moger }
1559*fa7d9493SBabu Moger 
1560*fa7d9493SBabu Moger /**
1561*fa7d9493SBabu Moger  * rdtgroup_kn_mode_restore - Restore user access to named resctrl file
1562*fa7d9493SBabu Moger  * @r: The resource group with which the file is associated.
1563*fa7d9493SBabu Moger  * @name: Name of the file
1564*fa7d9493SBabu Moger  * @mask: Mask of permissions that should be restored
1565*fa7d9493SBabu Moger  *
1566*fa7d9493SBabu Moger  * Restore the permissions of the named file. If @name is a directory the
1567*fa7d9493SBabu Moger  * permissions of its parent will be used.
1568*fa7d9493SBabu Moger  *
1569*fa7d9493SBabu Moger  * Return: 0 on success, <0 on failure.
1570*fa7d9493SBabu Moger  */
1571*fa7d9493SBabu Moger int rdtgroup_kn_mode_restore(struct rdtgroup *r, const char *name,
1572*fa7d9493SBabu Moger 			     umode_t mask)
1573*fa7d9493SBabu Moger {
1574*fa7d9493SBabu Moger 	struct iattr iattr = {.ia_valid = ATTR_MODE,};
1575*fa7d9493SBabu Moger 	struct kernfs_node *kn, *parent;
1576*fa7d9493SBabu Moger 	struct rftype *rfts, *rft;
1577*fa7d9493SBabu Moger 	int ret, len;
1578*fa7d9493SBabu Moger 
1579*fa7d9493SBabu Moger 	rfts = res_common_files;
1580*fa7d9493SBabu Moger 	len = ARRAY_SIZE(res_common_files);
1581*fa7d9493SBabu Moger 
1582*fa7d9493SBabu Moger 	for (rft = rfts; rft < rfts + len; rft++) {
1583*fa7d9493SBabu Moger 		if (!strcmp(rft->name, name))
1584*fa7d9493SBabu Moger 			iattr.ia_mode = rft->mode & mask;
1585*fa7d9493SBabu Moger 	}
1586*fa7d9493SBabu Moger 
1587*fa7d9493SBabu Moger 	kn = kernfs_find_and_get_ns(r->kn, name, NULL);
1588*fa7d9493SBabu Moger 	if (!kn)
1589*fa7d9493SBabu Moger 		return -ENOENT;
1590*fa7d9493SBabu Moger 
1591*fa7d9493SBabu Moger 	switch (kernfs_type(kn)) {
1592*fa7d9493SBabu Moger 	case KERNFS_DIR:
1593*fa7d9493SBabu Moger 		parent = kernfs_get_parent(kn);
1594*fa7d9493SBabu Moger 		if (parent) {
1595*fa7d9493SBabu Moger 			iattr.ia_mode |= parent->mode;
1596*fa7d9493SBabu Moger 			kernfs_put(parent);
1597*fa7d9493SBabu Moger 		}
1598*fa7d9493SBabu Moger 		iattr.ia_mode |= S_IFDIR;
1599*fa7d9493SBabu Moger 		break;
1600*fa7d9493SBabu Moger 	case KERNFS_FILE:
1601*fa7d9493SBabu Moger 		iattr.ia_mode |= S_IFREG;
1602*fa7d9493SBabu Moger 		break;
1603*fa7d9493SBabu Moger 	case KERNFS_LINK:
1604*fa7d9493SBabu Moger 		iattr.ia_mode |= S_IFLNK;
1605*fa7d9493SBabu Moger 		break;
1606*fa7d9493SBabu Moger 	}
1607*fa7d9493SBabu Moger 
1608*fa7d9493SBabu Moger 	ret = kernfs_setattr(kn, &iattr);
1609*fa7d9493SBabu Moger 	kernfs_put(kn);
1610*fa7d9493SBabu Moger 	return ret;
1611*fa7d9493SBabu Moger }
1612*fa7d9493SBabu Moger 
1613*fa7d9493SBabu Moger static int rdtgroup_mkdir_info_resdir(struct rdt_resource *r, char *name,
1614*fa7d9493SBabu Moger 				      unsigned long fflags)
1615*fa7d9493SBabu Moger {
1616*fa7d9493SBabu Moger 	struct kernfs_node *kn_subdir;
1617*fa7d9493SBabu Moger 	int ret;
1618*fa7d9493SBabu Moger 
1619*fa7d9493SBabu Moger 	kn_subdir = kernfs_create_dir(kn_info, name,
1620*fa7d9493SBabu Moger 				      kn_info->mode, r);
1621*fa7d9493SBabu Moger 	if (IS_ERR(kn_subdir))
1622*fa7d9493SBabu Moger 		return PTR_ERR(kn_subdir);
1623*fa7d9493SBabu Moger 
1624*fa7d9493SBabu Moger 	kernfs_get(kn_subdir);
1625*fa7d9493SBabu Moger 	ret = rdtgroup_kn_set_ugid(kn_subdir);
1626*fa7d9493SBabu Moger 	if (ret)
1627*fa7d9493SBabu Moger 		return ret;
1628*fa7d9493SBabu Moger 
1629*fa7d9493SBabu Moger 	ret = rdtgroup_add_files(kn_subdir, fflags);
1630*fa7d9493SBabu Moger 	if (!ret)
1631*fa7d9493SBabu Moger 		kernfs_activate(kn_subdir);
1632*fa7d9493SBabu Moger 
1633*fa7d9493SBabu Moger 	return ret;
1634*fa7d9493SBabu Moger }
1635*fa7d9493SBabu Moger 
1636*fa7d9493SBabu Moger static int rdtgroup_create_info_dir(struct kernfs_node *parent_kn)
1637*fa7d9493SBabu Moger {
1638*fa7d9493SBabu Moger 	struct rdt_resource *r;
1639*fa7d9493SBabu Moger 	unsigned long fflags;
1640*fa7d9493SBabu Moger 	char name[32];
1641*fa7d9493SBabu Moger 	int ret;
1642*fa7d9493SBabu Moger 
1643*fa7d9493SBabu Moger 	/* create the directory */
1644*fa7d9493SBabu Moger 	kn_info = kernfs_create_dir(parent_kn, "info", parent_kn->mode, NULL);
1645*fa7d9493SBabu Moger 	if (IS_ERR(kn_info))
1646*fa7d9493SBabu Moger 		return PTR_ERR(kn_info);
1647*fa7d9493SBabu Moger 	kernfs_get(kn_info);
1648*fa7d9493SBabu Moger 
1649*fa7d9493SBabu Moger 	ret = rdtgroup_add_files(kn_info, RF_TOP_INFO);
1650*fa7d9493SBabu Moger 	if (ret)
1651*fa7d9493SBabu Moger 		goto out_destroy;
1652*fa7d9493SBabu Moger 
1653*fa7d9493SBabu Moger 	for_each_alloc_enabled_rdt_resource(r) {
1654*fa7d9493SBabu Moger 		fflags =  r->fflags | RF_CTRL_INFO;
1655*fa7d9493SBabu Moger 		ret = rdtgroup_mkdir_info_resdir(r, r->name, fflags);
1656*fa7d9493SBabu Moger 		if (ret)
1657*fa7d9493SBabu Moger 			goto out_destroy;
1658*fa7d9493SBabu Moger 	}
1659*fa7d9493SBabu Moger 
1660*fa7d9493SBabu Moger 	for_each_mon_enabled_rdt_resource(r) {
1661*fa7d9493SBabu Moger 		fflags =  r->fflags | RF_MON_INFO;
1662*fa7d9493SBabu Moger 		sprintf(name, "%s_MON", r->name);
1663*fa7d9493SBabu Moger 		ret = rdtgroup_mkdir_info_resdir(r, name, fflags);
1664*fa7d9493SBabu Moger 		if (ret)
1665*fa7d9493SBabu Moger 			goto out_destroy;
1666*fa7d9493SBabu Moger 	}
1667*fa7d9493SBabu Moger 
1668*fa7d9493SBabu Moger 	/*
1669*fa7d9493SBabu Moger 	 * This extra ref will be put in kernfs_remove() and guarantees
1670*fa7d9493SBabu Moger 	 * that @rdtgrp->kn is always accessible.
1671*fa7d9493SBabu Moger 	 */
1672*fa7d9493SBabu Moger 	kernfs_get(kn_info);
1673*fa7d9493SBabu Moger 
1674*fa7d9493SBabu Moger 	ret = rdtgroup_kn_set_ugid(kn_info);
1675*fa7d9493SBabu Moger 	if (ret)
1676*fa7d9493SBabu Moger 		goto out_destroy;
1677*fa7d9493SBabu Moger 
1678*fa7d9493SBabu Moger 	kernfs_activate(kn_info);
1679*fa7d9493SBabu Moger 
1680*fa7d9493SBabu Moger 	return 0;
1681*fa7d9493SBabu Moger 
1682*fa7d9493SBabu Moger out_destroy:
1683*fa7d9493SBabu Moger 	kernfs_remove(kn_info);
1684*fa7d9493SBabu Moger 	return ret;
1685*fa7d9493SBabu Moger }
1686*fa7d9493SBabu Moger 
1687*fa7d9493SBabu Moger static int
1688*fa7d9493SBabu Moger mongroup_create_dir(struct kernfs_node *parent_kn, struct rdtgroup *prgrp,
1689*fa7d9493SBabu Moger 		    char *name, struct kernfs_node **dest_kn)
1690*fa7d9493SBabu Moger {
1691*fa7d9493SBabu Moger 	struct kernfs_node *kn;
1692*fa7d9493SBabu Moger 	int ret;
1693*fa7d9493SBabu Moger 
1694*fa7d9493SBabu Moger 	/* create the directory */
1695*fa7d9493SBabu Moger 	kn = kernfs_create_dir(parent_kn, name, parent_kn->mode, prgrp);
1696*fa7d9493SBabu Moger 	if (IS_ERR(kn))
1697*fa7d9493SBabu Moger 		return PTR_ERR(kn);
1698*fa7d9493SBabu Moger 
1699*fa7d9493SBabu Moger 	if (dest_kn)
1700*fa7d9493SBabu Moger 		*dest_kn = kn;
1701*fa7d9493SBabu Moger 
1702*fa7d9493SBabu Moger 	/*
1703*fa7d9493SBabu Moger 	 * This extra ref will be put in kernfs_remove() and guarantees
1704*fa7d9493SBabu Moger 	 * that @rdtgrp->kn is always accessible.
1705*fa7d9493SBabu Moger 	 */
1706*fa7d9493SBabu Moger 	kernfs_get(kn);
1707*fa7d9493SBabu Moger 
1708*fa7d9493SBabu Moger 	ret = rdtgroup_kn_set_ugid(kn);
1709*fa7d9493SBabu Moger 	if (ret)
1710*fa7d9493SBabu Moger 		goto out_destroy;
1711*fa7d9493SBabu Moger 
1712*fa7d9493SBabu Moger 	kernfs_activate(kn);
1713*fa7d9493SBabu Moger 
1714*fa7d9493SBabu Moger 	return 0;
1715*fa7d9493SBabu Moger 
1716*fa7d9493SBabu Moger out_destroy:
1717*fa7d9493SBabu Moger 	kernfs_remove(kn);
1718*fa7d9493SBabu Moger 	return ret;
1719*fa7d9493SBabu Moger }
1720*fa7d9493SBabu Moger 
1721*fa7d9493SBabu Moger static void l3_qos_cfg_update(void *arg)
1722*fa7d9493SBabu Moger {
1723*fa7d9493SBabu Moger 	bool *enable = arg;
1724*fa7d9493SBabu Moger 
1725*fa7d9493SBabu Moger 	wrmsrl(IA32_L3_QOS_CFG, *enable ? L3_QOS_CDP_ENABLE : 0ULL);
1726*fa7d9493SBabu Moger }
1727*fa7d9493SBabu Moger 
1728*fa7d9493SBabu Moger static void l2_qos_cfg_update(void *arg)
1729*fa7d9493SBabu Moger {
1730*fa7d9493SBabu Moger 	bool *enable = arg;
1731*fa7d9493SBabu Moger 
1732*fa7d9493SBabu Moger 	wrmsrl(IA32_L2_QOS_CFG, *enable ? L2_QOS_CDP_ENABLE : 0ULL);
1733*fa7d9493SBabu Moger }
1734*fa7d9493SBabu Moger 
1735*fa7d9493SBabu Moger static inline bool is_mba_linear(void)
1736*fa7d9493SBabu Moger {
1737*fa7d9493SBabu Moger 	return rdt_resources_all[RDT_RESOURCE_MBA].membw.delay_linear;
1738*fa7d9493SBabu Moger }
1739*fa7d9493SBabu Moger 
1740*fa7d9493SBabu Moger static int set_cache_qos_cfg(int level, bool enable)
1741*fa7d9493SBabu Moger {
1742*fa7d9493SBabu Moger 	void (*update)(void *arg);
1743*fa7d9493SBabu Moger 	struct rdt_resource *r_l;
1744*fa7d9493SBabu Moger 	cpumask_var_t cpu_mask;
1745*fa7d9493SBabu Moger 	struct rdt_domain *d;
1746*fa7d9493SBabu Moger 	int cpu;
1747*fa7d9493SBabu Moger 
1748*fa7d9493SBabu Moger 	if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
1749*fa7d9493SBabu Moger 		return -ENOMEM;
1750*fa7d9493SBabu Moger 
1751*fa7d9493SBabu Moger 	if (level == RDT_RESOURCE_L3)
1752*fa7d9493SBabu Moger 		update = l3_qos_cfg_update;
1753*fa7d9493SBabu Moger 	else if (level == RDT_RESOURCE_L2)
1754*fa7d9493SBabu Moger 		update = l2_qos_cfg_update;
1755*fa7d9493SBabu Moger 	else
1756*fa7d9493SBabu Moger 		return -EINVAL;
1757*fa7d9493SBabu Moger 
1758*fa7d9493SBabu Moger 	r_l = &rdt_resources_all[level];
1759*fa7d9493SBabu Moger 	list_for_each_entry(d, &r_l->domains, list) {
1760*fa7d9493SBabu Moger 		/* Pick one CPU from each domain instance to update MSR */
1761*fa7d9493SBabu Moger 		cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
1762*fa7d9493SBabu Moger 	}
1763*fa7d9493SBabu Moger 	cpu = get_cpu();
1764*fa7d9493SBabu Moger 	/* Update QOS_CFG MSR on this cpu if it's in cpu_mask. */
1765*fa7d9493SBabu Moger 	if (cpumask_test_cpu(cpu, cpu_mask))
1766*fa7d9493SBabu Moger 		update(&enable);
1767*fa7d9493SBabu Moger 	/* Update QOS_CFG MSR on all other cpus in cpu_mask. */
1768*fa7d9493SBabu Moger 	smp_call_function_many(cpu_mask, update, &enable, 1);
1769*fa7d9493SBabu Moger 	put_cpu();
1770*fa7d9493SBabu Moger 
1771*fa7d9493SBabu Moger 	free_cpumask_var(cpu_mask);
1772*fa7d9493SBabu Moger 
1773*fa7d9493SBabu Moger 	return 0;
1774*fa7d9493SBabu Moger }
1775*fa7d9493SBabu Moger 
1776*fa7d9493SBabu Moger /*
1777*fa7d9493SBabu Moger  * Enable or disable the MBA software controller
1778*fa7d9493SBabu Moger  * which helps user specify bandwidth in MBps.
1779*fa7d9493SBabu Moger  * MBA software controller is supported only if
1780*fa7d9493SBabu Moger  * MBM is supported and MBA is in linear scale.
1781*fa7d9493SBabu Moger  */
1782*fa7d9493SBabu Moger static int set_mba_sc(bool mba_sc)
1783*fa7d9493SBabu Moger {
1784*fa7d9493SBabu Moger 	struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_MBA];
1785*fa7d9493SBabu Moger 	struct rdt_domain *d;
1786*fa7d9493SBabu Moger 
1787*fa7d9493SBabu Moger 	if (!is_mbm_enabled() || !is_mba_linear() ||
1788*fa7d9493SBabu Moger 	    mba_sc == is_mba_sc(r))
1789*fa7d9493SBabu Moger 		return -EINVAL;
1790*fa7d9493SBabu Moger 
1791*fa7d9493SBabu Moger 	r->membw.mba_sc = mba_sc;
1792*fa7d9493SBabu Moger 	list_for_each_entry(d, &r->domains, list)
1793*fa7d9493SBabu Moger 		setup_default_ctrlval(r, d->ctrl_val, d->mbps_val);
1794*fa7d9493SBabu Moger 
1795*fa7d9493SBabu Moger 	return 0;
1796*fa7d9493SBabu Moger }
1797*fa7d9493SBabu Moger 
1798*fa7d9493SBabu Moger static int cdp_enable(int level, int data_type, int code_type)
1799*fa7d9493SBabu Moger {
1800*fa7d9493SBabu Moger 	struct rdt_resource *r_ldata = &rdt_resources_all[data_type];
1801*fa7d9493SBabu Moger 	struct rdt_resource *r_lcode = &rdt_resources_all[code_type];
1802*fa7d9493SBabu Moger 	struct rdt_resource *r_l = &rdt_resources_all[level];
1803*fa7d9493SBabu Moger 	int ret;
1804*fa7d9493SBabu Moger 
1805*fa7d9493SBabu Moger 	if (!r_l->alloc_capable || !r_ldata->alloc_capable ||
1806*fa7d9493SBabu Moger 	    !r_lcode->alloc_capable)
1807*fa7d9493SBabu Moger 		return -EINVAL;
1808*fa7d9493SBabu Moger 
1809*fa7d9493SBabu Moger 	ret = set_cache_qos_cfg(level, true);
1810*fa7d9493SBabu Moger 	if (!ret) {
1811*fa7d9493SBabu Moger 		r_l->alloc_enabled = false;
1812*fa7d9493SBabu Moger 		r_ldata->alloc_enabled = true;
1813*fa7d9493SBabu Moger 		r_lcode->alloc_enabled = true;
1814*fa7d9493SBabu Moger 	}
1815*fa7d9493SBabu Moger 	return ret;
1816*fa7d9493SBabu Moger }
1817*fa7d9493SBabu Moger 
1818*fa7d9493SBabu Moger static int cdpl3_enable(void)
1819*fa7d9493SBabu Moger {
1820*fa7d9493SBabu Moger 	return cdp_enable(RDT_RESOURCE_L3, RDT_RESOURCE_L3DATA,
1821*fa7d9493SBabu Moger 			  RDT_RESOURCE_L3CODE);
1822*fa7d9493SBabu Moger }
1823*fa7d9493SBabu Moger 
1824*fa7d9493SBabu Moger static int cdpl2_enable(void)
1825*fa7d9493SBabu Moger {
1826*fa7d9493SBabu Moger 	return cdp_enable(RDT_RESOURCE_L2, RDT_RESOURCE_L2DATA,
1827*fa7d9493SBabu Moger 			  RDT_RESOURCE_L2CODE);
1828*fa7d9493SBabu Moger }
1829*fa7d9493SBabu Moger 
1830*fa7d9493SBabu Moger static void cdp_disable(int level, int data_type, int code_type)
1831*fa7d9493SBabu Moger {
1832*fa7d9493SBabu Moger 	struct rdt_resource *r = &rdt_resources_all[level];
1833*fa7d9493SBabu Moger 
1834*fa7d9493SBabu Moger 	r->alloc_enabled = r->alloc_capable;
1835*fa7d9493SBabu Moger 
1836*fa7d9493SBabu Moger 	if (rdt_resources_all[data_type].alloc_enabled) {
1837*fa7d9493SBabu Moger 		rdt_resources_all[data_type].alloc_enabled = false;
1838*fa7d9493SBabu Moger 		rdt_resources_all[code_type].alloc_enabled = false;
1839*fa7d9493SBabu Moger 		set_cache_qos_cfg(level, false);
1840*fa7d9493SBabu Moger 	}
1841*fa7d9493SBabu Moger }
1842*fa7d9493SBabu Moger 
1843*fa7d9493SBabu Moger static void cdpl3_disable(void)
1844*fa7d9493SBabu Moger {
1845*fa7d9493SBabu Moger 	cdp_disable(RDT_RESOURCE_L3, RDT_RESOURCE_L3DATA, RDT_RESOURCE_L3CODE);
1846*fa7d9493SBabu Moger }
1847*fa7d9493SBabu Moger 
1848*fa7d9493SBabu Moger static void cdpl2_disable(void)
1849*fa7d9493SBabu Moger {
1850*fa7d9493SBabu Moger 	cdp_disable(RDT_RESOURCE_L2, RDT_RESOURCE_L2DATA, RDT_RESOURCE_L2CODE);
1851*fa7d9493SBabu Moger }
1852*fa7d9493SBabu Moger 
1853*fa7d9493SBabu Moger static void cdp_disable_all(void)
1854*fa7d9493SBabu Moger {
1855*fa7d9493SBabu Moger 	if (rdt_resources_all[RDT_RESOURCE_L3DATA].alloc_enabled)
1856*fa7d9493SBabu Moger 		cdpl3_disable();
1857*fa7d9493SBabu Moger 	if (rdt_resources_all[RDT_RESOURCE_L2DATA].alloc_enabled)
1858*fa7d9493SBabu Moger 		cdpl2_disable();
1859*fa7d9493SBabu Moger }
1860*fa7d9493SBabu Moger 
1861*fa7d9493SBabu Moger static int parse_rdtgroupfs_options(char *data)
1862*fa7d9493SBabu Moger {
1863*fa7d9493SBabu Moger 	char *token, *o = data;
1864*fa7d9493SBabu Moger 	int ret = 0;
1865*fa7d9493SBabu Moger 
1866*fa7d9493SBabu Moger 	while ((token = strsep(&o, ",")) != NULL) {
1867*fa7d9493SBabu Moger 		if (!*token) {
1868*fa7d9493SBabu Moger 			ret = -EINVAL;
1869*fa7d9493SBabu Moger 			goto out;
1870*fa7d9493SBabu Moger 		}
1871*fa7d9493SBabu Moger 
1872*fa7d9493SBabu Moger 		if (!strcmp(token, "cdp")) {
1873*fa7d9493SBabu Moger 			ret = cdpl3_enable();
1874*fa7d9493SBabu Moger 			if (ret)
1875*fa7d9493SBabu Moger 				goto out;
1876*fa7d9493SBabu Moger 		} else if (!strcmp(token, "cdpl2")) {
1877*fa7d9493SBabu Moger 			ret = cdpl2_enable();
1878*fa7d9493SBabu Moger 			if (ret)
1879*fa7d9493SBabu Moger 				goto out;
1880*fa7d9493SBabu Moger 		} else if (!strcmp(token, "mba_MBps")) {
1881*fa7d9493SBabu Moger 			ret = set_mba_sc(true);
1882*fa7d9493SBabu Moger 			if (ret)
1883*fa7d9493SBabu Moger 				goto out;
1884*fa7d9493SBabu Moger 		} else {
1885*fa7d9493SBabu Moger 			ret = -EINVAL;
1886*fa7d9493SBabu Moger 			goto out;
1887*fa7d9493SBabu Moger 		}
1888*fa7d9493SBabu Moger 	}
1889*fa7d9493SBabu Moger 
1890*fa7d9493SBabu Moger 	return 0;
1891*fa7d9493SBabu Moger 
1892*fa7d9493SBabu Moger out:
1893*fa7d9493SBabu Moger 	pr_err("Invalid mount option \"%s\"\n", token);
1894*fa7d9493SBabu Moger 
1895*fa7d9493SBabu Moger 	return ret;
1896*fa7d9493SBabu Moger }
1897*fa7d9493SBabu Moger 
1898*fa7d9493SBabu Moger /*
1899*fa7d9493SBabu Moger  * We don't allow rdtgroup directories to be created anywhere
1900*fa7d9493SBabu Moger  * except the root directory. Thus when looking for the rdtgroup
1901*fa7d9493SBabu Moger  * structure for a kernfs node we are either looking at a directory,
1902*fa7d9493SBabu Moger  * in which case the rdtgroup structure is pointed at by the "priv"
1903*fa7d9493SBabu Moger  * field, otherwise we have a file, and need only look to the parent
1904*fa7d9493SBabu Moger  * to find the rdtgroup.
1905*fa7d9493SBabu Moger  */
1906*fa7d9493SBabu Moger static struct rdtgroup *kernfs_to_rdtgroup(struct kernfs_node *kn)
1907*fa7d9493SBabu Moger {
1908*fa7d9493SBabu Moger 	if (kernfs_type(kn) == KERNFS_DIR) {
1909*fa7d9493SBabu Moger 		/*
1910*fa7d9493SBabu Moger 		 * All the resource directories use "kn->priv"
1911*fa7d9493SBabu Moger 		 * to point to the "struct rdtgroup" for the
1912*fa7d9493SBabu Moger 		 * resource. "info" and its subdirectories don't
1913*fa7d9493SBabu Moger 		 * have rdtgroup structures, so return NULL here.
1914*fa7d9493SBabu Moger 		 */
1915*fa7d9493SBabu Moger 		if (kn == kn_info || kn->parent == kn_info)
1916*fa7d9493SBabu Moger 			return NULL;
1917*fa7d9493SBabu Moger 		else
1918*fa7d9493SBabu Moger 			return kn->priv;
1919*fa7d9493SBabu Moger 	} else {
1920*fa7d9493SBabu Moger 		return kn->parent->priv;
1921*fa7d9493SBabu Moger 	}
1922*fa7d9493SBabu Moger }
1923*fa7d9493SBabu Moger 
1924*fa7d9493SBabu Moger struct rdtgroup *rdtgroup_kn_lock_live(struct kernfs_node *kn)
1925*fa7d9493SBabu Moger {
1926*fa7d9493SBabu Moger 	struct rdtgroup *rdtgrp = kernfs_to_rdtgroup(kn);
1927*fa7d9493SBabu Moger 
1928*fa7d9493SBabu Moger 	if (!rdtgrp)
1929*fa7d9493SBabu Moger 		return NULL;
1930*fa7d9493SBabu Moger 
1931*fa7d9493SBabu Moger 	atomic_inc(&rdtgrp->waitcount);
1932*fa7d9493SBabu Moger 	kernfs_break_active_protection(kn);
1933*fa7d9493SBabu Moger 
1934*fa7d9493SBabu Moger 	mutex_lock(&rdtgroup_mutex);
1935*fa7d9493SBabu Moger 
1936*fa7d9493SBabu Moger 	/* Was this group deleted while we waited? */
1937*fa7d9493SBabu Moger 	if (rdtgrp->flags & RDT_DELETED)
1938*fa7d9493SBabu Moger 		return NULL;
1939*fa7d9493SBabu Moger 
1940*fa7d9493SBabu Moger 	return rdtgrp;
1941*fa7d9493SBabu Moger }
1942*fa7d9493SBabu Moger 
1943*fa7d9493SBabu Moger void rdtgroup_kn_unlock(struct kernfs_node *kn)
1944*fa7d9493SBabu Moger {
1945*fa7d9493SBabu Moger 	struct rdtgroup *rdtgrp = kernfs_to_rdtgroup(kn);
1946*fa7d9493SBabu Moger 
1947*fa7d9493SBabu Moger 	if (!rdtgrp)
1948*fa7d9493SBabu Moger 		return;
1949*fa7d9493SBabu Moger 
1950*fa7d9493SBabu Moger 	mutex_unlock(&rdtgroup_mutex);
1951*fa7d9493SBabu Moger 
1952*fa7d9493SBabu Moger 	if (atomic_dec_and_test(&rdtgrp->waitcount) &&
1953*fa7d9493SBabu Moger 	    (rdtgrp->flags & RDT_DELETED)) {
1954*fa7d9493SBabu Moger 		if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP ||
1955*fa7d9493SBabu Moger 		    rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED)
1956*fa7d9493SBabu Moger 			rdtgroup_pseudo_lock_remove(rdtgrp);
1957*fa7d9493SBabu Moger 		kernfs_unbreak_active_protection(kn);
1958*fa7d9493SBabu Moger 		kernfs_put(rdtgrp->kn);
1959*fa7d9493SBabu Moger 		kfree(rdtgrp);
1960*fa7d9493SBabu Moger 	} else {
1961*fa7d9493SBabu Moger 		kernfs_unbreak_active_protection(kn);
1962*fa7d9493SBabu Moger 	}
1963*fa7d9493SBabu Moger }
1964*fa7d9493SBabu Moger 
1965*fa7d9493SBabu Moger static int mkdir_mondata_all(struct kernfs_node *parent_kn,
1966*fa7d9493SBabu Moger 			     struct rdtgroup *prgrp,
1967*fa7d9493SBabu Moger 			     struct kernfs_node **mon_data_kn);
1968*fa7d9493SBabu Moger 
1969*fa7d9493SBabu Moger static struct dentry *rdt_mount(struct file_system_type *fs_type,
1970*fa7d9493SBabu Moger 				int flags, const char *unused_dev_name,
1971*fa7d9493SBabu Moger 				void *data)
1972*fa7d9493SBabu Moger {
1973*fa7d9493SBabu Moger 	struct rdt_domain *dom;
1974*fa7d9493SBabu Moger 	struct rdt_resource *r;
1975*fa7d9493SBabu Moger 	struct dentry *dentry;
1976*fa7d9493SBabu Moger 	int ret;
1977*fa7d9493SBabu Moger 
1978*fa7d9493SBabu Moger 	cpus_read_lock();
1979*fa7d9493SBabu Moger 	mutex_lock(&rdtgroup_mutex);
1980*fa7d9493SBabu Moger 	/*
1981*fa7d9493SBabu Moger 	 * resctrl file system can only be mounted once.
1982*fa7d9493SBabu Moger 	 */
1983*fa7d9493SBabu Moger 	if (static_branch_unlikely(&rdt_enable_key)) {
1984*fa7d9493SBabu Moger 		dentry = ERR_PTR(-EBUSY);
1985*fa7d9493SBabu Moger 		goto out;
1986*fa7d9493SBabu Moger 	}
1987*fa7d9493SBabu Moger 
1988*fa7d9493SBabu Moger 	ret = parse_rdtgroupfs_options(data);
1989*fa7d9493SBabu Moger 	if (ret) {
1990*fa7d9493SBabu Moger 		dentry = ERR_PTR(ret);
1991*fa7d9493SBabu Moger 		goto out_cdp;
1992*fa7d9493SBabu Moger 	}
1993*fa7d9493SBabu Moger 
1994*fa7d9493SBabu Moger 	closid_init();
1995*fa7d9493SBabu Moger 
1996*fa7d9493SBabu Moger 	ret = rdtgroup_create_info_dir(rdtgroup_default.kn);
1997*fa7d9493SBabu Moger 	if (ret) {
1998*fa7d9493SBabu Moger 		dentry = ERR_PTR(ret);
1999*fa7d9493SBabu Moger 		goto out_cdp;
2000*fa7d9493SBabu Moger 	}
2001*fa7d9493SBabu Moger 
2002*fa7d9493SBabu Moger 	if (rdt_mon_capable) {
2003*fa7d9493SBabu Moger 		ret = mongroup_create_dir(rdtgroup_default.kn,
2004*fa7d9493SBabu Moger 					  NULL, "mon_groups",
2005*fa7d9493SBabu Moger 					  &kn_mongrp);
2006*fa7d9493SBabu Moger 		if (ret) {
2007*fa7d9493SBabu Moger 			dentry = ERR_PTR(ret);
2008*fa7d9493SBabu Moger 			goto out_info;
2009*fa7d9493SBabu Moger 		}
2010*fa7d9493SBabu Moger 		kernfs_get(kn_mongrp);
2011*fa7d9493SBabu Moger 
2012*fa7d9493SBabu Moger 		ret = mkdir_mondata_all(rdtgroup_default.kn,
2013*fa7d9493SBabu Moger 					&rdtgroup_default, &kn_mondata);
2014*fa7d9493SBabu Moger 		if (ret) {
2015*fa7d9493SBabu Moger 			dentry = ERR_PTR(ret);
2016*fa7d9493SBabu Moger 			goto out_mongrp;
2017*fa7d9493SBabu Moger 		}
2018*fa7d9493SBabu Moger 		kernfs_get(kn_mondata);
2019*fa7d9493SBabu Moger 		rdtgroup_default.mon.mon_data_kn = kn_mondata;
2020*fa7d9493SBabu Moger 	}
2021*fa7d9493SBabu Moger 
2022*fa7d9493SBabu Moger 	ret = rdt_pseudo_lock_init();
2023*fa7d9493SBabu Moger 	if (ret) {
2024*fa7d9493SBabu Moger 		dentry = ERR_PTR(ret);
2025*fa7d9493SBabu Moger 		goto out_mondata;
2026*fa7d9493SBabu Moger 	}
2027*fa7d9493SBabu Moger 
2028*fa7d9493SBabu Moger 	dentry = kernfs_mount(fs_type, flags, rdt_root,
2029*fa7d9493SBabu Moger 			      RDTGROUP_SUPER_MAGIC, NULL);
2030*fa7d9493SBabu Moger 	if (IS_ERR(dentry))
2031*fa7d9493SBabu Moger 		goto out_psl;
2032*fa7d9493SBabu Moger 
2033*fa7d9493SBabu Moger 	if (rdt_alloc_capable)
2034*fa7d9493SBabu Moger 		static_branch_enable_cpuslocked(&rdt_alloc_enable_key);
2035*fa7d9493SBabu Moger 	if (rdt_mon_capable)
2036*fa7d9493SBabu Moger 		static_branch_enable_cpuslocked(&rdt_mon_enable_key);
2037*fa7d9493SBabu Moger 
2038*fa7d9493SBabu Moger 	if (rdt_alloc_capable || rdt_mon_capable)
2039*fa7d9493SBabu Moger 		static_branch_enable_cpuslocked(&rdt_enable_key);
2040*fa7d9493SBabu Moger 
2041*fa7d9493SBabu Moger 	if (is_mbm_enabled()) {
2042*fa7d9493SBabu Moger 		r = &rdt_resources_all[RDT_RESOURCE_L3];
2043*fa7d9493SBabu Moger 		list_for_each_entry(dom, &r->domains, list)
2044*fa7d9493SBabu Moger 			mbm_setup_overflow_handler(dom, MBM_OVERFLOW_INTERVAL);
2045*fa7d9493SBabu Moger 	}
2046*fa7d9493SBabu Moger 
2047*fa7d9493SBabu Moger 	goto out;
2048*fa7d9493SBabu Moger 
2049*fa7d9493SBabu Moger out_psl:
2050*fa7d9493SBabu Moger 	rdt_pseudo_lock_release();
2051*fa7d9493SBabu Moger out_mondata:
2052*fa7d9493SBabu Moger 	if (rdt_mon_capable)
2053*fa7d9493SBabu Moger 		kernfs_remove(kn_mondata);
2054*fa7d9493SBabu Moger out_mongrp:
2055*fa7d9493SBabu Moger 	if (rdt_mon_capable)
2056*fa7d9493SBabu Moger 		kernfs_remove(kn_mongrp);
2057*fa7d9493SBabu Moger out_info:
2058*fa7d9493SBabu Moger 	kernfs_remove(kn_info);
2059*fa7d9493SBabu Moger out_cdp:
2060*fa7d9493SBabu Moger 	cdp_disable_all();
2061*fa7d9493SBabu Moger out:
2062*fa7d9493SBabu Moger 	rdt_last_cmd_clear();
2063*fa7d9493SBabu Moger 	mutex_unlock(&rdtgroup_mutex);
2064*fa7d9493SBabu Moger 	cpus_read_unlock();
2065*fa7d9493SBabu Moger 
2066*fa7d9493SBabu Moger 	return dentry;
2067*fa7d9493SBabu Moger }
2068*fa7d9493SBabu Moger 
2069*fa7d9493SBabu Moger static int reset_all_ctrls(struct rdt_resource *r)
2070*fa7d9493SBabu Moger {
2071*fa7d9493SBabu Moger 	struct msr_param msr_param;
2072*fa7d9493SBabu Moger 	cpumask_var_t cpu_mask;
2073*fa7d9493SBabu Moger 	struct rdt_domain *d;
2074*fa7d9493SBabu Moger 	int i, cpu;
2075*fa7d9493SBabu Moger 
2076*fa7d9493SBabu Moger 	if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
2077*fa7d9493SBabu Moger 		return -ENOMEM;
2078*fa7d9493SBabu Moger 
2079*fa7d9493SBabu Moger 	msr_param.res = r;
2080*fa7d9493SBabu Moger 	msr_param.low = 0;
2081*fa7d9493SBabu Moger 	msr_param.high = r->num_closid;
2082*fa7d9493SBabu Moger 
2083*fa7d9493SBabu Moger 	/*
2084*fa7d9493SBabu Moger 	 * Disable resource control for this resource by setting all
2085*fa7d9493SBabu Moger 	 * CBMs in all domains to the maximum mask value. Pick one CPU
2086*fa7d9493SBabu Moger 	 * from each domain to update the MSRs below.
2087*fa7d9493SBabu Moger 	 */
2088*fa7d9493SBabu Moger 	list_for_each_entry(d, &r->domains, list) {
2089*fa7d9493SBabu Moger 		cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
2090*fa7d9493SBabu Moger 
2091*fa7d9493SBabu Moger 		for (i = 0; i < r->num_closid; i++)
2092*fa7d9493SBabu Moger 			d->ctrl_val[i] = r->default_ctrl;
2093*fa7d9493SBabu Moger 	}
2094*fa7d9493SBabu Moger 	cpu = get_cpu();
2095*fa7d9493SBabu Moger 	/* Update CBM on this cpu if it's in cpu_mask. */
2096*fa7d9493SBabu Moger 	if (cpumask_test_cpu(cpu, cpu_mask))
2097*fa7d9493SBabu Moger 		rdt_ctrl_update(&msr_param);
2098*fa7d9493SBabu Moger 	/* Update CBM on all other cpus in cpu_mask. */
2099*fa7d9493SBabu Moger 	smp_call_function_many(cpu_mask, rdt_ctrl_update, &msr_param, 1);
2100*fa7d9493SBabu Moger 	put_cpu();
2101*fa7d9493SBabu Moger 
2102*fa7d9493SBabu Moger 	free_cpumask_var(cpu_mask);
2103*fa7d9493SBabu Moger 
2104*fa7d9493SBabu Moger 	return 0;
2105*fa7d9493SBabu Moger }
2106*fa7d9493SBabu Moger 
2107*fa7d9493SBabu Moger static bool is_closid_match(struct task_struct *t, struct rdtgroup *r)
2108*fa7d9493SBabu Moger {
2109*fa7d9493SBabu Moger 	return (rdt_alloc_capable &&
2110*fa7d9493SBabu Moger 		(r->type == RDTCTRL_GROUP) && (t->closid == r->closid));
2111*fa7d9493SBabu Moger }
2112*fa7d9493SBabu Moger 
2113*fa7d9493SBabu Moger static bool is_rmid_match(struct task_struct *t, struct rdtgroup *r)
2114*fa7d9493SBabu Moger {
2115*fa7d9493SBabu Moger 	return (rdt_mon_capable &&
2116*fa7d9493SBabu Moger 		(r->type == RDTMON_GROUP) && (t->rmid == r->mon.rmid));
2117*fa7d9493SBabu Moger }
2118*fa7d9493SBabu Moger 
2119*fa7d9493SBabu Moger /*
2120*fa7d9493SBabu Moger  * Move tasks from one to the other group. If @from is NULL, then all tasks
2121*fa7d9493SBabu Moger  * in the systems are moved unconditionally (used for teardown).
2122*fa7d9493SBabu Moger  *
2123*fa7d9493SBabu Moger  * If @mask is not NULL the cpus on which moved tasks are running are set
2124*fa7d9493SBabu Moger  * in that mask so the update smp function call is restricted to affected
2125*fa7d9493SBabu Moger  * cpus.
2126*fa7d9493SBabu Moger  */
2127*fa7d9493SBabu Moger static void rdt_move_group_tasks(struct rdtgroup *from, struct rdtgroup *to,
2128*fa7d9493SBabu Moger 				 struct cpumask *mask)
2129*fa7d9493SBabu Moger {
2130*fa7d9493SBabu Moger 	struct task_struct *p, *t;
2131*fa7d9493SBabu Moger 
2132*fa7d9493SBabu Moger 	read_lock(&tasklist_lock);
2133*fa7d9493SBabu Moger 	for_each_process_thread(p, t) {
2134*fa7d9493SBabu Moger 		if (!from || is_closid_match(t, from) ||
2135*fa7d9493SBabu Moger 		    is_rmid_match(t, from)) {
2136*fa7d9493SBabu Moger 			t->closid = to->closid;
2137*fa7d9493SBabu Moger 			t->rmid = to->mon.rmid;
2138*fa7d9493SBabu Moger 
2139*fa7d9493SBabu Moger #ifdef CONFIG_SMP
2140*fa7d9493SBabu Moger 			/*
2141*fa7d9493SBabu Moger 			 * This is safe on x86 w/o barriers as the ordering
2142*fa7d9493SBabu Moger 			 * of writing to task_cpu() and t->on_cpu is
2143*fa7d9493SBabu Moger 			 * reverse to the reading here. The detection is
2144*fa7d9493SBabu Moger 			 * inaccurate as tasks might move or schedule
2145*fa7d9493SBabu Moger 			 * before the smp function call takes place. In
2146*fa7d9493SBabu Moger 			 * such a case the function call is pointless, but
2147*fa7d9493SBabu Moger 			 * there is no other side effect.
2148*fa7d9493SBabu Moger 			 */
2149*fa7d9493SBabu Moger 			if (mask && t->on_cpu)
2150*fa7d9493SBabu Moger 				cpumask_set_cpu(task_cpu(t), mask);
2151*fa7d9493SBabu Moger #endif
2152*fa7d9493SBabu Moger 		}
2153*fa7d9493SBabu Moger 	}
2154*fa7d9493SBabu Moger 	read_unlock(&tasklist_lock);
2155*fa7d9493SBabu Moger }
2156*fa7d9493SBabu Moger 
2157*fa7d9493SBabu Moger static void free_all_child_rdtgrp(struct rdtgroup *rdtgrp)
2158*fa7d9493SBabu Moger {
2159*fa7d9493SBabu Moger 	struct rdtgroup *sentry, *stmp;
2160*fa7d9493SBabu Moger 	struct list_head *head;
2161*fa7d9493SBabu Moger 
2162*fa7d9493SBabu Moger 	head = &rdtgrp->mon.crdtgrp_list;
2163*fa7d9493SBabu Moger 	list_for_each_entry_safe(sentry, stmp, head, mon.crdtgrp_list) {
2164*fa7d9493SBabu Moger 		free_rmid(sentry->mon.rmid);
2165*fa7d9493SBabu Moger 		list_del(&sentry->mon.crdtgrp_list);
2166*fa7d9493SBabu Moger 		kfree(sentry);
2167*fa7d9493SBabu Moger 	}
2168*fa7d9493SBabu Moger }
2169*fa7d9493SBabu Moger 
2170*fa7d9493SBabu Moger /*
2171*fa7d9493SBabu Moger  * Forcibly remove all of subdirectories under root.
2172*fa7d9493SBabu Moger  */
2173*fa7d9493SBabu Moger static void rmdir_all_sub(void)
2174*fa7d9493SBabu Moger {
2175*fa7d9493SBabu Moger 	struct rdtgroup *rdtgrp, *tmp;
2176*fa7d9493SBabu Moger 
2177*fa7d9493SBabu Moger 	/* Move all tasks to the default resource group */
2178*fa7d9493SBabu Moger 	rdt_move_group_tasks(NULL, &rdtgroup_default, NULL);
2179*fa7d9493SBabu Moger 
2180*fa7d9493SBabu Moger 	list_for_each_entry_safe(rdtgrp, tmp, &rdt_all_groups, rdtgroup_list) {
2181*fa7d9493SBabu Moger 		/* Free any child rmids */
2182*fa7d9493SBabu Moger 		free_all_child_rdtgrp(rdtgrp);
2183*fa7d9493SBabu Moger 
2184*fa7d9493SBabu Moger 		/* Remove each rdtgroup other than root */
2185*fa7d9493SBabu Moger 		if (rdtgrp == &rdtgroup_default)
2186*fa7d9493SBabu Moger 			continue;
2187*fa7d9493SBabu Moger 
2188*fa7d9493SBabu Moger 		if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP ||
2189*fa7d9493SBabu Moger 		    rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED)
2190*fa7d9493SBabu Moger 			rdtgroup_pseudo_lock_remove(rdtgrp);
2191*fa7d9493SBabu Moger 
2192*fa7d9493SBabu Moger 		/*
2193*fa7d9493SBabu Moger 		 * Give any CPUs back to the default group. We cannot copy
2194*fa7d9493SBabu Moger 		 * cpu_online_mask because a CPU might have executed the
2195*fa7d9493SBabu Moger 		 * offline callback already, but is still marked online.
2196*fa7d9493SBabu Moger 		 */
2197*fa7d9493SBabu Moger 		cpumask_or(&rdtgroup_default.cpu_mask,
2198*fa7d9493SBabu Moger 			   &rdtgroup_default.cpu_mask, &rdtgrp->cpu_mask);
2199*fa7d9493SBabu Moger 
2200*fa7d9493SBabu Moger 		free_rmid(rdtgrp->mon.rmid);
2201*fa7d9493SBabu Moger 
2202*fa7d9493SBabu Moger 		kernfs_remove(rdtgrp->kn);
2203*fa7d9493SBabu Moger 		list_del(&rdtgrp->rdtgroup_list);
2204*fa7d9493SBabu Moger 		kfree(rdtgrp);
2205*fa7d9493SBabu Moger 	}
2206*fa7d9493SBabu Moger 	/* Notify online CPUs to update per cpu storage and PQR_ASSOC MSR */
2207*fa7d9493SBabu Moger 	update_closid_rmid(cpu_online_mask, &rdtgroup_default);
2208*fa7d9493SBabu Moger 
2209*fa7d9493SBabu Moger 	kernfs_remove(kn_info);
2210*fa7d9493SBabu Moger 	kernfs_remove(kn_mongrp);
2211*fa7d9493SBabu Moger 	kernfs_remove(kn_mondata);
2212*fa7d9493SBabu Moger }
2213*fa7d9493SBabu Moger 
2214*fa7d9493SBabu Moger static void rdt_kill_sb(struct super_block *sb)
2215*fa7d9493SBabu Moger {
2216*fa7d9493SBabu Moger 	struct rdt_resource *r;
2217*fa7d9493SBabu Moger 
2218*fa7d9493SBabu Moger 	cpus_read_lock();
2219*fa7d9493SBabu Moger 	mutex_lock(&rdtgroup_mutex);
2220*fa7d9493SBabu Moger 
2221*fa7d9493SBabu Moger 	set_mba_sc(false);
2222*fa7d9493SBabu Moger 
2223*fa7d9493SBabu Moger 	/*Put everything back to default values. */
2224*fa7d9493SBabu Moger 	for_each_alloc_enabled_rdt_resource(r)
2225*fa7d9493SBabu Moger 		reset_all_ctrls(r);
2226*fa7d9493SBabu Moger 	cdp_disable_all();
2227*fa7d9493SBabu Moger 	rmdir_all_sub();
2228*fa7d9493SBabu Moger 	rdt_pseudo_lock_release();
2229*fa7d9493SBabu Moger 	rdtgroup_default.mode = RDT_MODE_SHAREABLE;
2230*fa7d9493SBabu Moger 	static_branch_disable_cpuslocked(&rdt_alloc_enable_key);
2231*fa7d9493SBabu Moger 	static_branch_disable_cpuslocked(&rdt_mon_enable_key);
2232*fa7d9493SBabu Moger 	static_branch_disable_cpuslocked(&rdt_enable_key);
2233*fa7d9493SBabu Moger 	kernfs_kill_sb(sb);
2234*fa7d9493SBabu Moger 	mutex_unlock(&rdtgroup_mutex);
2235*fa7d9493SBabu Moger 	cpus_read_unlock();
2236*fa7d9493SBabu Moger }
2237*fa7d9493SBabu Moger 
2238*fa7d9493SBabu Moger static struct file_system_type rdt_fs_type = {
2239*fa7d9493SBabu Moger 	.name    = "resctrl",
2240*fa7d9493SBabu Moger 	.mount   = rdt_mount,
2241*fa7d9493SBabu Moger 	.kill_sb = rdt_kill_sb,
2242*fa7d9493SBabu Moger };
2243*fa7d9493SBabu Moger 
2244*fa7d9493SBabu Moger static int mon_addfile(struct kernfs_node *parent_kn, const char *name,
2245*fa7d9493SBabu Moger 		       void *priv)
2246*fa7d9493SBabu Moger {
2247*fa7d9493SBabu Moger 	struct kernfs_node *kn;
2248*fa7d9493SBabu Moger 	int ret = 0;
2249*fa7d9493SBabu Moger 
2250*fa7d9493SBabu Moger 	kn = __kernfs_create_file(parent_kn, name, 0444,
2251*fa7d9493SBabu Moger 				  GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, 0,
2252*fa7d9493SBabu Moger 				  &kf_mondata_ops, priv, NULL, NULL);
2253*fa7d9493SBabu Moger 	if (IS_ERR(kn))
2254*fa7d9493SBabu Moger 		return PTR_ERR(kn);
2255*fa7d9493SBabu Moger 
2256*fa7d9493SBabu Moger 	ret = rdtgroup_kn_set_ugid(kn);
2257*fa7d9493SBabu Moger 	if (ret) {
2258*fa7d9493SBabu Moger 		kernfs_remove(kn);
2259*fa7d9493SBabu Moger 		return ret;
2260*fa7d9493SBabu Moger 	}
2261*fa7d9493SBabu Moger 
2262*fa7d9493SBabu Moger 	return ret;
2263*fa7d9493SBabu Moger }
2264*fa7d9493SBabu Moger 
2265*fa7d9493SBabu Moger /*
2266*fa7d9493SBabu Moger  * Remove all subdirectories of mon_data of ctrl_mon groups
2267*fa7d9493SBabu Moger  * and monitor groups with given domain id.
2268*fa7d9493SBabu Moger  */
2269*fa7d9493SBabu Moger void rmdir_mondata_subdir_allrdtgrp(struct rdt_resource *r, unsigned int dom_id)
2270*fa7d9493SBabu Moger {
2271*fa7d9493SBabu Moger 	struct rdtgroup *prgrp, *crgrp;
2272*fa7d9493SBabu Moger 	char name[32];
2273*fa7d9493SBabu Moger 
2274*fa7d9493SBabu Moger 	if (!r->mon_enabled)
2275*fa7d9493SBabu Moger 		return;
2276*fa7d9493SBabu Moger 
2277*fa7d9493SBabu Moger 	list_for_each_entry(prgrp, &rdt_all_groups, rdtgroup_list) {
2278*fa7d9493SBabu Moger 		sprintf(name, "mon_%s_%02d", r->name, dom_id);
2279*fa7d9493SBabu Moger 		kernfs_remove_by_name(prgrp->mon.mon_data_kn, name);
2280*fa7d9493SBabu Moger 
2281*fa7d9493SBabu Moger 		list_for_each_entry(crgrp, &prgrp->mon.crdtgrp_list, mon.crdtgrp_list)
2282*fa7d9493SBabu Moger 			kernfs_remove_by_name(crgrp->mon.mon_data_kn, name);
2283*fa7d9493SBabu Moger 	}
2284*fa7d9493SBabu Moger }
2285*fa7d9493SBabu Moger 
2286*fa7d9493SBabu Moger static int mkdir_mondata_subdir(struct kernfs_node *parent_kn,
2287*fa7d9493SBabu Moger 				struct rdt_domain *d,
2288*fa7d9493SBabu Moger 				struct rdt_resource *r, struct rdtgroup *prgrp)
2289*fa7d9493SBabu Moger {
2290*fa7d9493SBabu Moger 	union mon_data_bits priv;
2291*fa7d9493SBabu Moger 	struct kernfs_node *kn;
2292*fa7d9493SBabu Moger 	struct mon_evt *mevt;
2293*fa7d9493SBabu Moger 	struct rmid_read rr;
2294*fa7d9493SBabu Moger 	char name[32];
2295*fa7d9493SBabu Moger 	int ret;
2296*fa7d9493SBabu Moger 
2297*fa7d9493SBabu Moger 	sprintf(name, "mon_%s_%02d", r->name, d->id);
2298*fa7d9493SBabu Moger 	/* create the directory */
2299*fa7d9493SBabu Moger 	kn = kernfs_create_dir(parent_kn, name, parent_kn->mode, prgrp);
2300*fa7d9493SBabu Moger 	if (IS_ERR(kn))
2301*fa7d9493SBabu Moger 		return PTR_ERR(kn);
2302*fa7d9493SBabu Moger 
2303*fa7d9493SBabu Moger 	/*
2304*fa7d9493SBabu Moger 	 * This extra ref will be put in kernfs_remove() and guarantees
2305*fa7d9493SBabu Moger 	 * that kn is always accessible.
2306*fa7d9493SBabu Moger 	 */
2307*fa7d9493SBabu Moger 	kernfs_get(kn);
2308*fa7d9493SBabu Moger 	ret = rdtgroup_kn_set_ugid(kn);
2309*fa7d9493SBabu Moger 	if (ret)
2310*fa7d9493SBabu Moger 		goto out_destroy;
2311*fa7d9493SBabu Moger 
2312*fa7d9493SBabu Moger 	if (WARN_ON(list_empty(&r->evt_list))) {
2313*fa7d9493SBabu Moger 		ret = -EPERM;
2314*fa7d9493SBabu Moger 		goto out_destroy;
2315*fa7d9493SBabu Moger 	}
2316*fa7d9493SBabu Moger 
2317*fa7d9493SBabu Moger 	priv.u.rid = r->rid;
2318*fa7d9493SBabu Moger 	priv.u.domid = d->id;
2319*fa7d9493SBabu Moger 	list_for_each_entry(mevt, &r->evt_list, list) {
2320*fa7d9493SBabu Moger 		priv.u.evtid = mevt->evtid;
2321*fa7d9493SBabu Moger 		ret = mon_addfile(kn, mevt->name, priv.priv);
2322*fa7d9493SBabu Moger 		if (ret)
2323*fa7d9493SBabu Moger 			goto out_destroy;
2324*fa7d9493SBabu Moger 
2325*fa7d9493SBabu Moger 		if (is_mbm_event(mevt->evtid))
2326*fa7d9493SBabu Moger 			mon_event_read(&rr, d, prgrp, mevt->evtid, true);
2327*fa7d9493SBabu Moger 	}
2328*fa7d9493SBabu Moger 	kernfs_activate(kn);
2329*fa7d9493SBabu Moger 	return 0;
2330*fa7d9493SBabu Moger 
2331*fa7d9493SBabu Moger out_destroy:
2332*fa7d9493SBabu Moger 	kernfs_remove(kn);
2333*fa7d9493SBabu Moger 	return ret;
2334*fa7d9493SBabu Moger }
2335*fa7d9493SBabu Moger 
2336*fa7d9493SBabu Moger /*
2337*fa7d9493SBabu Moger  * Add all subdirectories of mon_data for "ctrl_mon" groups
2338*fa7d9493SBabu Moger  * and "monitor" groups with given domain id.
2339*fa7d9493SBabu Moger  */
2340*fa7d9493SBabu Moger void mkdir_mondata_subdir_allrdtgrp(struct rdt_resource *r,
2341*fa7d9493SBabu Moger 				    struct rdt_domain *d)
2342*fa7d9493SBabu Moger {
2343*fa7d9493SBabu Moger 	struct kernfs_node *parent_kn;
2344*fa7d9493SBabu Moger 	struct rdtgroup *prgrp, *crgrp;
2345*fa7d9493SBabu Moger 	struct list_head *head;
2346*fa7d9493SBabu Moger 
2347*fa7d9493SBabu Moger 	if (!r->mon_enabled)
2348*fa7d9493SBabu Moger 		return;
2349*fa7d9493SBabu Moger 
2350*fa7d9493SBabu Moger 	list_for_each_entry(prgrp, &rdt_all_groups, rdtgroup_list) {
2351*fa7d9493SBabu Moger 		parent_kn = prgrp->mon.mon_data_kn;
2352*fa7d9493SBabu Moger 		mkdir_mondata_subdir(parent_kn, d, r, prgrp);
2353*fa7d9493SBabu Moger 
2354*fa7d9493SBabu Moger 		head = &prgrp->mon.crdtgrp_list;
2355*fa7d9493SBabu Moger 		list_for_each_entry(crgrp, head, mon.crdtgrp_list) {
2356*fa7d9493SBabu Moger 			parent_kn = crgrp->mon.mon_data_kn;
2357*fa7d9493SBabu Moger 			mkdir_mondata_subdir(parent_kn, d, r, crgrp);
2358*fa7d9493SBabu Moger 		}
2359*fa7d9493SBabu Moger 	}
2360*fa7d9493SBabu Moger }
2361*fa7d9493SBabu Moger 
2362*fa7d9493SBabu Moger static int mkdir_mondata_subdir_alldom(struct kernfs_node *parent_kn,
2363*fa7d9493SBabu Moger 				       struct rdt_resource *r,
2364*fa7d9493SBabu Moger 				       struct rdtgroup *prgrp)
2365*fa7d9493SBabu Moger {
2366*fa7d9493SBabu Moger 	struct rdt_domain *dom;
2367*fa7d9493SBabu Moger 	int ret;
2368*fa7d9493SBabu Moger 
2369*fa7d9493SBabu Moger 	list_for_each_entry(dom, &r->domains, list) {
2370*fa7d9493SBabu Moger 		ret = mkdir_mondata_subdir(parent_kn, dom, r, prgrp);
2371*fa7d9493SBabu Moger 		if (ret)
2372*fa7d9493SBabu Moger 			return ret;
2373*fa7d9493SBabu Moger 	}
2374*fa7d9493SBabu Moger 
2375*fa7d9493SBabu Moger 	return 0;
2376*fa7d9493SBabu Moger }
2377*fa7d9493SBabu Moger 
2378*fa7d9493SBabu Moger /*
2379*fa7d9493SBabu Moger  * This creates a directory mon_data which contains the monitored data.
2380*fa7d9493SBabu Moger  *
2381*fa7d9493SBabu Moger  * mon_data has one directory for each domain whic are named
2382*fa7d9493SBabu Moger  * in the format mon_<domain_name>_<domain_id>. For ex: A mon_data
2383*fa7d9493SBabu Moger  * with L3 domain looks as below:
2384*fa7d9493SBabu Moger  * ./mon_data:
2385*fa7d9493SBabu Moger  * mon_L3_00
2386*fa7d9493SBabu Moger  * mon_L3_01
2387*fa7d9493SBabu Moger  * mon_L3_02
2388*fa7d9493SBabu Moger  * ...
2389*fa7d9493SBabu Moger  *
2390*fa7d9493SBabu Moger  * Each domain directory has one file per event:
2391*fa7d9493SBabu Moger  * ./mon_L3_00/:
2392*fa7d9493SBabu Moger  * llc_occupancy
2393*fa7d9493SBabu Moger  *
2394*fa7d9493SBabu Moger  */
2395*fa7d9493SBabu Moger static int mkdir_mondata_all(struct kernfs_node *parent_kn,
2396*fa7d9493SBabu Moger 			     struct rdtgroup *prgrp,
2397*fa7d9493SBabu Moger 			     struct kernfs_node **dest_kn)
2398*fa7d9493SBabu Moger {
2399*fa7d9493SBabu Moger 	struct rdt_resource *r;
2400*fa7d9493SBabu Moger 	struct kernfs_node *kn;
2401*fa7d9493SBabu Moger 	int ret;
2402*fa7d9493SBabu Moger 
2403*fa7d9493SBabu Moger 	/*
2404*fa7d9493SBabu Moger 	 * Create the mon_data directory first.
2405*fa7d9493SBabu Moger 	 */
2406*fa7d9493SBabu Moger 	ret = mongroup_create_dir(parent_kn, NULL, "mon_data", &kn);
2407*fa7d9493SBabu Moger 	if (ret)
2408*fa7d9493SBabu Moger 		return ret;
2409*fa7d9493SBabu Moger 
2410*fa7d9493SBabu Moger 	if (dest_kn)
2411*fa7d9493SBabu Moger 		*dest_kn = kn;
2412*fa7d9493SBabu Moger 
2413*fa7d9493SBabu Moger 	/*
2414*fa7d9493SBabu Moger 	 * Create the subdirectories for each domain. Note that all events
2415*fa7d9493SBabu Moger 	 * in a domain like L3 are grouped into a resource whose domain is L3
2416*fa7d9493SBabu Moger 	 */
2417*fa7d9493SBabu Moger 	for_each_mon_enabled_rdt_resource(r) {
2418*fa7d9493SBabu Moger 		ret = mkdir_mondata_subdir_alldom(kn, r, prgrp);
2419*fa7d9493SBabu Moger 		if (ret)
2420*fa7d9493SBabu Moger 			goto out_destroy;
2421*fa7d9493SBabu Moger 	}
2422*fa7d9493SBabu Moger 
2423*fa7d9493SBabu Moger 	return 0;
2424*fa7d9493SBabu Moger 
2425*fa7d9493SBabu Moger out_destroy:
2426*fa7d9493SBabu Moger 	kernfs_remove(kn);
2427*fa7d9493SBabu Moger 	return ret;
2428*fa7d9493SBabu Moger }
2429*fa7d9493SBabu Moger 
2430*fa7d9493SBabu Moger /**
2431*fa7d9493SBabu Moger  * cbm_ensure_valid - Enforce validity on provided CBM
2432*fa7d9493SBabu Moger  * @_val:	Candidate CBM
2433*fa7d9493SBabu Moger  * @r:		RDT resource to which the CBM belongs
2434*fa7d9493SBabu Moger  *
2435*fa7d9493SBabu Moger  * The provided CBM represents all cache portions available for use. This
2436*fa7d9493SBabu Moger  * may be represented by a bitmap that does not consist of contiguous ones
2437*fa7d9493SBabu Moger  * and thus be an invalid CBM.
2438*fa7d9493SBabu Moger  * Here the provided CBM is forced to be a valid CBM by only considering
2439*fa7d9493SBabu Moger  * the first set of contiguous bits as valid and clearing all bits.
2440*fa7d9493SBabu Moger  * The intention here is to provide a valid default CBM with which a new
2441*fa7d9493SBabu Moger  * resource group is initialized. The user can follow this with a
2442*fa7d9493SBabu Moger  * modification to the CBM if the default does not satisfy the
2443*fa7d9493SBabu Moger  * requirements.
2444*fa7d9493SBabu Moger  */
2445*fa7d9493SBabu Moger static void cbm_ensure_valid(u32 *_val, struct rdt_resource *r)
2446*fa7d9493SBabu Moger {
2447*fa7d9493SBabu Moger 	/*
2448*fa7d9493SBabu Moger 	 * Convert the u32 _val to an unsigned long required by all the bit
2449*fa7d9493SBabu Moger 	 * operations within this function. No more than 32 bits of this
2450*fa7d9493SBabu Moger 	 * converted value can be accessed because all bit operations are
2451*fa7d9493SBabu Moger 	 * additionally provided with cbm_len that is initialized during
2452*fa7d9493SBabu Moger 	 * hardware enumeration using five bits from the EAX register and
2453*fa7d9493SBabu Moger 	 * thus never can exceed 32 bits.
2454*fa7d9493SBabu Moger 	 */
2455*fa7d9493SBabu Moger 	unsigned long *val = (unsigned long *)_val;
2456*fa7d9493SBabu Moger 	unsigned int cbm_len = r->cache.cbm_len;
2457*fa7d9493SBabu Moger 	unsigned long first_bit, zero_bit;
2458*fa7d9493SBabu Moger 
2459*fa7d9493SBabu Moger 	if (*val == 0)
2460*fa7d9493SBabu Moger 		return;
2461*fa7d9493SBabu Moger 
2462*fa7d9493SBabu Moger 	first_bit = find_first_bit(val, cbm_len);
2463*fa7d9493SBabu Moger 	zero_bit = find_next_zero_bit(val, cbm_len, first_bit);
2464*fa7d9493SBabu Moger 
2465*fa7d9493SBabu Moger 	/* Clear any remaining bits to ensure contiguous region */
2466*fa7d9493SBabu Moger 	bitmap_clear(val, zero_bit, cbm_len - zero_bit);
2467*fa7d9493SBabu Moger }
2468*fa7d9493SBabu Moger 
2469*fa7d9493SBabu Moger /**
2470*fa7d9493SBabu Moger  * rdtgroup_init_alloc - Initialize the new RDT group's allocations
2471*fa7d9493SBabu Moger  *
2472*fa7d9493SBabu Moger  * A new RDT group is being created on an allocation capable (CAT)
2473*fa7d9493SBabu Moger  * supporting system. Set this group up to start off with all usable
2474*fa7d9493SBabu Moger  * allocations. That is, all shareable and unused bits.
2475*fa7d9493SBabu Moger  *
2476*fa7d9493SBabu Moger  * All-zero CBM is invalid. If there are no more shareable bits available
2477*fa7d9493SBabu Moger  * on any domain then the entire allocation will fail.
2478*fa7d9493SBabu Moger  */
2479*fa7d9493SBabu Moger static int rdtgroup_init_alloc(struct rdtgroup *rdtgrp)
2480*fa7d9493SBabu Moger {
2481*fa7d9493SBabu Moger 	struct rdt_resource *r_cdp = NULL;
2482*fa7d9493SBabu Moger 	struct rdt_domain *d_cdp = NULL;
2483*fa7d9493SBabu Moger 	u32 used_b = 0, unused_b = 0;
2484*fa7d9493SBabu Moger 	u32 closid = rdtgrp->closid;
2485*fa7d9493SBabu Moger 	struct rdt_resource *r;
2486*fa7d9493SBabu Moger 	unsigned long tmp_cbm;
2487*fa7d9493SBabu Moger 	enum rdtgrp_mode mode;
2488*fa7d9493SBabu Moger 	struct rdt_domain *d;
2489*fa7d9493SBabu Moger 	u32 peer_ctl, *ctrl;
2490*fa7d9493SBabu Moger 	int i, ret;
2491*fa7d9493SBabu Moger 
2492*fa7d9493SBabu Moger 	for_each_alloc_enabled_rdt_resource(r) {
2493*fa7d9493SBabu Moger 		/*
2494*fa7d9493SBabu Moger 		 * Only initialize default allocations for CBM cache
2495*fa7d9493SBabu Moger 		 * resources
2496*fa7d9493SBabu Moger 		 */
2497*fa7d9493SBabu Moger 		if (r->rid == RDT_RESOURCE_MBA)
2498*fa7d9493SBabu Moger 			continue;
2499*fa7d9493SBabu Moger 		list_for_each_entry(d, &r->domains, list) {
2500*fa7d9493SBabu Moger 			rdt_cdp_peer_get(r, d, &r_cdp, &d_cdp);
2501*fa7d9493SBabu Moger 			d->have_new_ctrl = false;
2502*fa7d9493SBabu Moger 			d->new_ctrl = r->cache.shareable_bits;
2503*fa7d9493SBabu Moger 			used_b = r->cache.shareable_bits;
2504*fa7d9493SBabu Moger 			ctrl = d->ctrl_val;
2505*fa7d9493SBabu Moger 			for (i = 0; i < closids_supported(); i++, ctrl++) {
2506*fa7d9493SBabu Moger 				if (closid_allocated(i) && i != closid) {
2507*fa7d9493SBabu Moger 					mode = rdtgroup_mode_by_closid(i);
2508*fa7d9493SBabu Moger 					if (mode == RDT_MODE_PSEUDO_LOCKSETUP)
2509*fa7d9493SBabu Moger 						break;
2510*fa7d9493SBabu Moger 					/*
2511*fa7d9493SBabu Moger 					 * If CDP is active include peer
2512*fa7d9493SBabu Moger 					 * domain's usage to ensure there
2513*fa7d9493SBabu Moger 					 * is no overlap with an exclusive
2514*fa7d9493SBabu Moger 					 * group.
2515*fa7d9493SBabu Moger 					 */
2516*fa7d9493SBabu Moger 					if (d_cdp)
2517*fa7d9493SBabu Moger 						peer_ctl = d_cdp->ctrl_val[i];
2518*fa7d9493SBabu Moger 					else
2519*fa7d9493SBabu Moger 						peer_ctl = 0;
2520*fa7d9493SBabu Moger 					used_b |= *ctrl | peer_ctl;
2521*fa7d9493SBabu Moger 					if (mode == RDT_MODE_SHAREABLE)
2522*fa7d9493SBabu Moger 						d->new_ctrl |= *ctrl | peer_ctl;
2523*fa7d9493SBabu Moger 				}
2524*fa7d9493SBabu Moger 			}
2525*fa7d9493SBabu Moger 			if (d->plr && d->plr->cbm > 0)
2526*fa7d9493SBabu Moger 				used_b |= d->plr->cbm;
2527*fa7d9493SBabu Moger 			unused_b = used_b ^ (BIT_MASK(r->cache.cbm_len) - 1);
2528*fa7d9493SBabu Moger 			unused_b &= BIT_MASK(r->cache.cbm_len) - 1;
2529*fa7d9493SBabu Moger 			d->new_ctrl |= unused_b;
2530*fa7d9493SBabu Moger 			/*
2531*fa7d9493SBabu Moger 			 * Force the initial CBM to be valid, user can
2532*fa7d9493SBabu Moger 			 * modify the CBM based on system availability.
2533*fa7d9493SBabu Moger 			 */
2534*fa7d9493SBabu Moger 			cbm_ensure_valid(&d->new_ctrl, r);
2535*fa7d9493SBabu Moger 			/*
2536*fa7d9493SBabu Moger 			 * Assign the u32 CBM to an unsigned long to ensure
2537*fa7d9493SBabu Moger 			 * that bitmap_weight() does not access out-of-bound
2538*fa7d9493SBabu Moger 			 * memory.
2539*fa7d9493SBabu Moger 			 */
2540*fa7d9493SBabu Moger 			tmp_cbm = d->new_ctrl;
2541*fa7d9493SBabu Moger 			if (bitmap_weight(&tmp_cbm, r->cache.cbm_len) <
2542*fa7d9493SBabu Moger 			    r->cache.min_cbm_bits) {
2543*fa7d9493SBabu Moger 				rdt_last_cmd_printf("no space on %s:%d\n",
2544*fa7d9493SBabu Moger 						    r->name, d->id);
2545*fa7d9493SBabu Moger 				return -ENOSPC;
2546*fa7d9493SBabu Moger 			}
2547*fa7d9493SBabu Moger 			d->have_new_ctrl = true;
2548*fa7d9493SBabu Moger 		}
2549*fa7d9493SBabu Moger 	}
2550*fa7d9493SBabu Moger 
2551*fa7d9493SBabu Moger 	for_each_alloc_enabled_rdt_resource(r) {
2552*fa7d9493SBabu Moger 		/*
2553*fa7d9493SBabu Moger 		 * Only initialize default allocations for CBM cache
2554*fa7d9493SBabu Moger 		 * resources
2555*fa7d9493SBabu Moger 		 */
2556*fa7d9493SBabu Moger 		if (r->rid == RDT_RESOURCE_MBA)
2557*fa7d9493SBabu Moger 			continue;
2558*fa7d9493SBabu Moger 		ret = update_domains(r, rdtgrp->closid);
2559*fa7d9493SBabu Moger 		if (ret < 0) {
2560*fa7d9493SBabu Moger 			rdt_last_cmd_puts("failed to initialize allocations\n");
2561*fa7d9493SBabu Moger 			return ret;
2562*fa7d9493SBabu Moger 		}
2563*fa7d9493SBabu Moger 		rdtgrp->mode = RDT_MODE_SHAREABLE;
2564*fa7d9493SBabu Moger 	}
2565*fa7d9493SBabu Moger 
2566*fa7d9493SBabu Moger 	return 0;
2567*fa7d9493SBabu Moger }
2568*fa7d9493SBabu Moger 
2569*fa7d9493SBabu Moger static int mkdir_rdt_prepare(struct kernfs_node *parent_kn,
2570*fa7d9493SBabu Moger 			     struct kernfs_node *prgrp_kn,
2571*fa7d9493SBabu Moger 			     const char *name, umode_t mode,
2572*fa7d9493SBabu Moger 			     enum rdt_group_type rtype, struct rdtgroup **r)
2573*fa7d9493SBabu Moger {
2574*fa7d9493SBabu Moger 	struct rdtgroup *prdtgrp, *rdtgrp;
2575*fa7d9493SBabu Moger 	struct kernfs_node *kn;
2576*fa7d9493SBabu Moger 	uint files = 0;
2577*fa7d9493SBabu Moger 	int ret;
2578*fa7d9493SBabu Moger 
2579*fa7d9493SBabu Moger 	prdtgrp = rdtgroup_kn_lock_live(prgrp_kn);
2580*fa7d9493SBabu Moger 	rdt_last_cmd_clear();
2581*fa7d9493SBabu Moger 	if (!prdtgrp) {
2582*fa7d9493SBabu Moger 		ret = -ENODEV;
2583*fa7d9493SBabu Moger 		rdt_last_cmd_puts("directory was removed\n");
2584*fa7d9493SBabu Moger 		goto out_unlock;
2585*fa7d9493SBabu Moger 	}
2586*fa7d9493SBabu Moger 
2587*fa7d9493SBabu Moger 	if (rtype == RDTMON_GROUP &&
2588*fa7d9493SBabu Moger 	    (prdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP ||
2589*fa7d9493SBabu Moger 	     prdtgrp->mode == RDT_MODE_PSEUDO_LOCKED)) {
2590*fa7d9493SBabu Moger 		ret = -EINVAL;
2591*fa7d9493SBabu Moger 		rdt_last_cmd_puts("pseudo-locking in progress\n");
2592*fa7d9493SBabu Moger 		goto out_unlock;
2593*fa7d9493SBabu Moger 	}
2594*fa7d9493SBabu Moger 
2595*fa7d9493SBabu Moger 	/* allocate the rdtgroup. */
2596*fa7d9493SBabu Moger 	rdtgrp = kzalloc(sizeof(*rdtgrp), GFP_KERNEL);
2597*fa7d9493SBabu Moger 	if (!rdtgrp) {
2598*fa7d9493SBabu Moger 		ret = -ENOSPC;
2599*fa7d9493SBabu Moger 		rdt_last_cmd_puts("kernel out of memory\n");
2600*fa7d9493SBabu Moger 		goto out_unlock;
2601*fa7d9493SBabu Moger 	}
2602*fa7d9493SBabu Moger 	*r = rdtgrp;
2603*fa7d9493SBabu Moger 	rdtgrp->mon.parent = prdtgrp;
2604*fa7d9493SBabu Moger 	rdtgrp->type = rtype;
2605*fa7d9493SBabu Moger 	INIT_LIST_HEAD(&rdtgrp->mon.crdtgrp_list);
2606*fa7d9493SBabu Moger 
2607*fa7d9493SBabu Moger 	/* kernfs creates the directory for rdtgrp */
2608*fa7d9493SBabu Moger 	kn = kernfs_create_dir(parent_kn, name, mode, rdtgrp);
2609*fa7d9493SBabu Moger 	if (IS_ERR(kn)) {
2610*fa7d9493SBabu Moger 		ret = PTR_ERR(kn);
2611*fa7d9493SBabu Moger 		rdt_last_cmd_puts("kernfs create error\n");
2612*fa7d9493SBabu Moger 		goto out_free_rgrp;
2613*fa7d9493SBabu Moger 	}
2614*fa7d9493SBabu Moger 	rdtgrp->kn = kn;
2615*fa7d9493SBabu Moger 
2616*fa7d9493SBabu Moger 	/*
2617*fa7d9493SBabu Moger 	 * kernfs_remove() will drop the reference count on "kn" which
2618*fa7d9493SBabu Moger 	 * will free it. But we still need it to stick around for the
2619*fa7d9493SBabu Moger 	 * rdtgroup_kn_unlock(kn} call below. Take one extra reference
2620*fa7d9493SBabu Moger 	 * here, which will be dropped inside rdtgroup_kn_unlock().
2621*fa7d9493SBabu Moger 	 */
2622*fa7d9493SBabu Moger 	kernfs_get(kn);
2623*fa7d9493SBabu Moger 
2624*fa7d9493SBabu Moger 	ret = rdtgroup_kn_set_ugid(kn);
2625*fa7d9493SBabu Moger 	if (ret) {
2626*fa7d9493SBabu Moger 		rdt_last_cmd_puts("kernfs perm error\n");
2627*fa7d9493SBabu Moger 		goto out_destroy;
2628*fa7d9493SBabu Moger 	}
2629*fa7d9493SBabu Moger 
2630*fa7d9493SBabu Moger 	files = RFTYPE_BASE | BIT(RF_CTRLSHIFT + rtype);
2631*fa7d9493SBabu Moger 	ret = rdtgroup_add_files(kn, files);
2632*fa7d9493SBabu Moger 	if (ret) {
2633*fa7d9493SBabu Moger 		rdt_last_cmd_puts("kernfs fill error\n");
2634*fa7d9493SBabu Moger 		goto out_destroy;
2635*fa7d9493SBabu Moger 	}
2636*fa7d9493SBabu Moger 
2637*fa7d9493SBabu Moger 	if (rdt_mon_capable) {
2638*fa7d9493SBabu Moger 		ret = alloc_rmid();
2639*fa7d9493SBabu Moger 		if (ret < 0) {
2640*fa7d9493SBabu Moger 			rdt_last_cmd_puts("out of RMIDs\n");
2641*fa7d9493SBabu Moger 			goto out_destroy;
2642*fa7d9493SBabu Moger 		}
2643*fa7d9493SBabu Moger 		rdtgrp->mon.rmid = ret;
2644*fa7d9493SBabu Moger 
2645*fa7d9493SBabu Moger 		ret = mkdir_mondata_all(kn, rdtgrp, &rdtgrp->mon.mon_data_kn);
2646*fa7d9493SBabu Moger 		if (ret) {
2647*fa7d9493SBabu Moger 			rdt_last_cmd_puts("kernfs subdir error\n");
2648*fa7d9493SBabu Moger 			goto out_idfree;
2649*fa7d9493SBabu Moger 		}
2650*fa7d9493SBabu Moger 	}
2651*fa7d9493SBabu Moger 	kernfs_activate(kn);
2652*fa7d9493SBabu Moger 
2653*fa7d9493SBabu Moger 	/*
2654*fa7d9493SBabu Moger 	 * The caller unlocks the prgrp_kn upon success.
2655*fa7d9493SBabu Moger 	 */
2656*fa7d9493SBabu Moger 	return 0;
2657*fa7d9493SBabu Moger 
2658*fa7d9493SBabu Moger out_idfree:
2659*fa7d9493SBabu Moger 	free_rmid(rdtgrp->mon.rmid);
2660*fa7d9493SBabu Moger out_destroy:
2661*fa7d9493SBabu Moger 	kernfs_remove(rdtgrp->kn);
2662*fa7d9493SBabu Moger out_free_rgrp:
2663*fa7d9493SBabu Moger 	kfree(rdtgrp);
2664*fa7d9493SBabu Moger out_unlock:
2665*fa7d9493SBabu Moger 	rdtgroup_kn_unlock(prgrp_kn);
2666*fa7d9493SBabu Moger 	return ret;
2667*fa7d9493SBabu Moger }
2668*fa7d9493SBabu Moger 
2669*fa7d9493SBabu Moger static void mkdir_rdt_prepare_clean(struct rdtgroup *rgrp)
2670*fa7d9493SBabu Moger {
2671*fa7d9493SBabu Moger 	kernfs_remove(rgrp->kn);
2672*fa7d9493SBabu Moger 	free_rmid(rgrp->mon.rmid);
2673*fa7d9493SBabu Moger 	kfree(rgrp);
2674*fa7d9493SBabu Moger }
2675*fa7d9493SBabu Moger 
2676*fa7d9493SBabu Moger /*
2677*fa7d9493SBabu Moger  * Create a monitor group under "mon_groups" directory of a control
2678*fa7d9493SBabu Moger  * and monitor group(ctrl_mon). This is a resource group
2679*fa7d9493SBabu Moger  * to monitor a subset of tasks and cpus in its parent ctrl_mon group.
2680*fa7d9493SBabu Moger  */
2681*fa7d9493SBabu Moger static int rdtgroup_mkdir_mon(struct kernfs_node *parent_kn,
2682*fa7d9493SBabu Moger 			      struct kernfs_node *prgrp_kn,
2683*fa7d9493SBabu Moger 			      const char *name,
2684*fa7d9493SBabu Moger 			      umode_t mode)
2685*fa7d9493SBabu Moger {
2686*fa7d9493SBabu Moger 	struct rdtgroup *rdtgrp, *prgrp;
2687*fa7d9493SBabu Moger 	int ret;
2688*fa7d9493SBabu Moger 
2689*fa7d9493SBabu Moger 	ret = mkdir_rdt_prepare(parent_kn, prgrp_kn, name, mode, RDTMON_GROUP,
2690*fa7d9493SBabu Moger 				&rdtgrp);
2691*fa7d9493SBabu Moger 	if (ret)
2692*fa7d9493SBabu Moger 		return ret;
2693*fa7d9493SBabu Moger 
2694*fa7d9493SBabu Moger 	prgrp = rdtgrp->mon.parent;
2695*fa7d9493SBabu Moger 	rdtgrp->closid = prgrp->closid;
2696*fa7d9493SBabu Moger 
2697*fa7d9493SBabu Moger 	/*
2698*fa7d9493SBabu Moger 	 * Add the rdtgrp to the list of rdtgrps the parent
2699*fa7d9493SBabu Moger 	 * ctrl_mon group has to track.
2700*fa7d9493SBabu Moger 	 */
2701*fa7d9493SBabu Moger 	list_add_tail(&rdtgrp->mon.crdtgrp_list, &prgrp->mon.crdtgrp_list);
2702*fa7d9493SBabu Moger 
2703*fa7d9493SBabu Moger 	rdtgroup_kn_unlock(prgrp_kn);
2704*fa7d9493SBabu Moger 	return ret;
2705*fa7d9493SBabu Moger }
2706*fa7d9493SBabu Moger 
2707*fa7d9493SBabu Moger /*
2708*fa7d9493SBabu Moger  * These are rdtgroups created under the root directory. Can be used
2709*fa7d9493SBabu Moger  * to allocate and monitor resources.
2710*fa7d9493SBabu Moger  */
2711*fa7d9493SBabu Moger static int rdtgroup_mkdir_ctrl_mon(struct kernfs_node *parent_kn,
2712*fa7d9493SBabu Moger 				   struct kernfs_node *prgrp_kn,
2713*fa7d9493SBabu Moger 				   const char *name, umode_t mode)
2714*fa7d9493SBabu Moger {
2715*fa7d9493SBabu Moger 	struct rdtgroup *rdtgrp;
2716*fa7d9493SBabu Moger 	struct kernfs_node *kn;
2717*fa7d9493SBabu Moger 	u32 closid;
2718*fa7d9493SBabu Moger 	int ret;
2719*fa7d9493SBabu Moger 
2720*fa7d9493SBabu Moger 	ret = mkdir_rdt_prepare(parent_kn, prgrp_kn, name, mode, RDTCTRL_GROUP,
2721*fa7d9493SBabu Moger 				&rdtgrp);
2722*fa7d9493SBabu Moger 	if (ret)
2723*fa7d9493SBabu Moger 		return ret;
2724*fa7d9493SBabu Moger 
2725*fa7d9493SBabu Moger 	kn = rdtgrp->kn;
2726*fa7d9493SBabu Moger 	ret = closid_alloc();
2727*fa7d9493SBabu Moger 	if (ret < 0) {
2728*fa7d9493SBabu Moger 		rdt_last_cmd_puts("out of CLOSIDs\n");
2729*fa7d9493SBabu Moger 		goto out_common_fail;
2730*fa7d9493SBabu Moger 	}
2731*fa7d9493SBabu Moger 	closid = ret;
2732*fa7d9493SBabu Moger 	ret = 0;
2733*fa7d9493SBabu Moger 
2734*fa7d9493SBabu Moger 	rdtgrp->closid = closid;
2735*fa7d9493SBabu Moger 	ret = rdtgroup_init_alloc(rdtgrp);
2736*fa7d9493SBabu Moger 	if (ret < 0)
2737*fa7d9493SBabu Moger 		goto out_id_free;
2738*fa7d9493SBabu Moger 
2739*fa7d9493SBabu Moger 	list_add(&rdtgrp->rdtgroup_list, &rdt_all_groups);
2740*fa7d9493SBabu Moger 
2741*fa7d9493SBabu Moger 	if (rdt_mon_capable) {
2742*fa7d9493SBabu Moger 		/*
2743*fa7d9493SBabu Moger 		 * Create an empty mon_groups directory to hold the subset
2744*fa7d9493SBabu Moger 		 * of tasks and cpus to monitor.
2745*fa7d9493SBabu Moger 		 */
2746*fa7d9493SBabu Moger 		ret = mongroup_create_dir(kn, NULL, "mon_groups", NULL);
2747*fa7d9493SBabu Moger 		if (ret) {
2748*fa7d9493SBabu Moger 			rdt_last_cmd_puts("kernfs subdir error\n");
2749*fa7d9493SBabu Moger 			goto out_del_list;
2750*fa7d9493SBabu Moger 		}
2751*fa7d9493SBabu Moger 	}
2752*fa7d9493SBabu Moger 
2753*fa7d9493SBabu Moger 	goto out_unlock;
2754*fa7d9493SBabu Moger 
2755*fa7d9493SBabu Moger out_del_list:
2756*fa7d9493SBabu Moger 	list_del(&rdtgrp->rdtgroup_list);
2757*fa7d9493SBabu Moger out_id_free:
2758*fa7d9493SBabu Moger 	closid_free(closid);
2759*fa7d9493SBabu Moger out_common_fail:
2760*fa7d9493SBabu Moger 	mkdir_rdt_prepare_clean(rdtgrp);
2761*fa7d9493SBabu Moger out_unlock:
2762*fa7d9493SBabu Moger 	rdtgroup_kn_unlock(prgrp_kn);
2763*fa7d9493SBabu Moger 	return ret;
2764*fa7d9493SBabu Moger }
2765*fa7d9493SBabu Moger 
2766*fa7d9493SBabu Moger /*
2767*fa7d9493SBabu Moger  * We allow creating mon groups only with in a directory called "mon_groups"
2768*fa7d9493SBabu Moger  * which is present in every ctrl_mon group. Check if this is a valid
2769*fa7d9493SBabu Moger  * "mon_groups" directory.
2770*fa7d9493SBabu Moger  *
2771*fa7d9493SBabu Moger  * 1. The directory should be named "mon_groups".
2772*fa7d9493SBabu Moger  * 2. The mon group itself should "not" be named "mon_groups".
2773*fa7d9493SBabu Moger  *   This makes sure "mon_groups" directory always has a ctrl_mon group
2774*fa7d9493SBabu Moger  *   as parent.
2775*fa7d9493SBabu Moger  */
2776*fa7d9493SBabu Moger static bool is_mon_groups(struct kernfs_node *kn, const char *name)
2777*fa7d9493SBabu Moger {
2778*fa7d9493SBabu Moger 	return (!strcmp(kn->name, "mon_groups") &&
2779*fa7d9493SBabu Moger 		strcmp(name, "mon_groups"));
2780*fa7d9493SBabu Moger }
2781*fa7d9493SBabu Moger 
2782*fa7d9493SBabu Moger static int rdtgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
2783*fa7d9493SBabu Moger 			  umode_t mode)
2784*fa7d9493SBabu Moger {
2785*fa7d9493SBabu Moger 	/* Do not accept '\n' to avoid unparsable situation. */
2786*fa7d9493SBabu Moger 	if (strchr(name, '\n'))
2787*fa7d9493SBabu Moger 		return -EINVAL;
2788*fa7d9493SBabu Moger 
2789*fa7d9493SBabu Moger 	/*
2790*fa7d9493SBabu Moger 	 * If the parent directory is the root directory and RDT
2791*fa7d9493SBabu Moger 	 * allocation is supported, add a control and monitoring
2792*fa7d9493SBabu Moger 	 * subdirectory
2793*fa7d9493SBabu Moger 	 */
2794*fa7d9493SBabu Moger 	if (rdt_alloc_capable && parent_kn == rdtgroup_default.kn)
2795*fa7d9493SBabu Moger 		return rdtgroup_mkdir_ctrl_mon(parent_kn, parent_kn, name, mode);
2796*fa7d9493SBabu Moger 
2797*fa7d9493SBabu Moger 	/*
2798*fa7d9493SBabu Moger 	 * If RDT monitoring is supported and the parent directory is a valid
2799*fa7d9493SBabu Moger 	 * "mon_groups" directory, add a monitoring subdirectory.
2800*fa7d9493SBabu Moger 	 */
2801*fa7d9493SBabu Moger 	if (rdt_mon_capable && is_mon_groups(parent_kn, name))
2802*fa7d9493SBabu Moger 		return rdtgroup_mkdir_mon(parent_kn, parent_kn->parent, name, mode);
2803*fa7d9493SBabu Moger 
2804*fa7d9493SBabu Moger 	return -EPERM;
2805*fa7d9493SBabu Moger }
2806*fa7d9493SBabu Moger 
2807*fa7d9493SBabu Moger static int rdtgroup_rmdir_mon(struct kernfs_node *kn, struct rdtgroup *rdtgrp,
2808*fa7d9493SBabu Moger 			      cpumask_var_t tmpmask)
2809*fa7d9493SBabu Moger {
2810*fa7d9493SBabu Moger 	struct rdtgroup *prdtgrp = rdtgrp->mon.parent;
2811*fa7d9493SBabu Moger 	int cpu;
2812*fa7d9493SBabu Moger 
2813*fa7d9493SBabu Moger 	/* Give any tasks back to the parent group */
2814*fa7d9493SBabu Moger 	rdt_move_group_tasks(rdtgrp, prdtgrp, tmpmask);
2815*fa7d9493SBabu Moger 
2816*fa7d9493SBabu Moger 	/* Update per cpu rmid of the moved CPUs first */
2817*fa7d9493SBabu Moger 	for_each_cpu(cpu, &rdtgrp->cpu_mask)
2818*fa7d9493SBabu Moger 		per_cpu(pqr_state.default_rmid, cpu) = prdtgrp->mon.rmid;
2819*fa7d9493SBabu Moger 	/*
2820*fa7d9493SBabu Moger 	 * Update the MSR on moved CPUs and CPUs which have moved
2821*fa7d9493SBabu Moger 	 * task running on them.
2822*fa7d9493SBabu Moger 	 */
2823*fa7d9493SBabu Moger 	cpumask_or(tmpmask, tmpmask, &rdtgrp->cpu_mask);
2824*fa7d9493SBabu Moger 	update_closid_rmid(tmpmask, NULL);
2825*fa7d9493SBabu Moger 
2826*fa7d9493SBabu Moger 	rdtgrp->flags = RDT_DELETED;
2827*fa7d9493SBabu Moger 	free_rmid(rdtgrp->mon.rmid);
2828*fa7d9493SBabu Moger 
2829*fa7d9493SBabu Moger 	/*
2830*fa7d9493SBabu Moger 	 * Remove the rdtgrp from the parent ctrl_mon group's list
2831*fa7d9493SBabu Moger 	 */
2832*fa7d9493SBabu Moger 	WARN_ON(list_empty(&prdtgrp->mon.crdtgrp_list));
2833*fa7d9493SBabu Moger 	list_del(&rdtgrp->mon.crdtgrp_list);
2834*fa7d9493SBabu Moger 
2835*fa7d9493SBabu Moger 	/*
2836*fa7d9493SBabu Moger 	 * one extra hold on this, will drop when we kfree(rdtgrp)
2837*fa7d9493SBabu Moger 	 * in rdtgroup_kn_unlock()
2838*fa7d9493SBabu Moger 	 */
2839*fa7d9493SBabu Moger 	kernfs_get(kn);
2840*fa7d9493SBabu Moger 	kernfs_remove(rdtgrp->kn);
2841*fa7d9493SBabu Moger 
2842*fa7d9493SBabu Moger 	return 0;
2843*fa7d9493SBabu Moger }
2844*fa7d9493SBabu Moger 
2845*fa7d9493SBabu Moger static int rdtgroup_ctrl_remove(struct kernfs_node *kn,
2846*fa7d9493SBabu Moger 				struct rdtgroup *rdtgrp)
2847*fa7d9493SBabu Moger {
2848*fa7d9493SBabu Moger 	rdtgrp->flags = RDT_DELETED;
2849*fa7d9493SBabu Moger 	list_del(&rdtgrp->rdtgroup_list);
2850*fa7d9493SBabu Moger 
2851*fa7d9493SBabu Moger 	/*
2852*fa7d9493SBabu Moger 	 * one extra hold on this, will drop when we kfree(rdtgrp)
2853*fa7d9493SBabu Moger 	 * in rdtgroup_kn_unlock()
2854*fa7d9493SBabu Moger 	 */
2855*fa7d9493SBabu Moger 	kernfs_get(kn);
2856*fa7d9493SBabu Moger 	kernfs_remove(rdtgrp->kn);
2857*fa7d9493SBabu Moger 	return 0;
2858*fa7d9493SBabu Moger }
2859*fa7d9493SBabu Moger 
2860*fa7d9493SBabu Moger static int rdtgroup_rmdir_ctrl(struct kernfs_node *kn, struct rdtgroup *rdtgrp,
2861*fa7d9493SBabu Moger 			       cpumask_var_t tmpmask)
2862*fa7d9493SBabu Moger {
2863*fa7d9493SBabu Moger 	int cpu;
2864*fa7d9493SBabu Moger 
2865*fa7d9493SBabu Moger 	/* Give any tasks back to the default group */
2866*fa7d9493SBabu Moger 	rdt_move_group_tasks(rdtgrp, &rdtgroup_default, tmpmask);
2867*fa7d9493SBabu Moger 
2868*fa7d9493SBabu Moger 	/* Give any CPUs back to the default group */
2869*fa7d9493SBabu Moger 	cpumask_or(&rdtgroup_default.cpu_mask,
2870*fa7d9493SBabu Moger 		   &rdtgroup_default.cpu_mask, &rdtgrp->cpu_mask);
2871*fa7d9493SBabu Moger 
2872*fa7d9493SBabu Moger 	/* Update per cpu closid and rmid of the moved CPUs first */
2873*fa7d9493SBabu Moger 	for_each_cpu(cpu, &rdtgrp->cpu_mask) {
2874*fa7d9493SBabu Moger 		per_cpu(pqr_state.default_closid, cpu) = rdtgroup_default.closid;
2875*fa7d9493SBabu Moger 		per_cpu(pqr_state.default_rmid, cpu) = rdtgroup_default.mon.rmid;
2876*fa7d9493SBabu Moger 	}
2877*fa7d9493SBabu Moger 
2878*fa7d9493SBabu Moger 	/*
2879*fa7d9493SBabu Moger 	 * Update the MSR on moved CPUs and CPUs which have moved
2880*fa7d9493SBabu Moger 	 * task running on them.
2881*fa7d9493SBabu Moger 	 */
2882*fa7d9493SBabu Moger 	cpumask_or(tmpmask, tmpmask, &rdtgrp->cpu_mask);
2883*fa7d9493SBabu Moger 	update_closid_rmid(tmpmask, NULL);
2884*fa7d9493SBabu Moger 
2885*fa7d9493SBabu Moger 	closid_free(rdtgrp->closid);
2886*fa7d9493SBabu Moger 	free_rmid(rdtgrp->mon.rmid);
2887*fa7d9493SBabu Moger 
2888*fa7d9493SBabu Moger 	/*
2889*fa7d9493SBabu Moger 	 * Free all the child monitor group rmids.
2890*fa7d9493SBabu Moger 	 */
2891*fa7d9493SBabu Moger 	free_all_child_rdtgrp(rdtgrp);
2892*fa7d9493SBabu Moger 
2893*fa7d9493SBabu Moger 	rdtgroup_ctrl_remove(kn, rdtgrp);
2894*fa7d9493SBabu Moger 
2895*fa7d9493SBabu Moger 	return 0;
2896*fa7d9493SBabu Moger }
2897*fa7d9493SBabu Moger 
2898*fa7d9493SBabu Moger static int rdtgroup_rmdir(struct kernfs_node *kn)
2899*fa7d9493SBabu Moger {
2900*fa7d9493SBabu Moger 	struct kernfs_node *parent_kn = kn->parent;
2901*fa7d9493SBabu Moger 	struct rdtgroup *rdtgrp;
2902*fa7d9493SBabu Moger 	cpumask_var_t tmpmask;
2903*fa7d9493SBabu Moger 	int ret = 0;
2904*fa7d9493SBabu Moger 
2905*fa7d9493SBabu Moger 	if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
2906*fa7d9493SBabu Moger 		return -ENOMEM;
2907*fa7d9493SBabu Moger 
2908*fa7d9493SBabu Moger 	rdtgrp = rdtgroup_kn_lock_live(kn);
2909*fa7d9493SBabu Moger 	if (!rdtgrp) {
2910*fa7d9493SBabu Moger 		ret = -EPERM;
2911*fa7d9493SBabu Moger 		goto out;
2912*fa7d9493SBabu Moger 	}
2913*fa7d9493SBabu Moger 
2914*fa7d9493SBabu Moger 	/*
2915*fa7d9493SBabu Moger 	 * If the rdtgroup is a ctrl_mon group and parent directory
2916*fa7d9493SBabu Moger 	 * is the root directory, remove the ctrl_mon group.
2917*fa7d9493SBabu Moger 	 *
2918*fa7d9493SBabu Moger 	 * If the rdtgroup is a mon group and parent directory
2919*fa7d9493SBabu Moger 	 * is a valid "mon_groups" directory, remove the mon group.
2920*fa7d9493SBabu Moger 	 */
2921*fa7d9493SBabu Moger 	if (rdtgrp->type == RDTCTRL_GROUP && parent_kn == rdtgroup_default.kn) {
2922*fa7d9493SBabu Moger 		if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP ||
2923*fa7d9493SBabu Moger 		    rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
2924*fa7d9493SBabu Moger 			ret = rdtgroup_ctrl_remove(kn, rdtgrp);
2925*fa7d9493SBabu Moger 		} else {
2926*fa7d9493SBabu Moger 			ret = rdtgroup_rmdir_ctrl(kn, rdtgrp, tmpmask);
2927*fa7d9493SBabu Moger 		}
2928*fa7d9493SBabu Moger 	} else if (rdtgrp->type == RDTMON_GROUP &&
2929*fa7d9493SBabu Moger 		 is_mon_groups(parent_kn, kn->name)) {
2930*fa7d9493SBabu Moger 		ret = rdtgroup_rmdir_mon(kn, rdtgrp, tmpmask);
2931*fa7d9493SBabu Moger 	} else {
2932*fa7d9493SBabu Moger 		ret = -EPERM;
2933*fa7d9493SBabu Moger 	}
2934*fa7d9493SBabu Moger 
2935*fa7d9493SBabu Moger out:
2936*fa7d9493SBabu Moger 	rdtgroup_kn_unlock(kn);
2937*fa7d9493SBabu Moger 	free_cpumask_var(tmpmask);
2938*fa7d9493SBabu Moger 	return ret;
2939*fa7d9493SBabu Moger }
2940*fa7d9493SBabu Moger 
2941*fa7d9493SBabu Moger static int rdtgroup_show_options(struct seq_file *seq, struct kernfs_root *kf)
2942*fa7d9493SBabu Moger {
2943*fa7d9493SBabu Moger 	if (rdt_resources_all[RDT_RESOURCE_L3DATA].alloc_enabled)
2944*fa7d9493SBabu Moger 		seq_puts(seq, ",cdp");
2945*fa7d9493SBabu Moger 
2946*fa7d9493SBabu Moger 	if (rdt_resources_all[RDT_RESOURCE_L2DATA].alloc_enabled)
2947*fa7d9493SBabu Moger 		seq_puts(seq, ",cdpl2");
2948*fa7d9493SBabu Moger 
2949*fa7d9493SBabu Moger 	if (is_mba_sc(&rdt_resources_all[RDT_RESOURCE_MBA]))
2950*fa7d9493SBabu Moger 		seq_puts(seq, ",mba_MBps");
2951*fa7d9493SBabu Moger 
2952*fa7d9493SBabu Moger 	return 0;
2953*fa7d9493SBabu Moger }
2954*fa7d9493SBabu Moger 
2955*fa7d9493SBabu Moger static struct kernfs_syscall_ops rdtgroup_kf_syscall_ops = {
2956*fa7d9493SBabu Moger 	.mkdir		= rdtgroup_mkdir,
2957*fa7d9493SBabu Moger 	.rmdir		= rdtgroup_rmdir,
2958*fa7d9493SBabu Moger 	.show_options	= rdtgroup_show_options,
2959*fa7d9493SBabu Moger };
2960*fa7d9493SBabu Moger 
2961*fa7d9493SBabu Moger static int __init rdtgroup_setup_root(void)
2962*fa7d9493SBabu Moger {
2963*fa7d9493SBabu Moger 	int ret;
2964*fa7d9493SBabu Moger 
2965*fa7d9493SBabu Moger 	rdt_root = kernfs_create_root(&rdtgroup_kf_syscall_ops,
2966*fa7d9493SBabu Moger 				      KERNFS_ROOT_CREATE_DEACTIVATED |
2967*fa7d9493SBabu Moger 				      KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK,
2968*fa7d9493SBabu Moger 				      &rdtgroup_default);
2969*fa7d9493SBabu Moger 	if (IS_ERR(rdt_root))
2970*fa7d9493SBabu Moger 		return PTR_ERR(rdt_root);
2971*fa7d9493SBabu Moger 
2972*fa7d9493SBabu Moger 	mutex_lock(&rdtgroup_mutex);
2973*fa7d9493SBabu Moger 
2974*fa7d9493SBabu Moger 	rdtgroup_default.closid = 0;
2975*fa7d9493SBabu Moger 	rdtgroup_default.mon.rmid = 0;
2976*fa7d9493SBabu Moger 	rdtgroup_default.type = RDTCTRL_GROUP;
2977*fa7d9493SBabu Moger 	INIT_LIST_HEAD(&rdtgroup_default.mon.crdtgrp_list);
2978*fa7d9493SBabu Moger 
2979*fa7d9493SBabu Moger 	list_add(&rdtgroup_default.rdtgroup_list, &rdt_all_groups);
2980*fa7d9493SBabu Moger 
2981*fa7d9493SBabu Moger 	ret = rdtgroup_add_files(rdt_root->kn, RF_CTRL_BASE);
2982*fa7d9493SBabu Moger 	if (ret) {
2983*fa7d9493SBabu Moger 		kernfs_destroy_root(rdt_root);
2984*fa7d9493SBabu Moger 		goto out;
2985*fa7d9493SBabu Moger 	}
2986*fa7d9493SBabu Moger 
2987*fa7d9493SBabu Moger 	rdtgroup_default.kn = rdt_root->kn;
2988*fa7d9493SBabu Moger 	kernfs_activate(rdtgroup_default.kn);
2989*fa7d9493SBabu Moger 
2990*fa7d9493SBabu Moger out:
2991*fa7d9493SBabu Moger 	mutex_unlock(&rdtgroup_mutex);
2992*fa7d9493SBabu Moger 
2993*fa7d9493SBabu Moger 	return ret;
2994*fa7d9493SBabu Moger }
2995*fa7d9493SBabu Moger 
2996*fa7d9493SBabu Moger /*
2997*fa7d9493SBabu Moger  * rdtgroup_init - rdtgroup initialization
2998*fa7d9493SBabu Moger  *
2999*fa7d9493SBabu Moger  * Setup resctrl file system including set up root, create mount point,
3000*fa7d9493SBabu Moger  * register rdtgroup filesystem, and initialize files under root directory.
3001*fa7d9493SBabu Moger  *
3002*fa7d9493SBabu Moger  * Return: 0 on success or -errno
3003*fa7d9493SBabu Moger  */
3004*fa7d9493SBabu Moger int __init rdtgroup_init(void)
3005*fa7d9493SBabu Moger {
3006*fa7d9493SBabu Moger 	int ret = 0;
3007*fa7d9493SBabu Moger 
3008*fa7d9493SBabu Moger 	seq_buf_init(&last_cmd_status, last_cmd_status_buf,
3009*fa7d9493SBabu Moger 		     sizeof(last_cmd_status_buf));
3010*fa7d9493SBabu Moger 
3011*fa7d9493SBabu Moger 	ret = rdtgroup_setup_root();
3012*fa7d9493SBabu Moger 	if (ret)
3013*fa7d9493SBabu Moger 		return ret;
3014*fa7d9493SBabu Moger 
3015*fa7d9493SBabu Moger 	ret = sysfs_create_mount_point(fs_kobj, "resctrl");
3016*fa7d9493SBabu Moger 	if (ret)
3017*fa7d9493SBabu Moger 		goto cleanup_root;
3018*fa7d9493SBabu Moger 
3019*fa7d9493SBabu Moger 	ret = register_filesystem(&rdt_fs_type);
3020*fa7d9493SBabu Moger 	if (ret)
3021*fa7d9493SBabu Moger 		goto cleanup_mountpoint;
3022*fa7d9493SBabu Moger 
3023*fa7d9493SBabu Moger 	/*
3024*fa7d9493SBabu Moger 	 * Adding the resctrl debugfs directory here may not be ideal since
3025*fa7d9493SBabu Moger 	 * it would let the resctrl debugfs directory appear on the debugfs
3026*fa7d9493SBabu Moger 	 * filesystem before the resctrl filesystem is mounted.
3027*fa7d9493SBabu Moger 	 * It may also be ok since that would enable debugging of RDT before
3028*fa7d9493SBabu Moger 	 * resctrl is mounted.
3029*fa7d9493SBabu Moger 	 * The reason why the debugfs directory is created here and not in
3030*fa7d9493SBabu Moger 	 * rdt_mount() is because rdt_mount() takes rdtgroup_mutex and
3031*fa7d9493SBabu Moger 	 * during the debugfs directory creation also &sb->s_type->i_mutex_key
3032*fa7d9493SBabu Moger 	 * (the lockdep class of inode->i_rwsem). Other filesystem
3033*fa7d9493SBabu Moger 	 * interactions (eg. SyS_getdents) have the lock ordering:
3034*fa7d9493SBabu Moger 	 * &sb->s_type->i_mutex_key --> &mm->mmap_sem
3035*fa7d9493SBabu Moger 	 * During mmap(), called with &mm->mmap_sem, the rdtgroup_mutex
3036*fa7d9493SBabu Moger 	 * is taken, thus creating dependency:
3037*fa7d9493SBabu Moger 	 * &mm->mmap_sem --> rdtgroup_mutex for the latter that can cause
3038*fa7d9493SBabu Moger 	 * issues considering the other two lock dependencies.
3039*fa7d9493SBabu Moger 	 * By creating the debugfs directory here we avoid a dependency
3040*fa7d9493SBabu Moger 	 * that may cause deadlock (even though file operations cannot
3041*fa7d9493SBabu Moger 	 * occur until the filesystem is mounted, but I do not know how to
3042*fa7d9493SBabu Moger 	 * tell lockdep that).
3043*fa7d9493SBabu Moger 	 */
3044*fa7d9493SBabu Moger 	debugfs_resctrl = debugfs_create_dir("resctrl", NULL);
3045*fa7d9493SBabu Moger 
3046*fa7d9493SBabu Moger 	return 0;
3047*fa7d9493SBabu Moger 
3048*fa7d9493SBabu Moger cleanup_mountpoint:
3049*fa7d9493SBabu Moger 	sysfs_remove_mount_point(fs_kobj, "resctrl");
3050*fa7d9493SBabu Moger cleanup_root:
3051*fa7d9493SBabu Moger 	kernfs_destroy_root(rdt_root);
3052*fa7d9493SBabu Moger 
3053*fa7d9493SBabu Moger 	return ret;
3054*fa7d9493SBabu Moger }
3055*fa7d9493SBabu Moger 
3056*fa7d9493SBabu Moger void __exit rdtgroup_exit(void)
3057*fa7d9493SBabu Moger {
3058*fa7d9493SBabu Moger 	debugfs_remove_recursive(debugfs_resctrl);
3059*fa7d9493SBabu Moger 	unregister_filesystem(&rdt_fs_type);
3060*fa7d9493SBabu Moger 	sysfs_remove_mount_point(fs_kobj, "resctrl");
3061*fa7d9493SBabu Moger 	kernfs_destroy_root(rdt_root);
3062*fa7d9493SBabu Moger }
3063