x86/resctrl: Add cpumask_any_housekeeping() for limbo/overflow
[linux-2.6-microblaze.git] / arch / x86 / kernel / cpu / resctrl / monitor.c
index 3a6c069..38f85e5 100644 (file)
 
 #include "internal.h"
 
+/**
+ * struct rmid_entry - dirty tracking for all RMID.
+ * @closid:    The CLOSID for this entry.
+ * @rmid:      The RMID for this entry.
+ * @busy:      The number of domains with cached data using this RMID.
+ * @list:      Member of the rmid_free_lru list when busy == 0.
+ *
+ * Depending on the architecture the correct monitor is accessed using
+ * both @closid and @rmid, or @rmid only.
+ *
+ * Take the rdtgroup_mutex when accessing.
+ */
 struct rmid_entry {
+       u32                             closid;
        u32                             rmid;
        int                             busy;
        struct list_head                list;
@@ -37,6 +50,13 @@ struct rmid_entry {
  */
 static LIST_HEAD(rmid_free_lru);
 
+/*
+ * @closid_num_dirty_rmid    The number of dirty RMID each CLOSID has.
+ *     Only allocated when CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID is defined.
+ *     Indexed by CLOSID. Protected by rdtgroup_mutex.
+ */
+static u32 *closid_num_dirty_rmid;
+
 /*
  * @rmid_limbo_count - count of currently unused but (potentially)
  *     dirty RMIDs.
@@ -136,12 +156,29 @@ static inline u64 get_corrected_mbm_count(u32 rmid, unsigned long val)
        return val;
 }
 
-static inline struct rmid_entry *__rmid_entry(u32 rmid)
+/*
+ * x86 and arm64 differ in their handling of monitoring.
+ * x86's RMID are independent numbers, there is only one source of traffic
+ * with an RMID value of '1'.
+ * arm64's PMG extends the PARTID/CLOSID space, there are multiple sources of
+ * traffic with a PMG value of '1', one for each CLOSID, meaning the RMID
+ * value is no longer unique.
+ * To account for this, resctrl uses an index. On x86 this is just the RMID,
+ * on arm64 it encodes the CLOSID and RMID. This gives a unique number.
+ *
+ * The domain's rmid_busy_llc and rmid_ptrs[] are sized by index. The arch code
+ * must accept an attempt to read every index.
+ */
+static inline struct rmid_entry *__rmid_entry(u32 idx)
 {
        struct rmid_entry *entry;
+       u32 closid, rmid;
 
-       entry = &rmid_ptrs[rmid];
-       WARN_ON(entry->rmid != rmid);
+       entry = &rmid_ptrs[idx];
+       resctrl_arch_rmid_idx_decode(idx, &closid, &rmid);
+
+       WARN_ON_ONCE(entry->closid != closid);
+       WARN_ON_ONCE(entry->rmid != rmid);
 
        return entry;
 }
@@ -190,7 +227,8 @@ static struct arch_mbm_state *get_arch_mbm_state(struct rdt_hw_domain *hw_dom,
 }
 
 void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_domain *d,
-                            u32 rmid, enum resctrl_event_id eventid)
+                            u32 unused, u32 rmid,
+                            enum resctrl_event_id eventid)
 {
        struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d);
        struct arch_mbm_state *am;
@@ -230,7 +268,8 @@ static u64 mbm_overflow_count(u64 prev_msr, u64 cur_msr, unsigned int width)
 }
 
 int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d,
-                          u32 rmid, enum resctrl_event_id eventid, u64 *val)
+                          u32 unused, u32 rmid, enum resctrl_event_id eventid,
+                          u64 *val)
 {
        struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
        struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d);
@@ -260,6 +299,17 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d,
        return 0;
 }
 
