root/arch/x86/kernel/cpu/resctrl/ctrlmondata.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bw_validate_amd
  2. parse_bw_amd
  3. bw_validate
  4. parse_bw_intel
  5. cbm_validate_intel
  6. cbm_validate_amd
  7. parse_cbm
  8. parse_line
  9. update_domains
  10. rdtgroup_parse_resource
  11. rdtgroup_schemata_write
  12. show_doms
  13. rdtgroup_schemata_show
  14. mon_event_read
  15. rdtgroup_mondata_show

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Resource Director Technology(RDT)
   4  * - Cache Allocation code.
   5  *
   6  * Copyright (C) 2016 Intel Corporation
   7  *
   8  * Authors:
   9  *    Fenghua Yu <fenghua.yu@intel.com>
  10  *    Tony Luck <tony.luck@intel.com>
  11  *
  12  * More information about RDT be found in the Intel (R) x86 Architecture
  13  * Software Developer Manual June 2016, volume 3, section 17.17.
  14  */
  15 
  16 #define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
  17 
  18 #include <linux/cpu.h>
  19 #include <linux/kernfs.h>
  20 #include <linux/seq_file.h>
  21 #include <linux/slab.h>
  22 #include "internal.h"
  23 
  24 /*
  25  * Check whether MBA bandwidth percentage value is correct. The value is
  26  * checked against the minimum and maximum bandwidth values specified by
  27  * the hardware. The allocated bandwidth percentage is rounded to the next
  28  * control step available on the hardware.
  29  */
  30 static bool bw_validate_amd(char *buf, unsigned long *data,
  31                             struct rdt_resource *r)
  32 {
  33         unsigned long bw;
  34         int ret;
  35 
  36         ret = kstrtoul(buf, 10, &bw);
  37         if (ret) {
  38                 rdt_last_cmd_printf("Non-decimal digit in MB value %s\n", buf);
  39                 return false;
  40         }
  41 
  42         if (bw < r->membw.min_bw || bw > r->default_ctrl) {
  43                 rdt_last_cmd_printf("MB value %ld out of range [%d,%d]\n", bw,
  44                                     r->membw.min_bw, r->default_ctrl);
  45                 return false;
  46         }
  47 
  48         *data = roundup(bw, (unsigned long)r->membw.bw_gran);
  49         return true;
  50 }
  51 
  52 int parse_bw_amd(struct rdt_parse_data *data, struct rdt_resource *r,
  53                  struct rdt_domain *d)
  54 {
  55         unsigned long bw_val;
  56 
  57         if (d->have_new_ctrl) {
  58                 rdt_last_cmd_printf("Duplicate domain %d\n", d->id);
  59                 return -EINVAL;
  60         }
  61 
  62         if (!bw_validate_amd(data->buf, &bw_val, r))
  63                 return -EINVAL;
  64 
  65         d->new_ctrl = bw_val;
  66         d->have_new_ctrl = true;
  67 
  68         return 0;
  69 }
  70 
  71 /*
  72  * Check whether MBA bandwidth percentage value is correct. The value is
  73  * checked against the minimum and max bandwidth values specified by the
  74  * hardware. The allocated bandwidth percentage is rounded to the next
  75  * control step available on the hardware.
  76  */
  77 static bool bw_validate(char *buf, unsigned long *data, struct rdt_resource *r)
  78 {
  79         unsigned long bw;
  80         int ret;
  81 
  82         /*
  83          * Only linear delay values is supported for current Intel SKUs.
  84          */
  85         if (!r->membw.delay_linear) {
  86                 rdt_last_cmd_puts("No support for non-linear MB domains\n");
  87                 return false;
  88         }
  89 
  90         ret = kstrtoul(buf, 10, &bw);
  91         if (ret) {
  92                 rdt_last_cmd_printf("Non-decimal digit in MB value %s\n", buf);
  93                 return false;
  94         }
  95 
  96         if ((bw < r->membw.min_bw || bw > r->default_ctrl) &&
  97             !is_mba_sc(r)) {
  98                 rdt_last_cmd_printf("MB value %ld out of range [%d,%d]\n", bw,
  99                                     r->membw.min_bw, r->default_ctrl);
 100                 return false;
 101         }
 102 
 103         *data = roundup(bw, (unsigned long)r->membw.bw_gran);
 104         return true;
 105 }
 106 
 107 int parse_bw_intel(struct rdt_parse_data *data, struct rdt_resource *r,
 108                    struct rdt_domain *d)
 109 {
 110         unsigned long bw_val;
 111 
 112         if (d->have_new_ctrl) {
 113                 rdt_last_cmd_printf("Duplicate domain %d\n", d->id);
 114                 return -EINVAL;
 115         }
 116 
 117         if (!bw_validate(data->buf, &bw_val, r))
 118                 return -EINVAL;
 119         d->new_ctrl = bw_val;
 120         d->have_new_ctrl = true;
 121 
 122         return 0;
 123 }
 124 
 125 /*
 126  * Check whether a cache bit mask is valid. The SDM says:
 127  *      Please note that all (and only) contiguous '1' combinations
 128  *      are allowed (e.g. FFFFH, 0FF0H, 003CH, etc.).
 129  * Additionally Haswell requires at least two bits set.
 130  */
 131 bool cbm_validate_intel(char *buf, u32 *data, struct rdt_resource *r)
 132 {
 133         unsigned long first_bit, zero_bit, val;
 134         unsigned int cbm_len = r->cache.cbm_len;
 135         int ret;
 136 
 137         ret = kstrtoul(buf, 16, &val);
 138         if (ret) {
 139                 rdt_last_cmd_printf("Non-hex character in the mask %s\n", buf);
 140                 return false;
 141         }
 142 
 143         if (val == 0 || val > r->default_ctrl) {
 144                 rdt_last_cmd_puts("Mask out of range\n");
 145                 return false;
 146         }
 147 
 148         first_bit = find_first_bit(&val, cbm_len);
 149         zero_bit = find_next_zero_bit(&val, cbm_len, first_bit);
 150 
 151         if (find_next_bit(&val, cbm_len, zero_bit) < cbm_len) {
 152                 rdt_last_cmd_printf("The mask %lx has non-consecutive 1-bits\n", val);
 153                 return false;
 154         }
 155 
 156         if ((zero_bit - first_bit) < r->cache.min_cbm_bits) {
 157                 rdt_last_cmd_printf("Need at least %d bits in the mask\n",
 158                                     r->cache.min_cbm_bits);
 159                 return false;
 160         }
 161 
 162         *data = val;
 163         return true;
 164 }
 165 
 166 /*
 167  * Check whether a cache bit mask is valid. AMD allows non-contiguous
 168  * bitmasks
 169  */
 170 bool cbm_validate_amd(char *buf, u32 *data, struct rdt_resource *r)
 171 {
 172         unsigned long val;
 173         int ret;
 174 
 175         ret = kstrtoul(buf, 16, &val);
 176         if (ret) {
 177                 rdt_last_cmd_printf("Non-hex character in the mask %s\n", buf);
 178                 return false;
 179         }
 180 
 181         if (val > r->default_ctrl) {
 182                 rdt_last_cmd_puts("Mask out of range\n");
 183                 return false;
 184         }
 185 
 186         *data = val;
 187         return true;
 188 }
 189 
 190 /*
 191  * Read one cache bit mask (hex). Check that it is valid for the current
 192  * resource type.
 193  */
 194 int parse_cbm(struct rdt_parse_data *data, struct rdt_resource *r,
 195               struct rdt_domain *d)
 196 {
 197         struct rdtgroup *rdtgrp = data->rdtgrp;
 198         u32 cbm_val;
 199 
 200         if (d->have_new_ctrl) {
 201                 rdt_last_cmd_printf("Duplicate domain %d\n", d->id);
 202                 return -EINVAL;
 203         }
 204 
 205         /*
 206          * Cannot set up more than one pseudo-locked region in a cache
 207          * hierarchy.
 208          */
 209         if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP &&
 210             rdtgroup_pseudo_locked_in_hierarchy(d)) {
 211                 rdt_last_cmd_puts("Pseudo-locked region in hierarchy\n");
 212                 return -EINVAL;
 213         }
 214 
 215         if (!r->cbm_validate(data->buf, &cbm_val, r))
 216                 return -EINVAL;
 217 
 218         if ((rdtgrp->mode == RDT_MODE_EXCLUSIVE ||
 219              rdtgrp->mode == RDT_MODE_SHAREABLE) &&
 220             rdtgroup_cbm_overlaps_pseudo_locked(d, cbm_val)) {
 221                 rdt_last_cmd_puts("CBM overlaps with pseudo-locked region\n");
 222                 return -EINVAL;
 223         }
 224 
 225         /*
 226          * The CBM may not overlap with the CBM of another closid if
 227          * either is exclusive.
 228          */
 229         if (rdtgroup_cbm_overlaps(r, d, cbm_val, rdtgrp->closid, true)) {
 230                 rdt_last_cmd_puts("Overlaps with exclusive group\n");
 231                 return -EINVAL;
 232         }
 233 
 234         if (rdtgroup_cbm_overlaps(r, d, cbm_val, rdtgrp->closid, false)) {
 235                 if (rdtgrp->mode == RDT_MODE_EXCLUSIVE ||
 236                     rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
 237                         rdt_last_cmd_puts("Overlaps with other group\n");
 238                         return -EINVAL;
 239                 }
 240         }
 241 
 242         d->new_ctrl = cbm_val;
 243         d->have_new_ctrl = true;
 244 
 245         return 0;
 246 }
 247 
 248 /*
 249  * For each domain in this resource we expect to find a series of:
 250  *      id=mask
 251  * separated by ";". The "id" is in decimal, and must match one of
 252  * the "id"s for this resource.
 253  */
 254 static int parse_line(char *line, struct rdt_resource *r,
 255                       struct rdtgroup *rdtgrp)
 256 {
 257         struct rdt_parse_data data;
 258         char *dom = NULL, *id;
 259         struct rdt_domain *d;
 260         unsigned long dom_id;
 261 
 262         if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP &&
 263             r->rid == RDT_RESOURCE_MBA) {
 264                 rdt_last_cmd_puts("Cannot pseudo-lock MBA resource\n");
 265                 return -EINVAL;
 266         }
 267 
 268 next:
 269         if (!line || line[0] == '\0')
 270                 return 0;
 271         dom = strsep(&line, ";");
 272         id = strsep(&dom, "=");
 273         if (!dom || kstrtoul(id, 10, &dom_id)) {
 274                 rdt_last_cmd_puts("Missing '=' or non-numeric domain\n");
 275                 return -EINVAL;
 276         }
 277         dom = strim(dom);
 278         list_for_each_entry(d, &r->domains, list) {
 279                 if (d->id == dom_id) {
 280                         data.buf = dom;
 281                         data.rdtgrp = rdtgrp;
 282                         if (r->parse_ctrlval(&data, r, d))
 283                                 return -EINVAL;
 284                         if (rdtgrp->mode ==  RDT_MODE_PSEUDO_LOCKSETUP) {
 285                                 /*
 286                                  * In pseudo-locking setup mode and just
 287                                  * parsed a valid CBM that should be
 288                                  * pseudo-locked. Only one locked region per
 289                                  * resource group and domain so just do
 290                                  * the required initialization for single
 291                                  * region and return.
 292                                  */
 293                                 rdtgrp->plr->r = r;
 294                                 rdtgrp->plr->d = d;
 295                                 rdtgrp->plr->cbm = d->new_ctrl;
 296                                 d->plr = rdtgrp->plr;
 297                                 return 0;
 298                         }
 299                         goto next;
 300                 }
 301         }
 302         return -EINVAL;
 303 }
 304 
 305 int update_domains(struct rdt_resource *r, int closid)
 306 {
 307         struct msr_param msr_param;
 308         cpumask_var_t cpu_mask;
 309         struct rdt_domain *d;
 310         bool mba_sc;
 311         u32 *dc;
 312         int cpu;
 313 
 314         if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
 315                 return -ENOMEM;
 316 
 317         msr_param.low = closid;
 318         msr_param.high = msr_param.low + 1;
 319         msr_param.res = r;
 320 
 321         mba_sc = is_mba_sc(r);
 322         list_for_each_entry(d, &r->domains, list) {
 323                 dc = !mba_sc ? d->ctrl_val : d->mbps_val;
 324                 if (d->have_new_ctrl && d->new_ctrl != dc[closid]) {
 325                         cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
 326                         dc[closid] = d->new_ctrl;
 327                 }
 328         }
 329 
 330         /*
 331          * Avoid writing the control msr with control values when
 332          * MBA software controller is enabled
 333          */
 334         if (cpumask_empty(cpu_mask) || mba_sc)
 335                 goto done;
 336         cpu = get_cpu();
 337         /* Update resource control msr on this CPU if it's in cpu_mask. */
 338         if (cpumask_test_cpu(cpu, cpu_mask))
 339                 rdt_ctrl_update(&msr_param);
 340         /* Update resource control msr on other CPUs. */
 341         smp_call_function_many(cpu_mask, rdt_ctrl_update, &msr_param, 1);
 342         put_cpu();
 343 
 344 done:
 345         free_cpumask_var(cpu_mask);
 346 
 347         return 0;
 348 }
 349 
 350 static int rdtgroup_parse_resource(char *resname, char *tok,
 351                                    struct rdtgroup *rdtgrp)
 352 {
 353         struct rdt_resource *r;
 354 
 355         for_each_alloc_enabled_rdt_resource(r) {
 356                 if (!strcmp(resname, r->name) && rdtgrp->closid < r->num_closid)
 357                         return parse_line(tok, r, rdtgrp);
 358         }
 359         rdt_last_cmd_printf("Unknown or unsupported resource name '%s'\n", resname);
 360         return -EINVAL;
 361 }
 362 
 363 ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
 364                                 char *buf, size_t nbytes, loff_t off)
 365 {
 366         struct rdtgroup *rdtgrp;
 367         struct rdt_domain *dom;
 368         struct rdt_resource *r;
 369         char *tok, *resname;
 370         int ret = 0;
 371 
 372         /* Valid input requires a trailing newline */
 373         if (nbytes == 0 || buf[nbytes - 1] != '\n')
 374                 return -EINVAL;
 375         buf[nbytes - 1] = '\0';
 376 
 377         cpus_read_lock();
 378         rdtgrp = rdtgroup_kn_lock_live(of->kn);
 379         if (!rdtgrp) {
 380                 rdtgroup_kn_unlock(of->kn);
 381                 cpus_read_unlock();
 382                 return -ENOENT;
 383         }
 384         rdt_last_cmd_clear();
 385 
 386         /*
 387          * No changes to pseudo-locked region allowed. It has to be removed
 388          * and re-created instead.
 389          */
 390         if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
 391                 ret = -EINVAL;
 392                 rdt_last_cmd_puts("Resource group is pseudo-locked\n");
 393                 goto out;
 394         }
 395 
 396         for_each_alloc_enabled_rdt_resource(r) {
 397                 list_for_each_entry(dom, &r->domains, list)
 398                         dom->have_new_ctrl = false;
 399         }
 400 
 401         while ((tok = strsep(&buf, "\n")) != NULL) {
 402                 resname = strim(strsep(&tok, ":"));
 403                 if (!tok) {
 404                         rdt_last_cmd_puts("Missing ':'\n");
 405                         ret = -EINVAL;
 406                         goto out;
 407                 }
 408                 if (tok[0] == '\0') {
 409                         rdt_last_cmd_printf("Missing '%s' value\n", resname);
 410                         ret = -EINVAL;
 411                         goto out;
 412                 }
 413                 ret = rdtgroup_parse_resource(resname, tok, rdtgrp);
 414                 if (ret)
 415                         goto out;
 416         }
 417 
 418         for_each_alloc_enabled_rdt_resource(r) {
 419                 ret = update_domains(r, rdtgrp->closid);
 420                 if (ret)
 421                         goto out;
 422         }
 423 
 424         if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
 425                 /*
 426                  * If pseudo-locking fails we keep the resource group in
 427                  * mode RDT_MODE_PSEUDO_LOCKSETUP with its class of service
 428                  * active and updated for just the domain the pseudo-locked
 429                  * region was requested for.
 430                  */
 431                 ret = rdtgroup_pseudo_lock_create(rdtgrp);
 432         }
 433 
 434 out:
 435         rdtgroup_kn_unlock(of->kn);
 436         cpus_read_unlock();
 437         return ret ?: nbytes;
 438 }
 439 
 440 static void show_doms(struct seq_file *s, struct rdt_resource *r, int closid)
 441 {
 442         struct rdt_domain *dom;
 443         bool sep = false;
 444         u32 ctrl_val;
 445 
 446         seq_printf(s, "%*s:", max_name_width, r->name);
 447         list_for_each_entry(dom, &r->domains, list) {
 448                 if (sep)
 449                         seq_puts(s, ";");
 450 
 451                 ctrl_val = (!is_mba_sc(r) ? dom->ctrl_val[closid] :
 452                             dom->mbps_val[closid]);
 453                 seq_printf(s, r->format_str, dom->id, max_data_width,
 454                            ctrl_val);
 455                 sep = true;
 456         }
 457         seq_puts(s, "\n");
 458 }
 459 
 460 int rdtgroup_schemata_show(struct kernfs_open_file *of,
 461                            struct seq_file *s, void *v)
 462 {
 463         struct rdtgroup *rdtgrp;
 464         struct rdt_resource *r;
 465         int ret = 0;
 466         u32 closid;
 467 
 468         rdtgrp = rdtgroup_kn_lock_live(of->kn);
 469         if (rdtgrp) {
 470                 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) {
 471                         for_each_alloc_enabled_rdt_resource(r)
 472                                 seq_printf(s, "%s:uninitialized\n", r->name);
 473                 } else if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
 474                         if (!rdtgrp->plr->d) {
 475                                 rdt_last_cmd_clear();
 476                                 rdt_last_cmd_puts("Cache domain offline\n");
 477                                 ret = -ENODEV;
 478                         } else {
 479                                 seq_printf(s, "%s:%d=%x\n",
 480                                            rdtgrp->plr->r->name,
 481                                            rdtgrp->plr->d->id,
 482                                            rdtgrp->plr->cbm);
 483                         }
 484                 } else {
 485                         closid = rdtgrp->closid;
 486                         for_each_alloc_enabled_rdt_resource(r) {
 487                                 if (closid < r->num_closid)
 488                                         show_doms(s, r, closid);
 489                         }
 490                 }
 491         } else {
 492                 ret = -ENOENT;
 493         }
 494         rdtgroup_kn_unlock(of->kn);
 495         return ret;
 496 }
 497 
 498 void mon_event_read(struct rmid_read *rr, struct rdt_domain *d,
 499                     struct rdtgroup *rdtgrp, int evtid, int first)
 500 {
 501         /*
 502          * setup the parameters to send to the IPI to read the data.
 503          */
 504         rr->rgrp = rdtgrp;
 505         rr->evtid = evtid;
 506         rr->d = d;
 507         rr->val = 0;
 508         rr->first = first;
 509 
 510         smp_call_function_any(&d->cpu_mask, mon_event_count, rr, 1);
 511 }
 512 
 513 int rdtgroup_mondata_show(struct seq_file *m, void *arg)
 514 {
 515         struct kernfs_open_file *of = m->private;
 516         u32 resid, evtid, domid;
 517         struct rdtgroup *rdtgrp;
 518         struct rdt_resource *r;
 519         union mon_data_bits md;
 520         struct rdt_domain *d;
 521         struct rmid_read rr;
 522         int ret = 0;
 523 
 524         rdtgrp = rdtgroup_kn_lock_live(of->kn);
 525         if (!rdtgrp) {
 526                 ret = -ENOENT;
 527                 goto out;
 528         }
 529 
 530         md.priv = of->kn->priv;
 531         resid = md.u.rid;
 532         domid = md.u.domid;
 533         evtid = md.u.evtid;
 534 
 535         r = &rdt_resources_all[resid];
 536         d = rdt_find_domain(r, domid, NULL);
 537         if (IS_ERR_OR_NULL(d)) {
 538                 ret = -ENOENT;
 539                 goto out;
 540         }
 541 
 542         mon_event_read(&rr, d, rdtgrp, evtid, false);
 543 
 544         if (rr.val & RMID_VAL_ERROR)
 545                 seq_puts(m, "Error\n");
 546         else if (rr.val & RMID_VAL_UNAVAIL)
 547                 seq_puts(m, "Unavailable\n");
 548         else
 549                 seq_printf(m, "%llu\n", rr.val * r->mon_scale);
 550 
 551 out:
 552         rdtgroup_kn_unlock(of->kn);
 553         return ret;
 554 }

/* [<][>][^][v][top][bottom][index][help] */