xref: /linux/arch/x86/kernel/cpu/resctrl/core.c (revision fc5ced75d6dffc9e2a441520b7dc587b95281f86)
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