+static void limbo_release_entry(struct rmid_entry *entry)
+{
+       lockdep_assert_held(&rdtgroup_mutex);
+
+       rmid_limbo_count--;
+       list_add_tail(&entry->list, &rmid_free_lru);
+
+       if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID))
+               closid_num_dirty_rmid[entry->closid]--;
+}
+
 /*
  * Check the RMIDs that are marked as busy for this domain. If the
  * reported LLC occupancy is below the threshold clear the busy bit and
@@ -269,8 +319,9 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d,
 void __check_limbo(struct rdt_domain *d, bool force_free)
 {
        struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
+       u32 idx_limit = resctrl_arch_system_num_rmid_idx();
        struct rmid_entry *entry;
-       u32 crmid = 1, nrmid;
+       u32 idx, cur_idx = 1;
        bool rmid_dirty;
        u64 val = 0;
 
@@ -281,13 +332,12 @@ void __check_limbo(struct rdt_domain *d, bool force_free)
         * RMID and move it to the free list when the counter reaches 0.
         */
        for (;;) {
-               nrmid = find_next_bit(d->rmid_busy_llc, r->num_rmid, crmid);
-               if (nrmid >= r->num_rmid)
+               idx = find_next_bit(d->rmid_busy_llc, idx_limit, cur_idx);
+               if (idx >= idx_limit)
                        break;
 
-               entry = __rmid_entry(nrmid);
-
-               if (resctrl_arch_rmid_read(r, d, entry->rmid,
+               entry = __rmid_entry(idx);
+               if (resctrl_arch_rmid_read(r, d, entry->closid, entry->rmid,
                                           QOS_L3_OCCUP_EVENT_ID, &val)) {
                        rmid_dirty = true;
                } else {
@@ -295,39 +345,109 @@ void __check_limbo(struct rdt_domain *d, bool force_free)
                }
 
                if (force_free || !rmid_dirty) {
-                       clear_bit(entry->rmid, d->rmid_busy_llc);
-                       if (!--entry->busy) {
-                               rmid_limbo_count--;
-                               list_add_tail(&entry->list, &rmid_free_lru);
-                       }
+                       clear_bit(idx, d->rmid_busy_llc);
+                       if (!--entry->busy)
+                               limbo_release_entry(entry);
                }
-               crmid = nrmid + 1;
+               cur_idx = idx + 1;
        }
 }
 
-bool has_busy_rmid(struct rdt_resource *r, struct rdt_domain *d)
+bool has_busy_rmid(struct rdt_domain *d)
+{
+       u32 idx_limit = resctrl_arch_system_num_rmid_idx();
+
+       return find_first_bit(d->rmid_busy_llc, idx_limit) != idx_limit;
+}
+
+static struct rmid_entry *resctrl_find_free_rmid(u32 closid)
 {
-       return find_first_bit(d->rmid_busy_llc, r->num_rmid) != r->num_rmid;
+       struct rmid_entry *itr;
+       u32 itr_idx, cmp_idx;
+
+       if (list_empty(&rmid_free_lru))
+               return rmid_limbo_count ? ERR_PTR(-EBUSY) : ERR_PTR(-ENOSPC);
+
+       list_for_each_entry(itr, &rmid_free_lru, list) {
+               /*
+                * Get the index of this free RMID, and the index it would need
+                * to be if it were used with this CLOSID.
+                * If the CLOSID is irrelevant on this architecture, the two
+                * index values are always the same on every entry and thus the
+                * very first entry will be returned.
+                */
+               itr_idx = resctrl_arch_rmid_idx_encode(itr->closid, itr->rmid);
+               cmp_idx = resctrl_arch_rmid_idx_encode(closid, itr->rmid);
+
+               if (itr_idx == cmp_idx)
+                       return itr;
+       }
+
+       return ERR_PTR(-ENOSPC);
+}
+
+/**
+ * resctrl_find_cleanest_closid() - Find a CLOSID where all the associated
+ *                                  RMID are clean, or the CLOSID that has
+ *                                  the most clean RMID.
+ *
+ * MPAM's equivalent of RMID are per-CLOSID, meaning a freshly allocated CLOSID
+ * may not be able to allocate clean RMID. To avoid this the allocator will
+ * choose the CLOSID with the most clean RMID.
+ *
+ * When the CLOSID and RMID are independent numbers, the first free CLOSID will
+ * be returned.
+ */
+int resctrl_find_cleanest_closid(void)
+{
+       u32 cleanest_closid = ~0;
+       int i = 0;
+
+       lockdep_assert_held(&rdtgroup_mutex);
+
+       if (!IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID))
+               return -EIO;
+
+       for (i = 0; i < closids_supported(); i++) {
+               int num_dirty;
+
+               if (closid_allocated(i))
+                       continue;
+
+               num_dirty = closid_num_dirty_rmid[i];
+               if (num_dirty == 0)
+                       return i;
+
+               if (cleanest_closid == ~0)
+                       cleanest_closid = i;
+
+               if (num_dirty < closid_num_dirty_rmid[cleanest_closid])
+                       cleanest_closid = i;
+       }
+
+       if (cleanest_closid == ~0)
+               return -ENOSPC;
+
+       return cleanest_closid;
 }
 
 /*
- * As of now the RMIDs allocation is global.
- * However we keep track of which packages the RMIDs
- * are used to optimize the limbo list management.
+ * For MPAM the RMID value is not unique, and has to be considered with
+ * the CLOSID. The (CLOSID, RMID) pair is allocated on all domains, which
+ * allows all domains to be managed by a single free list.
+ * Each domain also has a rmid_busy_llc to reduce the work of the limbo handler.
  */
