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 *
12fa7d9493SBabu Moger * More information about RDT be found in the Intel (R) x86 Architecture
13fa7d9493SBabu Moger * Software Developer Manual June 2016, volume 3, section 17.17.
14fa7d9493SBabu Moger */
15fa7d9493SBabu Moger
16fa7d9493SBabu Moger #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17fa7d9493SBabu Moger
18a52fb43aSLinus Torvalds #include <linux/cpu.h>
19fa7d9493SBabu Moger #include <linux/kernfs.h>
20fa7d9493SBabu Moger #include <linux/seq_file.h>
21fa7d9493SBabu Moger #include <linux/slab.h>
22fa7d9493SBabu Moger #include "internal.h"
23fa7d9493SBabu Moger
24fa7d9493SBabu Moger /*
25fa7d9493SBabu Moger * Check whether MBA bandwidth percentage value is correct. The value is
26fa7d9493SBabu Moger * checked against the minimum and max bandwidth values specified by the
27fa7d9493SBabu Moger * hardware. The allocated bandwidth percentage is rounded to the next
28fa7d9493SBabu Moger * control step available on the hardware.
29fa7d9493SBabu Moger */
bw_validate(char * buf,u32 * data,struct rdt_resource * r)30*9e3d07e5SMartin Kletzander static bool bw_validate(char *buf, u32 *data, struct rdt_resource *r)
31fa7d9493SBabu Moger {
32fa7d9493SBabu Moger int ret;
33*9e3d07e5SMartin Kletzander u32 bw;
34fa7d9493SBabu Moger
35fa7d9493SBabu Moger /*
36fa7d9493SBabu Moger * Only linear delay values is supported for current Intel SKUs.
37fa7d9493SBabu Moger */
3841215b79SJames Morse if (!r->membw.delay_linear && r->membw.arch_needs_linear) {
39fa7d9493SBabu Moger rdt_last_cmd_puts("No support for non-linear MB domains\n");
40fa7d9493SBabu Moger return false;
41fa7d9493SBabu Moger }
42fa7d9493SBabu Moger
43*9e3d07e5SMartin Kletzander ret = kstrtou32(buf, 10, &bw);
44fa7d9493SBabu Moger if (ret) {
45*9e3d07e5SMartin Kletzander rdt_last_cmd_printf("Invalid MB value %s\n", buf);
46fa7d9493SBabu Moger return false;
47fa7d9493SBabu Moger }
48fa7d9493SBabu Moger
49*9e3d07e5SMartin Kletzander /* Nothing else to do if software controller is enabled. */
50*9e3d07e5SMartin Kletzander if (is_mba_sc(r)) {
51*9e3d07e5SMartin Kletzander *data = bw;
52*9e3d07e5SMartin Kletzander return true;
53*9e3d07e5SMartin Kletzander }
54*9e3d07e5SMartin Kletzander
55*9e3d07e5SMartin Kletzander if (bw < r->membw.min_bw || bw > r->default_ctrl) {
56*9e3d07e5SMartin Kletzander rdt_last_cmd_printf("MB value %u out of range [%d,%d]\n",
57*9e3d07e5SMartin Kletzander bw, r->membw.min_bw, r->default_ctrl);
58fa7d9493SBabu Moger return false;
59fa7d9493SBabu Moger }
60fa7d9493SBabu Moger
61fa7d9493SBabu Moger *data = roundup(bw, (unsigned long)r->membw.bw_gran);
62fa7d9493SBabu Moger return true;
63fa7d9493SBabu Moger }
64fa7d9493SBabu Moger
parse_bw(struct rdt_parse_data * data,struct resctrl_schema * s,struct rdt_domain * d)651c290682SJames Morse int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s,
66fa7d9493SBabu Moger struct rdt_domain *d)
67fa7d9493SBabu Moger {
6875408e43SJames Morse struct resctrl_staged_config *cfg;
696ce1560dSJames Morse u32 closid = data->rdtgrp->closid;
701c290682SJames Morse struct rdt_resource *r = s->res;
71*9e3d07e5SMartin Kletzander u32 bw_val;
72fa7d9493SBabu Moger
7375408e43SJames Morse cfg = &d->staged_config[s->conf_type];
74e8f72825SJames Morse if (cfg->have_new_ctrl) {
75723f1a0dSBabu Moger rdt_last_cmd_printf("Duplicate domain %d\n", d->id);
76fa7d9493SBabu Moger return -EINVAL;
77fa7d9493SBabu Moger }
78fa7d9493SBabu Moger
79fa7d9493SBabu Moger if (!bw_validate(data->buf, &bw_val, r))
80fa7d9493SBabu Moger return -EINVAL;
816ce1560dSJames Morse
826ce1560dSJames Morse if (is_mba_sc(r)) {
836ce1560dSJames Morse d->mbps_val[closid] = bw_val;
846ce1560dSJames Morse return 0;
856ce1560dSJames Morse }
866ce1560dSJames Morse
87e8f72825SJames Morse cfg->new_ctrl = bw_val;
88e8f72825SJames Morse cfg->have_new_ctrl = true;
89fa7d9493SBabu Moger
90fa7d9493SBabu Moger return 0;
91fa7d9493SBabu Moger }
92fa7d9493SBabu Moger
93fa7d9493SBabu Moger /*
94316e7f90SJames Morse * Check whether a cache bit mask is valid.
95316e7f90SJames Morse * For Intel the SDM says:
96fa7d9493SBabu Moger * Please note that all (and only) contiguous '1' combinations
97fa7d9493SBabu Moger * are allowed (e.g. FFFFH, 0FF0H, 003CH, etc.).
98fa7d9493SBabu Moger * Additionally Haswell requires at least two bits set.
99316e7f90SJames Morse * AMD allows non-contiguous bitmasks.
100fa7d9493SBabu Moger */
cbm_validate(char * buf,u32 * data,struct rdt_resource * r)101316e7f90SJames Morse static bool cbm_validate(char *buf, u32 *data, struct rdt_resource *r)
102fa7d9493SBabu Moger {
103fa7d9493SBabu Moger unsigned long first_bit, zero_bit, val;
104fa7d9493SBabu Moger unsigned int cbm_len = r->cache.cbm_len;
105fa7d9493SBabu Moger int ret;
106fa7d9493SBabu Moger
107fa7d9493SBabu Moger ret = kstrtoul(buf, 16, &val);
108fa7d9493SBabu Moger if (ret) {
109723f1a0dSBabu Moger rdt_last_cmd_printf("Non-hex character in the mask %s\n", buf);
110fa7d9493SBabu Moger return false;
111fa7d9493SBabu Moger }
112fa7d9493SBabu Moger
1132d4daa54SBabu Moger if ((r->cache.min_cbm_bits > 0 && val == 0) || val > r->default_ctrl) {
114723f1a0dSBabu Moger rdt_last_cmd_puts("Mask out of range\n");
115fa7d9493SBabu Moger return false;
116fa7d9493SBabu Moger }
117fa7d9493SBabu Moger
118fa7d9493SBabu Moger first_bit = find_first_bit(&val, cbm_len);
119fa7d9493SBabu Moger zero_bit = find_next_zero_bit(&val, cbm_len, first_bit);
120fa7d9493SBabu Moger
121316e7f90SJames Morse /* Are non-contiguous bitmaps allowed? */
122316e7f90SJames Morse if (!r->cache.arch_has_sparse_bitmaps &&
123316e7f90SJames Morse (find_next_bit(&val, cbm_len, zero_bit) < cbm_len)) {
124723f1a0dSBabu Moger rdt_last_cmd_printf("The mask %lx has non-consecutive 1-bits\n", val);
125fa7d9493SBabu Moger return false;
126fa7d9493SBabu Moger }
127fa7d9493SBabu Moger
128fa7d9493SBabu Moger if ((zero_bit - first_bit) < r->cache.min_cbm_bits) {
129723f1a0dSBabu Moger rdt_last_cmd_printf("Need at least %d bits in the mask\n",
130fa7d9493SBabu Moger r->cache.min_cbm_bits);
131fa7d9493SBabu Moger return false;
132fa7d9493SBabu Moger }
133fa7d9493SBabu Moger
134fa7d9493SBabu Moger *data = val;
135fa7d9493SBabu Moger return true;
136fa7d9493SBabu Moger }
137fa7d9493SBabu Moger
138fa7d9493SBabu Moger /*
139fa7d9493SBabu Moger * Read one cache bit mask (hex). Check that it is valid for the current
140fa7d9493SBabu Moger * resource type.
141fa7d9493SBabu Moger */
parse_cbm(struct rdt_parse_data * data,struct resctrl_schema * s,struct rdt_domain * d)1421c290682SJames Morse int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s,
143fa7d9493SBabu Moger struct rdt_domain *d)
144fa7d9493SBabu Moger {
145fa7d9493SBabu Moger struct rdtgroup *rdtgrp = data->rdtgrp;
14675408e43SJames Morse struct resctrl_staged_config *cfg;
1471c290682SJames Morse struct rdt_resource *r = s->res;
148fa7d9493SBabu Moger u32 cbm_val;
149fa7d9493SBabu Moger
15075408e43SJames Morse cfg = &d->staged_config[s->conf_type];
151e8f72825SJames Morse if (cfg->have_new_ctrl) {
152723f1a0dSBabu Moger rdt_last_cmd_printf("Duplicate domain %d\n", d->id);
153fa7d9493SBabu Moger return -EINVAL;
154fa7d9493SBabu Moger }
155fa7d9493SBabu Moger
156fa7d9493SBabu Moger /*
157fa7d9493SBabu Moger * Cannot set up more than one pseudo-locked region in a cache
158fa7d9493SBabu Moger * hierarchy.
159fa7d9493SBabu Moger */
160fa7d9493SBabu Moger if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP &&
161fa7d9493SBabu Moger rdtgroup_pseudo_locked_in_hierarchy(d)) {
16245682489SReinette Chatre rdt_last_cmd_puts("Pseudo-locked region in hierarchy\n");
163fa7d9493SBabu Moger return -EINVAL;
164fa7d9493SBabu Moger }
165fa7d9493SBabu Moger
166316e7f90SJames Morse if (!cbm_validate(data->buf, &cbm_val, r))
167fa7d9493SBabu Moger return -EINVAL;
168fa7d9493SBabu Moger
169fa7d9493SBabu Moger if ((rdtgrp->mode == RDT_MODE_EXCLUSIVE ||
170fa7d9493SBabu Moger rdtgrp->mode == RDT_MODE_SHAREABLE) &&
171fa7d9493SBabu Moger rdtgroup_cbm_overlaps_pseudo_locked(d, cbm_val)) {
17245682489SReinette Chatre rdt_last_cmd_puts("CBM overlaps with pseudo-locked region\n");
173fa7d9493SBabu Moger return -EINVAL;
174fa7d9493SBabu Moger }
175fa7d9493SBabu Moger
176fa7d9493SBabu Moger /*
177fa7d9493SBabu Moger * The CBM may not overlap with the CBM of another closid if
178fa7d9493SBabu Moger * either is exclusive.
179fa7d9493SBabu Moger */
1801c290682SJames Morse if (rdtgroup_cbm_overlaps(s, d, cbm_val, rdtgrp->closid, true)) {
18145682489SReinette Chatre rdt_last_cmd_puts("Overlaps with exclusive group\n");
182fa7d9493SBabu Moger return -EINVAL;
183fa7d9493SBabu Moger }
184fa7d9493SBabu Moger
1851c290682SJames Morse if (rdtgroup_cbm_overlaps(s, d, cbm_val, rdtgrp->closid, false)) {
186fa7d9493SBabu Moger if (rdtgrp->mode == RDT_MODE_EXCLUSIVE ||
187fa7d9493SBabu Moger rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
18845682489SReinette Chatre rdt_last_cmd_puts("Overlaps with other group\n");
189fa7d9493SBabu Moger return -EINVAL;
190fa7d9493SBabu Moger }
191fa7d9493SBabu Moger }
192fa7d9493SBabu Moger
193e8f72825SJames Morse cfg->new_ctrl = cbm_val;
194e8f72825SJames Morse cfg->have_new_ctrl = true;
195fa7d9493SBabu Moger
196fa7d9493SBabu Moger return 0;
197fa7d9493SBabu Moger }
198fa7d9493SBabu Moger
199fa7d9493SBabu Moger /*
200fa7d9493SBabu Moger * For each domain in this resource we expect to find a series of:
201fa7d9493SBabu Moger * id=mask
202fa7d9493SBabu Moger * separated by ";". The "id" is in decimal, and must match one of
203fa7d9493SBabu Moger * the "id"s for this resource.
204fa7d9493SBabu Moger */
parse_line(char * line,struct resctrl_schema * s,struct rdtgroup * rdtgrp)2051c290682SJames Morse static int parse_line(char *line, struct resctrl_schema *s,
206fa7d9493SBabu Moger struct rdtgroup *rdtgrp)
207fa7d9493SBabu Moger {
20875408e43SJames Morse enum resctrl_conf_type t = s->conf_type;
209e8f72825SJames Morse struct resctrl_staged_config *cfg;
2101c290682SJames Morse struct rdt_resource *r = s->res;
211fa7d9493SBabu Moger struct rdt_parse_data data;
212fa7d9493SBabu Moger char *dom = NULL, *id;
213fa7d9493SBabu Moger struct rdt_domain *d;
214fa7d9493SBabu Moger unsigned long dom_id;
215fa7d9493SBabu Moger
216fa7d9493SBabu Moger if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP &&
2175b6fac3fSBabu Moger (r->rid == RDT_RESOURCE_MBA || r->rid == RDT_RESOURCE_SMBA)) {
218fa7d9493SBabu Moger rdt_last_cmd_puts("Cannot pseudo-lock MBA resource\n");
219fa7d9493SBabu Moger return -EINVAL;
220fa7d9493SBabu Moger }
221fa7d9493SBabu Moger
222fa7d9493SBabu Moger next:
223fa7d9493SBabu Moger if (!line || line[0] == '\0')
224fa7d9493SBabu Moger return 0;
225fa7d9493SBabu Moger dom = strsep(&line, ";");
226fa7d9493SBabu Moger id = strsep(&dom, "=");
227fa7d9493SBabu Moger if (!dom || kstrtoul(id, 10, &dom_id)) {
228fa7d9493SBabu Moger rdt_last_cmd_puts("Missing '=' or non-numeric domain\n");
229fa7d9493SBabu Moger return -EINVAL;
230fa7d9493SBabu Moger }
231fa7d9493SBabu Moger dom = strim(dom);
232fa7d9493SBabu Moger list_for_each_entry(d, &r->domains, list) {
233fa7d9493SBabu Moger if (d->id == dom_id) {
234fa7d9493SBabu Moger data.buf = dom;
235fa7d9493SBabu Moger data.rdtgrp = rdtgrp;
2361c290682SJames Morse if (r->parse_ctrlval(&data, s, d))
237fa7d9493SBabu Moger return -EINVAL;
238fa7d9493SBabu Moger if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
23975408e43SJames Morse cfg = &d->staged_config[t];
240fa7d9493SBabu Moger /*
241fa7d9493SBabu Moger * In pseudo-locking setup mode and just
242fa7d9493SBabu Moger * parsed a valid CBM that should be
243fa7d9493SBabu Moger * pseudo-locked. Only one locked region per
244fa7d9493SBabu Moger * resource group and domain so just do
245fa7d9493SBabu Moger * the required initialization for single
246fa7d9493SBabu Moger * region and return.
247fa7d9493SBabu Moger */
24832150eddSJames Morse rdtgrp->plr->s = s;
249fa7d9493SBabu Moger rdtgrp->plr->d = d;
250e8f72825SJames Morse rdtgrp->plr->cbm = cfg->new_ctrl;
251fa7d9493SBabu Moger d->plr = rdtgrp->plr;
252fa7d9493SBabu Moger return 0;
253fa7d9493SBabu Moger }
254fa7d9493SBabu Moger goto next;
255fa7d9493SBabu Moger }
256fa7d9493SBabu Moger }
257fa7d9493SBabu Moger return -EINVAL;
258fa7d9493SBabu Moger }
259fa7d9493SBabu Moger
get_config_index(u32 closid,enum resctrl_conf_type type)2602b8dd4abSJames Morse static u32 get_config_index(u32 closid, enum resctrl_conf_type type)
2612e7df368SJames Morse {
2622b8dd4abSJames Morse switch (type) {
2632b8dd4abSJames Morse default:
2642b8dd4abSJames Morse case CDP_NONE:
2652e7df368SJames Morse return closid;
2662b8dd4abSJames Morse case CDP_CODE:
2672b8dd4abSJames Morse return closid * 2 + 1;
2682b8dd4abSJames Morse case CDP_DATA:
2692b8dd4abSJames Morse return closid * 2;
2702b8dd4abSJames Morse }
2712e7df368SJames Morse }
2722e7df368SJames Morse
apply_config(struct rdt_hw_domain * hw_dom,struct resctrl_staged_config * cfg,u32 idx,cpumask_var_t cpu_mask)2732e7df368SJames Morse static bool apply_config(struct rdt_hw_domain *hw_dom,
2742e7df368SJames Morse struct resctrl_staged_config *cfg, u32 idx,
2756ce1560dSJames Morse cpumask_var_t cpu_mask)
276e8f72825SJames Morse {
277e8f72825SJames Morse struct rdt_domain *dom = &hw_dom->d_resctrl;
278e8f72825SJames Morse
2796ce1560dSJames Morse if (cfg->new_ctrl != hw_dom->ctrl_val[idx]) {
280e8f72825SJames Morse cpumask_set_cpu(cpumask_any(&dom->cpu_mask), cpu_mask);
2816ce1560dSJames Morse hw_dom->ctrl_val[idx] = cfg->new_ctrl;
2822e7df368SJames Morse
2832e7df368SJames Morse return true;
284e8f72825SJames Morse }
2852e7df368SJames Morse
2862e7df368SJames Morse return false;
287e8f72825SJames Morse }
288e8f72825SJames Morse
resctrl_arch_update_one(struct rdt_resource * r,struct rdt_domain * d,u32 closid,enum resctrl_conf_type t,u32 cfg_val)289ff6357bbSJames Morse int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d,
290ff6357bbSJames Morse u32 closid, enum resctrl_conf_type t, u32 cfg_val)
291ff6357bbSJames Morse {
292ff6357bbSJames Morse struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r);
293ff6357bbSJames Morse struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d);
294ff6357bbSJames Morse u32 idx = get_config_index(closid, t);
295ff6357bbSJames Morse struct msr_param msr_param;
296ff6357bbSJames Morse
297ff6357bbSJames Morse if (!cpumask_test_cpu(smp_processor_id(), &d->cpu_mask))
298ff6357bbSJames Morse return -EINVAL;
299ff6357bbSJames Morse
300ff6357bbSJames Morse hw_dom->ctrl_val[idx] = cfg_val;
301ff6357bbSJames Morse
302ff6357bbSJames Morse msr_param.res = r;
303ff6357bbSJames Morse msr_param.low = idx;
304ff6357bbSJames Morse msr_param.high = idx + 1;
305ff6357bbSJames Morse hw_res->msr_update(d, &msr_param, r);
306ff6357bbSJames Morse
307ff6357bbSJames Morse return 0;
308ff6357bbSJames Morse }
309ff6357bbSJames Morse
resctrl_arch_update_domains(struct rdt_resource * r,u32 closid)3102e667819SJames Morse int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
311fa7d9493SBabu Moger {
312e8f72825SJames Morse struct resctrl_staged_config *cfg;
313792e0f6fSJames Morse struct rdt_hw_domain *hw_dom;
314fa7d9493SBabu Moger struct msr_param msr_param;
31575408e43SJames Morse enum resctrl_conf_type t;
316fa7d9493SBabu Moger cpumask_var_t cpu_mask;
317fa7d9493SBabu Moger struct rdt_domain *d;
3182e7df368SJames Morse u32 idx;
319fa7d9493SBabu Moger
320fa7d9493SBabu Moger if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
321fa7d9493SBabu Moger return -ENOMEM;
322fa7d9493SBabu Moger
323327364d5SJames Morse msr_param.res = NULL;
324fa7d9493SBabu Moger list_for_each_entry(d, &r->domains, list) {
325792e0f6fSJames Morse hw_dom = resctrl_to_arch_dom(d);
32675408e43SJames Morse for (t = 0; t < CDP_NUM_TYPES; t++) {
32775408e43SJames Morse cfg = &hw_dom->d_resctrl.staged_config[t];
32875408e43SJames Morse if (!cfg->have_new_ctrl)
32975408e43SJames Morse continue;
33075408e43SJames Morse
3312b8dd4abSJames Morse idx = get_config_index(closid, t);
3326ce1560dSJames Morse if (!apply_config(hw_dom, cfg, idx, cpu_mask))
3332e7df368SJames Morse continue;
3342b8dd4abSJames Morse
335327364d5SJames Morse if (!msr_param.res) {
3362b8dd4abSJames Morse msr_param.low = idx;
3372b8dd4abSJames Morse msr_param.high = msr_param.low + 1;
3382b8dd4abSJames Morse msr_param.res = r;
339327364d5SJames Morse } else {
340327364d5SJames Morse msr_param.low = min(msr_param.low, idx);
341327364d5SJames Morse msr_param.high = max(msr_param.high, idx + 1);
342327364d5SJames Morse }
343fa7d9493SBabu Moger }
34475408e43SJames Morse }
345fa7d9493SBabu Moger
3466ce1560dSJames Morse if (cpumask_empty(cpu_mask))
347fa7d9493SBabu Moger goto done;
348fc3b618cSBabu Moger
349fc3b618cSBabu Moger /* Update resource control msr on all the CPUs. */
350fc3b618cSBabu Moger on_each_cpu_mask(cpu_mask, rdt_ctrl_update, &msr_param, 1);
351fa7d9493SBabu Moger
352fa7d9493SBabu Moger done:
353fa7d9493SBabu Moger free_cpumask_var(cpu_mask);
354fa7d9493SBabu Moger
355fa7d9493SBabu Moger return 0;
356fa7d9493SBabu Moger }
357fa7d9493SBabu Moger
rdtgroup_parse_resource(char * resname,char * tok,struct rdtgroup * rdtgrp)358fa7d9493SBabu Moger static int rdtgroup_parse_resource(char *resname, char *tok,
359fa7d9493SBabu Moger struct rdtgroup *rdtgrp)
360fa7d9493SBabu Moger {
361331ebe4cSJames Morse struct resctrl_schema *s;
362fa7d9493SBabu Moger
363331ebe4cSJames Morse list_for_each_entry(s, &resctrl_schema_all, list) {
364e198fde3SJames Morse if (!strcmp(resname, s->name) && rdtgrp->closid < s->num_closid)
3651c290682SJames Morse return parse_line(tok, s, rdtgrp);
366fa7d9493SBabu Moger }
367723f1a0dSBabu Moger rdt_last_cmd_printf("Unknown or unsupported resource name '%s'\n", resname);
368fa7d9493SBabu Moger return -EINVAL;
369fa7d9493SBabu Moger }
370fa7d9493SBabu Moger
rdtgroup_schemata_write(struct kernfs_open_file * of,char * buf,size_t nbytes,loff_t off)371fa7d9493SBabu Moger ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
372fa7d9493SBabu Moger char *buf, size_t nbytes, loff_t off)
373fa7d9493SBabu Moger {
374331ebe4cSJames Morse struct resctrl_schema *s;
375fa7d9493SBabu Moger struct rdtgroup *rdtgrp;
376fa7d9493SBabu Moger struct rdt_resource *r;
377fa7d9493SBabu Moger char *tok, *resname;
378fa7d9493SBabu Moger int ret = 0;
379fa7d9493SBabu Moger
380fa7d9493SBabu Moger /* Valid input requires a trailing newline */
381fa7d9493SBabu Moger if (nbytes == 0 || buf[nbytes - 1] != '\n')
382fa7d9493SBabu Moger return -EINVAL;
383fa7d9493SBabu Moger buf[nbytes - 1] = '\0';
384fa7d9493SBabu Moger
385a52fb43aSLinus Torvalds cpus_read_lock();
386fa7d9493SBabu Moger rdtgrp = rdtgroup_kn_lock_live(of->kn);
387fa7d9493SBabu Moger if (!rdtgrp) {
388fa7d9493SBabu Moger rdtgroup_kn_unlock(of->kn);
389a52fb43aSLinus Torvalds cpus_read_unlock();
390fa7d9493SBabu Moger return -ENOENT;
391fa7d9493SBabu Moger }
392fa7d9493SBabu Moger rdt_last_cmd_clear();
393fa7d9493SBabu Moger
394fa7d9493SBabu Moger /*
395fa7d9493SBabu Moger * No changes to pseudo-locked region allowed. It has to be removed
396fa7d9493SBabu Moger * and re-created instead.
397fa7d9493SBabu Moger */
398fa7d9493SBabu Moger if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
399fa7d9493SBabu Moger ret = -EINVAL;
400723f1a0dSBabu Moger rdt_last_cmd_puts("Resource group is pseudo-locked\n");
401fa7d9493SBabu Moger goto out;
402fa7d9493SBabu Moger }
403fa7d9493SBabu Moger
4040424a7dfSShawn Wang rdt_staged_configs_clear();
405fa7d9493SBabu Moger
406fa7d9493SBabu Moger while ((tok = strsep(&buf, "\n")) != NULL) {
407fa7d9493SBabu Moger resname = strim(strsep(&tok, ":"));
408fa7d9493SBabu Moger if (!tok) {
409fa7d9493SBabu Moger rdt_last_cmd_puts("Missing ':'\n");
410fa7d9493SBabu Moger ret = -EINVAL;
411fa7d9493SBabu Moger goto out;
412fa7d9493SBabu Moger }
413fa7d9493SBabu Moger if (tok[0] == '\0') {
414fa7d9493SBabu Moger rdt_last_cmd_printf("Missing '%s' value\n", resname);
415fa7d9493SBabu Moger ret = -EINVAL;
416fa7d9493SBabu Moger goto out;
417fa7d9493SBabu Moger }
418fa7d9493SBabu Moger ret = rdtgroup_parse_resource(resname, tok, rdtgrp);
419fa7d9493SBabu Moger if (ret)
420fa7d9493SBabu Moger goto out;
421fa7d9493SBabu Moger }
422fa7d9493SBabu Moger
423331ebe4cSJames Morse list_for_each_entry(s, &resctrl_schema_all, list) {
424331ebe4cSJames Morse r = s->res;
4256ce1560dSJames Morse
4266ce1560dSJames Morse /*
4276ce1560dSJames Morse * Writes to mba_sc resources update the software controller,
4286ce1560dSJames Morse * not the control MSR.
4296ce1560dSJames Morse */
4306ce1560dSJames Morse if (is_mba_sc(r))
4316ce1560dSJames Morse continue;
4326ce1560dSJames Morse
4332e667819SJames Morse ret = resctrl_arch_update_domains(r, rdtgrp->closid);
434fa7d9493SBabu Moger if (ret)
435fa7d9493SBabu Moger goto out;
436fa7d9493SBabu Moger }
437fa7d9493SBabu Moger
438fa7d9493SBabu Moger if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
439fa7d9493SBabu Moger /*
440fa7d9493SBabu Moger * If pseudo-locking fails we keep the resource group in
441fa7d9493SBabu Moger * mode RDT_MODE_PSEUDO_LOCKSETUP with its class of service
442fa7d9493SBabu Moger * active and updated for just the domain the pseudo-locked
443fa7d9493SBabu Moger * region was requested for.
444fa7d9493SBabu Moger */
445fa7d9493SBabu Moger ret = rdtgroup_pseudo_lock_create(rdtgrp);
446fa7d9493SBabu Moger }
447fa7d9493SBabu Moger
448fa7d9493SBabu Moger out:
4490424a7dfSShawn Wang rdt_staged_configs_clear();
450fa7d9493SBabu Moger rdtgroup_kn_unlock(of->kn);
451a52fb43aSLinus Torvalds cpus_read_unlock();
452fa7d9493SBabu Moger return ret ?: nbytes;
453fa7d9493SBabu Moger }
454fa7d9493SBabu Moger
resctrl_arch_get_config(struct rdt_resource * r,struct rdt_domain * d,u32 closid,enum resctrl_conf_type type)455111136e6SJames Morse u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d,
456111136e6SJames Morse u32 closid, enum resctrl_conf_type type)
457f07e9d02SJames Morse {
458f07e9d02SJames Morse struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d);
4592b8dd4abSJames Morse u32 idx = get_config_index(closid, type);
460f07e9d02SJames Morse
461111136e6SJames Morse return hw_dom->ctrl_val[idx];
462f07e9d02SJames Morse }
463f07e9d02SJames Morse
show_doms(struct seq_file * s,struct resctrl_schema * schema,int closid)4641c290682SJames Morse static void show_doms(struct seq_file *s, struct resctrl_schema *schema, int closid)
465fa7d9493SBabu Moger {
4661c290682SJames Morse struct rdt_resource *r = schema->res;
467fa7d9493SBabu Moger struct rdt_domain *dom;
468fa7d9493SBabu Moger bool sep = false;
469fa7d9493SBabu Moger u32 ctrl_val;
470fa7d9493SBabu Moger
471e198fde3SJames Morse seq_printf(s, "%*s:", max_name_width, schema->name);
472fa7d9493SBabu Moger list_for_each_entry(dom, &r->domains, list) {
473fa7d9493SBabu Moger if (sep)
474fa7d9493SBabu Moger seq_puts(s, ";");
475fa7d9493SBabu Moger
4766ce1560dSJames Morse if (is_mba_sc(r))
4776ce1560dSJames Morse ctrl_val = dom->mbps_val[closid];
4786ce1560dSJames Morse else
479111136e6SJames Morse ctrl_val = resctrl_arch_get_config(r, dom, closid,
480111136e6SJames Morse schema->conf_type);
4816ce1560dSJames Morse
482fa7d9493SBabu Moger seq_printf(s, r->format_str, dom->id, max_data_width,
483fa7d9493SBabu Moger ctrl_val);
484fa7d9493SBabu Moger sep = true;
485fa7d9493SBabu Moger }
486fa7d9493SBabu Moger seq_puts(s, "\n");
487fa7d9493SBabu Moger }
488fa7d9493SBabu Moger
rdtgroup_schemata_show(struct kernfs_open_file * of,struct seq_file * s,void * v)489fa7d9493SBabu Moger int rdtgroup_schemata_show(struct kernfs_open_file *of,
490fa7d9493SBabu Moger struct seq_file *s, void *v)
491fa7d9493SBabu Moger {
492331ebe4cSJames Morse struct resctrl_schema *schema;
493fa7d9493SBabu Moger struct rdtgroup *rdtgrp;
494fa7d9493SBabu Moger int ret = 0;
495fa7d9493SBabu Moger u32 closid;
496fa7d9493SBabu Moger
497fa7d9493SBabu Moger rdtgrp = rdtgroup_kn_lock_live(of->kn);
498fa7d9493SBabu Moger if (rdtgrp) {
499fa7d9493SBabu Moger if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
500331ebe4cSJames Morse list_for_each_entry(schema, &resctrl_schema_all, list) {
501e198fde3SJames Morse seq_printf(s, "%s:uninitialized\n", schema->name);
502331ebe4cSJames Morse }
503fa7d9493SBabu Moger } else if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
504fa7d9493SBabu Moger if (!rdtgrp->plr->d) {
505fa7d9493SBabu Moger rdt_last_cmd_clear();
506fa7d9493SBabu Moger rdt_last_cmd_puts("Cache domain offline\n");
507fa7d9493SBabu Moger ret = -ENODEV;
508fa7d9493SBabu Moger } else {
509fa7d9493SBabu Moger seq_printf(s, "%s:%d=%x\n",
51032150eddSJames Morse rdtgrp->plr->s->res->name,
511fa7d9493SBabu Moger rdtgrp->plr->d->id,
512fa7d9493SBabu Moger rdtgrp->plr->cbm);
513fa7d9493SBabu Moger }
514fa7d9493SBabu Moger } else {
515fa7d9493SBabu Moger closid = rdtgrp->closid;
516331ebe4cSJames Morse list_for_each_entry(schema, &resctrl_schema_all, list) {
5173183e87cSJames Morse if (closid < schema->num_closid)
5181c290682SJames Morse show_doms(s, schema, closid);
519fa7d9493SBabu Moger }
520fa7d9493SBabu Moger }
521fa7d9493SBabu Moger } else {
522fa7d9493SBabu Moger ret = -ENOENT;
523fa7d9493SBabu Moger }
524fa7d9493SBabu Moger rdtgroup_kn_unlock(of->kn);
525fa7d9493SBabu Moger return ret;
526fa7d9493SBabu Moger }
527fa7d9493SBabu Moger
mon_event_read(struct rmid_read * rr,struct rdt_resource * r,struct rdt_domain * d,struct rdtgroup * rdtgrp,int evtid,int first)52846637d45SReinette Chatre void mon_event_read(struct rmid_read *rr, struct rdt_resource *r,
52946637d45SReinette Chatre struct rdt_domain *d, struct rdtgroup *rdtgrp,
53046637d45SReinette Chatre int evtid, int first)
531fa7d9493SBabu Moger {
532fa7d9493SBabu Moger /*
533fa7d9493SBabu Moger * setup the parameters to send to the IPI to read the data.
534fa7d9493SBabu Moger */
535fa7d9493SBabu Moger rr->rgrp = rdtgrp;
536fa7d9493SBabu Moger rr->evtid = evtid;
53746637d45SReinette Chatre rr->r = r;
538fa7d9493SBabu Moger rr->d = d;
539fa7d9493SBabu Moger rr->val = 0;
540fa7d9493SBabu Moger rr->first = first;
541fa7d9493SBabu Moger
542fa7d9493SBabu Moger smp_call_function_any(&d->cpu_mask, mon_event_count, rr, 1);
543fa7d9493SBabu Moger }
544fa7d9493SBabu Moger
rdtgroup_mondata_show(struct seq_file * m,void * arg)545fa7d9493SBabu Moger int rdtgroup_mondata_show(struct seq_file *m, void *arg)
546fa7d9493SBabu Moger {
547fa7d9493SBabu Moger struct kernfs_open_file *of = m->private;
548fa7d9493SBabu Moger u32 resid, evtid, domid;
549fa7d9493SBabu Moger struct rdtgroup *rdtgrp;
550fa7d9493SBabu Moger struct rdt_resource *r;
551fa7d9493SBabu Moger union mon_data_bits md;
552fa7d9493SBabu Moger struct rdt_domain *d;
553fa7d9493SBabu Moger struct rmid_read rr;
554fa7d9493SBabu Moger int ret = 0;
555fa7d9493SBabu Moger
556fa7d9493SBabu Moger rdtgrp = rdtgroup_kn_lock_live(of->kn);
55726467b0fSXiaochen Shen if (!rdtgrp) {
55826467b0fSXiaochen Shen ret = -ENOENT;
55926467b0fSXiaochen Shen goto out;
56026467b0fSXiaochen Shen }
561fa7d9493SBabu Moger
562fa7d9493SBabu Moger md.priv = of->kn->priv;
563fa7d9493SBabu Moger resid = md.u.rid;
564fa7d9493SBabu Moger domid = md.u.domid;
565fa7d9493SBabu Moger evtid = md.u.evtid;
566fa7d9493SBabu Moger
567f7b1843eSJames Morse r = &rdt_resources_all[resid].r_resctrl;
568fa7d9493SBabu Moger d = rdt_find_domain(r, domid, NULL);
56952eb7433SReinette Chatre if (IS_ERR_OR_NULL(d)) {
570fa7d9493SBabu Moger ret = -ENOENT;
571fa7d9493SBabu Moger goto out;
572fa7d9493SBabu Moger }
573fa7d9493SBabu Moger
57446637d45SReinette Chatre mon_event_read(&rr, r, d, rdtgrp, evtid, false);
575fa7d9493SBabu Moger
5764d044c52SJames Morse if (rr.err == -EIO)
577fa7d9493SBabu Moger seq_puts(m, "Error\n");
5784d044c52SJames Morse else if (rr.err == -EINVAL)
579fa7d9493SBabu Moger seq_puts(m, "Unavailable\n");
580fa7d9493SBabu Moger else
581f7b1843eSJames Morse seq_printf(m, "%llu\n", rr.val);
582fa7d9493SBabu Moger
583fa7d9493SBabu Moger out:
584fa7d9493SBabu Moger rdtgroup_kn_unlock(of->kn);
585fa7d9493SBabu Moger return ret;
586fa7d9493SBabu Moger }
587