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 17302cc6616SJames Morse u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d, 17402cc6616SJames Morse u32 closid, enum resctrl_conf_type type) 17502cc6616SJames Morse { 17602cc6616SJames Morse u32 partid; 17702cc6616SJames Morse struct mpam_config *cfg; 17802cc6616SJames Morse struct mpam_props *cprops; 17902cc6616SJames Morse struct mpam_resctrl_res *res; 18002cc6616SJames Morse struct mpam_resctrl_dom *dom; 18102cc6616SJames Morse enum mpam_device_features configured_by; 18202cc6616SJames Morse 18302cc6616SJames Morse lockdep_assert_cpus_held(); 18402cc6616SJames Morse 18502cc6616SJames Morse if (!mpam_is_enabled()) 18602cc6616SJames Morse return resctrl_get_default_ctrl(r); 18702cc6616SJames Morse 18802cc6616SJames Morse res = container_of(r, struct mpam_resctrl_res, resctrl_res); 18902cc6616SJames Morse dom = container_of(d, struct mpam_resctrl_dom, resctrl_ctrl_dom); 19002cc6616SJames Morse cprops = &res->class->props; 19102cc6616SJames Morse 19202cc6616SJames Morse partid = resctrl_get_config_index(closid, type); 19302cc6616SJames Morse cfg = &dom->ctrl_comp->cfg[partid]; 19402cc6616SJames Morse 19502cc6616SJames Morse switch (r->rid) { 19602cc6616SJames Morse case RDT_RESOURCE_L2: 19702cc6616SJames Morse case RDT_RESOURCE_L3: 19802cc6616SJames Morse configured_by = mpam_feat_cpor_part; 19902cc6616SJames Morse break; 20002cc6616SJames Morse default: 20102cc6616SJames Morse return resctrl_get_default_ctrl(r); 20202cc6616SJames Morse } 20302cc6616SJames Morse 20402cc6616SJames Morse if (!r->alloc_capable || partid >= resctrl_arch_get_num_closid(r) || 20502cc6616SJames Morse !mpam_has_feature(configured_by, cfg)) 20602cc6616SJames Morse return resctrl_get_default_ctrl(r); 20702cc6616SJames Morse 20802cc6616SJames Morse switch (configured_by) { 20902cc6616SJames Morse case mpam_feat_cpor_part: 21002cc6616SJames Morse return cfg->cpbm; 21102cc6616SJames Morse default: 21202cc6616SJames Morse return resctrl_get_default_ctrl(r); 21302cc6616SJames Morse } 21402cc6616SJames Morse } 21502cc6616SJames Morse 216*9cd2b522SJames Morse int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d, 217*9cd2b522SJames Morse u32 closid, enum resctrl_conf_type t, u32 cfg_val) 218*9cd2b522SJames Morse { 219*9cd2b522SJames Morse u32 partid; 220*9cd2b522SJames Morse struct mpam_config cfg; 221*9cd2b522SJames Morse struct mpam_props *cprops; 222*9cd2b522SJames Morse struct mpam_resctrl_res *res; 223*9cd2b522SJames Morse struct mpam_resctrl_dom *dom; 224*9cd2b522SJames Morse 225*9cd2b522SJames Morse lockdep_assert_cpus_held(); 226*9cd2b522SJames Morse lockdep_assert_irqs_enabled(); 227*9cd2b522SJames Morse 228*9cd2b522SJames Morse /* 229*9cd2b522SJames Morse * No need to check the CPU as mpam_apply_config() doesn't care, and 230*9cd2b522SJames Morse * resctrl_arch_update_domains() relies on this. 231*9cd2b522SJames Morse */ 232*9cd2b522SJames Morse res = container_of(r, struct mpam_resctrl_res, resctrl_res); 233*9cd2b522SJames Morse dom = container_of(d, struct mpam_resctrl_dom, resctrl_ctrl_dom); 234*9cd2b522SJames Morse cprops = &res->class->props; 235*9cd2b522SJames Morse 236*9cd2b522SJames Morse partid = resctrl_get_config_index(closid, t); 237*9cd2b522SJames Morse if (!r->alloc_capable || partid >= resctrl_arch_get_num_closid(r)) { 238*9cd2b522SJames Morse pr_debug("Not alloc capable or computed PARTID out of range\n"); 239*9cd2b522SJames Morse return -EINVAL; 240*9cd2b522SJames Morse } 241*9cd2b522SJames Morse 242*9cd2b522SJames Morse /* 243*9cd2b522SJames Morse * Copy the current config to avoid clearing other resources when the 244*9cd2b522SJames Morse * same component is exposed multiple times through resctrl. 245*9cd2b522SJames Morse */ 246*9cd2b522SJames Morse cfg = dom->ctrl_comp->cfg[partid]; 247*9cd2b522SJames Morse 248*9cd2b522SJames Morse switch (r->rid) { 249*9cd2b522SJames Morse case RDT_RESOURCE_L2: 250*9cd2b522SJames Morse case RDT_RESOURCE_L3: 251*9cd2b522SJames Morse cfg.cpbm = cfg_val; 252*9cd2b522SJames Morse mpam_set_feature(mpam_feat_cpor_part, &cfg); 253*9cd2b522SJames Morse break; 254*9cd2b522SJames Morse default: 255*9cd2b522SJames Morse return -EINVAL; 256*9cd2b522SJames Morse } 257*9cd2b522SJames Morse 258*9cd2b522SJames Morse return mpam_apply_config(dom->ctrl_comp, partid, &cfg); 259*9cd2b522SJames Morse } 260*9cd2b522SJames Morse 261*9cd2b522SJames Morse int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid) 262*9cd2b522SJames Morse { 263*9cd2b522SJames Morse int err; 264*9cd2b522SJames Morse struct rdt_ctrl_domain *d; 265*9cd2b522SJames Morse 266*9cd2b522SJames Morse lockdep_assert_cpus_held(); 267*9cd2b522SJames Morse lockdep_assert_irqs_enabled(); 268*9cd2b522SJames Morse 269*9cd2b522SJames Morse list_for_each_entry_rcu(d, &r->ctrl_domains, hdr.list) { 270*9cd2b522SJames Morse for (enum resctrl_conf_type t = 0; t < CDP_NUM_TYPES; t++) { 271*9cd2b522SJames Morse struct resctrl_staged_config *cfg = &d->staged_config[t]; 272*9cd2b522SJames Morse 273*9cd2b522SJames Morse if (!cfg->have_new_ctrl) 274*9cd2b522SJames Morse continue; 275*9cd2b522SJames Morse 276*9cd2b522SJames Morse err = resctrl_arch_update_one(r, d, closid, t, 277*9cd2b522SJames Morse cfg->new_ctrl); 278*9cd2b522SJames Morse if (err) 279*9cd2b522SJames Morse return err; 280*9cd2b522SJames Morse } 281*9cd2b522SJames Morse } 282*9cd2b522SJames Morse 283*9cd2b522SJames Morse return 0; 284*9cd2b522SJames Morse } 285*9cd2b522SJames Morse 286370d166dSJames Morse void resctrl_arch_reset_all_ctrls(struct rdt_resource *r) 287370d166dSJames Morse { 288370d166dSJames Morse struct mpam_resctrl_res *res; 289370d166dSJames Morse 290370d166dSJames Morse lockdep_assert_cpus_held(); 291370d166dSJames Morse 292370d166dSJames Morse if (!mpam_is_enabled()) 293370d166dSJames Morse return; 294370d166dSJames Morse 295370d166dSJames Morse res = container_of(r, struct mpam_resctrl_res, resctrl_res); 296370d166dSJames Morse mpam_reset_class_locked(res->class); 297370d166dSJames Morse } 298370d166dSJames Morse 29909e61dafSJames Morse static void mpam_resctrl_domain_hdr_init(int cpu, struct mpam_component *comp, 30009e61dafSJames Morse enum resctrl_res_level rid, 30109e61dafSJames Morse struct rdt_domain_hdr *hdr) 30209e61dafSJames Morse { 30309e61dafSJames Morse lockdep_assert_cpus_held(); 30409e61dafSJames Morse 30509e61dafSJames Morse INIT_LIST_HEAD(&hdr->list); 30609e61dafSJames Morse hdr->id = mpam_resctrl_pick_domain_id(cpu, comp); 30709e61dafSJames Morse hdr->rid = rid; 30809e61dafSJames Morse cpumask_set_cpu(cpu, &hdr->cpu_mask); 30909e61dafSJames Morse } 31009e61dafSJames Morse 31109e61dafSJames Morse static void mpam_resctrl_online_domain_hdr(unsigned int cpu, 31209e61dafSJames Morse struct rdt_domain_hdr *hdr) 31309e61dafSJames Morse { 31409e61dafSJames Morse lockdep_assert_cpus_held(); 31509e61dafSJames Morse 31609e61dafSJames Morse cpumask_set_cpu(cpu, &hdr->cpu_mask); 31709e61dafSJames Morse } 31809e61dafSJames Morse 31909e61dafSJames Morse /** 32009e61dafSJames Morse * mpam_resctrl_offline_domain_hdr() - Update the domain header to remove a CPU. 32109e61dafSJames Morse * @cpu: The CPU to remove from the domain. 32209e61dafSJames Morse * @hdr: The domain's header. 32309e61dafSJames Morse * 32409e61dafSJames Morse * Removes @cpu from the header mask. If this was the last CPU in the domain, 32509e61dafSJames Morse * the domain header is removed from its parent list and true is returned, 32609e61dafSJames Morse * indicating the parent structure can be freed. 32709e61dafSJames Morse * If there are other CPUs in the domain, returns false. 32809e61dafSJames Morse */ 32909e61dafSJames Morse static bool mpam_resctrl_offline_domain_hdr(unsigned int cpu, 33009e61dafSJames Morse struct rdt_domain_hdr *hdr) 33109e61dafSJames Morse { 33209e61dafSJames Morse lockdep_assert_held(&domain_list_lock); 33309e61dafSJames Morse 33409e61dafSJames Morse cpumask_clear_cpu(cpu, &hdr->cpu_mask); 33509e61dafSJames Morse if (cpumask_empty(&hdr->cpu_mask)) { 33609e61dafSJames Morse list_del_rcu(&hdr->list); 33709e61dafSJames Morse synchronize_rcu(); 33809e61dafSJames Morse return true; 33909e61dafSJames Morse } 34009e61dafSJames Morse 34109e61dafSJames Morse return false; 34209e61dafSJames Morse } 34309e61dafSJames Morse 34409e61dafSJames Morse static void mpam_resctrl_domain_insert(struct list_head *list, 34509e61dafSJames Morse struct rdt_domain_hdr *new) 34609e61dafSJames Morse { 34709e61dafSJames Morse struct rdt_domain_hdr *err; 34809e61dafSJames Morse struct list_head *pos = NULL; 34909e61dafSJames Morse 35009e61dafSJames Morse lockdep_assert_held(&domain_list_lock); 35109e61dafSJames Morse 35209e61dafSJames Morse err = resctrl_find_domain(list, new->id, &pos); 35309e61dafSJames Morse if (WARN_ON_ONCE(err)) 35409e61dafSJames Morse return; 35509e61dafSJames Morse 35609e61dafSJames Morse list_add_tail_rcu(&new->list, pos); 35709e61dafSJames Morse } 35809e61dafSJames Morse 35909e61dafSJames Morse static struct mpam_resctrl_dom * 36009e61dafSJames Morse mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res) 36109e61dafSJames Morse { 36209e61dafSJames Morse int err; 36309e61dafSJames Morse struct mpam_resctrl_dom *dom; 36409e61dafSJames Morse struct rdt_ctrl_domain *ctrl_d; 36509e61dafSJames Morse struct mpam_class *class = res->class; 36609e61dafSJames Morse struct mpam_component *comp_iter, *ctrl_comp; 36709e61dafSJames Morse struct rdt_resource *r = &res->resctrl_res; 36809e61dafSJames Morse 36909e61dafSJames Morse lockdep_assert_held(&domain_list_lock); 37009e61dafSJames Morse 37109e61dafSJames Morse ctrl_comp = NULL; 37209e61dafSJames Morse guard(srcu)(&mpam_srcu); 37309e61dafSJames Morse list_for_each_entry_srcu(comp_iter, &class->components, class_list, 37409e61dafSJames Morse srcu_read_lock_held(&mpam_srcu)) { 37509e61dafSJames Morse if (cpumask_test_cpu(cpu, &comp_iter->affinity)) { 37609e61dafSJames Morse ctrl_comp = comp_iter; 37709e61dafSJames Morse break; 37809e61dafSJames Morse } 37909e61dafSJames Morse } 38009e61dafSJames Morse 38109e61dafSJames Morse /* class has no component for this CPU */ 38209e61dafSJames Morse if (WARN_ON_ONCE(!ctrl_comp)) 38309e61dafSJames Morse return ERR_PTR(-EINVAL); 38409e61dafSJames Morse 38509e61dafSJames Morse dom = kzalloc_node(sizeof(*dom), GFP_KERNEL, cpu_to_node(cpu)); 38609e61dafSJames Morse if (!dom) 38709e61dafSJames Morse return ERR_PTR(-ENOMEM); 38809e61dafSJames Morse 38909e61dafSJames Morse if (r->alloc_capable) { 39009e61dafSJames Morse dom->ctrl_comp = ctrl_comp; 39109e61dafSJames Morse 39209e61dafSJames Morse ctrl_d = &dom->resctrl_ctrl_dom; 39309e61dafSJames Morse mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, r->rid, &ctrl_d->hdr); 39409e61dafSJames Morse ctrl_d->hdr.type = RESCTRL_CTRL_DOMAIN; 39509e61dafSJames Morse err = resctrl_online_ctrl_domain(r, ctrl_d); 39609e61dafSJames Morse if (err) 39709e61dafSJames Morse goto free_domain; 39809e61dafSJames Morse 39909e61dafSJames Morse mpam_resctrl_domain_insert(&r->ctrl_domains, &ctrl_d->hdr); 40009e61dafSJames Morse } else { 40109e61dafSJames Morse pr_debug("Skipped control domain online - no controls\n"); 40209e61dafSJames Morse } 40309e61dafSJames Morse return dom; 40409e61dafSJames Morse 40509e61dafSJames Morse free_domain: 40609e61dafSJames Morse kfree(dom); 40709e61dafSJames Morse dom = ERR_PTR(err); 40809e61dafSJames Morse 40909e61dafSJames Morse return dom; 41009e61dafSJames Morse } 41109e61dafSJames Morse 41209e61dafSJames Morse static struct mpam_resctrl_dom * 41309e61dafSJames Morse mpam_resctrl_get_domain_from_cpu(int cpu, struct mpam_resctrl_res *res) 41409e61dafSJames Morse { 41509e61dafSJames Morse struct mpam_resctrl_dom *dom; 41609e61dafSJames Morse struct rdt_resource *r = &res->resctrl_res; 41709e61dafSJames Morse 41809e61dafSJames Morse lockdep_assert_cpus_held(); 41909e61dafSJames Morse 42009e61dafSJames Morse list_for_each_entry_rcu(dom, &r->ctrl_domains, resctrl_ctrl_dom.hdr.list) { 42109e61dafSJames Morse if (cpumask_test_cpu(cpu, &dom->ctrl_comp->affinity)) 42209e61dafSJames Morse return dom; 42309e61dafSJames Morse } 42409e61dafSJames Morse 42509e61dafSJames Morse return NULL; 42609e61dafSJames Morse } 42709e61dafSJames Morse 42809e61dafSJames Morse int mpam_resctrl_online_cpu(unsigned int cpu) 42909e61dafSJames Morse { 43009e61dafSJames Morse struct mpam_resctrl_res *res; 43109e61dafSJames Morse enum resctrl_res_level rid; 43209e61dafSJames Morse 43309e61dafSJames Morse guard(mutex)(&domain_list_lock); 43409e61dafSJames Morse for_each_mpam_resctrl_control(res, rid) { 43509e61dafSJames Morse struct mpam_resctrl_dom *dom; 43609e61dafSJames Morse struct rdt_resource *r = &res->resctrl_res; 43709e61dafSJames Morse 43809e61dafSJames Morse if (!res->class) 43909e61dafSJames Morse continue; // dummy_resource; 44009e61dafSJames Morse 44109e61dafSJames Morse dom = mpam_resctrl_get_domain_from_cpu(cpu, res); 44209e61dafSJames Morse if (!dom) { 44309e61dafSJames Morse dom = mpam_resctrl_alloc_domain(cpu, res); 44409e61dafSJames Morse if (IS_ERR(dom)) 44509e61dafSJames Morse return PTR_ERR(dom); 44609e61dafSJames Morse } else { 44709e61dafSJames Morse if (r->alloc_capable) { 44809e61dafSJames Morse struct rdt_ctrl_domain *ctrl_d = &dom->resctrl_ctrl_dom; 44909e61dafSJames Morse 45009e61dafSJames Morse mpam_resctrl_online_domain_hdr(cpu, &ctrl_d->hdr); 45109e61dafSJames Morse } 45209e61dafSJames Morse } 45309e61dafSJames Morse } 45409e61dafSJames Morse 45509e61dafSJames Morse resctrl_online_cpu(cpu); 45609e61dafSJames Morse 45709e61dafSJames Morse return 0; 45809e61dafSJames Morse } 45909e61dafSJames Morse 46009e61dafSJames Morse void mpam_resctrl_offline_cpu(unsigned int cpu) 46109e61dafSJames Morse { 46209e61dafSJames Morse struct mpam_resctrl_res *res; 46309e61dafSJames Morse enum resctrl_res_level rid; 46409e61dafSJames Morse 46509e61dafSJames Morse resctrl_offline_cpu(cpu); 46609e61dafSJames Morse 46709e61dafSJames Morse guard(mutex)(&domain_list_lock); 46809e61dafSJames Morse for_each_mpam_resctrl_control(res, rid) { 46909e61dafSJames Morse struct mpam_resctrl_dom *dom; 47009e61dafSJames Morse struct rdt_ctrl_domain *ctrl_d; 47109e61dafSJames Morse bool ctrl_dom_empty; 47209e61dafSJames Morse struct rdt_resource *r = &res->resctrl_res; 47309e61dafSJames Morse 47409e61dafSJames Morse if (!res->class) 47509e61dafSJames Morse continue; // dummy resource 47609e61dafSJames Morse 47709e61dafSJames Morse dom = mpam_resctrl_get_domain_from_cpu(cpu, res); 47809e61dafSJames Morse if (WARN_ON_ONCE(!dom)) 47909e61dafSJames Morse continue; 48009e61dafSJames Morse 48109e61dafSJames Morse if (r->alloc_capable) { 48209e61dafSJames Morse ctrl_d = &dom->resctrl_ctrl_dom; 48309e61dafSJames Morse ctrl_dom_empty = mpam_resctrl_offline_domain_hdr(cpu, &ctrl_d->hdr); 48409e61dafSJames Morse if (ctrl_dom_empty) 48509e61dafSJames Morse resctrl_offline_ctrl_domain(&res->resctrl_res, ctrl_d); 48609e61dafSJames Morse } else { 48709e61dafSJames Morse ctrl_dom_empty = true; 48809e61dafSJames Morse } 48909e61dafSJames Morse 49009e61dafSJames Morse if (ctrl_dom_empty) 49109e61dafSJames Morse kfree(dom); 49209e61dafSJames Morse } 49309e61dafSJames Morse } 49409e61dafSJames Morse 49509e61dafSJames Morse int mpam_resctrl_setup(void) 49609e61dafSJames Morse { 49709e61dafSJames Morse int err = 0; 49809e61dafSJames Morse struct mpam_resctrl_res *res; 49909e61dafSJames Morse enum resctrl_res_level rid; 50009e61dafSJames Morse 50109e61dafSJames Morse cpus_read_lock(); 50209e61dafSJames Morse for_each_mpam_resctrl_control(res, rid) { 50309e61dafSJames Morse INIT_LIST_HEAD_RCU(&res->resctrl_res.ctrl_domains); 50409e61dafSJames Morse res->resctrl_res.rid = rid; 50509e61dafSJames Morse } 50609e61dafSJames Morse 50752a4edb1SJames Morse /* Find some classes to use for controls */ 50852a4edb1SJames Morse mpam_resctrl_pick_caches(); 50909e61dafSJames Morse 51009e61dafSJames Morse /* Initialise the resctrl structures from the classes */ 51109e61dafSJames Morse for_each_mpam_resctrl_control(res, rid) { 51209e61dafSJames Morse if (!res->class) 51309e61dafSJames Morse continue; // dummy resource 51409e61dafSJames Morse 51509e61dafSJames Morse err = mpam_resctrl_control_init(res); 51609e61dafSJames Morse if (err) { 51709e61dafSJames Morse pr_debug("Failed to initialise rid %u\n", rid); 51809e61dafSJames Morse break; 51909e61dafSJames Morse } 52009e61dafSJames Morse } 52109e61dafSJames Morse cpus_read_unlock(); 52209e61dafSJames Morse 52309e61dafSJames Morse if (err) { 52409e61dafSJames Morse pr_debug("Internal error %d - resctrl not supported\n", err); 52509e61dafSJames Morse return err; 52609e61dafSJames Morse } 52709e61dafSJames Morse 52809e61dafSJames Morse if (!resctrl_arch_alloc_capable()) { 52909e61dafSJames Morse pr_debug("No alloc(%u) found - resctrl not supported\n", 53009e61dafSJames Morse resctrl_arch_alloc_capable()); 53109e61dafSJames Morse return -EOPNOTSUPP; 53209e61dafSJames Morse } 53309e61dafSJames Morse 53409e61dafSJames Morse /* TODO: call resctrl_init() */ 53509e61dafSJames Morse 53609e61dafSJames Morse return 0; 53709e61dafSJames Morse } 538