-int alloc_rmid(void)
+int alloc_rmid(u32 closid)
 {
        struct rmid_entry *entry;
 
        lockdep_assert_held(&rdtgroup_mutex);
 
-       if (list_empty(&rmid_free_lru))
-               return rmid_limbo_count ? -EBUSY : -ENOSPC;
+       entry = resctrl_find_free_rmid(closid);
+       if (IS_ERR(entry))
+               return PTR_ERR(entry);
 
-       entry = list_first_entry(&rmid_free_lru,
-                                struct rmid_entry, list);
        list_del(&entry->list);
-
        return entry->rmid;
 }
 
@@ -337,12 +457,18 @@ static void add_rmid_to_limbo(struct rmid_entry *entry)
        struct rdt_domain *d;
        int cpu, err;
        u64 val = 0;
+       u32 idx;
+
+       lockdep_assert_held(&rdtgroup_mutex);
+
+       idx = resctrl_arch_rmid_idx_encode(entry->closid, entry->rmid);
 
        entry->busy = 0;
        cpu = get_cpu();
        list_for_each_entry(d, &r->domains, list) {
                if (cpumask_test_cpu(cpu, &d->cpu_mask)) {
-                       err = resctrl_arch_rmid_read(r, d, entry->rmid,
+                       err = resctrl_arch_rmid_read(r, d, entry->closid,
+                                                    entry->rmid,
                                                     QOS_L3_OCCUP_EVENT_ID,
                                                     &val);
                        if (err || val <= resctrl_rmid_realloc_threshold)
@@ -353,29 +479,39 @@ static void add_rmid_to_limbo(struct rmid_entry *entry)
                 * For the first limbo RMID in the domain,
                 * setup up the limbo worker.
                 */
-               if (!has_busy_rmid(r, d))
+               if (!has_busy_rmid(d))
                        cqm_setup_limbo_handler(d, CQM_LIMBOCHECK_INTERVAL);
-               set_bit(entry->rmid, d->rmid_busy_llc);
+               set_bit(idx, d->rmid_busy_llc);
                entry->busy++;
        }
        put_cpu();
 
-       if (entry->busy)
+       if (entry->busy) {
                rmid_limbo_count++;
-       else
+               if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID))
+                       closid_num_dirty_rmid[entry->closid]++;
+       } else {
                list_add_tail(&entry->list, &rmid_free_lru);
+       }
 }
 
-void free_rmid(u32 rmid)
+void free_rmid(u32 closid, u32 rmid)
 {
+       u32 idx = resctrl_arch_rmid_idx_encode(closid, rmid);
        struct rmid_entry *entry;
 
-       if (!rmid)
-               return;
-
        lockdep_assert_held(&rdtgroup_mutex);
 
-       entry = __rmid_entry(rmid);
+       /*
+        * Do not allow the default rmid to be free'd. Comparing by index
+        * allows architectures that ignore the closid parameter to avoid an
+        * unnecessary check.
+        */
+       if (idx == resctrl_arch_rmid_idx_encode(RESCTRL_RESERVED_CLOSID,
+                                               RESCTRL_RESERVED_RMID))
+               return;
+
+       entry = __rmid_entry(idx);
 
        if (is_llc_occupancy_enabled())
                add_rmid_to_limbo(entry);
@@ -383,33 +519,36 @@ void free_rmid(u32 rmid)
                list_add_tail(&entry->list, &rmid_free_lru);
 }
 
