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*370d166dSJames Morse void resctrl_arch_reset_all_ctrls(struct rdt_resource *r) 174*370d166dSJames Morse { 175*370d166dSJames Morse struct mpam_resctrl_res *res; 176*370d166dSJames Morse 177*370d166dSJames Morse lockdep_assert_cpus_held(); 178*370d166dSJames Morse 179*370d166dSJames Morse if (!mpam_is_enabled()) 180*370d166dSJames Morse return; 181*370d166dSJames Morse 182*370d166dSJames Morse res = container_of(r, struct mpam_resctrl_res, resctrl_res); 183*370d166dSJames Morse mpam_reset_class_locked(res->class); 184*370d166dSJames Morse } 185*370d166dSJames Morse 18609e61dafSJames Morse static void mpam_resctrl_domain_hdr_init(int cpu, struct mpam_component *comp, 18709e61dafSJames Morse enum resctrl_res_level rid, 18809e61dafSJames Morse struct rdt_domain_hdr *hdr) 18909e61dafSJames Morse { 19009e61dafSJames Morse lockdep_assert_cpus_held(); 19109e61dafSJames Morse 19209e61dafSJames Morse INIT_LIST_HEAD(&hdr->list); 19309e61dafSJames Morse hdr->id = mpam_resctrl_pick_domain_id(cpu, comp); 19409e61dafSJames Morse hdr->rid = rid; 19509e61dafSJames Morse cpumask_set_cpu(cpu, &hdr->cpu_mask); 19609e61dafSJames Morse } 19709e61dafSJames Morse 19809e61dafSJames Morse static void mpam_resctrl_online_domain_hdr(unsigned int cpu, 19909e61dafSJames Morse struct rdt_domain_hdr *hdr) 20009e61dafSJames Morse { 20109e61dafSJames Morse lockdep_assert_cpus_held(); 20209e61dafSJames Morse 20309e61dafSJames Morse cpumask_set_cpu(cpu, &hdr->cpu_mask); 20409e61dafSJames Morse } 20509e61dafSJames Morse 20609e61dafSJames Morse /** 20709e61dafSJames Morse * mpam_resctrl_offline_domain_hdr() - Update the domain header to remove a CPU. 20809e61dafSJames Morse * @cpu: The CPU to remove from the domain. 20909e61dafSJames Morse * @hdr: The domain's header. 21009e61dafSJames Morse * 21109e61dafSJames Morse * Removes @cpu from the header mask. If this was the last CPU in the domain, 21209e61dafSJames Morse * the domain header is removed from its parent list and true is returned, 21309e61dafSJames Morse * indicating the parent structure can be freed. 21409e61dafSJames Morse * If there are other CPUs in the domain, returns false. 21509e61dafSJames Morse */ 21609e61dafSJames Morse static bool mpam_resctrl_offline_domain_hdr(unsigned int cpu, 21709e61dafSJames Morse struct rdt_domain_hdr *hdr) 21809e61dafSJames Morse { 21909e61dafSJames Morse lockdep_assert_held(&domain_list_lock); 22009e61dafSJames Morse 22109e61dafSJames Morse cpumask_clear_cpu(cpu, &hdr->cpu_mask); 22209e61dafSJames Morse if (cpumask_empty(&hdr->cpu_mask)) { 22309e61dafSJames Morse list_del_rcu(&hdr->list); 22409e61dafSJames Morse synchronize_rcu(); 22509e61dafSJames Morse return true; 22609e61dafSJames Morse } 22709e61dafSJames Morse 22809e61dafSJames Morse return false; 22909e61dafSJames Morse } 23009e61dafSJames Morse 23109e61dafSJames Morse static void mpam_resctrl_domain_insert(struct list_head *list, 23209e61dafSJames Morse struct rdt_domain_hdr *new) 23309e61dafSJames Morse { 23409e61dafSJames Morse struct rdt_domain_hdr *err; 23509e61dafSJames Morse struct list_head *pos = NULL; 23609e61dafSJames Morse 23709e61dafSJames Morse lockdep_assert_held(&domain_list_lock); 23809e61dafSJames Morse 23909e61dafSJames Morse err = resctrl_find_domain(list, new->id, &pos); 24009e61dafSJames Morse if (WARN_ON_ONCE(err)) 24109e61dafSJames Morse return; 24209e61dafSJames Morse 24309e61dafSJames Morse list_add_tail_rcu(&new->list, pos); 24409e61dafSJames Morse } 24509e61dafSJames Morse 24609e61dafSJames Morse static struct mpam_resctrl_dom * 24709e61dafSJames Morse mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res) 24809e61dafSJames Morse { 24909e61dafSJames Morse int err; 25009e61dafSJames Morse struct mpam_resctrl_dom *dom; 25109e61dafSJames Morse struct rdt_ctrl_domain *ctrl_d; 25209e61dafSJames Morse struct mpam_class *class = res->class; 25309e61dafSJames Morse struct mpam_component *comp_iter, *ctrl_comp; 25409e61dafSJames Morse struct rdt_resource *r = &res->resctrl_res; 25509e61dafSJames Morse 25609e61dafSJames Morse lockdep_assert_held(&domain_list_lock); 25709e61dafSJames Morse 25809e61dafSJames Morse ctrl_comp = NULL; 25909e61dafSJames Morse guard(srcu)(&mpam_srcu); 26009e61dafSJames Morse list_for_each_entry_srcu(comp_iter, &class->components, class_list, 26109e61dafSJames Morse srcu_read_lock_held(&mpam_srcu)) { 26209e61dafSJames Morse if (cpumask_test_cpu(cpu, &comp_iter->affinity)) { 26309e61dafSJames Morse ctrl_comp = comp_iter; 26409e61dafSJames Morse break; 26509e61dafSJames Morse } 26609e61dafSJames Morse } 26709e61dafSJames Morse 26809e61dafSJames Morse /* class has no component for this CPU */ 26909e61dafSJames Morse if (WARN_ON_ONCE(!ctrl_comp)) 27009e61dafSJames Morse return ERR_PTR(-EINVAL); 27109e61dafSJames Morse 27209e61dafSJames Morse dom = kzalloc_node(sizeof(*dom), GFP_KERNEL, cpu_to_node(cpu)); 27309e61dafSJames Morse if (!dom) 27409e61dafSJames Morse return ERR_PTR(-ENOMEM); 27509e61dafSJames Morse 27609e61dafSJames Morse if (r->alloc_capable) { 27709e61dafSJames Morse dom->ctrl_comp = ctrl_comp; 27809e61dafSJames Morse 27909e61dafSJames Morse ctrl_d = &dom->resctrl_ctrl_dom; 28009e61dafSJames Morse mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, r->rid, &ctrl_d->hdr); 28109e61dafSJames Morse ctrl_d->hdr.type = RESCTRL_CTRL_DOMAIN; 28209e61dafSJames Morse err = resctrl_online_ctrl_domain(r, ctrl_d); 28309e61dafSJames Morse if (err) 28409e61dafSJames Morse goto free_domain; 28509e61dafSJames Morse 28609e61dafSJames Morse mpam_resctrl_domain_insert(&r->ctrl_domains, &ctrl_d->hdr); 28709e61dafSJames Morse } else { 28809e61dafSJames Morse pr_debug("Skipped control domain online - no controls\n"); 28909e61dafSJames Morse } 29009e61dafSJames Morse return dom; 29109e61dafSJames Morse 29209e61dafSJames Morse free_domain: 29309e61dafSJames Morse kfree(dom); 29409e61dafSJames Morse dom = ERR_PTR(err); 29509e61dafSJames Morse 29609e61dafSJames Morse return dom; 29709e61dafSJames Morse } 29809e61dafSJames Morse 29909e61dafSJames Morse static struct mpam_resctrl_dom * 30009e61dafSJames Morse mpam_resctrl_get_domain_from_cpu(int cpu, struct mpam_resctrl_res *res) 30109e61dafSJames Morse { 30209e61dafSJames Morse struct mpam_resctrl_dom *dom; 30309e61dafSJames Morse struct rdt_resource *r = &res->resctrl_res; 30409e61dafSJames Morse 30509e61dafSJames Morse lockdep_assert_cpus_held(); 30609e61dafSJames Morse 30709e61dafSJames Morse list_for_each_entry_rcu(dom, &r->ctrl_domains, resctrl_ctrl_dom.hdr.list) { 30809e61dafSJames Morse if (cpumask_test_cpu(cpu, &dom->ctrl_comp->affinity)) 30909e61dafSJames Morse return dom; 31009e61dafSJames Morse } 31109e61dafSJames Morse 31209e61dafSJames Morse return NULL; 31309e61dafSJames Morse } 31409e61dafSJames Morse 31509e61dafSJames Morse int mpam_resctrl_online_cpu(unsigned int cpu) 31609e61dafSJames Morse { 31709e61dafSJames Morse struct mpam_resctrl_res *res; 31809e61dafSJames Morse enum resctrl_res_level rid; 31909e61dafSJames Morse 32009e61dafSJames Morse guard(mutex)(&domain_list_lock); 32109e61dafSJames Morse for_each_mpam_resctrl_control(res, rid) { 32209e61dafSJames Morse struct mpam_resctrl_dom *dom; 32309e61dafSJames Morse struct rdt_resource *r = &res->resctrl_res; 32409e61dafSJames Morse 32509e61dafSJames Morse if (!res->class) 32609e61dafSJames Morse continue; // dummy_resource; 32709e61dafSJames Morse 32809e61dafSJames Morse dom = mpam_resctrl_get_domain_from_cpu(cpu, res); 32909e61dafSJames Morse if (!dom) { 33009e61dafSJames Morse dom = mpam_resctrl_alloc_domain(cpu, res); 33109e61dafSJames Morse if (IS_ERR(dom)) 33209e61dafSJames Morse return PTR_ERR(dom); 33309e61dafSJames Morse } else { 33409e61dafSJames Morse if (r->alloc_capable) { 33509e61dafSJames Morse struct rdt_ctrl_domain *ctrl_d = &dom->resctrl_ctrl_dom; 33609e61dafSJames Morse 33709e61dafSJames Morse mpam_resctrl_online_domain_hdr(cpu, &ctrl_d->hdr); 33809e61dafSJames Morse } 33909e61dafSJames Morse } 34009e61dafSJames Morse } 34109e61dafSJames Morse 34209e61dafSJames Morse resctrl_online_cpu(cpu); 34309e61dafSJames Morse 34409e61dafSJames Morse return 0; 34509e61dafSJames Morse } 34609e61dafSJames Morse 34709e61dafSJames Morse void mpam_resctrl_offline_cpu(unsigned int cpu) 34809e61dafSJames Morse { 34909e61dafSJames Morse struct mpam_resctrl_res *res; 35009e61dafSJames Morse enum resctrl_res_level rid; 35109e61dafSJames Morse 35209e61dafSJames Morse resctrl_offline_cpu(cpu); 35309e61dafSJames Morse 35409e61dafSJames Morse guard(mutex)(&domain_list_lock); 35509e61dafSJames Morse for_each_mpam_resctrl_control(res, rid) { 35609e61dafSJames Morse struct mpam_resctrl_dom *dom; 35709e61dafSJames Morse struct rdt_ctrl_domain *ctrl_d; 35809e61dafSJames Morse bool ctrl_dom_empty; 35909e61dafSJames Morse struct rdt_resource *r = &res->resctrl_res; 36009e61dafSJames Morse 36109e61dafSJames Morse if (!res->class) 36209e61dafSJames Morse continue; // dummy resource 36309e61dafSJames Morse 36409e61dafSJames Morse dom = mpam_resctrl_get_domain_from_cpu(cpu, res); 36509e61dafSJames Morse if (WARN_ON_ONCE(!dom)) 36609e61dafSJames Morse continue; 36709e61dafSJames Morse 36809e61dafSJames Morse if (r->alloc_capable) { 36909e61dafSJames Morse ctrl_d = &dom->resctrl_ctrl_dom; 37009e61dafSJames Morse ctrl_dom_empty = mpam_resctrl_offline_domain_hdr(cpu, &ctrl_d->hdr); 37109e61dafSJames Morse if (ctrl_dom_empty) 37209e61dafSJames Morse resctrl_offline_ctrl_domain(&res->resctrl_res, ctrl_d); 37309e61dafSJames Morse } else { 37409e61dafSJames Morse ctrl_dom_empty = true; 37509e61dafSJames Morse } 37609e61dafSJames Morse 37709e61dafSJames Morse if (ctrl_dom_empty) 37809e61dafSJames Morse kfree(dom); 37909e61dafSJames Morse } 38009e61dafSJames Morse } 38109e61dafSJames Morse 38209e61dafSJames Morse int mpam_resctrl_setup(void) 38309e61dafSJames Morse { 38409e61dafSJames Morse int err = 0; 38509e61dafSJames Morse struct mpam_resctrl_res *res; 38609e61dafSJames Morse enum resctrl_res_level rid; 38709e61dafSJames Morse 38809e61dafSJames Morse cpus_read_lock(); 38909e61dafSJames Morse for_each_mpam_resctrl_control(res, rid) { 39009e61dafSJames Morse INIT_LIST_HEAD_RCU(&res->resctrl_res.ctrl_domains); 39109e61dafSJames Morse res->resctrl_res.rid = rid; 39209e61dafSJames Morse } 39309e61dafSJames Morse 39452a4edb1SJames Morse /* Find some classes to use for controls */ 39552a4edb1SJames Morse mpam_resctrl_pick_caches(); 39609e61dafSJames Morse 39709e61dafSJames Morse /* Initialise the resctrl structures from the classes */ 39809e61dafSJames Morse for_each_mpam_resctrl_control(res, rid) { 39909e61dafSJames Morse if (!res->class) 40009e61dafSJames Morse continue; // dummy resource 40109e61dafSJames Morse 40209e61dafSJames Morse err = mpam_resctrl_control_init(res); 40309e61dafSJames Morse if (err) { 40409e61dafSJames Morse pr_debug("Failed to initialise rid %u\n", rid); 40509e61dafSJames Morse break; 40609e61dafSJames Morse } 40709e61dafSJames Morse } 40809e61dafSJames Morse cpus_read_unlock(); 40909e61dafSJames Morse 41009e61dafSJames Morse if (err) { 41109e61dafSJames Morse pr_debug("Internal error %d - resctrl not supported\n", err); 41209e61dafSJames Morse return err; 41309e61dafSJames Morse } 41409e61dafSJames Morse 41509e61dafSJames Morse if (!resctrl_arch_alloc_capable()) { 41609e61dafSJames Morse pr_debug("No alloc(%u) found - resctrl not supported\n", 41709e61dafSJames Morse resctrl_arch_alloc_capable()); 41809e61dafSJames Morse return -EOPNOTSUPP; 41909e61dafSJames Morse } 42009e61dafSJames Morse 42109e61dafSJames Morse /* TODO: call resctrl_init() */ 42209e61dafSJames Morse 42309e61dafSJames Morse return 0; 42409e61dafSJames Morse } 425