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 <linux/tick.h> 23 24 #include "internal.h" 25 26 struct rdt_parse_data { 27 u32 closid; 28 enum rdtgrp_mode mode; 29 char *buf; 30 }; 31 32 typedef int (ctrlval_parser_t)(struct rdt_parse_data *data, 33 struct resctrl_schema *s, 34 struct rdt_ctrl_domain *d); 35 36 /* 37 * Check whether MBA bandwidth percentage value is correct. The value is 38 * checked against the minimum and max bandwidth values specified by the 39 * hardware. The allocated bandwidth percentage is rounded to the next 40 * control step available on the hardware. 41 */ 42 static bool bw_validate(char *buf, u32 *data, struct rdt_resource *r) 43 { 44 int ret; 45 u32 bw; 46 47 /* 48 * Only linear delay values is supported for current Intel SKUs. 49 */ 50 if (!r->membw.delay_linear && r->membw.arch_needs_linear) { 51 rdt_last_cmd_puts("No support for non-linear MB domains\n"); 52 return false; 53 } 54 55 ret = kstrtou32(buf, 10, &bw); 56 if (ret) { 57 rdt_last_cmd_printf("Invalid MB value %s\n", buf); 58 return false; 59 } 60 61 /* Nothing else to do if software controller is enabled. */ 62 if (is_mba_sc(r)) { 63 *data = bw; 64 return true; 65 } 66 67 if (bw < r->membw.min_bw || bw > r->membw.max_bw) { 68 rdt_last_cmd_printf("MB value %u out of range [%d,%d]\n", 69 bw, r->membw.min_bw, r->membw.max_bw); 70 return false; 71 } 72 73 *data = roundup(bw, (unsigned long)r->membw.bw_gran); 74 return true; 75 } 76 77 static int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s, 78 struct rdt_ctrl_domain *d) 79 { 80 struct resctrl_staged_config *cfg; 81 struct rdt_resource *r = s->res; 82 u32 closid = data->closid; 83 u32 bw_val; 84 85 cfg = &d->staged_config[s->conf_type]; 86 if (cfg->have_new_ctrl) { 87 rdt_last_cmd_printf("Duplicate domain %d\n", d->hdr.id); 88 return -EINVAL; 89 } 90 91 if (!bw_validate(data->buf, &bw_val, r)) 92 return -EINVAL; 93 94 if (is_mba_sc(r)) { 95 d->mbps_val[closid] = bw_val; 96 return 0; 97 } 98 99 cfg->new_ctrl = bw_val; 100 cfg->have_new_ctrl = true; 101 102 return 0; 103 } 104 105 /* 106 * Check whether a cache bit mask is valid. 107 * On Intel CPUs, non-contiguous 1s value support is indicated by CPUID: 108 * - CPUID.0x10.1:ECX[3]: L3 non-contiguous 1s value supported if 1 109 * - CPUID.0x10.2:ECX[3]: L2 non-contiguous 1s value supported if 1 110 * 111 * Haswell does not support a non-contiguous 1s value and additionally 112 * requires at least two bits set. 113 * AMD allows non-contiguous bitmasks. 114 */ 115 static bool cbm_validate(char *buf, u32 *data, struct rdt_resource *r) 116 { 117 u32 supported_bits = BIT_MASK(r->cache.cbm_len) - 1; 118 unsigned int cbm_len = r->cache.cbm_len; 119 unsigned long first_bit, zero_bit, val; 120 int ret; 121 122 ret = kstrtoul(buf, 16, &val); 123 if (ret) { 124 rdt_last_cmd_printf("Non-hex character in the mask %s\n", buf); 125 return false; 126 } 127 128 if ((r->cache.min_cbm_bits > 0 && val == 0) || val > supported_bits) { 129 rdt_last_cmd_puts("Mask out of range\n"); 130 return false; 131 } 132 133 first_bit = find_first_bit(&val, cbm_len); 134 zero_bit = find_next_zero_bit(&val, cbm_len, first_bit); 135 136 /* Are non-contiguous bitmasks allowed? */ 137 if (!r->cache.arch_has_sparse_bitmasks && 138 (find_next_bit(&val, cbm_len, zero_bit) < cbm_len)) { 139 rdt_last_cmd_printf("The mask %lx has non-consecutive 1-bits\n", val); 140 return false; 141 } 142 143 if ((zero_bit - first_bit) < r->cache.min_cbm_bits) { 144 rdt_last_cmd_printf("Need at least %d bits in the mask\n", 145 r->cache.min_cbm_bits); 146 return false; 147 } 148 149 *data = val; 150 return true; 151 } 152 153 /* 154 * Read one cache bit mask (hex). Check that it is valid for the current 155 * resource type. 156 */ 157 static int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s, 158 struct rdt_ctrl_domain *d) 159 { 160 enum rdtgrp_mode mode = data->mode; 161 struct resctrl_staged_config *cfg; 162 struct rdt_resource *r = s->res; 163 u32 closid = data->closid; 164 u32 cbm_val; 165 166 cfg = &d->staged_config[s->conf_type]; 167 if (cfg->have_new_ctrl) { 168 rdt_last_cmd_printf("Duplicate domain %d\n", d->hdr.id); 169 return -EINVAL; 170 } 171 172 /* 173 * Cannot set up more than one pseudo-locked region in a cache 174 * hierarchy. 175 */ 176 if (mode == RDT_MODE_PSEUDO_LOCKSETUP && 177 rdtgroup_pseudo_locked_in_hierarchy(d)) { 178 rdt_last_cmd_puts("Pseudo-locked region in hierarchy\n"); 179 return -EINVAL; 180 } 181 182 if (!cbm_validate(data->buf, &cbm_val, r)) 183 return -EINVAL; 184 185 if ((mode == RDT_MODE_EXCLUSIVE || mode == RDT_MODE_SHAREABLE) && 186 rdtgroup_cbm_overlaps_pseudo_locked(d, cbm_val)) { 187 rdt_last_cmd_puts("CBM overlaps with pseudo-locked region\n"); 188 return -EINVAL; 189 } 190 191 /* 192 * The CBM may not overlap with the CBM of another closid if 193 * either is exclusive. 194 */ 195 if (rdtgroup_cbm_overlaps(s, d, cbm_val, closid, true)) { 196 rdt_last_cmd_puts("Overlaps with exclusive group\n"); 197 return -EINVAL; 198 } 199 200 if (rdtgroup_cbm_overlaps(s, d, cbm_val, closid, false)) { 201 if (mode == RDT_MODE_EXCLUSIVE || 202 mode == RDT_MODE_PSEUDO_LOCKSETUP) { 203 rdt_last_cmd_puts("Overlaps with other group\n"); 204 return -EINVAL; 205 } 206 } 207 208 cfg->new_ctrl = cbm_val; 209 cfg->have_new_ctrl = true; 210 211 return 0; 212 } 213 214 /* 215 * For each domain in this resource we expect to find a series of: 216 * id=mask 217 * separated by ";". The "id" is in decimal, and must match one of 218 * the "id"s for this resource. 219 */ 220 static int parse_line(char *line, struct resctrl_schema *s, 221 struct rdtgroup *rdtgrp) 222 { 223 enum resctrl_conf_type t = s->conf_type; 224 ctrlval_parser_t *parse_ctrlval = NULL; 225 struct resctrl_staged_config *cfg; 226 struct rdt_resource *r = s->res; 227 struct rdt_parse_data data; 228 struct rdt_ctrl_domain *d; 229 char *dom = NULL, *id; 230 unsigned long dom_id; 231 232 /* Walking r->domains, ensure it can't race with cpuhp */ 233 lockdep_assert_cpus_held(); 234 235 switch (r->schema_fmt) { 236 case RESCTRL_SCHEMA_BITMAP: 237 parse_ctrlval = &parse_cbm; 238 break; 239 case RESCTRL_SCHEMA_RANGE: 240 parse_ctrlval = &parse_bw; 241 break; 242 } 243 244 if (WARN_ON_ONCE(!parse_ctrlval)) 245 return -EINVAL; 246 247 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP && 248 (r->rid == RDT_RESOURCE_MBA || r->rid == RDT_RESOURCE_SMBA)) { 249 rdt_last_cmd_puts("Cannot pseudo-lock MBA resource\n"); 250 return -EINVAL; 251 } 252 253 next: 254 if (!line || line[0] == '\0') 255 return 0; 256 dom = strsep(&line, ";"); 257 id = strsep(&dom, "="); 258 if (!dom || kstrtoul(id, 10, &dom_id)) { 259 rdt_last_cmd_puts("Missing '=' or non-numeric domain\n"); 260 return -EINVAL; 261 } 262 dom = strim(dom); 263 list_for_each_entry(d, &r->ctrl_domains, hdr.list) { 264 if (d->hdr.id == dom_id) { 265 data.buf = dom; 266 data.closid = rdtgrp->closid; 267 data.mode = rdtgrp->mode; 268 if (parse_ctrlval(&data, s, d)) 269 return -EINVAL; 270 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) { 271 cfg = &d->staged_config[t]; 272 /* 273 * In pseudo-locking setup mode and just 274 * parsed a valid CBM that should be 275 * pseudo-locked. Only one locked region per 276 * resource group and domain so just do 277 * the required initialization for single 278 * region and return. 279 */ 280 rdtgrp->plr->s = s; 281 rdtgrp->plr->d = d; 282 rdtgrp->plr->cbm = cfg->new_ctrl; 283 d->plr = rdtgrp->plr; 284 return 0; 285 } 286 goto next; 287 } 288 } 289 return -EINVAL; 290 } 291 292 static int rdtgroup_parse_resource(char *resname, char *tok, 293 struct rdtgroup *rdtgrp) 294 { 295 struct resctrl_schema *s; 296 297 list_for_each_entry(s, &resctrl_schema_all, list) { 298 if (!strcmp(resname, s->name) && rdtgrp->closid < s->num_closid) 299 return parse_line(tok, s, rdtgrp); 300 } 301 rdt_last_cmd_printf("Unknown or unsupported resource name '%s'\n", resname); 302 return -EINVAL; 303 } 304 305 ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of, 306 char *buf, size_t nbytes, loff_t off) 307 { 308 struct resctrl_schema *s; 309 struct rdtgroup *rdtgrp; 310 struct rdt_resource *r; 311 char *tok, *resname; 312 int ret = 0; 313 314 /* Valid input requires a trailing newline */ 315 if (nbytes == 0 || buf[nbytes - 1] != '\n') 316 return -EINVAL; 317 buf[nbytes - 1] = '\0'; 318 319 rdtgrp = rdtgroup_kn_lock_live(of->kn); 320 if (!rdtgrp) { 321 rdtgroup_kn_unlock(of->kn); 322 return -ENOENT; 323 } 324 rdt_last_cmd_clear(); 325 326 /* 327 * No changes to pseudo-locked region allowed. It has to be removed 328 * and re-created instead. 329 */ 330 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) { 331 ret = -EINVAL; 332 rdt_last_cmd_puts("Resource group is pseudo-locked\n"); 333 goto out; 334 } 335 336 rdt_staged_configs_clear(); 337 338 while ((tok = strsep(&buf, "\n")) != NULL) { 339 resname = strim(strsep(&tok, ":")); 340 if (!tok) { 341 rdt_last_cmd_puts("Missing ':'\n"); 342 ret = -EINVAL; 343 goto out; 344 } 345 if (tok[0] == '\0') { 346 rdt_last_cmd_printf("Missing '%s' value\n", resname); 347 ret = -EINVAL; 348 goto out; 349 } 350 ret = rdtgroup_parse_resource(resname, tok, rdtgrp); 351 if (ret) 352 goto out; 353 } 354 355 list_for_each_entry(s, &resctrl_schema_all, list) { 356 r = s->res; 357 358 /* 359 * Writes to mba_sc resources update the software controller, 360 * not the control MSR. 361 */ 362 if (is_mba_sc(r)) 363 continue; 364 365 ret = resctrl_arch_update_domains(r, rdtgrp->closid); 366 if (ret) 367 goto out; 368 } 369 370 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) { 371 /* 372 * If pseudo-locking fails we keep the resource group in 373 * mode RDT_MODE_PSEUDO_LOCKSETUP with its class of service 374 * active and updated for just the domain the pseudo-locked 375 * region was requested for. 376 */ 377 ret = rdtgroup_pseudo_lock_create(rdtgrp); 378 } 379 380 out: 381 rdt_staged_configs_clear(); 382 rdtgroup_kn_unlock(of->kn); 383 return ret ?: nbytes; 384 } 385 386 static void show_doms(struct seq_file *s, struct resctrl_schema *schema, 387 char *resource_name, int closid) 388 { 389 struct rdt_resource *r = schema->res; 390 struct rdt_ctrl_domain *dom; 391 bool sep = false; 392 u32 ctrl_val; 393 394 /* Walking r->domains, ensure it can't race with cpuhp */ 395 lockdep_assert_cpus_held(); 396 397 if (resource_name) 398 seq_printf(s, "%*s:", max_name_width, resource_name); 399 list_for_each_entry(dom, &r->ctrl_domains, hdr.list) { 400 if (sep) 401 seq_puts(s, ";"); 402 403 if (is_mba_sc(r)) 404 ctrl_val = dom->mbps_val[closid]; 405 else 406 ctrl_val = resctrl_arch_get_config(r, dom, closid, 407 schema->conf_type); 408 409 seq_printf(s, schema->fmt_str, dom->hdr.id, ctrl_val); 410 sep = true; 411 } 412 seq_puts(s, "\n"); 413 } 414 415 int rdtgroup_schemata_show(struct kernfs_open_file *of, 416 struct seq_file *s, void *v) 417 { 418 struct resctrl_schema *schema; 419 struct rdtgroup *rdtgrp; 420 int ret = 0; 421 u32 closid; 422 423 rdtgrp = rdtgroup_kn_lock_live(of->kn); 424 if (rdtgrp) { 425 if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP) { 426 list_for_each_entry(schema, &resctrl_schema_all, list) { 427 seq_printf(s, "%s:uninitialized\n", schema->name); 428 } 429 } else if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) { 430 if (!rdtgrp->plr->d) { 431 rdt_last_cmd_clear(); 432 rdt_last_cmd_puts("Cache domain offline\n"); 433 ret = -ENODEV; 434 } else { 435 seq_printf(s, "%s:%d=%x\n", 436 rdtgrp->plr->s->res->name, 437 rdtgrp->plr->d->hdr.id, 438 rdtgrp->plr->cbm); 439 } 440 } else { 441 closid = rdtgrp->closid; 442 list_for_each_entry(schema, &resctrl_schema_all, list) { 443 if (closid < schema->num_closid) 444 show_doms(s, schema, schema->name, closid); 445 } 446 } 447 } else { 448 ret = -ENOENT; 449 } 450 rdtgroup_kn_unlock(of->kn); 451 return ret; 452 } 453 454 static int smp_mon_event_count(void *arg) 455 { 456 mon_event_count(arg); 457 458 return 0; 459 } 460 461 ssize_t rdtgroup_mba_mbps_event_write(struct kernfs_open_file *of, 462 char *buf, size_t nbytes, loff_t off) 463 { 464 struct rdtgroup *rdtgrp; 465 int ret = 0; 466 467 /* Valid input requires a trailing newline */ 468 if (nbytes == 0 || buf[nbytes - 1] != '\n') 469 return -EINVAL; 470 buf[nbytes - 1] = '\0'; 471 472 rdtgrp = rdtgroup_kn_lock_live(of->kn); 473 if (!rdtgrp) { 474 rdtgroup_kn_unlock(of->kn); 475 return -ENOENT; 476 } 477 rdt_last_cmd_clear(); 478 479 if (!strcmp(buf, "mbm_local_bytes")) { 480 if (resctrl_is_mon_event_enabled(QOS_L3_MBM_LOCAL_EVENT_ID)) 481 rdtgrp->mba_mbps_event = QOS_L3_MBM_LOCAL_EVENT_ID; 482 else 483 ret = -EINVAL; 484 } else if (!strcmp(buf, "mbm_total_bytes")) { 485 if (resctrl_is_mon_event_enabled(QOS_L3_MBM_TOTAL_EVENT_ID)) 486 rdtgrp->mba_mbps_event = QOS_L3_MBM_TOTAL_EVENT_ID; 487 else 488 ret = -EINVAL; 489 } else { 490 ret = -EINVAL; 491 } 492 493 if (ret) 494 rdt_last_cmd_printf("Unsupported event id '%s'\n", buf); 495 496 rdtgroup_kn_unlock(of->kn); 497 498 return ret ?: nbytes; 499 } 500 501 int rdtgroup_mba_mbps_event_show(struct kernfs_open_file *of, 502 struct seq_file *s, void *v) 503 { 504 struct rdtgroup *rdtgrp; 505 int ret = 0; 506 507 rdtgrp = rdtgroup_kn_lock_live(of->kn); 508 509 if (rdtgrp) { 510 switch (rdtgrp->mba_mbps_event) { 511 case QOS_L3_MBM_LOCAL_EVENT_ID: 512 seq_puts(s, "mbm_local_bytes\n"); 513 break; 514 case QOS_L3_MBM_TOTAL_EVENT_ID: 515 seq_puts(s, "mbm_total_bytes\n"); 516 break; 517 default: 518 pr_warn_once("Bad event %d\n", rdtgrp->mba_mbps_event); 519 ret = -EINVAL; 520 break; 521 } 522 } else { 523 ret = -ENOENT; 524 } 525 526 rdtgroup_kn_unlock(of->kn); 527 528 return ret; 529 } 530 531 struct rdt_domain_hdr *resctrl_find_domain(struct list_head *h, int id, 532 struct list_head **pos) 533 { 534 struct rdt_domain_hdr *d; 535 struct list_head *l; 536 537 list_for_each(l, h) { 538 d = list_entry(l, struct rdt_domain_hdr, list); 539 /* When id is found, return its domain. */ 540 if (id == d->id) 541 return d; 542 /* Stop searching when finding id's position in sorted list. */ 543 if (id < d->id) 544 break; 545 } 546 547 if (pos) 548 *pos = l; 549 550 return NULL; 551 } 552 553 void mon_event_read(struct rmid_read *rr, struct rdt_resource *r, 554 struct rdt_domain_hdr *hdr, struct rdtgroup *rdtgrp, 555 cpumask_t *cpumask, int evtid, int first) 556 { 557 int cpu; 558 559 /* When picking a CPU from cpu_mask, ensure it can't race with cpuhp */ 560 lockdep_assert_cpus_held(); 561 562 /* 563 * Setup the parameters to pass to mon_event_count() to read the data. 564 */ 565 rr->rgrp = rdtgrp; 566 rr->evtid = evtid; 567 rr->r = r; 568 rr->hdr = hdr; 569 rr->first = first; 570 if (resctrl_arch_mbm_cntr_assign_enabled(r) && 571 resctrl_is_mbm_event(evtid)) { 572 rr->is_mbm_cntr = true; 573 } else { 574 rr->arch_mon_ctx = resctrl_arch_mon_ctx_alloc(r, evtid); 575 if (IS_ERR(rr->arch_mon_ctx)) { 576 rr->err = -EINVAL; 577 return; 578 } 579 } 580 581 cpu = cpumask_any_housekeeping(cpumask, RESCTRL_PICK_ANY_CPU); 582 583 /* 584 * cpumask_any_housekeeping() prefers housekeeping CPUs, but 585 * are all the CPUs nohz_full? If yes, pick a CPU to IPI. 586 * MPAM's resctrl_arch_rmid_read() is unable to read the 587 * counters on some platforms if its called in IRQ context. 588 */ 589 if (tick_nohz_full_cpu(cpu)) 590 smp_call_function_any(cpumask, mon_event_count, rr, 1); 591 else 592 smp_call_on_cpu(cpu, smp_mon_event_count, rr, false); 593 594 if (rr->arch_mon_ctx) 595 resctrl_arch_mon_ctx_free(r, evtid, rr->arch_mon_ctx); 596 } 597 598 int rdtgroup_mondata_show(struct seq_file *m, void *arg) 599 { 600 struct kernfs_open_file *of = m->private; 601 enum resctrl_res_level resid; 602 enum resctrl_event_id evtid; 603 struct rdt_l3_mon_domain *d; 604 struct rdt_domain_hdr *hdr; 605 struct rmid_read rr = {0}; 606 struct rdtgroup *rdtgrp; 607 int domid, cpu, ret = 0; 608 struct rdt_resource *r; 609 struct cacheinfo *ci; 610 struct mon_data *md; 611 612 rdtgrp = rdtgroup_kn_lock_live(of->kn); 613 if (!rdtgrp) { 614 ret = -ENOENT; 615 goto out; 616 } 617 618 md = of->kn->priv; 619 if (WARN_ON_ONCE(!md)) { 620 ret = -EIO; 621 goto out; 622 } 623 624 resid = md->rid; 625 domid = md->domid; 626 evtid = md->evtid; 627 r = resctrl_arch_get_resource(resid); 628 629 if (md->sum) { 630 /* 631 * This file requires summing across all domains that share 632 * the L3 cache id that was provided in the "domid" field of the 633 * struct mon_data. Search all domains in the resource for 634 * one that matches this cache id. 635 */ 636 list_for_each_entry(d, &r->mon_domains, hdr.list) { 637 if (d->ci_id == domid) { 638 cpu = cpumask_any(&d->hdr.cpu_mask); 639 ci = get_cpu_cacheinfo_level(cpu, RESCTRL_L3_CACHE); 640 if (!ci) 641 continue; 642 rr.ci = ci; 643 mon_event_read(&rr, r, NULL, rdtgrp, 644 &ci->shared_cpu_map, evtid, false); 645 goto checkresult; 646 } 647 } 648 ret = -ENOENT; 649 goto out; 650 } else { 651 /* 652 * This file provides data from a single domain. Search 653 * the resource to find the domain with "domid". 654 */ 655 hdr = resctrl_find_domain(&r->mon_domains, domid, NULL); 656 if (!hdr) { 657 ret = -ENOENT; 658 goto out; 659 } 660 mon_event_read(&rr, r, hdr, rdtgrp, &hdr->cpu_mask, evtid, false); 661 } 662 663 checkresult: 664 665 /* 666 * -ENOENT is a special case, set only when "mbm_event" counter assignment 667 * mode is enabled and no counter has been assigned. 668 */ 669 if (rr.err == -EIO) 670 seq_puts(m, "Error\n"); 671 else if (rr.err == -EINVAL) 672 seq_puts(m, "Unavailable\n"); 673 else if (rr.err == -ENOENT) 674 seq_puts(m, "Unassigned\n"); 675 else 676 seq_printf(m, "%llu\n", rr.val); 677 678 out: 679 rdtgroup_kn_unlock(of->kn); 680 return ret; 681 } 682 683 int resctrl_io_alloc_show(struct kernfs_open_file *of, struct seq_file *seq, void *v) 684 { 685 struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); 686 struct rdt_resource *r = s->res; 687 688 mutex_lock(&rdtgroup_mutex); 689 690 if (r->cache.io_alloc_capable) { 691 if (resctrl_arch_get_io_alloc_enabled(r)) 692 seq_puts(seq, "enabled\n"); 693 else 694 seq_puts(seq, "disabled\n"); 695 } else { 696 seq_puts(seq, "not supported\n"); 697 } 698 699 mutex_unlock(&rdtgroup_mutex); 700 701 return 0; 702 } 703 704 /* 705 * resctrl_io_alloc_closid_supported() - io_alloc feature utilizes the 706 * highest CLOSID value to direct I/O traffic. Ensure that io_alloc_closid 707 * is in the supported range. 708 */ 709 static bool resctrl_io_alloc_closid_supported(u32 io_alloc_closid) 710 { 711 return io_alloc_closid < closids_supported(); 712 } 713 714 /* 715 * Initialize io_alloc CLOSID cache resource CBM with all usable (shared 716 * and unused) cache portions. 717 */ 718 static int resctrl_io_alloc_init_cbm(struct resctrl_schema *s, u32 closid) 719 { 720 enum resctrl_conf_type peer_type; 721 struct rdt_resource *r = s->res; 722 struct rdt_ctrl_domain *d; 723 int ret; 724 725 rdt_staged_configs_clear(); 726 727 ret = rdtgroup_init_cat(s, closid); 728 if (ret < 0) 729 goto out; 730 731 /* Keep CDP_CODE and CDP_DATA of io_alloc CLOSID's CBM in sync. */ 732 if (resctrl_arch_get_cdp_enabled(r->rid)) { 733 peer_type = resctrl_peer_type(s->conf_type); 734 list_for_each_entry(d, &s->res->ctrl_domains, hdr.list) 735 memcpy(&d->staged_config[peer_type], 736 &d->staged_config[s->conf_type], 737 sizeof(d->staged_config[0])); 738 } 739 740 ret = resctrl_arch_update_domains(r, closid); 741 out: 742 rdt_staged_configs_clear(); 743 return ret; 744 } 745 746 /* 747 * resctrl_io_alloc_closid() - io_alloc feature routes I/O traffic using 748 * the highest available CLOSID. Retrieve the maximum CLOSID supported by the 749 * resource. Note that if Code Data Prioritization (CDP) is enabled, the number 750 * of available CLOSIDs is reduced by half. 751 */ 752 u32 resctrl_io_alloc_closid(struct rdt_resource *r) 753 { 754 if (resctrl_arch_get_cdp_enabled(r->rid)) 755 return resctrl_arch_get_num_closid(r) / 2 - 1; 756 else 757 return resctrl_arch_get_num_closid(r) - 1; 758 } 759 760 ssize_t resctrl_io_alloc_write(struct kernfs_open_file *of, char *buf, 761 size_t nbytes, loff_t off) 762 { 763 struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); 764 struct rdt_resource *r = s->res; 765 char const *grp_name; 766 u32 io_alloc_closid; 767 bool enable; 768 int ret; 769 770 ret = kstrtobool(buf, &enable); 771 if (ret) 772 return ret; 773 774 cpus_read_lock(); 775 mutex_lock(&rdtgroup_mutex); 776 777 rdt_last_cmd_clear(); 778 779 if (!r->cache.io_alloc_capable) { 780 rdt_last_cmd_printf("io_alloc is not supported on %s\n", s->name); 781 ret = -ENODEV; 782 goto out_unlock; 783 } 784 785 /* If the feature is already up to date, no action is needed. */ 786 if (resctrl_arch_get_io_alloc_enabled(r) == enable) 787 goto out_unlock; 788 789 io_alloc_closid = resctrl_io_alloc_closid(r); 790 if (!resctrl_io_alloc_closid_supported(io_alloc_closid)) { 791 rdt_last_cmd_printf("io_alloc CLOSID (ctrl_hw_id) %u is not available\n", 792 io_alloc_closid); 793 ret = -EINVAL; 794 goto out_unlock; 795 } 796 797 if (enable) { 798 if (!closid_alloc_fixed(io_alloc_closid)) { 799 grp_name = rdtgroup_name_by_closid(io_alloc_closid); 800 WARN_ON_ONCE(!grp_name); 801 rdt_last_cmd_printf("CLOSID (ctrl_hw_id) %u for io_alloc is used by %s group\n", 802 io_alloc_closid, grp_name ? grp_name : "another"); 803 ret = -ENOSPC; 804 goto out_unlock; 805 } 806 807 ret = resctrl_io_alloc_init_cbm(s, io_alloc_closid); 808 if (ret) { 809 rdt_last_cmd_puts("Failed to initialize io_alloc allocations\n"); 810 closid_free(io_alloc_closid); 811 goto out_unlock; 812 } 813 } else { 814 closid_free(io_alloc_closid); 815 } 816 817 ret = resctrl_arch_io_alloc_enable(r, enable); 818 if (enable && ret) { 819 rdt_last_cmd_puts("Failed to enable io_alloc feature\n"); 820 closid_free(io_alloc_closid); 821 } 822 823 out_unlock: 824 mutex_unlock(&rdtgroup_mutex); 825 cpus_read_unlock(); 826 827 return ret ?: nbytes; 828 } 829 830 int resctrl_io_alloc_cbm_show(struct kernfs_open_file *of, struct seq_file *seq, void *v) 831 { 832 struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); 833 struct rdt_resource *r = s->res; 834 int ret = 0; 835 836 cpus_read_lock(); 837 mutex_lock(&rdtgroup_mutex); 838 839 rdt_last_cmd_clear(); 840 841 if (!r->cache.io_alloc_capable) { 842 rdt_last_cmd_printf("io_alloc is not supported on %s\n", s->name); 843 ret = -ENODEV; 844 goto out_unlock; 845 } 846 847 if (!resctrl_arch_get_io_alloc_enabled(r)) { 848 rdt_last_cmd_printf("io_alloc is not enabled on %s\n", s->name); 849 ret = -EINVAL; 850 goto out_unlock; 851 } 852 853 /* 854 * When CDP is enabled, the CBMs of the highest CLOSID of CDP_CODE and 855 * CDP_DATA are kept in sync. As a result, the io_alloc CBMs shown for 856 * either CDP resource are identical and accurately represent the CBMs 857 * used for I/O. 858 */ 859 show_doms(seq, s, NULL, resctrl_io_alloc_closid(r)); 860 861 out_unlock: 862 mutex_unlock(&rdtgroup_mutex); 863 cpus_read_unlock(); 864 return ret; 865 } 866 867 static int resctrl_io_alloc_parse_line(char *line, struct rdt_resource *r, 868 struct resctrl_schema *s, u32 closid) 869 { 870 enum resctrl_conf_type peer_type; 871 struct rdt_parse_data data; 872 struct rdt_ctrl_domain *d; 873 char *dom = NULL, *id; 874 unsigned long dom_id; 875 876 next: 877 if (!line || line[0] == '\0') 878 return 0; 879 880 dom = strsep(&line, ";"); 881 id = strsep(&dom, "="); 882 if (!dom || kstrtoul(id, 10, &dom_id)) { 883 rdt_last_cmd_puts("Missing '=' or non-numeric domain\n"); 884 return -EINVAL; 885 } 886 887 dom = strim(dom); 888 list_for_each_entry(d, &r->ctrl_domains, hdr.list) { 889 if (d->hdr.id == dom_id) { 890 data.buf = dom; 891 data.mode = RDT_MODE_SHAREABLE; 892 data.closid = closid; 893 if (parse_cbm(&data, s, d)) 894 return -EINVAL; 895 /* 896 * Keep io_alloc CLOSID's CBM of CDP_CODE and CDP_DATA 897 * in sync. 898 */ 899 if (resctrl_arch_get_cdp_enabled(r->rid)) { 900 peer_type = resctrl_peer_type(s->conf_type); 901 memcpy(&d->staged_config[peer_type], 902 &d->staged_config[s->conf_type], 903 sizeof(d->staged_config[0])); 904 } 905 goto next; 906 } 907 } 908 909 return -EINVAL; 910 } 911 912 ssize_t resctrl_io_alloc_cbm_write(struct kernfs_open_file *of, char *buf, 913 size_t nbytes, loff_t off) 914 { 915 struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); 916 struct rdt_resource *r = s->res; 917 u32 io_alloc_closid; 918 int ret = 0; 919 920 /* Valid input requires a trailing newline */ 921 if (nbytes == 0 || buf[nbytes - 1] != '\n') 922 return -EINVAL; 923 924 buf[nbytes - 1] = '\0'; 925 926 cpus_read_lock(); 927 mutex_lock(&rdtgroup_mutex); 928 rdt_last_cmd_clear(); 929 930 if (!r->cache.io_alloc_capable) { 931 rdt_last_cmd_printf("io_alloc is not supported on %s\n", s->name); 932 ret = -ENODEV; 933 goto out_unlock; 934 } 935 936 if (!resctrl_arch_get_io_alloc_enabled(r)) { 937 rdt_last_cmd_printf("io_alloc is not enabled on %s\n", s->name); 938 ret = -EINVAL; 939 goto out_unlock; 940 } 941 942 io_alloc_closid = resctrl_io_alloc_closid(r); 943 944 rdt_staged_configs_clear(); 945 ret = resctrl_io_alloc_parse_line(buf, r, s, io_alloc_closid); 946 if (ret) 947 goto out_clear_configs; 948 949 ret = resctrl_arch_update_domains(r, io_alloc_closid); 950 951 out_clear_configs: 952 rdt_staged_configs_clear(); 953 out_unlock: 954 mutex_unlock(&rdtgroup_mutex); 955 cpus_read_unlock(); 956 957 return ret ?: nbytes; 958 } 959