#include <uapi/linux/magic.h>
  
- #include <asm/resctrl.h>
 +#include <asm/msr.h>
  #include "internal.h"
  
  DEFINE_STATIC_KEY_FALSE(rdt_enable_key);
- DEFINE_STATIC_KEY_FALSE(rdt_mon_enable_key);
- DEFINE_STATIC_KEY_FALSE(rdt_alloc_enable_key);
- 
- /* Mutex to protect rdtgroup access. */
- DEFINE_MUTEX(rdtgroup_mutex);
- 
- static struct kernfs_root *rdt_root;
- struct rdtgroup rdtgroup_default;
- LIST_HEAD(rdt_all_groups);
- 
- /* list of entries for the schemata file */
- LIST_HEAD(resctrl_schema_all);
- 
- /* The filesystem can only be mounted once. */
- bool resctrl_mounted;
- 
- /* Kernel fs node for "info" directory under root */
- static struct kernfs_node *kn_info;
- 
- /* Kernel fs node for "mon_groups" directory under root */
- static struct kernfs_node *kn_mongrp;
  
- /* Kernel fs node for "mon_data" directory under root */
- static struct kernfs_node *kn_mondata;
- 
- /*
-  * Used to store the max resource name width to display the schemata names in
-  * a tabular format.
-  */
- int max_name_width;
- 
- static struct seq_buf last_cmd_status;
- static char last_cmd_status_buf[512];
- 
- static int rdtgroup_setup_root(struct rdt_fs_context *ctx);
- static void rdtgroup_destroy_root(void);
+ DEFINE_STATIC_KEY_FALSE(rdt_mon_enable_key);
  
- struct dentry *debugfs_resctrl;
+ DEFINE_STATIC_KEY_FALSE(rdt_alloc_enable_key);
  
  /*
-  * Memory bandwidth monitoring event to use for the default CTRL_MON group
-  * and each new CTRL_MON group created by the user.  Only relevant when
-  * the filesystem is mounted with the "mba_MBps" option so it does not
-  * matter that it remains uninitialized on systems that do not support
-  * the "mba_MBps" option.
+  * This is safe against resctrl_arch_sched_in() called from __switch_to()
+  * because __switch_to() is executed with interrupts disabled. A local call
+  * from update_closid_rmid() is protected against __switch_to() because
+  * preemption is disabled.
   */
