aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/intel_rdt.h26
-rw-r--r--arch/x86/kernel/cpu/Makefile2
-rw-r--r--arch/x86/kernel/cpu/intel_rdt.c8
-rw-r--r--arch/x86/kernel/cpu/intel_rdt_rdtgroup.c271
-rw-r--r--include/uapi/linux/magic.h1
5 files changed, 306 insertions, 2 deletions
diff --git a/arch/x86/include/asm/intel_rdt.h b/arch/x86/include/asm/intel_rdt.h
index c0d0a6e6448c..09d00e6f7ad6 100644
--- a/arch/x86/include/asm/intel_rdt.h
+++ b/arch/x86/include/asm/intel_rdt.h
@@ -1,9 +1,31 @@
1#ifndef _ASM_X86_INTEL_RDT_H 1#ifndef _ASM_X86_INTEL_RDT_H
2#define _ASM_X86_INTEL_RDT_H 2#define _ASM_X86_INTEL_RDT_H
3 3
4#include <linux/jump_label.h>
5
6#define IA32_L3_QOS_CFG 0xc81
4#define IA32_L3_CBM_BASE 0xc90 7#define IA32_L3_CBM_BASE 0xc90
5#define IA32_L2_CBM_BASE 0xd10 8#define IA32_L2_CBM_BASE 0xd10
6 9
10#define L3_QOS_CDP_ENABLE 0x01ULL
11
12/**
13 * struct rdtgroup - store rdtgroup's data in resctrl file system.
14 * @kn: kernfs node
15 * @rdtgroup_list: linked list for all rdtgroups
16 * @closid: closid for this rdtgroup
17 */
18struct rdtgroup {
19 struct kernfs_node *kn;
20 struct list_head rdtgroup_list;
21 int closid;
22};
23
24/* List of all resource groups */
25extern struct list_head rdt_all_groups;
26
27int __init rdtgroup_init(void);
28
7/** 29/**
8 * struct rdt_resource - attributes of an RDT resource 30 * struct rdt_resource - attributes of an RDT resource
9 * @enabled: Is this feature enabled on this machine 31 * @enabled: Is this feature enabled on this machine
@@ -68,6 +90,10 @@ struct msr_param {
68extern struct mutex rdtgroup_mutex; 90extern struct mutex rdtgroup_mutex;
69 91
70extern struct rdt_resource rdt_resources_all[]; 92extern struct rdt_resource rdt_resources_all[];
93extern struct rdtgroup rdtgroup_default;
94DECLARE_STATIC_KEY_FALSE(rdt_enable_key);
95
96int __init rdtgroup_init(void);
71 97
72enum { 98enum {
73 RDT_RESOURCE_L3, 99 RDT_RESOURCE_L3,
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
index cf4bfd030c0c..b4334e86c1a9 100644
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -34,7 +34,7 @@ obj-$(CONFIG_CPU_SUP_CENTAUR) += centaur.o
34obj-$(CONFIG_CPU_SUP_TRANSMETA_32) += transmeta.o 34obj-$(CONFIG_CPU_SUP_TRANSMETA_32) += transmeta.o
35obj-$(CONFIG_CPU_SUP_UMC_32) += umc.o 35obj-$(CONFIG_CPU_SUP_UMC_32) += umc.o
36 36
37obj-$(CONFIG_INTEL_RDT_A) += intel_rdt.o 37obj-$(CONFIG_INTEL_RDT_A) += intel_rdt.o intel_rdt_rdtgroup.o
38 38
39obj-$(CONFIG_X86_MCE) += mcheck/ 39obj-$(CONFIG_X86_MCE) += mcheck/
40obj-$(CONFIG_MTRR) += mtrr/ 40obj-$(CONFIG_MTRR) += mtrr/
diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c
index 3d4b397a1181..9d95414f7117 100644
--- a/arch/x86/kernel/cpu/intel_rdt.c
+++ b/arch/x86/kernel/cpu/intel_rdt.c
@@ -361,7 +361,7 @@ static int intel_rdt_offline_cpu(unsigned int cpu)
361static int __init intel_rdt_late_init(void) 361static int __init intel_rdt_late_init(void)
362{ 362{
363 struct rdt_resource *r; 363 struct rdt_resource *r;
364 int state; 364 int state, ret;
365 365
366 if (!get_rdt_resources()) 366 if (!get_rdt_resources())
367 return -ENODEV; 367 return -ENODEV;
@@ -372,6 +372,12 @@ static int __init intel_rdt_late_init(void)
372 if (state < 0) 372 if (state < 0)
373 return state; 373 return state;
374 374
375 ret = rdtgroup_init();
376 if (ret) {
377 cpuhp_remove_state(state);
378 return ret;
379 }
380
375 for_each_capable_rdt_resource(r) 381 for_each_capable_rdt_resource(r)
376 pr_info("Intel RDT %s allocation detected\n", r->name); 382 pr_info("Intel RDT %s allocation detected\n", r->name);
377 383
diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
new file mode 100644
index 000000000000..106e4ce8f7e0
--- /dev/null
+++ b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
@@ -0,0 +1,271 @@
1/*
2 * User interface for Resource Alloction in Resource Director Technology(RDT)
3 *
4 * Copyright (C) 2016 Intel Corporation
5 *
6 * Author: Fenghua Yu <fenghua.yu@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * More information about RDT be found in the Intel (R) x86 Architecture
18 * Software Developer Manual.
19 */
20
21#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22
23#include <linux/fs.h>
24#include <linux/sysfs.h>
25#include <linux/kernfs.h>
26#include <linux/slab.h>
27
28#include <uapi/linux/magic.h>
29
30#include <asm/intel_rdt.h>
31
32DEFINE_STATIC_KEY_FALSE(rdt_enable_key);
33struct kernfs_root *rdt_root;
34struct rdtgroup rdtgroup_default;
35LIST_HEAD(rdt_all_groups);
36
37static void l3_qos_cfg_update(void *arg)
38{
39 bool *enable = arg;
40
41 wrmsrl(IA32_L3_QOS_CFG, *enable ? L3_QOS_CDP_ENABLE : 0ULL);
42}
43
44static int set_l3_qos_cfg(struct rdt_resource *r, bool enable)
45{
46 cpumask_var_t cpu_mask;
47 struct rdt_domain *d;
48 int cpu;
49
50 if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
51 return -ENOMEM;
52
53 list_for_each_entry(d, &r->domains, list) {
54 /* Pick one CPU from each domain instance to update MSR */
55 cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
56 }
57 cpu = get_cpu();
58 /* Update QOS_CFG MSR on this cpu if it's in cpu_mask. */
59 if (cpumask_test_cpu(cpu, cpu_mask))
60 l3_qos_cfg_update(&enable);
61 /* Update QOS_CFG MSR on all other cpus in cpu_mask. */
62 smp_call_function_many(cpu_mask, l3_qos_cfg_update, &enable, 1);
63 put_cpu();
64
65 free_cpumask_var(cpu_mask);
66
67 return 0;
68}
69
70static int cdp_enable(void)
71{
72 struct rdt_resource *r_l3data = &rdt_resources_all[RDT_RESOURCE_L3DATA];
73 struct rdt_resource *r_l3code = &rdt_resources_all[RDT_RESOURCE_L3CODE];
74 struct rdt_resource *r_l3 = &rdt_resources_all[RDT_RESOURCE_L3];
75 int ret;
76
77 if (!r_l3->capable || !r_l3data->capable || !r_l3code->capable)
78 return -EINVAL;
79
80 ret = set_l3_qos_cfg(r_l3, true);
81 if (!ret) {
82 r_l3->enabled = false;
83 r_l3data->enabled = true;
84 r_l3code->enabled = true;
85 }
86 return ret;
87}
88
89static void cdp_disable(void)
90{
91 struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3];
92
93 r->enabled = r->capable;
94
95 if (rdt_resources_all[RDT_RESOURCE_L3DATA].enabled) {
96 rdt_resources_all[RDT_RESOURCE_L3DATA].enabled = false;
97 rdt_resources_all[RDT_RESOURCE_L3CODE].enabled = false;
98 set_l3_qos_cfg(r, false);
99 }
100}
101
102static int parse_rdtgroupfs_options(char *data)
103{
104 char *token, *o = data;
105 int ret = 0;
106
107 while ((token = strsep(&o, ",")) != NULL) {
108 if (!*token)
109 return -EINVAL;
110
111 if (!strcmp(token, "cdp"))
112 ret = cdp_enable();
113 }
114
115 return ret;
116}
117
118static struct dentry *rdt_mount(struct file_system_type *fs_type,
119 int flags, const char *unused_dev_name,
120 void *data)
121{
122 struct dentry *dentry;
123 int ret;
124
125 mutex_lock(&rdtgroup_mutex);
126 /*
127 * resctrl file system can only be mounted once.
128 */
129 if (static_branch_unlikely(&rdt_enable_key)) {
130 dentry = ERR_PTR(-EBUSY);
131 goto out;
132 }
133
134 ret = parse_rdtgroupfs_options(data);
135 if (ret) {
136 dentry = ERR_PTR(ret);
137 goto out_cdp;
138 }
139
140 dentry = kernfs_mount(fs_type, flags, rdt_root,
141 RDTGROUP_SUPER_MAGIC, NULL);
142 if (IS_ERR(dentry))
143 goto out_cdp;
144
145 static_branch_enable(&rdt_enable_key);
146 goto out;
147
148out_cdp:
149 cdp_disable();
150out:
151 mutex_unlock(&rdtgroup_mutex);
152
153 return dentry;
154}
155
156static int reset_all_cbms(struct rdt_resource *r)
157{
158 struct msr_param msr_param;
159 cpumask_var_t cpu_mask;
160 struct rdt_domain *d;
161 int i, cpu;
162
163 if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
164 return -ENOMEM;
165
166 msr_param.res = r;
167 msr_param.low = 0;
168 msr_param.high = r->num_closid;
169
170 /*
171 * Disable resource control for this resource by setting all
172 * CBMs in all domains to the maximum mask value. Pick one CPU
173 * from each domain to update the MSRs below.
174 */
175 list_for_each_entry(d, &r->domains, list) {
176 cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
177
178 for (i = 0; i < r->num_closid; i++)
179 d->cbm[i] = r->max_cbm;
180 }
181 cpu = get_cpu();
182 /* Update CBM on this cpu if it's in cpu_mask. */
183 if (cpumask_test_cpu(cpu, cpu_mask))
184 rdt_cbm_update(&msr_param);
185 /* Update CBM on all other cpus in cpu_mask. */
186 smp_call_function_many(cpu_mask, rdt_cbm_update, &msr_param, 1);
187 put_cpu();
188
189 free_cpumask_var(cpu_mask);
190
191 return 0;
192}
193
194static void rdt_kill_sb(struct super_block *sb)
195{
196 struct rdt_resource *r;
197
198 mutex_lock(&rdtgroup_mutex);
199
200 /*Put everything back to default values. */
201 for_each_enabled_rdt_resource(r)
202 reset_all_cbms(r);
203 cdp_disable();
204 static_branch_disable(&rdt_enable_key);
205 kernfs_kill_sb(sb);
206 mutex_unlock(&rdtgroup_mutex);
207}
208
209static struct file_system_type rdt_fs_type = {
210 .name = "resctrl",
211 .mount = rdt_mount,
212 .kill_sb = rdt_kill_sb,
213};
214
215static struct kernfs_syscall_ops rdtgroup_kf_syscall_ops = {
216};
217
218static int __init rdtgroup_setup_root(void)
219{
220 rdt_root = kernfs_create_root(&rdtgroup_kf_syscall_ops,
221 KERNFS_ROOT_CREATE_DEACTIVATED,
222 &rdtgroup_default);
223 if (IS_ERR(rdt_root))
224 return PTR_ERR(rdt_root);
225
226 mutex_lock(&rdtgroup_mutex);
227
228 rdtgroup_default.closid = 0;
229 list_add(&rdtgroup_default.rdtgroup_list, &rdt_all_groups);
230
231 rdtgroup_default.kn = rdt_root->kn;
232 kernfs_activate(rdtgroup_default.kn);
233
234 mutex_unlock(&rdtgroup_mutex);
235
236 return 0;
237}
238
239/*
240 * rdtgroup_init - rdtgroup initialization
241 *
242 * Setup resctrl file system including set up root, create mount point,
243 * register rdtgroup filesystem, and initialize files under root directory.
244 *
245 * Return: 0 on success or -errno
246 */
247int __init rdtgroup_init(void)
248{
249 int ret = 0;
250
251 ret = rdtgroup_setup_root();
252 if (ret)
253 return ret;
254
255 ret = sysfs_create_mount_point(fs_kobj, "resctrl");
256 if (ret)
257 goto cleanup_root;
258
259 ret = register_filesystem(&rdt_fs_type);
260 if (ret)
261 goto cleanup_mountpoint;
262
263 return 0;
264
265cleanup_mountpoint:
266 sysfs_remove_mount_point(fs_kobj, "resctrl");
267cleanup_root:
268 kernfs_destroy_root(rdt_root);
269
270 return ret;
271}
diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h
index 9bd559472c92..e230af2e6855 100644
--- a/include/uapi/linux/magic.h
+++ b/include/uapi/linux/magic.h
@@ -57,6 +57,7 @@
57#define CGROUP_SUPER_MAGIC 0x27e0eb 57#define CGROUP_SUPER_MAGIC 0x27e0eb
58#define CGROUP2_SUPER_MAGIC 0x63677270 58#define CGROUP2_SUPER_MAGIC 0x63677270
59 59
60#define RDTGROUP_SUPER_MAGIC 0x7655821
60 61
61#define STACK_END_MAGIC 0x57AC6E9D 62#define STACK_END_MAGIC 0x57AC6E9D
62 63