}
 }
 
+static u32 *alloc_ctrlval_array(struct rdt_resource *r, struct rdt_domain *d,
+                               bool mba_sc)
+{
+       /* these are for the underlying hardware, they may not match r/d */
+       struct rdt_domain *underlying_domain;
+       struct rdt_hw_resource *hw_res;
+       struct rdt_hw_domain *hw_dom;
+       bool remapped;
+
+       switch (r->rid) {
+       case RDT_RESOURCE_L3DATA:
+       case RDT_RESOURCE_L3CODE:
+               hw_res = &rdt_resources_all[RDT_RESOURCE_L3];
+               remapped = true;
+               break;
+       case RDT_RESOURCE_L2DATA:
+       case RDT_RESOURCE_L2CODE:
+               hw_res = &rdt_resources_all[RDT_RESOURCE_L2];
+               remapped = true;
+               break;
+       default:
+               hw_res = resctrl_to_arch_res(r);
+               remapped = false;
+       }
+
+       /*
+        * If we changed the resource, we need to search for the underlying
+        * domain. Doing this for all resources would make it tricky to add the
+        * first resource, as domains aren't added to a resource list until
+        * after the ctrlval arrays have been allocated.
+        */
+       if (remapped)
+               underlying_domain = rdt_find_domain(&hw_res->r_resctrl, d->id,
+                                                   NULL);
+       else
+               underlying_domain = d;
+       hw_dom = resctrl_to_arch_dom(underlying_domain);
+
+       if (mba_sc) {
+               if (hw_dom->mbps_val)
+                       return hw_dom->mbps_val;
+               return kmalloc_array(hw_res->num_closid,
+                                    sizeof(*hw_dom->mbps_val), GFP_KERNEL);
+       } else {
+               if (hw_dom->ctrl_val)
+                       return hw_dom->ctrl_val;
+               return kmalloc_array(hw_res->num_closid,
+                                    sizeof(*hw_dom->ctrl_val), GFP_KERNEL);
+       }
+}
+
 static int domain_setup_ctrlval(struct rdt_resource *r, struct rdt_domain *d)
 {
        struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
        struct msr_param m;
        u32 *dc, *dm;
 
-       dc = kmalloc_array(hw_res->num_closid, sizeof(*hw_dom->ctrl_val), GFP_KERNEL);
+       dc = alloc_ctrlval_array(r, d, false);
        if (!dc)
                return -ENOMEM;
 
-       dm = kmalloc_array(hw_res->num_closid, sizeof(*hw_dom->mbps_val), GFP_KERNEL);
+       dm = alloc_ctrlval_array(r, d, true);
        if (!dm) {
                kfree(dc);
                return -ENOMEM;
                if (d->plr)
                        d->plr->d = NULL;
 
-               kfree(hw_dom->ctrl_val);
-               kfree(hw_dom->mbps_val);
+               /* temporary: these four don't have a unique ctrlval array */
+               if (r->rid != RDT_RESOURCE_L3CODE &&
+                   r->rid != RDT_RESOURCE_L3DATA &&
+                   r->rid != RDT_RESOURCE_L2CODE &&
+                   r->rid != RDT_RESOURCE_L2DATA) {
+                       kfree(hw_dom->ctrl_val);
+                       kfree(hw_dom->mbps_val);
+               }
                bitmap_free(d->rmid_busy_llc);
                kfree(d->mbm_total);
                kfree(d->mbm_local);