- enum resctrl_event_id mba_mbps_default_event;
- 
- static bool resctrl_debug;
- 
- void rdt_last_cmd_clear(void)
- {
-       lockdep_assert_held(&rdtgroup_mutex);
-       seq_buf_clear(&last_cmd_status);
- }
- 
- void rdt_last_cmd_puts(const char *s)
- {
-       lockdep_assert_held(&rdtgroup_mutex);
-       seq_buf_puts(&last_cmd_status, s);
- }
- 
- void rdt_last_cmd_printf(const char *fmt, ...)
- {
-       va_list ap;
- 
-       va_start(ap, fmt);
-       lockdep_assert_held(&rdtgroup_mutex);
-       seq_buf_vprintf(&last_cmd_status, fmt, ap);
-       va_end(ap);
- }
- 
- void rdt_staged_configs_clear(void)
+ void resctrl_arch_sync_cpu_closid_rmid(void *info)
  {
-       struct rdt_ctrl_domain *dom;
-       struct rdt_resource *r;
- 
-       lockdep_assert_held(&rdtgroup_mutex);
+       struct resctrl_cpu_defaults *r = info;
  
-       for_each_alloc_capable_rdt_resource(r) {
-               list_for_each_entry(dom, &r->ctrl_domains, hdr.list)
-                       memset(dom->staged_config, 0, sizeof(dom->staged_config));
+       if (r) {
+               this_cpu_write(pqr_state.default_closid, r->closid);
+               this_cpu_write(pqr_state.default_rmid, r->rmid);
        }
- }
  
- static bool resctrl_is_mbm_enabled(void)
- {
-       return (resctrl_arch_is_mbm_total_enabled() ||
-               resctrl_arch_is_mbm_local_enabled());
+       /*
+        * We cannot unconditionally write the MSR because the current
+        * executing task might have its own closid selected. Just reuse
+        * the context switch code.
+        */
+       resctrl_arch_sched_in(current);
  }
  
- static bool resctrl_is_mbm_event(int e)
- {
-       return (e >= QOS_L3_MBM_TOTAL_EVENT_ID &&
-               e <= QOS_L3_MBM_LOCAL_EVENT_ID);
- }
+ #define INVALID_CONFIG_INDEX   UINT_MAX
  
- /*
-  * Trivial allocator for CLOSIDs. Since h/w only supports a small number,
-  * we can keep a bitmap of free CLOSIDs in a single integer.
+ /**
+  * mon_event_config_index_get - get the hardware index for the
+  *                              configurable event
+  * @evtid: event id.
   *
-  * Using a global CLOSID across all resources has some advantages and
-  * some drawbacks:
-  * + We can simply set current's closid to assign a task to a resource
-  *   group.
-  * + Context switch code can avoid extra memory references deciding which
-  *   CLOSID to load into the PQR_ASSOC MSR
-  * - We give up some options in configuring resource groups across multi-socket
-  *   systems.
-  * - Our choices on how to configure each resource become progressively more
-  *   limited as the number of resources grows.
+  * Return: 0 for evtid == QOS_L3_MBM_TOTAL_EVENT_ID
+  *         1 for evtid == QOS_L3_MBM_LOCAL_EVENT_ID
+  *         INVALID_CONFIG_INDEX for invalid evtid
   */
- static unsigned long closid_free_map;
- static int closid_free_map_len;
- 
- int closids_supported(void)
- {
-       return closid_free_map_len;
- }
- 
- static void closid_init(void)
+ static inline unsigned int mon_event_config_index_get(u32 evtid)
  {
-       struct resctrl_schema *s;
-       u32 rdt_min_closid = 32;
- 
-       /* Compute rdt_min_closid across all resources */
-       list_for_each_entry(s, &resctrl_schema_all, list)
-               rdt_min_closid = min(rdt_min_closid, s->num_closid);
- 
-       closid_free_map = BIT_MASK(rdt_min_closid) - 1;
- 
-       /* RESCTRL_RESERVED_CLOSID is always reserved for the default group */
-       __clear_bit(RESCTRL_RESERVED_CLOSID, &closid_free_map);
-       closid_free_map_len = rdt_min_closid;
+       switch (evtid) {
+       case QOS_L3_MBM_TOTAL_EVENT_ID:
+               return 0;
+       case QOS_L3_MBM_LOCAL_EVENT_ID:
+               return 1;
+       default:
+               /* Should never reach here */
+               return INVALID_CONFIG_INDEX;
+       }
  }
  
- static int closid_alloc(void)
+ void resctrl_arch_mon_event_config_read(void *_config_info)
  {
-       int cleanest_closid;
-       u32 closid;
- 
-       lockdep_assert_held(&rdtgroup_mutex);
+       struct resctrl_mon_config_info *config_info = _config_info;
+       unsigned int index;
+       u64 msrval;
  
-       if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID) &&
-           resctrl_arch_is_llc_occupancy_enabled()) {
-               cleanest_closid = resctrl_find_cleanest_closid();
-               if (cleanest_closid < 0)
-                       return cleanest_closid;
-               closid = cleanest_closid;
-       } else {
-               closid = ffs(closid_free_map);
-               if (closid == 0)
-                       return -ENOSPC;
-               closid--;
+       index = mon_event_config_index_get(config_info->evtid);
+       if (index == INVALID_CONFIG_INDEX) {
+               pr_warn_once("Invalid event id %d\n", config_info->evtid);
+               return;
        }
-       __clear_bit(closid, &closid_free_map);
- 
-       return closid;
- }
- 
- void closid_free(int closid)
- {
-       lockdep_assert_held(&rdtgroup_mutex);
 -      rdmsrl(MSR_IA32_EVT_CFG_BASE + index, msrval);
++      rdmsrq(MSR_IA32_EVT_CFG_BASE + index, msrval);
  
-       __set_bit(closid, &closid_free_map);
+       /* Report only the valid event configuration bits */
+       config_info->mon_config = msrval & MAX_EVT_CONFIG_BITS;
  }
  
- /**
-  * closid_allocated - test if provided closid is in use
-  * @closid: closid to be tested
-  *
-  * Return: true if @closid is currently associated with a resource group,
-  * false if @closid is free
-  */
- bool closid_allocated(unsigned int closid)
+ void resctrl_arch_mon_event_config_write(void *_config_info)
  {
-       lockdep_assert_held(&rdtgroup_mutex);
+       struct resctrl_mon_config_info *config_info = _config_info;
+       unsigned int index;
  
-       return !test_bit(closid, &closid_free_map);
+       index = mon_event_config_index_get(config_info->evtid);
+       if (index == INVALID_CONFIG_INDEX) {
+               pr_warn_once("Invalid event id %d\n", config_info->evtid);
+               return;
+       }
 -      wrmsr(MSR_IA32_EVT_CFG_BASE + index, config_info->mon_config, 0);
++      wrmsrq(MSR_IA32_EVT_CFG_BASE + index, config_info->mon_config);
  }
  