-static struct mbm_state *get_mbm_state(struct rdt_domain *d, u32 rmid,
-                                      enum resctrl_event_id evtid)
+static struct mbm_state *get_mbm_state(struct rdt_domain *d, u32 closid,
+                                      u32 rmid, enum resctrl_event_id evtid)
 {
+       u32 idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+
        switch (evtid) {
        case QOS_L3_MBM_TOTAL_EVENT_ID:
-               return &d->mbm_total[rmid];
+               return &d->mbm_total[idx];
        case QOS_L3_MBM_LOCAL_EVENT_ID:
-               return &d->mbm_local[rmid];
+               return &d->mbm_local[idx];
        default:
                return NULL;
        }
 }
 
-static int __mon_event_count(u32 rmid, struct rmid_read *rr)
+static int __mon_event_count(u32 closid, u32 rmid, struct rmid_read *rr)
 {
        struct mbm_state *m;
        u64 tval = 0;
 
        if (rr->first) {
-               resctrl_arch_reset_rmid(rr->r, rr->d, rmid, rr->evtid);
-               m = get_mbm_state(rr->d, rmid, rr->evtid);
+               resctrl_arch_reset_rmid(rr->r, rr->d, closid, rmid, rr->evtid);
+               m = get_mbm_state(rr->d, closid, rmid, rr->evtid);
                if (m)
                        memset(m, 0, sizeof(struct mbm_state));
                return 0;
        }
 
-       rr->err = resctrl_arch_rmid_read(rr->r, rr->d, rmid, rr->evtid, &tval);
+       rr->err = resctrl_arch_rmid_read(rr->r, rr->d, closid, rmid, rr->evtid,
+                                        &tval);
        if (rr->err)
                return rr->err;
 
@@ -421,6 +560,7 @@ static int __mon_event_count(u32 rmid, struct rmid_read *rr)
 /*
  * mbm_bw_count() - Update bw count from values previously read by
  *                 __mon_event_count().
+ * @closid:    The closid used to identify the cached mbm_state.
  * @rmid:      The rmid used to identify the cached mbm_state.
  * @rr:                The struct rmid_read populated by __mon_event_count().
  *
@@ -429,9 +569,10 @@ static int __mon_event_count(u32 rmid, struct rmid_read *rr)
  * __mon_event_count() is compared with the chunks value from the previous
  * invocation. This must be called once per second to maintain values in MBps.
  */
-static void mbm_bw_count(u32 rmid, struct rmid_read *rr)
+static void mbm_bw_count(u32 closid, u32 rmid, struct rmid_read *rr)
 {
-       struct mbm_state *m = &rr->d->mbm_local[rmid];
+       u32 idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+       struct mbm_state *m = &rr->d->mbm_local[idx];
        u64 cur_bw, bytes, cur_bytes;
 
        cur_bytes = rr->val;
@@ -456,7 +597,7 @@ void mon_event_count(void *info)
 
        rdtgrp = rr->rgrp;
 
-       ret = __mon_event_count(rdtgrp->mon.rmid, rr);
+       ret = __mon_event_count(rdtgrp->closid, rdtgrp->mon.rmid, rr);
 
        /*
         * For Ctrl groups read data from child monitor groups and
@@ -467,7 +608,8 @@ void mon_event_count(void *info)
 
        if (rdtgrp->type == RDTCTRL_GROUP) {
                list_for_each_entry(entry, head, mon.crdtgrp_list) {
-                       if (__mon_event_count(entry->mon.rmid, rr) == 0)
+                       if (__mon_event_count(entry->closid, entry->mon.rmid,
+                                             rr) == 0)
                                ret = 0;
                }
        }
@@ -519,9 +661,9 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm)
        struct mbm_state *pmbm_data, *cmbm_data;
        struct rdt_resource *r_mba;
        struct rdt_domain *dom_mba;
+       u32 cur_bw, user_bw, idx;
        struct list_head *head;
        struct rdtgroup *entry;
-       u32 cur_bw, user_bw;
 
        if (!is_mbm_local_enabled())
                return;
@@ -530,7 +672,8 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm)
 
        closid = rgrp->closid;
        rmid = rgrp->mon.rmid;
-       pmbm_data = &dom_mbm->mbm_local[rmid];
+       idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+       pmbm_data = &dom_mbm->mbm_local[idx];
 
        dom_mba = get_domain_from_cpu(smp_processor_id(), r_mba);
        if (!dom_mba) {
@@ -578,7 +721,8 @@ static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm)
        resctrl_arch_update_one(r_mba, dom_mba, closid, CDP_NONE, new_msr_val);
 }
 
-static void mbm_update(struct rdt_resource *r, struct rdt_domain *d, int rmid)
+static void mbm_update(struct rdt_resource *r, struct rdt_domain *d,
+                      u32 closid, u32 rmid)
 {
        struct rmid_read rr;
 
@@ -593,12 +737,12 @@ static void mbm_update(struct rdt_resource *r, struct rdt_domain *d, int rmid)
        if (is_mbm_total_enabled()) {
                rr.evtid = QOS_L3_MBM_TOTAL_EVENT_ID;
                rr.val = 0;
-               __mon_event_count(rmid, &rr);
+               __mon_event_count(closid, rmid, &rr);
        }
        if (is_mbm_local_enabled()) {
                rr.evtid = QOS_L3_MBM_LOCAL_EVENT_ID;
                rr.val = 0;
-               __mon_event_count(rmid, &rr);
+               __mon_event_count(closid, rmid, &rr);
 
                /*
                 * Call the MBA software controller only for the
@@ -606,7 +750,7 @@ static void mbm_update(struct rdt_resource *r, struct rdt_domain *d, int rmid)
                 * the software controller explicitly.
                 */
                if (is_mba_sc(NULL))
-                       mbm_bw_count(rmid, &rr);
+                       mbm_bw_count(closid, rmid, &rr);
        }
 }
 
