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