aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu/intel_rdt_schemata.c
diff options
context:
space:
mode:
authorTony Luck <tony.luck@intel.com>2016-10-28 18:04:47 -0400
committerThomas Gleixner <tglx@linutronix.de>2016-10-30 21:10:16 -0400
commit60ec2440c63dea88a5ef13e2b2549730a0d75a37 (patch)
tree7267615654ca4eb05acc3ae2cb82b3c58d3199a7 /arch/x86/kernel/cpu/intel_rdt_schemata.c
parente02737d5b82640497637d18428e2793bb7f02881 (diff)
x86/intel_rdt: Add schemata file
Last of the per resource group files. Also mode 0644. This one shows the resources available to the group. Syntax depends on whether the "cdp" mount option was given. With code/data prioritization disabled it is simply a list of masks for each cache domain. Initial value allows access to all of the L3 cache on all domains. E.g. on a 2 socket Broadwell: L3:0=fffff;1=fffff With CDP enabled, separate masks for data and instructions are provided: L3DATA:0=fffff;1=fffff L3CODE:0=fffff;1=fffff Signed-off-by: Tony Luck <tony.luck@intel.com> Signed-off-by: Fenghua Yu <fenghua.yu@intel.com> Cc: "Ravi V Shankar" <ravi.v.shankar@intel.com> Cc: "Shaohua Li" <shli@fb.com> Cc: "Sai Prakhya" <sai.praneeth.prakhya@intel.com> Cc: "Peter Zijlstra" <peterz@infradead.org> Cc: "Stephane Eranian" <eranian@google.com> Cc: "Dave Hansen" <dave.hansen@intel.com> Cc: "David Carrillo-Cisneros" <davidcc@google.com> Cc: "Nilay Vaish" <nilayvaish@gmail.com> Cc: "Vikas Shivappa" <vikas.shivappa@linux.intel.com> Cc: "Ingo Molnar" <mingo@elte.hu> Cc: "Borislav Petkov" <bp@suse.de> Cc: "H. Peter Anvin" <h.peter.anvin@intel.com> Link: http://lkml.kernel.org/r/1477692289-37412-9-git-send-email-fenghua.yu@intel.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/kernel/cpu/intel_rdt_schemata.c')
-rw-r--r--arch/x86/kernel/cpu/intel_rdt_schemata.c245
1 files changed, 245 insertions, 0 deletions
diff --git a/arch/x86/kernel/cpu/intel_rdt_schemata.c b/arch/x86/kernel/cpu/intel_rdt_schemata.c
new file mode 100644
index 000000000000..f369cb8db0d5
--- /dev/null
+++ b/arch/x86/kernel/cpu/intel_rdt_schemata.c
@@ -0,0 +1,245 @@
1/*
2 * Resource Director Technology(RDT)
3 * - Cache Allocation code.
4 *
5 * Copyright (C) 2016 Intel Corporation
6 *
7 * Authors:
8 * Fenghua Yu <fenghua.yu@intel.com>
9 * Tony Luck <tony.luck@intel.com>
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms and conditions of the GNU General Public License,
13 * version 2, as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * more details.
19 *
20 * More information about RDT be found in the Intel (R) x86 Architecture
21 * Software Developer Manual June 2016, volume 3, section 17.17.
22 */
23
24#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
25
26#include <linux/kernfs.h>
27#include <linux/seq_file.h>
28#include <linux/slab.h>
29#include <asm/intel_rdt.h>
30
31/*
32 * Check whether a cache bit mask is valid. The SDM says:
33 * Please note that all (and only) contiguous '1' combinations
34 * are allowed (e.g. FFFFH, 0FF0H, 003CH, etc.).
35 * Additionally Haswell requires at least two bits set.
36 */
37static bool cbm_validate(unsigned long var, struct rdt_resource *r)
38{
39 unsigned long first_bit, zero_bit;
40
41 if (var == 0 || var > r->max_cbm)
42 return false;
43
44 first_bit = find_first_bit(&var, r->cbm_len);
45 zero_bit = find_next_zero_bit(&var, r->cbm_len, first_bit);
46
47 if (find_next_bit(&var, r->cbm_len, zero_bit) < r->cbm_len)
48 return false;
49
50 if ((zero_bit - first_bit) < r->min_cbm_bits)
51 return false;
52 return true;
53}
54
55/*
56 * Read one cache bit mask (hex). Check that it is valid for the current
57 * resource type.
58 */
59static int parse_cbm(char *buf, struct rdt_resource *r)
60{
61 unsigned long data;
62 int ret;
63
64 ret = kstrtoul(buf, 16, &data);
65 if (ret)
66 return ret;
67 if (!cbm_validate(data, r))
68 return -EINVAL;
69 r->tmp_cbms[r->num_tmp_cbms++] = data;
70
71 return 0;
72}
73
74/*
75 * For each domain in this resource we expect to find a series of:
76 * id=mask
77 * separated by ";". The "id" is in decimal, and must appear in the
78 * right order.
79 */
80static int parse_line(char *line, struct rdt_resource *r)
81{
82 char *dom = NULL, *id;
83 struct rdt_domain *d;
84 unsigned long dom_id;
85
86 list_for_each_entry(d, &r->domains, list) {
87 dom = strsep(&line, ";");
88 if (!dom)
89 return -EINVAL;
90 id = strsep(&dom, "=");
91 if (kstrtoul(id, 10, &dom_id) || dom_id != d->id)
92 return -EINVAL;
93 if (parse_cbm(dom, r))
94 return -EINVAL;
95 }
96
97 /* Any garbage at the end of the line? */
98 if (line && line[0])
99 return -EINVAL;
100 return 0;
101}
102
103static int update_domains(struct rdt_resource *r, int closid)
104{
105 struct msr_param msr_param;
106 cpumask_var_t cpu_mask;
107 struct rdt_domain *d;
108 int cpu, idx = 0;
109
110 if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
111 return -ENOMEM;
112
113 msr_param.low = closid;
114 msr_param.high = msr_param.low + 1;
115 msr_param.res = r;
116
117 list_for_each_entry(d, &r->domains, list) {
118 cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
119 d->cbm[msr_param.low] = r->tmp_cbms[idx++];
120 }
121 cpu = get_cpu();
122 /* Update CBM on this cpu if it's in cpu_mask. */
123 if (cpumask_test_cpu(cpu, cpu_mask))
124 rdt_cbm_update(&msr_param);
125 /* Update CBM on other cpus. */
126 smp_call_function_many(cpu_mask, rdt_cbm_update, &msr_param, 1);
127 put_cpu();
128
129 free_cpumask_var(cpu_mask);
130
131 return 0;
132}
133
134ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
135 char *buf, size_t nbytes, loff_t off)
136{
137 struct rdtgroup *rdtgrp;
138 struct rdt_resource *r;
139 char *tok, *resname;
140 int closid, ret = 0;
141 u32 *l3_cbms = NULL;
142
143 /* Valid input requires a trailing newline */
144 if (nbytes == 0 || buf[nbytes - 1] != '\n')
145 return -EINVAL;
146 buf[nbytes - 1] = '\0';
147
148 rdtgrp = rdtgroup_kn_lock_live(of->kn);
149 if (!rdtgrp) {
150 rdtgroup_kn_unlock(of->kn);
151 return -ENOENT;
152 }
153
154 closid = rdtgrp->closid;
155
156 /* get scratch space to save all the masks while we validate input */
157 for_each_enabled_rdt_resource(r) {
158 r->tmp_cbms = kcalloc(r->num_domains, sizeof(*l3_cbms),
159 GFP_KERNEL);
160 if (!r->tmp_cbms) {
161 ret = -ENOMEM;
162 goto out;
163 }
164 r->num_tmp_cbms = 0;
165 }
166
167 while ((tok = strsep(&buf, "\n")) != NULL) {
168 resname = strsep(&tok, ":");
169 if (!tok) {
170 ret = -EINVAL;
171 goto out;
172 }
173 for_each_enabled_rdt_resource(r) {
174 if (!strcmp(resname, r->name) &&
175 closid < r->num_closid) {
176 ret = parse_line(tok, r);
177 if (ret)
178 goto out;
179 break;
180 }
181 }
182 if (!r->name) {
183 ret = -EINVAL;
184 goto out;
185 }
186 }
187
188 /* Did the parser find all the masks we need? */
189 for_each_enabled_rdt_resource(r) {
190 if (r->num_tmp_cbms != r->num_domains) {
191 ret = -EINVAL;
192 goto out;
193 }
194 }
195
196 for_each_enabled_rdt_resource(r) {
197 ret = update_domains(r, closid);
198 if (ret)
199 goto out;
200 }
201
202out:
203 rdtgroup_kn_unlock(of->kn);
204 for_each_enabled_rdt_resource(r) {
205 kfree(r->tmp_cbms);
206 r->tmp_cbms = NULL;
207 }
208 return ret ?: nbytes;
209}
210
211static void show_doms(struct seq_file *s, struct rdt_resource *r, int closid)
212{
213 struct rdt_domain *dom;
214 bool sep = false;
215
216 seq_printf(s, "%s:", r->name);
217 list_for_each_entry(dom, &r->domains, list) {
218 if (sep)
219 seq_puts(s, ";");
220 seq_printf(s, "%d=%x", dom->id, dom->cbm[closid]);
221 sep = true;
222 }
223 seq_puts(s, "\n");
224}
225
226int rdtgroup_schemata_show(struct kernfs_open_file *of,
227 struct seq_file *s, void *v)
228{
229 struct rdtgroup *rdtgrp;
230 struct rdt_resource *r;
231 int closid, ret = 0;
232
233 rdtgrp = rdtgroup_kn_lock_live(of->kn);
234 if (rdtgrp) {
235 closid = rdtgrp->closid;
236 for_each_enabled_rdt_resource(r) {
237 if (closid < r->num_closid)
238 show_doms(s, r, closid);
239 }
240 } else {
241 ret = -ENOENT;
242 }
243 rdtgroup_kn_unlock(of->kn);
244 return ret;
245}