@@ -617,19 +761,19 @@ static void mbm_update(struct rdt_resource *r, struct rdt_domain *d, int rmid)
 void cqm_handle_limbo(struct work_struct *work)
 {
        unsigned long delay = msecs_to_jiffies(CQM_LIMBOCHECK_INTERVAL);
-       int cpu = smp_processor_id();
-       struct rdt_resource *r;
        struct rdt_domain *d;
 
        mutex_lock(&rdtgroup_mutex);
 
-       r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
        d = container_of(work, struct rdt_domain, cqm_limbo.work);
 
        __check_limbo(d, false);
 
-       if (has_busy_rmid(r, d))
-               schedule_delayed_work_on(cpu, &d->cqm_limbo, delay);
+       if (has_busy_rmid(d)) {
+               d->cqm_work_cpu = cpumask_any_housekeeping(&d->cpu_mask);
+               schedule_delayed_work_on(d->cqm_work_cpu, &d->cqm_limbo,
+                                        delay);
+       }
 
        mutex_unlock(&rdtgroup_mutex);
 }
@@ -639,7 +783,7 @@ void cqm_setup_limbo_handler(struct rdt_domain *dom, unsigned long delay_ms)
        unsigned long delay = msecs_to_jiffies(delay_ms);
        int cpu;
 
-       cpu = cpumask_any(&dom->cpu_mask);
+       cpu = cpumask_any_housekeeping(&dom->cpu_mask);
        dom->cqm_work_cpu = cpu;
 
        schedule_delayed_work_on(cpu, &dom->cqm_limbo, delay);
