linux/arch/x86/kernel/cpu/resctrl/ctrlmondata.c
<<
>>
Prefs
   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 */
  30static 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
  52int 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 */
  77static 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
 107int 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 */
 131bool 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 */
 170bool 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 */
 194int 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 */
 254static 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
 268next:
 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
 305int 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
 344done:
 345        free_cpumask_var(cpu_mask);
 346
 347        return 0;
 348}
 349
 350static 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
 363ssize_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
 434out:
 435        rdtgroup_kn_unlock(of->kn);
 436        cpus_read_unlock();
 437        return ret ?: nbytes;
 438}
 439
 440static 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
 460int 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
 498void 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
 513int 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
 526        md.priv = of->kn->priv;
 527        resid = md.u.rid;
 528        domid = md.u.domid;
 529        evtid = md.u.evtid;
 530
 531        r = &rdt_resources_all[resid];
 532        d = rdt_find_domain(r, domid, NULL);
 533        if (IS_ERR_OR_NULL(d)) {
 534                ret = -ENOENT;
 535                goto out;
 536        }
 537
 538        mon_event_read(&rr, d, rdtgrp, evtid, false);
 539
 540        if (rr.val & RMID_VAL_ERROR)
 541                seq_puts(m, "Error\n");
 542        else if (rr.val & RMID_VAL_UNAVAIL)
 543                seq_puts(m, "Unavailable\n");
 544        else
 545                seq_printf(m, "%llu\n", rr.val * r->mon_scale);
 546
 547out:
 548        rdtgroup_kn_unlock(of->kn);
 549        return ret;
 550}
 551