109e61dafSJames Morse // SPDX-License-Identifier: GPL-2.0 209e61dafSJames Morse // Copyright (C) 2025 Arm Ltd. 309e61dafSJames Morse 409e61dafSJames Morse #define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__ 509e61dafSJames Morse 609e61dafSJames Morse #include <linux/arm_mpam.h> 709e61dafSJames Morse #include <linux/cacheinfo.h> 809e61dafSJames Morse #include <linux/cpu.h> 909e61dafSJames Morse #include <linux/cpumask.h> 1009e61dafSJames Morse #include <linux/errno.h> 1109e61dafSJames Morse #include <linux/list.h> 1209e61dafSJames Morse #include <linux/printk.h> 1309e61dafSJames Morse #include <linux/rculist.h> 1409e61dafSJames Morse #include <linux/resctrl.h> 1509e61dafSJames Morse #include <linux/slab.h> 1609e61dafSJames Morse #include <linux/types.h> 1709e61dafSJames Morse 1809e61dafSJames Morse #include <asm/mpam.h> 1909e61dafSJames Morse 2009e61dafSJames Morse #include "mpam_internal.h" 2109e61dafSJames Morse 2209e61dafSJames Morse /* 2309e61dafSJames Morse * The classes we've picked to map to resctrl resources, wrapped 2409e61dafSJames Morse * in with their resctrl structure. 2509e61dafSJames Morse * Class pointer may be NULL. 2609e61dafSJames Morse */ 2709e61dafSJames Morse static struct mpam_resctrl_res mpam_resctrl_controls[RDT_NUM_RESOURCES]; 2809e61dafSJames Morse 2909e61dafSJames Morse #define for_each_mpam_resctrl_control(res, rid) \ 3009e61dafSJames Morse for (rid = 0, res = &mpam_resctrl_controls[rid]; \ 3109e61dafSJames Morse rid < RDT_NUM_RESOURCES; \ 3209e61dafSJames Morse rid++, res = &mpam_resctrl_controls[rid]) 3309e61dafSJames Morse 3409e61dafSJames Morse /* The lock for modifying resctrl's domain lists from cpuhp callbacks. */ 3509e61dafSJames Morse static DEFINE_MUTEX(domain_list_lock); 3609e61dafSJames Morse 3709e61dafSJames Morse bool resctrl_arch_alloc_capable(void) 3809e61dafSJames Morse { 3909e61dafSJames Morse struct mpam_resctrl_res *res; 4009e61dafSJames Morse enum resctrl_res_level rid; 4109e61dafSJames Morse 4209e61dafSJames Morse for_each_mpam_resctrl_control(res, rid) { 4309e61dafSJames Morse if (res->resctrl_res.alloc_capable) 4409e61dafSJames Morse return true; 4509e61dafSJames Morse } 4609e61dafSJames Morse 4709e61dafSJames Morse return false; 4809e61dafSJames Morse } 4909e61dafSJames Morse 5009e61dafSJames Morse /* 5109e61dafSJames Morse * MSC may raise an error interrupt if it sees an out or range partid/pmg, 5209e61dafSJames Morse * and go on to truncate the value. Regardless of what the hardware supports, 5309e61dafSJames Morse * only the system wide safe value is safe to use. 5409e61dafSJames Morse */ 5509e61dafSJames Morse u32 resctrl_arch_get_num_closid(struct rdt_resource *ignored) 5609e61dafSJames Morse { 5709e61dafSJames Morse return mpam_partid_max + 1; 5809e61dafSJames Morse } 5909e61dafSJames Morse 6009e61dafSJames Morse struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l) 6109e61dafSJames Morse { 6209e61dafSJames Morse if (l >= RDT_NUM_RESOURCES) 6309e61dafSJames Morse return NULL; 6409e61dafSJames Morse 6509e61dafSJames Morse return &mpam_resctrl_controls[l].resctrl_res; 6609e61dafSJames Morse } 6709e61dafSJames Morse 6852a4edb1SJames Morse static bool cache_has_usable_cpor(struct mpam_class *class) 6952a4edb1SJames Morse { 7052a4edb1SJames Morse struct mpam_props *cprops = &class->props; 7152a4edb1SJames Morse 7252a4edb1SJames Morse if (!mpam_has_feature(mpam_feat_cpor_part, cprops)) 7352a4edb1SJames Morse return false; 7452a4edb1SJames Morse 7552a4edb1SJames Morse /* resctrl uses u32 for all bitmap configurations */ 7652a4edb1SJames Morse return class->props.cpbm_wd <= 32; 7752a4edb1SJames Morse } 7852a4edb1SJames Morse 7952a4edb1SJames Morse /* Test whether we can export MPAM_CLASS_CACHE:{2,3}? */ 8052a4edb1SJames Morse static void mpam_resctrl_pick_caches(void) 8152a4edb1SJames Morse { 8252a4edb1SJames Morse struct mpam_class *class; 8352a4edb1SJames Morse struct mpam_resctrl_res *res; 8452a4edb1SJames Morse 8552a4edb1SJames Morse lockdep_assert_cpus_held(); 8652a4edb1SJames Morse 8752a4edb1SJames Morse guard(srcu)(&mpam_srcu); 8852a4edb1SJames Morse list_for_each_entry_srcu(class, &mpam_classes, classes_list, 8952a4edb1SJames Morse srcu_read_lock_held(&mpam_srcu)) { 9052a4edb1SJames Morse if (class->type != MPAM_CLASS_CACHE) { 9152a4edb1SJames Morse pr_debug("class %u is not a cache\n", class->level); 9252a4edb1SJames Morse continue; 9352a4edb1SJames Morse } 9452a4edb1SJames Morse 9552a4edb1SJames Morse if (class->level != 2 && class->level != 3) { 9652a4edb1SJames Morse pr_debug("class %u is not L2 or L3\n", class->level); 9752a4edb1SJames Morse continue; 9852a4edb1SJames Morse } 9952a4edb1SJames Morse 10052a4edb1SJames Morse if (!cache_has_usable_cpor(class)) { 10152a4edb1SJames Morse pr_debug("class %u cache misses CPOR\n", class->level); 10252a4edb1SJames Morse continue; 10352a4edb1SJames Morse } 10452a4edb1SJames Morse 10552a4edb1SJames Morse if (!cpumask_equal(&class->affinity, cpu_possible_mask)) { 10652a4edb1SJames Morse pr_debug("class %u has missing CPUs, mask %*pb != %*pb\n", class->level, 10752a4edb1SJames Morse cpumask_pr_args(&class->affinity), 10852a4edb1SJames Morse cpumask_pr_args(cpu_possible_mask)); 10952a4edb1SJames Morse continue; 11052a4edb1SJames Morse } 11152a4edb1SJames Morse 11252a4edb1SJames Morse if (class->level == 2) 11352a4edb1SJames Morse res = &mpam_resctrl_controls[RDT_RESOURCE_L2]; 11452a4edb1SJames Morse else 11552a4edb1SJames Morse res = &mpam_resctrl_controls[RDT_RESOURCE_L3]; 11652a4edb1SJames Morse res->class = class; 11752a4edb1SJames Morse } 11852a4edb1SJames Morse } 11952a4edb1SJames Morse 12009e61dafSJames Morse static int mpam_resctrl_control_init(struct mpam_resctrl_res *res) 12109e61dafSJames Morse { 12252a4edb1SJames Morse struct mpam_class *class = res->class; 12352a4edb1SJames Morse struct rdt_resource *r = &res->resctrl_res; 12452a4edb1SJames Morse 12552a4edb1SJames Morse switch (r->rid) { 12652a4edb1SJames Morse case RDT_RESOURCE_L2: 12752a4edb1SJames Morse case RDT_RESOURCE_L3: 12852a4edb1SJames Morse r->schema_fmt = RESCTRL_SCHEMA_BITMAP; 12952a4edb1SJames Morse r->cache.arch_has_sparse_bitmasks = true; 13052a4edb1SJames Morse 13152a4edb1SJames Morse r->cache.cbm_len = class->props.cpbm_wd; 13252a4edb1SJames Morse /* mpam_devices will reject empty bitmaps */ 13352a4edb1SJames Morse r->cache.min_cbm_bits = 1; 13452a4edb1SJames Morse 13552a4edb1SJames Morse if (r->rid == RDT_RESOURCE_L2) { 13652a4edb1SJames Morse r->name = "L2"; 13752a4edb1SJames Morse r->ctrl_scope = RESCTRL_L2_CACHE; 13852a4edb1SJames Morse r->cdp_capable = true; 13952a4edb1SJames Morse } else { 14052a4edb1SJames Morse r->name = "L3"; 14152a4edb1SJames Morse r->ctrl_scope = RESCTRL_L3_CACHE; 14252a4edb1SJames Morse r->cdp_capable = true; 14352a4edb1SJames Morse } 14452a4edb1SJames Morse 14552a4edb1SJames Morse /* 14652a4edb1SJames Morse * Which bits are shared with other ...things... Unknown 14752a4edb1SJames Morse * devices use partid-0 which uses all the bitmap fields. Until 14852a4edb1SJames Morse * we have configured the SMMU and GIC not to do this 'all the 14952a4edb1SJames Morse * bits' is the correct answer here. 15052a4edb1SJames Morse */ 15152a4edb1SJames Morse r->cache.shareable_bits = resctrl_get_default_ctrl(r); 15252a4edb1SJames Morse r->alloc_capable = true; 15352a4edb1SJames Morse break; 15452a4edb1SJames Morse default: 15552a4edb1SJames Morse return -EINVAL; 15652a4edb1SJames Morse } 15709e61dafSJames Morse 15809e61dafSJames Morse return 0; 15909e61dafSJames Morse } 16009e61dafSJames Morse 16109e61dafSJames Morse static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp) 16209e61dafSJames Morse { 16309e61dafSJames Morse struct mpam_class *class = comp->class; 16409e61dafSJames Morse 16509e61dafSJames Morse if (class->type == MPAM_CLASS_CACHE) 16609e61dafSJames Morse return comp->comp_id; 16709e61dafSJames Morse 16809e61dafSJames Morse /* TODO: repaint domain ids to match the L3 domain ids */ 16909e61dafSJames Morse /* Otherwise, expose the ID used by the firmware table code. */ 17009e61dafSJames Morse return comp->comp_id; 17109e61dafSJames Morse } 17209e61dafSJames Morse 173*02cc6616SJames Morse u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d, 174*02cc6616SJames Morse u32 closid, enum resctrl_conf_type type) 175*02cc6616SJames Morse { 176*02cc6616SJames Morse u32 partid; 177*02cc6616SJames Morse struct mpam_config *cfg; 178*02cc6616SJames Morse struct mpam_props *cprops; 179*02cc6616SJames Morse struct mpam_resctrl_res *res; 180*02cc6616SJames Morse struct mpam_resctrl_dom *dom; 181*02cc6616SJames Morse enum mpam_device_features configured_by; 182*02cc6616SJames Morse 183*02cc6616SJames Morse lockdep_assert_cpus_held(); 184*02cc6616SJames Morse 185*02cc6616SJames Morse if (!mpam_is_enabled()) 186*02cc6616SJames Morse return resctrl_get_default_ctrl(r); 187*02cc6616SJames Morse 188*02cc6616SJames Morse res = container_of(r, struct mpam_resctrl_res, resctrl_res); 189*02cc6616SJames Morse dom = container_of(d, struct mpam_resctrl_dom, resctrl_ctrl_dom); 190*02cc6616SJames Morse cprops = &res->class->props; 191*02cc6616SJames Morse 192*02cc6616SJames Morse partid = resctrl_get_config_index(closid, type); 193*02cc6616SJames Morse cfg = &dom->ctrl_comp->cfg[partid]; 194*02cc6616SJames Morse 195*02cc6616SJames Morse switch (r->rid) { 196*02cc6616SJames Morse case RDT_RESOURCE_L2: 197*02cc6616SJames Morse case RDT_RESOURCE_L3: 198*02cc6616SJames Morse configured_by = mpam_feat_cpor_part; 199*02cc6616SJames Morse break; 200*02cc6616SJames Morse default: 201*02cc6616SJames Morse return resctrl_get_default_ctrl(r); 202*02cc6616SJames Morse } 203*02cc6616SJames Morse 204*02cc6616SJames Morse if (!r->alloc_capable || partid >= resctrl_arch_get_num_closid(r) || 205*02cc6616SJames Morse !mpam_has_feature(configured_by, cfg)) 206*02cc6616SJames Morse return resctrl_get_default_ctrl(r); 207*02cc6616SJames Morse 208*02cc6616SJames Morse switch (configured_by) { 209*02cc6616SJames Morse case mpam_feat_cpor_part: 210*02cc6616SJames Morse return cfg->cpbm; 211*02cc6616SJames Morse default: 212*02cc6616SJames Morse return resctrl_get_default_ctrl(r); 213*02cc6616SJames Morse } 214*02cc6616SJames Morse } 215*02cc6616SJames Morse 216370d166dSJames Morse void resctrl_arch_reset_all_ctrls(struct rdt_resource *r) 217370d166dSJames Morse { 218370d166dSJames Morse struct mpam_resctrl_res *res; 219370d166dSJames Morse 220370d166dSJames Morse lockdep_assert_cpus_held(); 221370d166dSJames Morse 222370d166dSJames Morse if (!mpam_is_enabled()) 223370d166dSJames Morse return; 224370d166dSJames Morse 225370d166dSJames Morse res = container_of(r, struct mpam_resctrl_res, resctrl_res); 226370d166dSJames Morse mpam_reset_class_locked(res->class); 227370d166dSJames Morse } 228370d166dSJames Morse 22909e61dafSJames Morse static void mpam_resctrl_domain_hdr_init(int cpu, struct mpam_component *comp, 23009e61dafSJames Morse enum resctrl_res_level rid, 23109e61dafSJames Morse struct rdt_domain_hdr *hdr) 23209e61dafSJames Morse { 23309e61dafSJames Morse lockdep_assert_cpus_held(); 23409e61dafSJames Morse 23509e61dafSJames Morse INIT_LIST_HEAD(&hdr->list); 23609e61dafSJames Morse hdr->id = mpam_resctrl_pick_domain_id(cpu, comp); 23709e61dafSJames Morse hdr->rid = rid; 23809e61dafSJames Morse cpumask_set_cpu(cpu, &hdr->cpu_mask); 23909e61dafSJames Morse } 24009e61dafSJames Morse 24109e61dafSJames Morse static void mpam_resctrl_online_domain_hdr(unsigned int cpu, 24209e61dafSJames Morse struct rdt_domain_hdr *hdr) 24309e61dafSJames Morse { 24409e61dafSJames Morse lockdep_assert_cpus_held(); 24509e61dafSJames Morse 24609e61dafSJames Morse cpumask_set_cpu(cpu, &hdr->cpu_mask); 24709e61dafSJames Morse } 24809e61dafSJames Morse 24909e61dafSJames Morse /** 25009e61dafSJames Morse * mpam_resctrl_offline_domain_hdr() - Update the domain header to remove a CPU. 25109e61dafSJames Morse * @cpu: The CPU to remove from the domain. 25209e61dafSJames Morse * @hdr: The domain's header. 25309e61dafSJames Morse * 25409e61dafSJames Morse * Removes @cpu from the header mask. If this was the last CPU in the domain, 25509e61dafSJames Morse * the domain header is removed from its parent list and true is returned, 25609e61dafSJames Morse * indicating the parent structure can be freed. 25709e61dafSJames Morse * If there are other CPUs in the domain, returns false. 25809e61dafSJames Morse */ 25909e61dafSJames Morse static bool mpam_resctrl_offline_domain_hdr(unsigned int cpu, 26009e61dafSJames Morse struct rdt_domain_hdr *hdr) 26109e61dafSJames Morse { 26209e61dafSJames Morse lockdep_assert_held(&domain_list_lock); 26309e61dafSJames Morse 26409e61dafSJames Morse cpumask_clear_cpu(cpu, &hdr->cpu_mask); 26509e61dafSJames Morse if (cpumask_empty(&hdr->cpu_mask)) { 26609e61dafSJames Morse list_del_rcu(&hdr->list); 26709e61dafSJames Morse synchronize_rcu(); 26809e61dafSJames Morse return true; 26909e61dafSJames Morse } 27009e61dafSJames Morse 27109e61dafSJames Morse return false; 27209e61dafSJames Morse } 27309e61dafSJames Morse 27409e61dafSJames Morse static void mpam_resctrl_domain_insert(struct list_head *list, 27509e61dafSJames Morse struct rdt_domain_hdr *new) 27609e61dafSJames Morse { 27709e61dafSJames Morse struct rdt_domain_hdr *err; 27809e61dafSJames Morse struct list_head *pos = NULL; 27909e61dafSJames Morse 28009e61dafSJames Morse lockdep_assert_held(&domain_list_lock); 28109e61dafSJames Morse 28209e61dafSJames Morse err = resctrl_find_domain(list, new->id, &pos); 28309e61dafSJames Morse if (WARN_ON_ONCE(err)) 28409e61dafSJames Morse return; 28509e61dafSJames Morse 28609e61dafSJames Morse list_add_tail_rcu(&new->list, pos); 28709e61dafSJames Morse } 28809e61dafSJames Morse 28909e61dafSJames Morse static struct mpam_resctrl_dom * 29009e61dafSJames Morse mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res) 29109e61dafSJames Morse { 29209e61dafSJames Morse int err; 29309e61dafSJames Morse struct mpam_resctrl_dom *dom; 29409e61dafSJames Morse struct rdt_ctrl_domain *ctrl_d; 29509e61dafSJames Morse struct mpam_class *class = res->class; 29609e61dafSJames Morse struct mpam_component *comp_iter, *ctrl_comp; 29709e61dafSJames Morse struct rdt_resource *r = &res->resctrl_res; 29809e61dafSJames Morse 29909e61dafSJames Morse lockdep_assert_held(&domain_list_lock); 30009e61dafSJames Morse 30109e61dafSJames Morse ctrl_comp = NULL; 30209e61dafSJames Morse guard(srcu)(&mpam_srcu); 30309e61dafSJames Morse list_for_each_entry_srcu(comp_iter, &class->components, class_list, 30409e61dafSJames Morse srcu_read_lock_held(&mpam_srcu)) { 30509e61dafSJames Morse if (cpumask_test_cpu(cpu, &comp_iter->affinity)) { 30609e61dafSJames Morse ctrl_comp = comp_iter; 30709e61dafSJames Morse break; 30809e61dafSJames Morse } 30909e61dafSJames Morse } 31009e61dafSJames Morse 31109e61dafSJames Morse /* class has no component for this CPU */ 31209e61dafSJames Morse if (WARN_ON_ONCE(!ctrl_comp)) 31309e61dafSJames Morse return ERR_PTR(-EINVAL); 31409e61dafSJames Morse 31509e61dafSJames Morse dom = kzalloc_node(sizeof(*dom), GFP_KERNEL, cpu_to_node(cpu)); 31609e61dafSJames Morse if (!dom) 31709e61dafSJames Morse return ERR_PTR(-ENOMEM); 31809e61dafSJames Morse 31909e61dafSJames Morse if (r->alloc_capable) { 32009e61dafSJames Morse dom->ctrl_comp = ctrl_comp; 32109e61dafSJames Morse 32209e61dafSJames Morse ctrl_d = &dom->resctrl_ctrl_dom; 32309e61dafSJames Morse mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, r->rid, &ctrl_d->hdr); 32409e61dafSJames Morse ctrl_d->hdr.type = RESCTRL_CTRL_DOMAIN; 32509e61dafSJames Morse err = resctrl_online_ctrl_domain(r, ctrl_d); 32609e61dafSJames Morse if (err) 32709e61dafSJames Morse goto free_domain; 32809e61dafSJames Morse 32909e61dafSJames Morse mpam_resctrl_domain_insert(&r->ctrl_domains, &ctrl_d->hdr); 33009e61dafSJames Morse } else { 33109e61dafSJames Morse pr_debug("Skipped control domain online - no controls\n"); 33209e61dafSJames Morse } 33309e61dafSJames Morse return dom; 33409e61dafSJames Morse 33509e61dafSJames Morse free_domain: 33609e61dafSJames Morse kfree(dom); 33709e61dafSJames Morse dom = ERR_PTR(err); 33809e61dafSJames Morse 33909e61dafSJames Morse return dom; 34009e61dafSJames Morse } 34109e61dafSJames Morse 34209e61dafSJames Morse static struct mpam_resctrl_dom * 34309e61dafSJames Morse mpam_resctrl_get_domain_from_cpu(int cpu, struct mpam_resctrl_res *res) 34409e61dafSJames Morse { 34509e61dafSJames Morse struct mpam_resctrl_dom *dom; 34609e61dafSJames Morse struct rdt_resource *r = &res->resctrl_res; 34709e61dafSJames Morse 34809e61dafSJames Morse lockdep_assert_cpus_held(); 34909e61dafSJames Morse 35009e61dafSJames Morse list_for_each_entry_rcu(dom, &r->ctrl_domains, resctrl_ctrl_dom.hdr.list) { 35109e61dafSJames Morse if (cpumask_test_cpu(cpu, &dom->ctrl_comp->affinity)) 35209e61dafSJames Morse return dom; 35309e61dafSJames Morse } 35409e61dafSJames Morse 35509e61dafSJames Morse return NULL; 35609e61dafSJames Morse } 35709e61dafSJames Morse 35809e61dafSJames Morse int mpam_resctrl_online_cpu(unsigned int cpu) 35909e61dafSJames Morse { 36009e61dafSJames Morse struct mpam_resctrl_res *res; 36109e61dafSJames Morse enum resctrl_res_level rid; 36209e61dafSJames Morse 36309e61dafSJames Morse guard(mutex)(&domain_list_lock); 36409e61dafSJames Morse for_each_mpam_resctrl_control(res, rid) { 36509e61dafSJames Morse struct mpam_resctrl_dom *dom; 36609e61dafSJames Morse struct rdt_resource *r = &res->resctrl_res; 36709e61dafSJames Morse 36809e61dafSJames Morse if (!res->class) 36909e61dafSJames Morse continue; // dummy_resource; 37009e61dafSJames Morse 37109e61dafSJames Morse dom = mpam_resctrl_get_domain_from_cpu(cpu, res); 37209e61dafSJames Morse if (!dom) { 37309e61dafSJames Morse dom = mpam_resctrl_alloc_domain(cpu, res); 37409e61dafSJames Morse if (IS_ERR(dom)) 37509e61dafSJames Morse return PTR_ERR(dom); 37609e61dafSJames Morse } else { 37709e61dafSJames Morse if (r->alloc_capable) { 37809e61dafSJames Morse struct rdt_ctrl_domain *ctrl_d = &dom->resctrl_ctrl_dom; 37909e61dafSJames Morse 38009e61dafSJames Morse mpam_resctrl_online_domain_hdr(cpu, &ctrl_d->hdr); 38109e61dafSJames Morse } 38209e61dafSJames Morse } 38309e61dafSJames Morse } 38409e61dafSJames Morse 38509e61dafSJames Morse resctrl_online_cpu(cpu); 38609e61dafSJames Morse 38709e61dafSJames Morse return 0; 38809e61dafSJames Morse } 38909e61dafSJames Morse 39009e61dafSJames Morse void mpam_resctrl_offline_cpu(unsigned int cpu) 39109e61dafSJames Morse { 39209e61dafSJames Morse struct mpam_resctrl_res *res; 39309e61dafSJames Morse enum resctrl_res_level rid; 39409e61dafSJames Morse 39509e61dafSJames Morse resctrl_offline_cpu(cpu); 39609e61dafSJames Morse 39709e61dafSJames Morse guard(mutex)(&domain_list_lock); 39809e61dafSJames Morse for_each_mpam_resctrl_control(res, rid) { 39909e61dafSJames Morse struct mpam_resctrl_dom *dom; 40009e61dafSJames Morse struct rdt_ctrl_domain *ctrl_d; 40109e61dafSJames Morse bool ctrl_dom_empty; 40209e61dafSJames Morse struct rdt_resource *r = &res->resctrl_res; 40309e61dafSJames Morse 40409e61dafSJames Morse if (!res->class) 40509e61dafSJames Morse continue; // dummy resource 40609e61dafSJames Morse 40709e61dafSJames Morse dom = mpam_resctrl_get_domain_from_cpu(cpu, res); 40809e61dafSJames Morse if (WARN_ON_ONCE(!dom)) 40909e61dafSJames Morse continue; 41009e61dafSJames Morse 41109e61dafSJames Morse if (r->alloc_capable) { 41209e61dafSJames Morse ctrl_d = &dom->resctrl_ctrl_dom; 41309e61dafSJames Morse ctrl_dom_empty = mpam_resctrl_offline_domain_hdr(cpu, &ctrl_d->hdr); 41409e61dafSJames Morse if (ctrl_dom_empty) 41509e61dafSJames Morse resctrl_offline_ctrl_domain(&res->resctrl_res, ctrl_d); 41609e61dafSJames Morse } else { 41709e61dafSJames Morse ctrl_dom_empty = true; 41809e61dafSJames Morse } 41909e61dafSJames Morse 42009e61dafSJames Morse if (ctrl_dom_empty) 42109e61dafSJames Morse kfree(dom); 42209e61dafSJames Morse } 42309e61dafSJames Morse } 42409e61dafSJames Morse 42509e61dafSJames Morse int mpam_resctrl_setup(void) 42609e61dafSJames Morse { 42709e61dafSJames Morse int err = 0; 42809e61dafSJames Morse struct mpam_resctrl_res *res; 42909e61dafSJames Morse enum resctrl_res_level rid; 43009e61dafSJames Morse 43109e61dafSJames Morse cpus_read_lock(); 43209e61dafSJames Morse for_each_mpam_resctrl_control(res, rid) { 43309e61dafSJames Morse INIT_LIST_HEAD_RCU(&res->resctrl_res.ctrl_domains); 43409e61dafSJames Morse res->resctrl_res.rid = rid; 43509e61dafSJames Morse } 43609e61dafSJames Morse 43752a4edb1SJames Morse /* Find some classes to use for controls */ 43852a4edb1SJames Morse mpam_resctrl_pick_caches(); 43909e61dafSJames Morse 44009e61dafSJames Morse /* Initialise the resctrl structures from the classes */ 44109e61dafSJames Morse for_each_mpam_resctrl_control(res, rid) { 44209e61dafSJames Morse if (!res->class) 44309e61dafSJames Morse continue; // dummy resource 44409e61dafSJames Morse 44509e61dafSJames Morse err = mpam_resctrl_control_init(res); 44609e61dafSJames Morse if (err) { 44709e61dafSJames Morse pr_debug("Failed to initialise rid %u\n", rid); 44809e61dafSJames Morse break; 44909e61dafSJames Morse } 45009e61dafSJames Morse } 45109e61dafSJames Morse cpus_read_unlock(); 45209e61dafSJames Morse 45309e61dafSJames Morse if (err) { 45409e61dafSJames Morse pr_debug("Internal error %d - resctrl not supported\n", err); 45509e61dafSJames Morse return err; 45609e61dafSJames Morse } 45709e61dafSJames Morse 45809e61dafSJames Morse if (!resctrl_arch_alloc_capable()) { 45909e61dafSJames Morse pr_debug("No alloc(%u) found - resctrl not supported\n", 46009e61dafSJames Morse resctrl_arch_alloc_capable()); 46109e61dafSJames Morse return -EOPNOTSUPP; 46209e61dafSJames Morse } 46309e61dafSJames Morse 46409e61dafSJames Morse /* TODO: call resctrl_init() */ 46509e61dafSJames Morse 46609e61dafSJames Morse return 0; 46709e61dafSJames Morse } 468