@@ -649,7 +793,6 @@ void mbm_handle_overflow(struct work_struct *work)
 {
        unsigned long delay = msecs_to_jiffies(MBM_OVERFLOW_INTERVAL);
        struct rdtgroup *prgrp, *crgrp;
-       int cpu = smp_processor_id();
        struct list_head *head;
        struct rdt_resource *r;
        struct rdt_domain *d;
@@ -663,17 +806,22 @@ void mbm_handle_overflow(struct work_struct *work)
        d = container_of(work, struct rdt_domain, mbm_over.work);
 
        list_for_each_entry(prgrp, &rdt_all_groups, rdtgroup_list) {
-               mbm_update(r, d, prgrp->mon.rmid);
+               mbm_update(r, d, prgrp->closid, prgrp->mon.rmid);
 
                head = &prgrp->mon.crdtgrp_list;
                list_for_each_entry(crgrp, head, mon.crdtgrp_list)
-                       mbm_update(r, d, crgrp->mon.rmid);
+                       mbm_update(r, d, crgrp->closid, crgrp->mon.rmid);
 
                if (is_mba_sc(NULL))
                        update_mba_bw(prgrp, d);
        }
 
-       schedule_delayed_work_on(cpu, &d->mbm_over, delay);
+       /*
+        * Re-check for housekeeping CPUs. This allows the overflow handler to
+        * move off a nohz_full CPU quickly.
+        */
+       d->mbm_work_cpu = cpumask_any_housekeeping(&d->cpu_mask);
+       schedule_delayed_work_on(d->mbm_work_cpu, &d->mbm_over, delay);
 
 out_unlock:
        mutex_unlock(&rdtgroup_mutex);
@@ -686,37 +834,85 @@ void mbm_setup_overflow_handler(struct rdt_domain *dom, unsigned long delay_ms)
 
        if (!static_branch_likely(&rdt_mon_enable_key))
                return;
-       cpu = cpumask_any(&dom->cpu_mask);
+       cpu = cpumask_any_housekeeping(&dom->cpu_mask);
        dom->mbm_work_cpu = cpu;
        schedule_delayed_work_on(cpu, &dom->mbm_over, delay);
 }
 
 static int dom_data_init(struct rdt_resource *r)
 {
+       u32 idx_limit = resctrl_arch_system_num_rmid_idx();
+       u32 num_closid = resctrl_arch_get_num_closid(r);
        struct rmid_entry *entry = NULL;
-       int i, nr_rmids;
+       int err = 0, i;
+       u32 idx;
 
-       nr_rmids = r->num_rmid;
-       rmid_ptrs = kcalloc(nr_rmids, sizeof(struct rmid_entry), GFP_KERNEL);
-       if (!rmid_ptrs)
-               return -ENOMEM;
+       mutex_lock(&rdtgroup_mutex);
+       if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID)) {
+               u32 *tmp;
 
-       for (i = 0; i < nr_rmids; i++) {
+               /*
+                * If the architecture hasn't provided a sanitised value here,
+                * this may result in larger arrays than necessary. Resctrl will
+                * use a smaller system wide value based on the resources in
+                * use.
+                */
+               tmp = kcalloc(num_closid, sizeof(*tmp), GFP_KERNEL);
+               if (!tmp) {
+                       err = -ENOMEM;
+                       goto out_unlock;
+               }
+
+               closid_num_dirty_rmid = tmp;
+       }
+
+       rmid_ptrs = kcalloc(idx_limit, sizeof(struct rmid_entry), GFP_KERNEL);
+       if (!rmid_ptrs) {
+               if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID)) {
+                       kfree(closid_num_dirty_rmid);
+                       closid_num_dirty_rmid = NULL;
+               }
+               err = -ENOMEM;
+               goto out_unlock;
+       }
+
+       for (i = 0; i < idx_limit; i++) {
                entry = &rmid_ptrs[i];
                INIT_LIST_HEAD(&entry->list);
 
-               entry->rmid = i;
+               resctrl_arch_rmid_idx_decode(i, &entry->closid, &entry->rmid);
                list_add_tail(&entry->list, &rmid_free_lru);
        }
 
        /*
-        * RMID 0 is special and is always allocated. It's used for all
-        * tasks that are not monitored.
+        * RESCTRL_RESERVED_CLOSID and RESCTRL_RESERVED_RMID are special and
+        * are always allocated. These are used for the rdtgroup_default
+        * control group, which will be setup later in rdtgroup_init().
         */
-       entry = __rmid_entry(0);
+       idx = resctrl_arch_rmid_idx_encode(RESCTRL_RESERVED_CLOSID,
+                                          RESCTRL_RESERVED_RMID);
+       entry = __rmid_entry(idx);
        list_del(&entry->list);
 
-       return 0;
+out_unlock:
+       mutex_unlock(&rdtgroup_mutex);
+
+       return err;
+}
+
+static void __exit dom_data_exit(void)
+{
+       mutex_lock(&rdtgroup_mutex);
+
+       if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID)) {
+               kfree(closid_num_dirty_rmid);
+               closid_num_dirty_rmid = NULL;
+       }
+
+       kfree(rmid_ptrs);
+       rmid_ptrs = NULL;
+
+       mutex_unlock(&rdtgroup_mutex);
 }
 
 static struct mon_evt llc_occupancy_event = {
@@ -814,6 +1010,11 @@ int __init rdt_get_mon_l3_config(struct rdt_resource *r)
        return 0;
 }
 
+void __exit rdt_put_mon_l3_config(void)
+{
+       dom_data_exit();
+}
+
 void __init intel_rdt_mbm_apply_quirk(void)
 {
        int cf_index;