12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2fa7d9493SBabu Moger /*
3fa7d9493SBabu Moger * Resource Director Technology(RDT)
4fa7d9493SBabu Moger * - Cache Allocation code.
5fa7d9493SBabu Moger *
6fa7d9493SBabu Moger * Copyright (C) 2016 Intel Corporation
7fa7d9493SBabu Moger *
8fa7d9493SBabu Moger * Authors:
9fa7d9493SBabu Moger * Fenghua Yu <fenghua.yu@intel.com>
10fa7d9493SBabu Moger * Tony Luck <tony.luck@intel.com>
11fa7d9493SBabu Moger * Vikas Shivappa <vikas.shivappa@intel.com>
12fa7d9493SBabu Moger *
13fa7d9493SBabu Moger * More information about RDT be found in the Intel (R) x86 Architecture
14fa7d9493SBabu Moger * Software Developer Manual June 2016, volume 3, section 17.17.
15fa7d9493SBabu Moger */
16fa7d9493SBabu Moger
17352940ecSBabu Moger #define pr_fmt(fmt) "resctrl: " fmt
18fa7d9493SBabu Moger
19fb700810SJames Morse #include <linux/cpu.h>
20fa7d9493SBabu Moger #include <linux/slab.h>
21fa7d9493SBabu Moger #include <linux/err.h>
22fa7d9493SBabu Moger #include <linux/cpuhotplug.h>
23fa7d9493SBabu Moger
24db99675eSTony Luck #include <asm/cpu_device_id.h>
258dd97c65SReinette Chatre #include <asm/resctrl.h>
26fa7d9493SBabu Moger #include "internal.h"
27fa7d9493SBabu Moger
28fb700810SJames Morse /*
29fb700810SJames Morse * rdt_domain structures are kfree()d when their last CPU goes offline,
30fb700810SJames Morse * and allocated when the first CPU in a new domain comes online.
31fb700810SJames Morse * The rdt_resource's domain list is updated when this happens. Readers of
32fb700810SJames Morse * the domain list must either take cpus_read_lock(), or rely on an RCU
33fb700810SJames Morse * read-side critical section, to avoid observing concurrent modification.
34fb700810SJames Morse * All writers take this mutex:
35fb700810SJames Morse */
36fb700810SJames Morse static DEFINE_MUTEX(domain_list_lock);
37fa7d9493SBabu Moger
38fa7d9493SBabu Moger /*
39352940ecSBabu Moger * The cached resctrl_pqr_state is strictly per CPU and can never be
40fa7d9493SBabu Moger * updated from a remote CPU. Functions which modify the state
41fa7d9493SBabu Moger * are called with interrupts disabled and no preemption, which
42fa7d9493SBabu Moger * is sufficient for the protection.
43fa7d9493SBabu Moger */
44352940ecSBabu Moger DEFINE_PER_CPU(struct resctrl_pqr_state, pqr_state);
45fa7d9493SBabu Moger
46fa7d9493SBabu Moger /*
47fa7d9493SBabu Moger * Used to store the max resource name width and max resource data width
48fa7d9493SBabu Moger * to display the schemata in a tabular format
49fa7d9493SBabu Moger */
50fa7d9493SBabu Moger int max_name_width, max_data_width;
51fa7d9493SBabu Moger
52fa7d9493SBabu Moger /*
53fa7d9493SBabu Moger * Global boolean for rdt_alloc which is true if any
54fa7d9493SBabu Moger * resource allocation is enabled.
55fa7d9493SBabu Moger */
56fa7d9493SBabu Moger bool rdt_alloc_capable;
57fa7d9493SBabu Moger
58bd4955d4STony Luck static void mba_wrmsr_intel(struct msr_param *m);
59bd4955d4STony Luck static void cat_wrmsr(struct msr_param *m);
60bd4955d4STony Luck static void mba_wrmsr_amd(struct msr_param *m);
61fa7d9493SBabu Moger
62cd84f72bSTony Luck #define ctrl_domain_init(id) LIST_HEAD_INIT(rdt_resources_all[id].r_resctrl.ctrl_domains)
63cd84f72bSTony Luck #define mon_domain_init(id) LIST_HEAD_INIT(rdt_resources_all[id].r_resctrl.mon_domains)
64fa7d9493SBabu Moger
6563c8b123SJames Morse struct rdt_hw_resource rdt_resources_all[] = {
66fa7d9493SBabu Moger [RDT_RESOURCE_L3] =
67fa7d9493SBabu Moger {
6863c8b123SJames Morse .r_resctrl = {
69fa7d9493SBabu Moger .rid = RDT_RESOURCE_L3,
70fa7d9493SBabu Moger .name = "L3",
71cd84f72bSTony Luck .ctrl_scope = RESCTRL_L3_CACHE,
72cd84f72bSTony Luck .mon_scope = RESCTRL_L3_CACHE,
73cd84f72bSTony Luck .ctrl_domains = ctrl_domain_init(RDT_RESOURCE_L3),
74cd84f72bSTony Luck .mon_domains = mon_domain_init(RDT_RESOURCE_L3),
75fa7d9493SBabu Moger .parse_ctrlval = parse_cbm,
76fa7d9493SBabu Moger .format_str = "%d=%0*x",
77fa7d9493SBabu Moger .fflags = RFTYPE_RES_CACHE,
78fa7d9493SBabu Moger },
7963c8b123SJames Morse .msr_base = MSR_IA32_L3_CBM_BASE,
8063c8b123SJames Morse .msr_update = cat_wrmsr,
8163c8b123SJames Morse },
82fa7d9493SBabu Moger [RDT_RESOURCE_L2] =
83fa7d9493SBabu Moger {
8463c8b123SJames Morse .r_resctrl = {
85fa7d9493SBabu Moger .rid = RDT_RESOURCE_L2,
86fa7d9493SBabu Moger .name = "L2",
87cd84f72bSTony Luck .ctrl_scope = RESCTRL_L2_CACHE,
88cd84f72bSTony Luck .ctrl_domains = ctrl_domain_init(RDT_RESOURCE_L2),
89fa7d9493SBabu Moger .parse_ctrlval = parse_cbm,
90fa7d9493SBabu Moger .format_str = "%d=%0*x",
91fa7d9493SBabu Moger .fflags = RFTYPE_RES_CACHE,
92fa7d9493SBabu Moger },
93aa50453aSBabu Moger .msr_base = MSR_IA32_L2_CBM_BASE,
94fa7d9493SBabu Moger .msr_update = cat_wrmsr,
9563c8b123SJames Morse },
96fa7d9493SBabu Moger [RDT_RESOURCE_MBA] =
97fa7d9493SBabu Moger {
9863c8b123SJames Morse .r_resctrl = {
99fa7d9493SBabu Moger .rid = RDT_RESOURCE_MBA,
100fa7d9493SBabu Moger .name = "MB",
101cd84f72bSTony Luck .ctrl_scope = RESCTRL_L3_CACHE,
102cd84f72bSTony Luck .ctrl_domains = ctrl_domain_init(RDT_RESOURCE_MBA),
1035df3ca93SJames Morse .parse_ctrlval = parse_bw,
104fa7d9493SBabu Moger .format_str = "%d=%*u",
105fa7d9493SBabu Moger .fflags = RFTYPE_RES_MB,
106fa7d9493SBabu Moger },
10763c8b123SJames Morse },
108a5b69966SBabu Moger [RDT_RESOURCE_SMBA] =
109a5b69966SBabu Moger {
110a5b69966SBabu Moger .r_resctrl = {
111a5b69966SBabu Moger .rid = RDT_RESOURCE_SMBA,
112a5b69966SBabu Moger .name = "SMBA",
113cd84f72bSTony Luck .ctrl_scope = RESCTRL_L3_CACHE,
114cd84f72bSTony Luck .ctrl_domains = ctrl_domain_init(RDT_RESOURCE_SMBA),
115a5b69966SBabu Moger .parse_ctrlval = parse_bw,
116a5b69966SBabu Moger .format_str = "%d=%*u",
117a5b69966SBabu Moger .fflags = RFTYPE_RES_MB,
118a5b69966SBabu Moger },
119a5b69966SBabu Moger },
120fa7d9493SBabu Moger };
121fa7d9493SBabu Moger
resctrl_arch_system_num_rmid_idx(void)122a547a588SPeter Newman u32 resctrl_arch_system_num_rmid_idx(void)
123a547a588SPeter Newman {
124a547a588SPeter Newman struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
125a547a588SPeter Newman
126a547a588SPeter Newman /* RMID are independent numbers for x86. num_rmid_idx == num_rmid */
127a547a588SPeter Newman return r->num_rmid;
128a547a588SPeter Newman }
129a547a588SPeter Newman
130fa7d9493SBabu Moger /*
131fa7d9493SBabu Moger * cache_alloc_hsw_probe() - Have to probe for Intel haswell server CPUs
132fa7d9493SBabu Moger * as they do not have CPUID enumeration support for Cache allocation.
133fa7d9493SBabu Moger * The check for Vendor/Family/Model is not enough to guarantee that
134fa7d9493SBabu Moger * the MSRs won't #GP fault because only the following SKUs support
135fa7d9493SBabu Moger * CAT:
136fa7d9493SBabu Moger * Intel(R) Xeon(R) CPU E5-2658 v3 @ 2.20GHz
137fa7d9493SBabu Moger * Intel(R) Xeon(R) CPU E5-2648L v3 @ 1.80GHz
138fa7d9493SBabu Moger * Intel(R) Xeon(R) CPU E5-2628L v3 @ 2.00GHz
139fa7d9493SBabu Moger * Intel(R) Xeon(R) CPU E5-2618L v3 @ 2.30GHz
140fa7d9493SBabu Moger * Intel(R) Xeon(R) CPU E5-2608L v3 @ 2.00GHz
141fa7d9493SBabu Moger * Intel(R) Xeon(R) CPU E5-2658A v3 @ 2.20GHz
142fa7d9493SBabu Moger *
143d9f6e12fSIngo Molnar * Probe by trying to write the first of the L3 cache mask registers
144fa7d9493SBabu Moger * and checking that the bits stick. Max CLOSids is always 4 and max cbm length
145fa7d9493SBabu Moger * is always 20 on hsw server parts. The minimum cache bitmask length
146fa7d9493SBabu Moger * allowed for HSW server is always 2 bits. Hardcode all of them.
147fa7d9493SBabu Moger */
cache_alloc_hsw_probe(void)148fa7d9493SBabu Moger static inline void cache_alloc_hsw_probe(void)
149fa7d9493SBabu Moger {
15063c8b123SJames Morse struct rdt_hw_resource *hw_res = &rdt_resources_all[RDT_RESOURCE_L3];
15163c8b123SJames Morse struct rdt_resource *r = &hw_res->r_resctrl;
1521b908debSTony Luck u64 max_cbm = BIT_ULL_MASK(20) - 1, l3_cbm_0;
153fa7d9493SBabu Moger
1541b908debSTony Luck if (wrmsrl_safe(MSR_IA32_L3_CBM_BASE, max_cbm))
155fa7d9493SBabu Moger return;
156aa50453aSBabu Moger
1571b908debSTony Luck rdmsrl(MSR_IA32_L3_CBM_BASE, l3_cbm_0);
158fa7d9493SBabu Moger
159fa7d9493SBabu Moger /* If all the bits were set in MSR, return success */
1601b908debSTony Luck if (l3_cbm_0 != max_cbm)
161fa7d9493SBabu Moger return;
162fa7d9493SBabu Moger
16363c8b123SJames Morse hw_res->num_closid = 4;
164fa7d9493SBabu Moger r->default_ctrl = max_cbm;
165fa7d9493SBabu Moger r->cache.cbm_len = 20;
166fa7d9493SBabu Moger r->cache.shareable_bits = 0xc0000;
167fa7d9493SBabu Moger r->cache.min_cbm_bits = 2;
1680e3cd31fSMaciej Wieczor-Retman r->cache.arch_has_sparse_bitmasks = false;
169fa7d9493SBabu Moger r->alloc_capable = true;
170fa7d9493SBabu Moger
171fa7d9493SBabu Moger rdt_alloc_capable = true;
172fa7d9493SBabu Moger }
173fa7d9493SBabu Moger
is_mba_sc(struct rdt_resource * r)174fa7d9493SBabu Moger bool is_mba_sc(struct rdt_resource *r)
175fa7d9493SBabu Moger {
176fa7d9493SBabu Moger if (!r)
17763c8b123SJames Morse return rdt_resources_all[RDT_RESOURCE_MBA].r_resctrl.membw.mba_sc;
178fa7d9493SBabu Moger
1795b6fac3fSBabu Moger /*
1805b6fac3fSBabu Moger * The software controller support is only applicable to MBA resource.
1815b6fac3fSBabu Moger * Make sure to check for resource type.
1825b6fac3fSBabu Moger */
1835b6fac3fSBabu Moger if (r->rid != RDT_RESOURCE_MBA)
1845b6fac3fSBabu Moger return false;
1855b6fac3fSBabu Moger
186fa7d9493SBabu Moger return r->membw.mba_sc;
187fa7d9493SBabu Moger }
188fa7d9493SBabu Moger
189fa7d9493SBabu Moger /*
190fa7d9493SBabu Moger * rdt_get_mb_table() - get a mapping of bandwidth(b/w) percentage values
191fa7d9493SBabu Moger * exposed to user interface and the h/w understandable delay values.
192fa7d9493SBabu Moger *
193fa7d9493SBabu Moger * The non-linear delay values have the granularity of power of two
194fa7d9493SBabu Moger * and also the h/w does not guarantee a curve for configured delay
195fa7d9493SBabu Moger * values vs. actual b/w enforced.
196fa7d9493SBabu Moger * Hence we need a mapping that is pre calibrated so the user can
197fa7d9493SBabu Moger * express the memory b/w as a percentage value.
198fa7d9493SBabu Moger */
rdt_get_mb_table(struct rdt_resource * r)199fa7d9493SBabu Moger static inline bool rdt_get_mb_table(struct rdt_resource *r)
200fa7d9493SBabu Moger {
201fa7d9493SBabu Moger /*
202fa7d9493SBabu Moger * There are no Intel SKUs as of now to support non-linear delay.
203fa7d9493SBabu Moger */
204fa7d9493SBabu Moger pr_info("MBA b/w map not implemented for cpu:%d, model:%d",
205fa7d9493SBabu Moger boot_cpu_data.x86, boot_cpu_data.x86_model);
206fa7d9493SBabu Moger
207fa7d9493SBabu Moger return false;
208fa7d9493SBabu Moger }
209fa7d9493SBabu Moger
__get_mem_config_intel(struct rdt_resource * r)210*d5fd042bSNathan Chancellor static __init bool __get_mem_config_intel(struct rdt_resource *r)
211fa7d9493SBabu Moger {
21263c8b123SJames Morse struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
213fa7d9493SBabu Moger union cpuid_0x10_3_eax eax;
214fa7d9493SBabu Moger union cpuid_0x10_x_edx edx;
215e89f85b9SJames Morse u32 ebx, ecx, max_delay;
216fa7d9493SBabu Moger
217fa7d9493SBabu Moger cpuid_count(0x00000010, 3, &eax.full, &ebx, &ecx, &edx.full);
21863c8b123SJames Morse hw_res->num_closid = edx.split.cos_max + 1;
219e89f85b9SJames Morse max_delay = eax.split.max_delay + 1;
220fa7d9493SBabu Moger r->default_ctrl = MAX_MBA_BW;
22141215b79SJames Morse r->membw.arch_needs_linear = true;
222fa7d9493SBabu Moger if (ecx & MBA_IS_LINEAR) {
223fa7d9493SBabu Moger r->membw.delay_linear = true;
224e89f85b9SJames Morse r->membw.min_bw = MAX_MBA_BW - max_delay;
225e89f85b9SJames Morse r->membw.bw_gran = MAX_MBA_BW - max_delay;
226fa7d9493SBabu Moger } else {
227fa7d9493SBabu Moger if (!rdt_get_mb_table(r))
228fa7d9493SBabu Moger return false;
22941215b79SJames Morse r->membw.arch_needs_linear = false;
230fa7d9493SBabu Moger }
231fa7d9493SBabu Moger r->data_width = 3;
232fa7d9493SBabu Moger
23329b6bd41SFenghua Yu if (boot_cpu_has(X86_FEATURE_PER_THREAD_MBA))
23429b6bd41SFenghua Yu r->membw.throttle_mode = THREAD_THROTTLE_PER_THREAD;
23529b6bd41SFenghua Yu else
23629b6bd41SFenghua Yu r->membw.throttle_mode = THREAD_THROTTLE_MAX;
23729b6bd41SFenghua Yu thread_throttle_mode_init();
23829b6bd41SFenghua Yu
239fa7d9493SBabu Moger r->alloc_capable = true;
240fa7d9493SBabu Moger
241fa7d9493SBabu Moger return true;
242fa7d9493SBabu Moger }
243fa7d9493SBabu Moger
__rdt_get_mem_config_amd(struct rdt_resource * r)244*d5fd042bSNathan Chancellor static __init bool __rdt_get_mem_config_amd(struct rdt_resource *r)
2454d05bf71SBabu Moger {
24663c8b123SJames Morse struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
2470976783bSBabu Moger u32 eax, ebx, ecx, edx, subleaf;
2484d05bf71SBabu Moger
2495b6fac3fSBabu Moger /*
2505b6fac3fSBabu Moger * Query CPUID_Fn80000020_EDX_x01 for MBA and
2515b6fac3fSBabu Moger * CPUID_Fn80000020_EDX_x02 for SMBA
2525b6fac3fSBabu Moger */
2535b6fac3fSBabu Moger subleaf = (r->rid == RDT_RESOURCE_SMBA) ? 2 : 1;
2545b6fac3fSBabu Moger
2550976783bSBabu Moger cpuid_count(0x80000020, subleaf, &eax, &ebx, &ecx, &edx);
2560976783bSBabu Moger hw_res->num_closid = edx + 1;
2570976783bSBabu Moger r->default_ctrl = 1 << eax;
2584d05bf71SBabu Moger
2594d05bf71SBabu Moger /* AMD does not use delay */
2604d05bf71SBabu Moger r->membw.delay_linear = false;
26141215b79SJames Morse r->membw.arch_needs_linear = false;
2624d05bf71SBabu Moger
26329b6bd41SFenghua Yu /*
26429b6bd41SFenghua Yu * AMD does not use memory delay throttle model to control
26529b6bd41SFenghua Yu * the allocation like Intel does.
26629b6bd41SFenghua Yu */
26729b6bd41SFenghua Yu r->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
2684d05bf71SBabu Moger r->membw.min_bw = 0;
2694d05bf71SBabu Moger r->membw.bw_gran = 1;
2704d05bf71SBabu Moger /* Max value is 2048, Data width should be 4 in decimal */
2714d05bf71SBabu Moger r->data_width = 4;
2724d05bf71SBabu Moger
2734d05bf71SBabu Moger r->alloc_capable = true;
2744d05bf71SBabu Moger
2754d05bf71SBabu Moger return true;
2764d05bf71SBabu Moger }
2774d05bf71SBabu Moger
rdt_get_cache_alloc_cfg(int idx,struct rdt_resource * r)278fa7d9493SBabu Moger static void rdt_get_cache_alloc_cfg(int idx, struct rdt_resource *r)
279fa7d9493SBabu Moger {
28063c8b123SJames Morse struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
281fa7d9493SBabu Moger union cpuid_0x10_1_eax eax;
2820e3cd31fSMaciej Wieczor-Retman union cpuid_0x10_x_ecx ecx;
283fa7d9493SBabu Moger union cpuid_0x10_x_edx edx;
2840e3cd31fSMaciej Wieczor-Retman u32 ebx;
285fa7d9493SBabu Moger
2860e3cd31fSMaciej Wieczor-Retman cpuid_count(0x00000010, idx, &eax.full, &ebx, &ecx.full, &edx.full);
28763c8b123SJames Morse hw_res->num_closid = edx.split.cos_max + 1;
288fa7d9493SBabu Moger r->cache.cbm_len = eax.split.cbm_len + 1;
289fa7d9493SBabu Moger r->default_ctrl = BIT_MASK(eax.split.cbm_len + 1) - 1;
290fa7d9493SBabu Moger r->cache.shareable_bits = ebx & r->default_ctrl;
291fa7d9493SBabu Moger r->data_width = (r->cache.cbm_len + 3) / 4;
2920e3cd31fSMaciej Wieczor-Retman if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
2930e3cd31fSMaciej Wieczor-Retman r->cache.arch_has_sparse_bitmasks = ecx.split.noncont;
294fa7d9493SBabu Moger r->alloc_capable = true;
295fa7d9493SBabu Moger }
296fa7d9493SBabu Moger
rdt_get_cdp_config(int level)2975c3b63cdSJames Morse static void rdt_get_cdp_config(int level)
298fa7d9493SBabu Moger {
299fa7d9493SBabu Moger /*
300fa7d9493SBabu Moger * By default, CDP is disabled. CDP can be enabled by mount parameter
301fa7d9493SBabu Moger * "cdp" during resctrl file system mount time.
302fa7d9493SBabu Moger */
303c091e907SJames Morse rdt_resources_all[level].cdp_enabled = false;
3045c3b63cdSJames Morse rdt_resources_all[level].r_resctrl.cdp_capable = true;
305fa7d9493SBabu Moger }
306fa7d9493SBabu Moger
rdt_get_cdp_l3_config(void)307fa7d9493SBabu Moger static void rdt_get_cdp_l3_config(void)
308fa7d9493SBabu Moger {
3095c3b63cdSJames Morse rdt_get_cdp_config(RDT_RESOURCE_L3);
310fa7d9493SBabu Moger }
311fa7d9493SBabu Moger
rdt_get_cdp_l2_config(void)312fa7d9493SBabu Moger static void rdt_get_cdp_l2_config(void)
313fa7d9493SBabu Moger {
3145c3b63cdSJames Morse rdt_get_cdp_config(RDT_RESOURCE_L2);
315fa7d9493SBabu Moger }
316fa7d9493SBabu Moger
mba_wrmsr_amd(struct msr_param * m)317bd4955d4STony Luck static void mba_wrmsr_amd(struct msr_param *m)
3184d05bf71SBabu Moger {
319cae2bcb6STony Luck struct rdt_hw_ctrl_domain *hw_dom = resctrl_to_arch_ctrl_dom(m->dom);
320bd4955d4STony Luck struct rdt_hw_resource *hw_res = resctrl_to_arch_res(m->res);
3214d05bf71SBabu Moger unsigned int i;
3224d05bf71SBabu Moger
3234d05bf71SBabu Moger for (i = m->low; i < m->high; i++)
324792e0f6fSJames Morse wrmsrl(hw_res->msr_base + i, hw_dom->ctrl_val[i]);
3254d05bf71SBabu Moger }
3264d05bf71SBabu Moger
327fa7d9493SBabu Moger /*
328fa7d9493SBabu Moger * Map the memory b/w percentage value to delay values
329fa7d9493SBabu Moger * that can be written to QOS_MSRs.
330fa7d9493SBabu Moger * There are currently no SKUs which support non linear delay values.
331fa7d9493SBabu Moger */
delay_bw_map(unsigned long bw,struct rdt_resource * r)332ff6357bbSJames Morse static u32 delay_bw_map(unsigned long bw, struct rdt_resource *r)
333fa7d9493SBabu Moger {
334fa7d9493SBabu Moger if (r->membw.delay_linear)
335fa7d9493SBabu Moger return MAX_MBA_BW - bw;
336fa7d9493SBabu Moger
337fa7d9493SBabu Moger pr_warn_once("Non Linear delay-bw map not supported but queried\n");
338fa7d9493SBabu Moger return r->default_ctrl;
339fa7d9493SBabu Moger }
340fa7d9493SBabu Moger
mba_wrmsr_intel(struct msr_param * m)341bd4955d4STony Luck static void mba_wrmsr_intel(struct msr_param *m)
342fa7d9493SBabu Moger {
343cae2bcb6STony Luck struct rdt_hw_ctrl_domain *hw_dom = resctrl_to_arch_ctrl_dom(m->dom);
344bd4955d4STony Luck struct rdt_hw_resource *hw_res = resctrl_to_arch_res(m->res);
345fa7d9493SBabu Moger unsigned int i;
346fa7d9493SBabu Moger
347fa7d9493SBabu Moger /* Write the delay values for mba. */
348fa7d9493SBabu Moger for (i = m->low; i < m->high; i++)
349bd4955d4STony Luck wrmsrl(hw_res->msr_base + i, delay_bw_map(hw_dom->ctrl_val[i], m->res));
350fa7d9493SBabu Moger }
351fa7d9493SBabu Moger
cat_wrmsr(struct msr_param * m)352bd4955d4STony Luck static void cat_wrmsr(struct msr_param *m)
353fa7d9493SBabu Moger {
354cae2bcb6STony Luck struct rdt_hw_ctrl_domain *hw_dom = resctrl_to_arch_ctrl_dom(m->dom);
355bd4955d4STony Luck struct rdt_hw_resource *hw_res = resctrl_to_arch_res(m->res);
356fa7d9493SBabu Moger unsigned int i;
357fa7d9493SBabu Moger
358fa7d9493SBabu Moger for (i = m->low; i < m->high; i++)
3592e7df368SJames Morse wrmsrl(hw_res->msr_base + i, hw_dom->ctrl_val[i]);
360fa7d9493SBabu Moger }
361fa7d9493SBabu Moger
get_ctrl_domain_from_cpu(int cpu,struct rdt_resource * r)362cae2bcb6STony Luck struct rdt_ctrl_domain *get_ctrl_domain_from_cpu(int cpu, struct rdt_resource *r)
363fa7d9493SBabu Moger {
364cae2bcb6STony Luck struct rdt_ctrl_domain *d;
365fa7d9493SBabu Moger
366e3ca96e4STony Luck lockdep_assert_cpus_held();
367e3ca96e4STony Luck
368cd84f72bSTony Luck list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
369cd84f72bSTony Luck /* Find the domain that contains this CPU */
370cd84f72bSTony Luck if (cpumask_test_cpu(cpu, &d->hdr.cpu_mask))
371cd84f72bSTony Luck return d;
372cd84f72bSTony Luck }
373cd84f72bSTony Luck
374cd84f72bSTony Luck return NULL;
375cd84f72bSTony Luck }
376cd84f72bSTony Luck
get_mon_domain_from_cpu(int cpu,struct rdt_resource * r)377cae2bcb6STony Luck struct rdt_mon_domain *get_mon_domain_from_cpu(int cpu, struct rdt_resource *r)
378cd84f72bSTony Luck {
379cae2bcb6STony Luck struct rdt_mon_domain *d;
380cd84f72bSTony Luck
381cd84f72bSTony Luck lockdep_assert_cpus_held();
382cd84f72bSTony Luck
383cd84f72bSTony Luck list_for_each_entry(d, &r->mon_domains, hdr.list) {
384fa7d9493SBabu Moger /* Find the domain that contains this CPU */
385c103d4d4STony Luck if (cpumask_test_cpu(cpu, &d->hdr.cpu_mask))
386fa7d9493SBabu Moger return d;
387fa7d9493SBabu Moger }
388fa7d9493SBabu Moger
389fa7d9493SBabu Moger return NULL;
390fa7d9493SBabu Moger }
391fa7d9493SBabu Moger
resctrl_arch_get_num_closid(struct rdt_resource * r)392eb6f3187SJames Morse u32 resctrl_arch_get_num_closid(struct rdt_resource *r)
393eb6f3187SJames Morse {
394eb6f3187SJames Morse return resctrl_to_arch_res(r)->num_closid;
395eb6f3187SJames Morse }
396eb6f3187SJames Morse
rdt_ctrl_update(void * arg)397fa7d9493SBabu Moger void rdt_ctrl_update(void *arg)
398fa7d9493SBabu Moger {
399e3ca96e4STony Luck struct rdt_hw_resource *hw_res;
400fa7d9493SBabu Moger struct msr_param *m = arg;
401fa7d9493SBabu Moger
402e3ca96e4STony Luck hw_res = resctrl_to_arch_res(m->res);
403bd4955d4STony Luck hw_res->msr_update(m);
404fa7d9493SBabu Moger }
405fa7d9493SBabu Moger
406fa7d9493SBabu Moger /*
407cd84f72bSTony Luck * rdt_find_domain - Search for a domain id in a resource domain list.
408fa7d9493SBabu Moger *
409cd84f72bSTony Luck * Search the domain list to find the domain id. If the domain id is
410cd84f72bSTony Luck * found, return the domain. NULL otherwise. If the domain id is not
411cd84f72bSTony Luck * found (and NULL returned) then the first domain with id bigger than
412cd84f72bSTony Luck * the input id can be returned to the caller via @pos.
413fa7d9493SBabu Moger */
rdt_find_domain(struct list_head * h,int id,struct list_head ** pos)414cd84f72bSTony Luck struct rdt_domain_hdr *rdt_find_domain(struct list_head *h, int id,
415fa7d9493SBabu Moger struct list_head **pos)
416fa7d9493SBabu Moger {
417cd84f72bSTony Luck struct rdt_domain_hdr *d;
418fa7d9493SBabu Moger struct list_head *l;
419fa7d9493SBabu Moger
420cd84f72bSTony Luck list_for_each(l, h) {
421cd84f72bSTony Luck d = list_entry(l, struct rdt_domain_hdr, list);
422fa7d9493SBabu Moger /* When id is found, return its domain. */
423cd84f72bSTony Luck if (id == d->id)
424fa7d9493SBabu Moger return d;
425fa7d9493SBabu Moger /* Stop searching when finding id's position in sorted list. */
426cd84f72bSTony Luck if (id < d->id)
427fa7d9493SBabu Moger break;
428fa7d9493SBabu Moger }
429fa7d9493SBabu Moger
430fa7d9493SBabu Moger if (pos)
431fa7d9493SBabu Moger *pos = l;
432fa7d9493SBabu Moger
433fa7d9493SBabu Moger return NULL;
434fa7d9493SBabu Moger }
435fa7d9493SBabu Moger
setup_default_ctrlval(struct rdt_resource * r,u32 * dc)436b58d4eb1SJames Morse static void setup_default_ctrlval(struct rdt_resource *r, u32 *dc)
437fa7d9493SBabu Moger {
43863c8b123SJames Morse struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
439fa7d9493SBabu Moger int i;
440fa7d9493SBabu Moger
441fa7d9493SBabu Moger /*
442fa7d9493SBabu Moger * Initialize the Control MSRs to having no control.
443fa7d9493SBabu Moger * For Cache Allocation: Set all bits in cbm
444fa7d9493SBabu Moger * For Memory Allocation: Set b/w requested to 100%
445fa7d9493SBabu Moger */
446b58d4eb1SJames Morse for (i = 0; i < hw_res->num_closid; i++, dc++)
447fa7d9493SBabu Moger *dc = r->default_ctrl;
448fa7d9493SBabu Moger }
449fa7d9493SBabu Moger
ctrl_domain_free(struct rdt_hw_ctrl_domain * hw_dom)450cae2bcb6STony Luck static void ctrl_domain_free(struct rdt_hw_ctrl_domain *hw_dom)
4517add3af4SJames Morse {
4527add3af4SJames Morse kfree(hw_dom->ctrl_val);
4537add3af4SJames Morse kfree(hw_dom);
4547add3af4SJames Morse }
4557add3af4SJames Morse
mon_domain_free(struct rdt_hw_mon_domain * hw_dom)456cae2bcb6STony Luck static void mon_domain_free(struct rdt_hw_mon_domain *hw_dom)
457fa7d9493SBabu Moger {
458cae2bcb6STony Luck kfree(hw_dom->arch_mbm_total);
459cae2bcb6STony Luck kfree(hw_dom->arch_mbm_local);
460cae2bcb6STony Luck kfree(hw_dom);
461cae2bcb6STony Luck }
462cae2bcb6STony Luck
domain_setup_ctrlval(struct rdt_resource * r,struct rdt_ctrl_domain * d)463cae2bcb6STony Luck static int domain_setup_ctrlval(struct rdt_resource *r, struct rdt_ctrl_domain *d)
464cae2bcb6STony Luck {
465cae2bcb6STony Luck struct rdt_hw_ctrl_domain *hw_dom = resctrl_to_arch_ctrl_dom(d);
46663c8b123SJames Morse struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
467fa7d9493SBabu Moger struct msr_param m;
468b58d4eb1SJames Morse u32 *dc;
469fa7d9493SBabu Moger
4705c3b63cdSJames Morse dc = kmalloc_array(hw_res->num_closid, sizeof(*hw_dom->ctrl_val),
4715c3b63cdSJames Morse GFP_KERNEL);
472fa7d9493SBabu Moger if (!dc)
473fa7d9493SBabu Moger return -ENOMEM;
474fa7d9493SBabu Moger
475792e0f6fSJames Morse hw_dom->ctrl_val = dc;
476b58d4eb1SJames Morse setup_default_ctrlval(r, dc);
477fa7d9493SBabu Moger
478bd4955d4STony Luck m.res = r;
479e3ca96e4STony Luck m.dom = d;
480fa7d9493SBabu Moger m.low = 0;
48163c8b123SJames Morse m.high = hw_res->num_closid;
482bd4955d4STony Luck hw_res->msr_update(&m);
483fa7d9493SBabu Moger return 0;
484fa7d9493SBabu Moger }
485fa7d9493SBabu Moger
48648dbe31aSJames Morse /**
48748dbe31aSJames Morse * arch_domain_mbm_alloc() - Allocate arch private storage for the MBM counters
48848dbe31aSJames Morse * @num_rmid: The size of the MBM counter array
48948dbe31aSJames Morse * @hw_dom: The domain that owns the allocated arrays
49048dbe31aSJames Morse */
arch_domain_mbm_alloc(u32 num_rmid,struct rdt_hw_mon_domain * hw_dom)491cae2bcb6STony Luck static int arch_domain_mbm_alloc(u32 num_rmid, struct rdt_hw_mon_domain *hw_dom)
49248dbe31aSJames Morse {
49348dbe31aSJames Morse size_t tsize;
49448dbe31aSJames Morse
49548dbe31aSJames Morse if (is_mbm_total_enabled()) {
49648dbe31aSJames Morse tsize = sizeof(*hw_dom->arch_mbm_total);
49748dbe31aSJames Morse hw_dom->arch_mbm_total = kcalloc(num_rmid, tsize, GFP_KERNEL);
49848dbe31aSJames Morse if (!hw_dom->arch_mbm_total)
49948dbe31aSJames Morse return -ENOMEM;
50048dbe31aSJames Morse }
50148dbe31aSJames Morse if (is_mbm_local_enabled()) {
50248dbe31aSJames Morse tsize = sizeof(*hw_dom->arch_mbm_local);
50348dbe31aSJames Morse hw_dom->arch_mbm_local = kcalloc(num_rmid, tsize, GFP_KERNEL);
50448dbe31aSJames Morse if (!hw_dom->arch_mbm_local) {
50548dbe31aSJames Morse kfree(hw_dom->arch_mbm_total);
50648dbe31aSJames Morse hw_dom->arch_mbm_total = NULL;
50748dbe31aSJames Morse return -ENOMEM;
50848dbe31aSJames Morse }
50948dbe31aSJames Morse }
51048dbe31aSJames Morse
51148dbe31aSJames Morse return 0;
51248dbe31aSJames Morse }
51348dbe31aSJames Morse
get_domain_id_from_scope(int cpu,enum resctrl_scope scope)514f436cb69STony Luck static int get_domain_id_from_scope(int cpu, enum resctrl_scope scope)
515f436cb69STony Luck {
516f436cb69STony Luck switch (scope) {
517f436cb69STony Luck case RESCTRL_L2_CACHE:
518f436cb69STony Luck case RESCTRL_L3_CACHE:
519f436cb69STony Luck return get_cpu_cacheinfo_id(cpu, scope);
5201a171608STony Luck case RESCTRL_L3_NODE:
5211a171608STony Luck return cpu_to_node(cpu);
522f436cb69STony Luck default:
523f436cb69STony Luck break;
524f436cb69STony Luck }
525f436cb69STony Luck
526f436cb69STony Luck return -EINVAL;
527f436cb69STony Luck }
528f436cb69STony Luck
domain_add_cpu_ctrl(int cpu,struct rdt_resource * r)529cd84f72bSTony Luck static void domain_add_cpu_ctrl(int cpu, struct rdt_resource *r)
530fa7d9493SBabu Moger {
531cd84f72bSTony Luck int id = get_domain_id_from_scope(cpu, r->ctrl_scope);
532cae2bcb6STony Luck struct rdt_hw_ctrl_domain *hw_dom;
533fa7d9493SBabu Moger struct list_head *add_pos = NULL;
534cd84f72bSTony Luck struct rdt_domain_hdr *hdr;
535cae2bcb6STony Luck struct rdt_ctrl_domain *d;
5363a7232cdSJames Morse int err;
537fa7d9493SBabu Moger
538fb700810SJames Morse lockdep_assert_held(&domain_list_lock);
539fb700810SJames Morse
540f436cb69STony Luck if (id < 0) {
541cd84f72bSTony Luck pr_warn_once("Can't find control domain id for CPU:%d scope:%d for resource %s\n",
542cd84f72bSTony Luck cpu, r->ctrl_scope, r->name);
543fa7d9493SBabu Moger return;
544fa7d9493SBabu Moger }
545fa7d9493SBabu Moger
546cd84f72bSTony Luck hdr = rdt_find_domain(&r->ctrl_domains, id, &add_pos);
547cd84f72bSTony Luck if (hdr) {
548cd84f72bSTony Luck if (WARN_ON_ONCE(hdr->type != RESCTRL_CTRL_DOMAIN))
549cd84f72bSTony Luck return;
550cae2bcb6STony Luck d = container_of(hdr, struct rdt_ctrl_domain, hdr);
551f436cb69STony Luck
552c103d4d4STony Luck cpumask_set_cpu(cpu, &d->hdr.cpu_mask);
553fae3a13dSBabu Moger if (r->cache.arch_has_per_cpu_cfg)
554fae3a13dSBabu Moger rdt_domain_reconfigure_cdp(r);
555fa7d9493SBabu Moger return;
556fa7d9493SBabu Moger }
557fa7d9493SBabu Moger
558792e0f6fSJames Morse hw_dom = kzalloc_node(sizeof(*hw_dom), GFP_KERNEL, cpu_to_node(cpu));
559792e0f6fSJames Morse if (!hw_dom)
560fa7d9493SBabu Moger return;
561fa7d9493SBabu Moger
562792e0f6fSJames Morse d = &hw_dom->d_resctrl;
563c103d4d4STony Luck d->hdr.id = id;
564cd84f72bSTony Luck d->hdr.type = RESCTRL_CTRL_DOMAIN;
565c103d4d4STony Luck cpumask_set_cpu(cpu, &d->hdr.cpu_mask);
566fa7d9493SBabu Moger
5679fe04507SJames Morse rdt_domain_reconfigure_cdp(r);
5689fe04507SJames Morse
569cd84f72bSTony Luck if (domain_setup_ctrlval(r, d)) {
570cae2bcb6STony Luck ctrl_domain_free(hw_dom);
57148dbe31aSJames Morse return;
57248dbe31aSJames Morse }
57348dbe31aSJames Morse
574c103d4d4STony Luck list_add_tail_rcu(&d->hdr.list, add_pos);
5753a7232cdSJames Morse
576cd84f72bSTony Luck err = resctrl_online_ctrl_domain(r, d);
5773a7232cdSJames Morse if (err) {
578c103d4d4STony Luck list_del_rcu(&d->hdr.list);
579fb700810SJames Morse synchronize_rcu();
580cae2bcb6STony Luck ctrl_domain_free(hw_dom);
581fa7d9493SBabu Moger }
582fa7d9493SBabu Moger }
583fa7d9493SBabu Moger
domain_add_cpu_mon(int cpu,struct rdt_resource * r)584cd84f72bSTony Luck static void domain_add_cpu_mon(int cpu, struct rdt_resource *r)
585fa7d9493SBabu Moger {
586cd84f72bSTony Luck int id = get_domain_id_from_scope(cpu, r->mon_scope);
587cd84f72bSTony Luck struct list_head *add_pos = NULL;
588cae2bcb6STony Luck struct rdt_hw_mon_domain *hw_dom;
589cd84f72bSTony Luck struct rdt_domain_hdr *hdr;
590cae2bcb6STony Luck struct rdt_mon_domain *d;
591cd84f72bSTony Luck int err;
592cd84f72bSTony Luck
593cd84f72bSTony Luck lockdep_assert_held(&domain_list_lock);
594cd84f72bSTony Luck
595cd84f72bSTony Luck if (id < 0) {
596cd84f72bSTony Luck pr_warn_once("Can't find monitor domain id for CPU:%d scope:%d for resource %s\n",
597cd84f72bSTony Luck cpu, r->mon_scope, r->name);
598cd84f72bSTony Luck return;
599cd84f72bSTony Luck }
600cd84f72bSTony Luck
601cd84f72bSTony Luck hdr = rdt_find_domain(&r->mon_domains, id, &add_pos);
602cd84f72bSTony Luck if (hdr) {
603cd84f72bSTony Luck if (WARN_ON_ONCE(hdr->type != RESCTRL_MON_DOMAIN))
604cd84f72bSTony Luck return;
605cae2bcb6STony Luck d = container_of(hdr, struct rdt_mon_domain, hdr);
606cd84f72bSTony Luck
607cd84f72bSTony Luck cpumask_set_cpu(cpu, &d->hdr.cpu_mask);
608cd84f72bSTony Luck return;
609cd84f72bSTony Luck }
610cd84f72bSTony Luck
611cd84f72bSTony Luck hw_dom = kzalloc_node(sizeof(*hw_dom), GFP_KERNEL, cpu_to_node(cpu));
612cd84f72bSTony Luck if (!hw_dom)
613cd84f72bSTony Luck return;
614cd84f72bSTony Luck
615cd84f72bSTony Luck d = &hw_dom->d_resctrl;
616cd84f72bSTony Luck d->hdr.id = id;
617cd84f72bSTony Luck d->hdr.type = RESCTRL_MON_DOMAIN;
618328ea688STony Luck d->ci = get_cpu_cacheinfo_level(cpu, RESCTRL_L3_CACHE);
619328ea688STony Luck if (!d->ci) {
620328ea688STony Luck pr_warn_once("Can't find L3 cache for CPU:%d resource %s\n", cpu, r->name);
621328ea688STony Luck mon_domain_free(hw_dom);
622328ea688STony Luck return;
623328ea688STony Luck }
624cd84f72bSTony Luck cpumask_set_cpu(cpu, &d->hdr.cpu_mask);
625cd84f72bSTony Luck
62621b362ccSTony Luck arch_mon_domain_online(r, d);
62721b362ccSTony Luck
628cd84f72bSTony Luck if (arch_domain_mbm_alloc(r->num_rmid, hw_dom)) {
629cae2bcb6STony Luck mon_domain_free(hw_dom);
630cd84f72bSTony Luck return;
631cd84f72bSTony Luck }
632cd84f72bSTony Luck
633cd84f72bSTony Luck list_add_tail_rcu(&d->hdr.list, add_pos);
634cd84f72bSTony Luck
635cd84f72bSTony Luck err = resctrl_online_mon_domain(r, d);
636cd84f72bSTony Luck if (err) {
637cd84f72bSTony Luck list_del_rcu(&d->hdr.list);
638cd84f72bSTony Luck synchronize_rcu();
639cae2bcb6STony Luck mon_domain_free(hw_dom);
640cd84f72bSTony Luck }
641cd84f72bSTony Luck }
642cd84f72bSTony Luck
domain_add_cpu(int cpu,struct rdt_resource * r)643cd84f72bSTony Luck static void domain_add_cpu(int cpu, struct rdt_resource *r)
644cd84f72bSTony Luck {
645cd84f72bSTony Luck if (r->alloc_capable)
646cd84f72bSTony Luck domain_add_cpu_ctrl(cpu, r);
647cd84f72bSTony Luck if (r->mon_capable)
648cd84f72bSTony Luck domain_add_cpu_mon(cpu, r);
649cd84f72bSTony Luck }
650cd84f72bSTony Luck
domain_remove_cpu_ctrl(int cpu,struct rdt_resource * r)651cd84f72bSTony Luck static void domain_remove_cpu_ctrl(int cpu, struct rdt_resource *r)
652cd84f72bSTony Luck {
653cd84f72bSTony Luck int id = get_domain_id_from_scope(cpu, r->ctrl_scope);
654cae2bcb6STony Luck struct rdt_hw_ctrl_domain *hw_dom;
655cd84f72bSTony Luck struct rdt_domain_hdr *hdr;
656cae2bcb6STony Luck struct rdt_ctrl_domain *d;
657fa7d9493SBabu Moger
658fb700810SJames Morse lockdep_assert_held(&domain_list_lock);
659fb700810SJames Morse
660f436cb69STony Luck if (id < 0) {
661cd84f72bSTony Luck pr_warn_once("Can't find control domain id for CPU:%d scope:%d for resource %s\n",
662cd84f72bSTony Luck cpu, r->ctrl_scope, r->name);
663f436cb69STony Luck return;
664f436cb69STony Luck }
665f436cb69STony Luck
666cd84f72bSTony Luck hdr = rdt_find_domain(&r->ctrl_domains, id, NULL);
667cd84f72bSTony Luck if (!hdr) {
668cd84f72bSTony Luck pr_warn("Can't find control domain for id=%d for CPU %d for resource %s\n",
669cd84f72bSTony Luck id, cpu, r->name);
670fa7d9493SBabu Moger return;
671fa7d9493SBabu Moger }
672cd84f72bSTony Luck
673cd84f72bSTony Luck if (WARN_ON_ONCE(hdr->type != RESCTRL_CTRL_DOMAIN))
674cd84f72bSTony Luck return;
675cd84f72bSTony Luck
676cae2bcb6STony Luck d = container_of(hdr, struct rdt_ctrl_domain, hdr);
677cae2bcb6STony Luck hw_dom = resctrl_to_arch_ctrl_dom(d);
678fa7d9493SBabu Moger
679c103d4d4STony Luck cpumask_clear_cpu(cpu, &d->hdr.cpu_mask);
680c103d4d4STony Luck if (cpumask_empty(&d->hdr.cpu_mask)) {
681cd84f72bSTony Luck resctrl_offline_ctrl_domain(r, d);
682c103d4d4STony Luck list_del_rcu(&d->hdr.list);
683fb700810SJames Morse synchronize_rcu();
684fa7d9493SBabu Moger
685fa7d9493SBabu Moger /*
686cae2bcb6STony Luck * rdt_ctrl_domain "d" is going to be freed below, so clear
687fa7d9493SBabu Moger * its pointer from pseudo_lock_region struct.
688fa7d9493SBabu Moger */
689fa7d9493SBabu Moger if (d->plr)
690fa7d9493SBabu Moger d->plr->d = NULL;
691cae2bcb6STony Luck ctrl_domain_free(hw_dom);
692798fd4b9SJames Morse
693fa7d9493SBabu Moger return;
694fa7d9493SBabu Moger }
695fa7d9493SBabu Moger }
696fa7d9493SBabu Moger
domain_remove_cpu_mon(int cpu,struct rdt_resource * r)697cd84f72bSTony Luck static void domain_remove_cpu_mon(int cpu, struct rdt_resource *r)
698cd84f72bSTony Luck {
699cd84f72bSTony Luck int id = get_domain_id_from_scope(cpu, r->mon_scope);
700cae2bcb6STony Luck struct rdt_hw_mon_domain *hw_dom;
701cd84f72bSTony Luck struct rdt_domain_hdr *hdr;
702cae2bcb6STony Luck struct rdt_mon_domain *d;
703cd84f72bSTony Luck
704cd84f72bSTony Luck lockdep_assert_held(&domain_list_lock);
705cd84f72bSTony Luck
706cd84f72bSTony Luck if (id < 0) {
707cd84f72bSTony Luck pr_warn_once("Can't find monitor domain id for CPU:%d scope:%d for resource %s\n",
708cd84f72bSTony Luck cpu, r->mon_scope, r->name);
709cd84f72bSTony Luck return;
710cd84f72bSTony Luck }
711cd84f72bSTony Luck
712cd84f72bSTony Luck hdr = rdt_find_domain(&r->mon_domains, id, NULL);
713cd84f72bSTony Luck if (!hdr) {
714cd84f72bSTony Luck pr_warn("Can't find monitor domain for id=%d for CPU %d for resource %s\n",
715cd84f72bSTony Luck id, cpu, r->name);
716cd84f72bSTony Luck return;
717cd84f72bSTony Luck }
718cd84f72bSTony Luck
719cd84f72bSTony Luck if (WARN_ON_ONCE(hdr->type != RESCTRL_MON_DOMAIN))
720cd84f72bSTony Luck return;
721cd84f72bSTony Luck
722cae2bcb6STony Luck d = container_of(hdr, struct rdt_mon_domain, hdr);
723cae2bcb6STony Luck hw_dom = resctrl_to_arch_mon_dom(d);
724cd84f72bSTony Luck
725cd84f72bSTony Luck cpumask_clear_cpu(cpu, &d->hdr.cpu_mask);
726cd84f72bSTony Luck if (cpumask_empty(&d->hdr.cpu_mask)) {
727cd84f72bSTony Luck resctrl_offline_mon_domain(r, d);
728cd84f72bSTony Luck list_del_rcu(&d->hdr.list);
729cd84f72bSTony Luck synchronize_rcu();
730cae2bcb6STony Luck mon_domain_free(hw_dom);
731cd84f72bSTony Luck
732cd84f72bSTony Luck return;
733cd84f72bSTony Luck }
734cd84f72bSTony Luck }
735cd84f72bSTony Luck
domain_remove_cpu(int cpu,struct rdt_resource * r)736cd84f72bSTony Luck static void domain_remove_cpu(int cpu, struct rdt_resource *r)
737cd84f72bSTony Luck {
738cd84f72bSTony Luck if (r->alloc_capable)
739cd84f72bSTony Luck domain_remove_cpu_ctrl(cpu, r);
740cd84f72bSTony Luck if (r->mon_capable)
741cd84f72bSTony Luck domain_remove_cpu_mon(cpu, r);
742cd84f72bSTony Luck }
743cd84f72bSTony Luck
clear_closid_rmid(int cpu)744fa7d9493SBabu Moger static void clear_closid_rmid(int cpu)
745fa7d9493SBabu Moger {
746352940ecSBabu Moger struct resctrl_pqr_state *state = this_cpu_ptr(&pqr_state);
747fa7d9493SBabu Moger
7486791e0eaSJames Morse state->default_closid = RESCTRL_RESERVED_CLOSID;
7496791e0eaSJames Morse state->default_rmid = RESCTRL_RESERVED_RMID;
7506791e0eaSJames Morse state->cur_closid = RESCTRL_RESERVED_CLOSID;
7516791e0eaSJames Morse state->cur_rmid = RESCTRL_RESERVED_RMID;
7526791e0eaSJames Morse wrmsr(MSR_IA32_PQR_ASSOC, RESCTRL_RESERVED_RMID,
7536791e0eaSJames Morse RESCTRL_RESERVED_CLOSID);
754fa7d9493SBabu Moger }
755fa7d9493SBabu Moger
resctrl_arch_online_cpu(unsigned int cpu)7561b3e50ceSJames Morse static int resctrl_arch_online_cpu(unsigned int cpu)
757fa7d9493SBabu Moger {
758fa7d9493SBabu Moger struct rdt_resource *r;
759fa7d9493SBabu Moger
760fb700810SJames Morse mutex_lock(&domain_list_lock);
761fa7d9493SBabu Moger for_each_capable_rdt_resource(r)
762fa7d9493SBabu Moger domain_add_cpu(cpu, r);
763fb700810SJames Morse mutex_unlock(&domain_list_lock);
7641b3e50ceSJames Morse
765fb700810SJames Morse clear_closid_rmid(cpu);
7661b3e50ceSJames Morse resctrl_online_cpu(cpu);
767fa7d9493SBabu Moger
768fa7d9493SBabu Moger return 0;
769fa7d9493SBabu Moger }
770fa7d9493SBabu Moger
resctrl_arch_offline_cpu(unsigned int cpu)771258c91e8SJames Morse static int resctrl_arch_offline_cpu(unsigned int cpu)
772fa7d9493SBabu Moger {
773fa7d9493SBabu Moger struct rdt_resource *r;
774fa7d9493SBabu Moger
775258c91e8SJames Morse resctrl_offline_cpu(cpu);
776258c91e8SJames Morse
777fb700810SJames Morse mutex_lock(&domain_list_lock);
778fa7d9493SBabu Moger for_each_capable_rdt_resource(r)
779fa7d9493SBabu Moger domain_remove_cpu(cpu, r);
780fb700810SJames Morse mutex_unlock(&domain_list_lock);
781fb700810SJames Morse
782fa7d9493SBabu Moger clear_closid_rmid(cpu);
783fa7d9493SBabu Moger
784fa7d9493SBabu Moger return 0;
785fa7d9493SBabu Moger }
786fa7d9493SBabu Moger
787fa7d9493SBabu Moger /*
788fa7d9493SBabu Moger * Choose a width for the resource name and resource data based on the
789fa7d9493SBabu Moger * resource that has widest name and cbm.
790fa7d9493SBabu Moger */
rdt_init_padding(void)791fa7d9493SBabu Moger static __init void rdt_init_padding(void)
792fa7d9493SBabu Moger {
793fa7d9493SBabu Moger struct rdt_resource *r;
794fa7d9493SBabu Moger
795fa7d9493SBabu Moger for_each_alloc_capable_rdt_resource(r) {
796fa7d9493SBabu Moger if (r->data_width > max_data_width)
797fa7d9493SBabu Moger max_data_width = r->data_width;
798fa7d9493SBabu Moger }
799fa7d9493SBabu Moger }
800fa7d9493SBabu Moger
801fa7d9493SBabu Moger enum {
802fa7d9493SBabu Moger RDT_FLAG_CMT,
803fa7d9493SBabu Moger RDT_FLAG_MBM_TOTAL,
804fa7d9493SBabu Moger RDT_FLAG_MBM_LOCAL,
805fa7d9493SBabu Moger RDT_FLAG_L3_CAT,
806fa7d9493SBabu Moger RDT_FLAG_L3_CDP,
807fa7d9493SBabu Moger RDT_FLAG_L2_CAT,
808fa7d9493SBabu Moger RDT_FLAG_L2_CDP,
809fa7d9493SBabu Moger RDT_FLAG_MBA,
810a76f65c8SBabu Moger RDT_FLAG_SMBA,
811a76f65c8SBabu Moger RDT_FLAG_BMEC,
812fa7d9493SBabu Moger };
813fa7d9493SBabu Moger
814fa7d9493SBabu Moger #define RDT_OPT(idx, n, f) \
815fa7d9493SBabu Moger [idx] = { \
816fa7d9493SBabu Moger .name = n, \
817fa7d9493SBabu Moger .flag = f \
818fa7d9493SBabu Moger }
819fa7d9493SBabu Moger
820fa7d9493SBabu Moger struct rdt_options {
821fa7d9493SBabu Moger char *name;
822fa7d9493SBabu Moger int flag;
823fa7d9493SBabu Moger bool force_off, force_on;
824fa7d9493SBabu Moger };
825fa7d9493SBabu Moger
826fa7d9493SBabu Moger static struct rdt_options rdt_options[] __initdata = {
827fa7d9493SBabu Moger RDT_OPT(RDT_FLAG_CMT, "cmt", X86_FEATURE_CQM_OCCUP_LLC),
828fa7d9493SBabu Moger RDT_OPT(RDT_FLAG_MBM_TOTAL, "mbmtotal", X86_FEATURE_CQM_MBM_TOTAL),
829fa7d9493SBabu Moger RDT_OPT(RDT_FLAG_MBM_LOCAL, "mbmlocal", X86_FEATURE_CQM_MBM_LOCAL),
830fa7d9493SBabu Moger RDT_OPT(RDT_FLAG_L3_CAT, "l3cat", X86_FEATURE_CAT_L3),
831fa7d9493SBabu Moger RDT_OPT(RDT_FLAG_L3_CDP, "l3cdp", X86_FEATURE_CDP_L3),
832fa7d9493SBabu Moger RDT_OPT(RDT_FLAG_L2_CAT, "l2cat", X86_FEATURE_CAT_L2),
833fa7d9493SBabu Moger RDT_OPT(RDT_FLAG_L2_CDP, "l2cdp", X86_FEATURE_CDP_L2),
834fa7d9493SBabu Moger RDT_OPT(RDT_FLAG_MBA, "mba", X86_FEATURE_MBA),
835a76f65c8SBabu Moger RDT_OPT(RDT_FLAG_SMBA, "smba", X86_FEATURE_SMBA),
836a76f65c8SBabu Moger RDT_OPT(RDT_FLAG_BMEC, "bmec", X86_FEATURE_BMEC),
837fa7d9493SBabu Moger };
838fa7d9493SBabu Moger #define NUM_RDT_OPTIONS ARRAY_SIZE(rdt_options)
839fa7d9493SBabu Moger
set_rdt_options(char * str)840fa7d9493SBabu Moger static int __init set_rdt_options(char *str)
841fa7d9493SBabu Moger {
842fa7d9493SBabu Moger struct rdt_options *o;
843fa7d9493SBabu Moger bool force_off;
844fa7d9493SBabu Moger char *tok;
845fa7d9493SBabu Moger
846fa7d9493SBabu Moger if (*str == '=')
847fa7d9493SBabu Moger str++;
848fa7d9493SBabu Moger while ((tok = strsep(&str, ",")) != NULL) {
849fa7d9493SBabu Moger force_off = *tok == '!';
850fa7d9493SBabu Moger if (force_off)
851fa7d9493SBabu Moger tok++;
852fa7d9493SBabu Moger for (o = rdt_options; o < &rdt_options[NUM_RDT_OPTIONS]; o++) {
853fa7d9493SBabu Moger if (strcmp(tok, o->name) == 0) {
854fa7d9493SBabu Moger if (force_off)
855fa7d9493SBabu Moger o->force_off = true;
856fa7d9493SBabu Moger else
857fa7d9493SBabu Moger o->force_on = true;
858fa7d9493SBabu Moger break;
859fa7d9493SBabu Moger }
860fa7d9493SBabu Moger }
861fa7d9493SBabu Moger }
862fa7d9493SBabu Moger return 1;
863fa7d9493SBabu Moger }
864fa7d9493SBabu Moger __setup("rdt", set_rdt_options);
865fa7d9493SBabu Moger
rdt_cpu_has(int flag)866bd334c86SBabu Moger bool __init rdt_cpu_has(int flag)
867fa7d9493SBabu Moger {
868fa7d9493SBabu Moger bool ret = boot_cpu_has(flag);
869fa7d9493SBabu Moger struct rdt_options *o;
870fa7d9493SBabu Moger
871fa7d9493SBabu Moger if (!ret)
872fa7d9493SBabu Moger return ret;
873fa7d9493SBabu Moger
874fa7d9493SBabu Moger for (o = rdt_options; o < &rdt_options[NUM_RDT_OPTIONS]; o++) {
875fa7d9493SBabu Moger if (flag == o->flag) {
876fa7d9493SBabu Moger if (o->force_off)
877fa7d9493SBabu Moger ret = false;
878fa7d9493SBabu Moger if (o->force_on)
879fa7d9493SBabu Moger ret = true;
880fa7d9493SBabu Moger break;
881fa7d9493SBabu Moger }
882fa7d9493SBabu Moger }
883fa7d9493SBabu Moger return ret;
884fa7d9493SBabu Moger }
885fa7d9493SBabu Moger
get_mem_config(void)8860f00717eSBabu Moger static __init bool get_mem_config(void)
8870f00717eSBabu Moger {
88863c8b123SJames Morse struct rdt_hw_resource *hw_res = &rdt_resources_all[RDT_RESOURCE_MBA];
88963c8b123SJames Morse
8904d05bf71SBabu Moger if (!rdt_cpu_has(X86_FEATURE_MBA))
8914d05bf71SBabu Moger return false;
8924d05bf71SBabu Moger
8934d05bf71SBabu Moger if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
89463c8b123SJames Morse return __get_mem_config_intel(&hw_res->r_resctrl);
8954d05bf71SBabu Moger else if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
89663c8b123SJames Morse return __rdt_get_mem_config_amd(&hw_res->r_resctrl);
8970f00717eSBabu Moger
8980f00717eSBabu Moger return false;
8990f00717eSBabu Moger }
9000f00717eSBabu Moger
get_slow_mem_config(void)9015b6fac3fSBabu Moger static __init bool get_slow_mem_config(void)
9025b6fac3fSBabu Moger {
9035b6fac3fSBabu Moger struct rdt_hw_resource *hw_res = &rdt_resources_all[RDT_RESOURCE_SMBA];
9045b6fac3fSBabu Moger
9055b6fac3fSBabu Moger if (!rdt_cpu_has(X86_FEATURE_SMBA))
9065b6fac3fSBabu Moger return false;
9075b6fac3fSBabu Moger
9085b6fac3fSBabu Moger if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
9095b6fac3fSBabu Moger return __rdt_get_mem_config_amd(&hw_res->r_resctrl);
9105b6fac3fSBabu Moger
9115b6fac3fSBabu Moger return false;
9125b6fac3fSBabu Moger }
9135b6fac3fSBabu Moger
get_rdt_alloc_resources(void)914fa7d9493SBabu Moger static __init bool get_rdt_alloc_resources(void)
915fa7d9493SBabu Moger {
91663c8b123SJames Morse struct rdt_resource *r;
917fa7d9493SBabu Moger bool ret = false;
918fa7d9493SBabu Moger
919fa7d9493SBabu Moger if (rdt_alloc_capable)
920fa7d9493SBabu Moger return true;
921fa7d9493SBabu Moger
922fa7d9493SBabu Moger if (!boot_cpu_has(X86_FEATURE_RDT_A))
923fa7d9493SBabu Moger return false;
924fa7d9493SBabu Moger
925fa7d9493SBabu Moger if (rdt_cpu_has(X86_FEATURE_CAT_L3)) {
92663c8b123SJames Morse r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
92763c8b123SJames Morse rdt_get_cache_alloc_cfg(1, r);
928fa7d9493SBabu Moger if (rdt_cpu_has(X86_FEATURE_CDP_L3))
929fa7d9493SBabu Moger rdt_get_cdp_l3_config();
930fa7d9493SBabu Moger ret = true;
931fa7d9493SBabu Moger }
932fa7d9493SBabu Moger if (rdt_cpu_has(X86_FEATURE_CAT_L2)) {
933fa7d9493SBabu Moger /* CPUID 0x10.2 fields are same format at 0x10.1 */
93463c8b123SJames Morse r = &rdt_resources_all[RDT_RESOURCE_L2].r_resctrl;
93563c8b123SJames Morse rdt_get_cache_alloc_cfg(2, r);
936fa7d9493SBabu Moger if (rdt_cpu_has(X86_FEATURE_CDP_L2))
937fa7d9493SBabu Moger rdt_get_cdp_l2_config();
938fa7d9493SBabu Moger ret = true;
939fa7d9493SBabu Moger }
940fa7d9493SBabu Moger
9410f00717eSBabu Moger if (get_mem_config())
942fa7d9493SBabu Moger ret = true;
9430f00717eSBabu Moger
9445b6fac3fSBabu Moger if (get_slow_mem_config())
9455b6fac3fSBabu Moger ret = true;
9465b6fac3fSBabu Moger
947fa7d9493SBabu Moger return ret;
948fa7d9493SBabu Moger }
949fa7d9493SBabu Moger
get_rdt_mon_resources(void)950fa7d9493SBabu Moger static __init bool get_rdt_mon_resources(void)
951fa7d9493SBabu Moger {
95263c8b123SJames Morse struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
95363c8b123SJames Morse
954fa7d9493SBabu Moger if (rdt_cpu_has(X86_FEATURE_CQM_OCCUP_LLC))
955fa7d9493SBabu Moger rdt_mon_features |= (1 << QOS_L3_OCCUP_EVENT_ID);
956fa7d9493SBabu Moger if (rdt_cpu_has(X86_FEATURE_CQM_MBM_TOTAL))
957fa7d9493SBabu Moger rdt_mon_features |= (1 << QOS_L3_MBM_TOTAL_EVENT_ID);
958fa7d9493SBabu Moger if (rdt_cpu_has(X86_FEATURE_CQM_MBM_LOCAL))
959fa7d9493SBabu Moger rdt_mon_features |= (1 << QOS_L3_MBM_LOCAL_EVENT_ID);
960fa7d9493SBabu Moger
961fa7d9493SBabu Moger if (!rdt_mon_features)
962fa7d9493SBabu Moger return false;
963fa7d9493SBabu Moger
96463c8b123SJames Morse return !rdt_get_mon_l3_config(r);
965fa7d9493SBabu Moger }
966fa7d9493SBabu Moger
__check_quirks_intel(void)9670f00717eSBabu Moger static __init void __check_quirks_intel(void)
968fa7d9493SBabu Moger {
969db99675eSTony Luck switch (boot_cpu_data.x86_vfm) {
970db99675eSTony Luck case INTEL_HASWELL_X:
971fa7d9493SBabu Moger if (!rdt_options[RDT_FLAG_L3_CAT].force_off)
972fa7d9493SBabu Moger cache_alloc_hsw_probe();
973fa7d9493SBabu Moger break;
974db99675eSTony Luck case INTEL_SKYLAKE_X:
975fa7d9493SBabu Moger if (boot_cpu_data.x86_stepping <= 4)
976fa7d9493SBabu Moger set_rdt_options("!cmt,!mbmtotal,!mbmlocal,!l3cat");
977fa7d9493SBabu Moger else
978fa7d9493SBabu Moger set_rdt_options("!l3cat");
9794868a61dSFenghua Yu fallthrough;
980db99675eSTony Luck case INTEL_BROADWELL_X:
9814868a61dSFenghua Yu intel_rdt_mbm_apply_quirk();
9824868a61dSFenghua Yu break;
983fa7d9493SBabu Moger }
984fa7d9493SBabu Moger }
985fa7d9493SBabu Moger
check_quirks(void)9860f00717eSBabu Moger static __init void check_quirks(void)
9870f00717eSBabu Moger {
9880f00717eSBabu Moger if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
9890f00717eSBabu Moger __check_quirks_intel();
9900f00717eSBabu Moger }
9910f00717eSBabu Moger
get_rdt_resources(void)992fa7d9493SBabu Moger static __init bool get_rdt_resources(void)
993fa7d9493SBabu Moger {
994fa7d9493SBabu Moger rdt_alloc_capable = get_rdt_alloc_resources();
995fa7d9493SBabu Moger rdt_mon_capable = get_rdt_mon_resources();
996fa7d9493SBabu Moger
997fa7d9493SBabu Moger return (rdt_mon_capable || rdt_alloc_capable);
998fa7d9493SBabu Moger }
999fa7d9493SBabu Moger
rdt_init_res_defs_intel(void)10001ad4fa41SBabu Moger static __init void rdt_init_res_defs_intel(void)
10011ad4fa41SBabu Moger {
100263c8b123SJames Morse struct rdt_hw_resource *hw_res;
10031ad4fa41SBabu Moger struct rdt_resource *r;
10041ad4fa41SBabu Moger
10051ad4fa41SBabu Moger for_each_rdt_resource(r) {
100663c8b123SJames Morse hw_res = resctrl_to_arch_res(r);
100763c8b123SJames Morse
1008a36c5ff5SBabu Moger if (r->rid == RDT_RESOURCE_L3 ||
10095c3b63cdSJames Morse r->rid == RDT_RESOURCE_L2) {
1010fae3a13dSBabu Moger r->cache.arch_has_per_cpu_cfg = false;
101167bf6493SBabu Moger r->cache.min_cbm_bits = 1;
1012316e7f90SJames Morse } else if (r->rid == RDT_RESOURCE_MBA) {
101363c8b123SJames Morse hw_res->msr_base = MSR_IA32_MBA_THRTL_BASE;
101463c8b123SJames Morse hw_res->msr_update = mba_wrmsr_intel;
10151ad4fa41SBabu Moger }
10161ad4fa41SBabu Moger }
10171ad4fa41SBabu Moger }
10181ad4fa41SBabu Moger
rdt_init_res_defs_amd(void)10194d05bf71SBabu Moger static __init void rdt_init_res_defs_amd(void)
10204d05bf71SBabu Moger {
102163c8b123SJames Morse struct rdt_hw_resource *hw_res;
10224d05bf71SBabu Moger struct rdt_resource *r;
10234d05bf71SBabu Moger
10244d05bf71SBabu Moger for_each_rdt_resource(r) {
102563c8b123SJames Morse hw_res = resctrl_to_arch_res(r);
102663c8b123SJames Morse
10274d05bf71SBabu Moger if (r->rid == RDT_RESOURCE_L3 ||
10285c3b63cdSJames Morse r->rid == RDT_RESOURCE_L2) {
102939c6eed1SMaciej Wieczor-Retman r->cache.arch_has_sparse_bitmasks = true;
1030fae3a13dSBabu Moger r->cache.arch_has_per_cpu_cfg = true;
103167bf6493SBabu Moger r->cache.min_cbm_bits = 0;
1032316e7f90SJames Morse } else if (r->rid == RDT_RESOURCE_MBA) {
103363c8b123SJames Morse hw_res->msr_base = MSR_IA32_MBA_BW_BASE;
103463c8b123SJames Morse hw_res->msr_update = mba_wrmsr_amd;
10355b6fac3fSBabu Moger } else if (r->rid == RDT_RESOURCE_SMBA) {
10365b6fac3fSBabu Moger hw_res->msr_base = MSR_IA32_SMBA_BW_BASE;
10375b6fac3fSBabu Moger hw_res->msr_update = mba_wrmsr_amd;
10384d05bf71SBabu Moger }
10394d05bf71SBabu Moger }
10404d05bf71SBabu Moger }
10414d05bf71SBabu Moger
rdt_init_res_defs(void)10421ad4fa41SBabu Moger static __init void rdt_init_res_defs(void)
10431ad4fa41SBabu Moger {
10441ad4fa41SBabu Moger if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
10451ad4fa41SBabu Moger rdt_init_res_defs_intel();
10464d05bf71SBabu Moger else if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
10474d05bf71SBabu Moger rdt_init_res_defs_amd();
10481ad4fa41SBabu Moger }
10491ad4fa41SBabu Moger
1050fa7d9493SBabu Moger static enum cpuhp_state rdt_online;
1051fa7d9493SBabu Moger
1052923f3a2bSReinette Chatre /* Runs once on the BSP during boot. */
resctrl_cpu_detect(struct cpuinfo_x86 * c)10530118ad82SReinette Chatre void resctrl_cpu_detect(struct cpuinfo_x86 *c)
10540118ad82SReinette Chatre {
10550118ad82SReinette Chatre if (!cpu_has(c, X86_FEATURE_CQM_LLC)) {
10560118ad82SReinette Chatre c->x86_cache_max_rmid = -1;
10570118ad82SReinette Chatre c->x86_cache_occ_scale = -1;
1058f3d44f18SReinette Chatre c->x86_cache_mbm_width_offset = -1;
10590118ad82SReinette Chatre return;
10600118ad82SReinette Chatre }
10610118ad82SReinette Chatre
10620118ad82SReinette Chatre /* will be overridden if occupancy monitoring exists */
10630118ad82SReinette Chatre c->x86_cache_max_rmid = cpuid_ebx(0xf);
10640118ad82SReinette Chatre
10650118ad82SReinette Chatre if (cpu_has(c, X86_FEATURE_CQM_OCCUP_LLC) ||
10660118ad82SReinette Chatre cpu_has(c, X86_FEATURE_CQM_MBM_TOTAL) ||
10670118ad82SReinette Chatre cpu_has(c, X86_FEATURE_CQM_MBM_LOCAL)) {
10680118ad82SReinette Chatre u32 eax, ebx, ecx, edx;
10690118ad82SReinette Chatre
10700118ad82SReinette Chatre /* QoS sub-leaf, EAX=0Fh, ECX=1 */
10710118ad82SReinette Chatre cpuid_count(0xf, 1, &eax, &ebx, &ecx, &edx);
10720118ad82SReinette Chatre
10730118ad82SReinette Chatre c->x86_cache_max_rmid = ecx;
10740118ad82SReinette Chatre c->x86_cache_occ_scale = ebx;
1075f3d44f18SReinette Chatre c->x86_cache_mbm_width_offset = eax & 0xff;
10762c18bd52SBabu Moger
10772c18bd52SBabu Moger if (c->x86_vendor == X86_VENDOR_AMD && !c->x86_cache_mbm_width_offset)
10782c18bd52SBabu Moger c->x86_cache_mbm_width_offset = MBM_CNTR_WIDTH_OFFSET_AMD;
10790118ad82SReinette Chatre }
10800118ad82SReinette Chatre }
10810118ad82SReinette Chatre
resctrl_late_init(void)1082352940ecSBabu Moger static int __init resctrl_late_init(void)
1083fa7d9493SBabu Moger {
1084fa7d9493SBabu Moger struct rdt_resource *r;
1085fa7d9493SBabu Moger int state, ret;
1086fa7d9493SBabu Moger
10871ad4fa41SBabu Moger /*
10881ad4fa41SBabu Moger * Initialize functions(or definitions) that are different
10891ad4fa41SBabu Moger * between vendors here.
10901ad4fa41SBabu Moger */
10911ad4fa41SBabu Moger rdt_init_res_defs();
10921ad4fa41SBabu Moger
10930f00717eSBabu Moger check_quirks();
10940f00717eSBabu Moger
1095fa7d9493SBabu Moger if (!get_rdt_resources())
1096fa7d9493SBabu Moger return -ENODEV;
1097fa7d9493SBabu Moger
1098fa7d9493SBabu Moger rdt_init_padding();
1099fa7d9493SBabu Moger
1100fa7d9493SBabu Moger state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
1101352940ecSBabu Moger "x86/resctrl/cat:online:",
1102258c91e8SJames Morse resctrl_arch_online_cpu,
1103258c91e8SJames Morse resctrl_arch_offline_cpu);
1104fa7d9493SBabu Moger if (state < 0)
1105fa7d9493SBabu Moger return state;
1106fa7d9493SBabu Moger
1107fa7d9493SBabu Moger ret = rdtgroup_init();
1108fa7d9493SBabu Moger if (ret) {
1109fa7d9493SBabu Moger cpuhp_remove_state(state);
1110fa7d9493SBabu Moger return ret;
1111fa7d9493SBabu Moger }
1112fa7d9493SBabu Moger rdt_online = state;
1113fa7d9493SBabu Moger
1114fa7d9493SBabu Moger for_each_alloc_capable_rdt_resource(r)
1115352940ecSBabu Moger pr_info("%s allocation detected\n", r->name);
1116fa7d9493SBabu Moger
1117fa7d9493SBabu Moger for_each_mon_capable_rdt_resource(r)
1118352940ecSBabu Moger pr_info("%s monitoring detected\n", r->name);
1119fa7d9493SBabu Moger
1120fa7d9493SBabu Moger return 0;
1121fa7d9493SBabu Moger }
1122fa7d9493SBabu Moger
1123352940ecSBabu Moger late_initcall(resctrl_late_init);
1124fa7d9493SBabu Moger
resctrl_exit(void)1125352940ecSBabu Moger static void __exit resctrl_exit(void)
1126fa7d9493SBabu Moger {
11273f7b0738SJames Morse struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3].r_resctrl;
11283f7b0738SJames Morse
1129fa7d9493SBabu Moger cpuhp_remove_state(rdt_online);
11303f7b0738SJames Morse
1131fa7d9493SBabu Moger rdtgroup_exit();
11323f7b0738SJames Morse
11333f7b0738SJames Morse if (r->mon_capable)
11343f7b0738SJames Morse rdt_put_mon_l3_config();
1135fa7d9493SBabu Moger }
1136fa7d9493SBabu Moger
1137352940ecSBabu Moger __exitcall(resctrl_exit);
1138