- /**
-  * rdtgroup_mode_by_closid - Return mode of resource group with closid
-  * @closid: closid if the resource group
-  *
-  * Each resource group is associated with a @closid. Here the mode
-  * of a resource group can be queried by searching for it using its closid.
-  *
-  * Return: mode as &enum rdtgrp_mode of resource group with closid @closid
-  */
- enum rdtgrp_mode rdtgroup_mode_by_closid(int closid)
+ static void l3_qos_cfg_update(void *arg)
  {
-       struct rdtgroup *rdtgrp;
- 
-       list_for_each_entry(rdtgrp, &rdt_all_groups, rdtgroup_list) {
-               if (rdtgrp->closid == closid)
-                       return rdtgrp->mode;
-       }
+       bool *enable = arg;
  
-       return RDT_NUM_MODES;
 -      wrmsrl(MSR_IA32_L3_QOS_CFG, *enable ? L3_QOS_CDP_ENABLE : 0ULL);
++      wrmsrq(MSR_IA32_L3_QOS_CFG, *enable ? L3_QOS_CDP_ENABLE : 0ULL);
  }
  
- static const char * const rdt_mode_str[] = {
-       [RDT_MODE_SHAREABLE]            = "shareable",
-       [RDT_MODE_EXCLUSIVE]            = "exclusive",
-       [RDT_MODE_PSEUDO_LOCKSETUP]     = "pseudo-locksetup",
-       [RDT_MODE_PSEUDO_LOCKED]        = "pseudo-locked",
- };
- 
- /**
-  * rdtgroup_mode_str - Return the string representation of mode
-  * @mode: the resource group mode as &enum rdtgroup_mode
-  *
-  * Return: string representation of valid mode, "unknown" otherwise
-  */
- static const char *rdtgroup_mode_str(enum rdtgrp_mode mode)
+ static void l2_qos_cfg_update(void *arg)
  {
-       if (mode < RDT_MODE_SHAREABLE || mode >= RDT_NUM_MODES)
-               return "unknown";
+       bool *enable = arg;
  
-       return rdt_mode_str[mode];
 -      wrmsrl(MSR_IA32_L2_QOS_CFG, *enable ? L2_QOS_CDP_ENABLE : 0ULL);
++      wrmsrq(MSR_IA32_L2_QOS_CFG, *enable ? L2_QOS_CDP_ENABLE : 0ULL);
  }
  
- /* set uid and gid of rdtgroup dirs and files to that of the creator */
- static int rdtgroup_kn_set_ugid(struct kernfs_node *kn)
+ static int set_cache_qos_cfg(int level, bool enable)
  {
-       struct iattr iattr = { .ia_valid = ATTR_UID | ATTR_GID,
-                               .ia_uid = current_fsuid(),
-                               .ia_gid = current_fsgid(), };
- 
-       if (uid_eq(iattr.ia_uid, GLOBAL_ROOT_UID) &&
-           gid_eq(iattr.ia_gid, GLOBAL_ROOT_GID))
-               return 0;
+       void (*update)(void *arg);
+       struct rdt_ctrl_domain *d;
+       struct rdt_resource *r_l;
+       cpumask_var_t cpu_mask;
+       int cpu;
  
-       return kernfs_setattr(kn, &iattr);
- }
+       /* Walking r->domains, ensure it can't race with cpuhp */
+       lockdep_assert_cpus_held();
  
- static int rdtgroup_add_file(struct kernfs_node *parent_kn, struct rftype *rft)
- {
-       struct kernfs_node *kn;
-       int ret;
+       if (level == RDT_RESOURCE_L3)
+               update = l3_qos_cfg_update;
+       else if (level == RDT_RESOURCE_L2)
+               update = l2_qos_cfg_update;
+       else
+               return -EINVAL;
  
-       kn = __kernfs_create_file(parent_kn, rft->name, rft->mode,
-                                 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
-                                 0, rft->kf_ops, rft, NULL, NULL);
-       if (IS_ERR(kn))
-               return PTR_ERR(kn);
+       if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
+               return -ENOMEM;
  
-       ret = rdtgroup_kn_set_ugid(kn);
-       if (ret) {
-               kernfs_remove(kn);
-               return ret;
+       r_l = &rdt_resources_all[level].r_resctrl;
+       list_for_each_entry(d, &r_l->ctrl_domains, hdr.list) {
+               if (r_l->cache.arch_has_per_cpu_cfg)
+                       /* Pick all the CPUs in the domain instance */
+                       for_each_cpu(cpu, &d->hdr.cpu_mask)
+                               cpumask_set_cpu(cpu, cpu_mask);
+               else
+                       /* Pick one CPU from each domain instance to update MSR */
+                       cpumask_set_cpu(cpumask_any(&d->hdr.cpu_mask), cpu_mask);
        }
  
-       return 0;
- }
+       /* Update QOS_CFG MSR on all the CPUs in cpu_mask */
+       on_each_cpu_mask(cpu_mask, update, &enable, 1);
  
- static int rdtgroup_seqfile_show(struct seq_file *m, void *arg)
- {
-       struct kernfs_open_file *of = m->private;
-       struct rftype *rft = of->kn->priv;
+       free_cpumask_var(cpu_mask);
  
-       if (rft->seq_show)
-               return rft->seq_show(of, m, arg);
        return 0;
  }