1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright 2014 IBM Corp. 4 */ 5 6 #include <linux/kernel.h> 7 #include <linux/device.h> 8 #include <linux/sysfs.h> 9 #include <linux/pci_regs.h> 10 11 #include "cxl.h" 12 13 #define to_afu_chardev_m(d) dev_get_drvdata(d) 14 15 /********* Adapter attributes **********************************************/ 16 17 static ssize_t caia_version_show(struct device *device, 18 struct device_attribute *attr, 19 char *buf) 20 { 21 struct cxl *adapter = to_cxl_adapter(device); 22 23 return scnprintf(buf, PAGE_SIZE, "%i.%i\n", adapter->caia_major, 24 adapter->caia_minor); 25 } 26 27 static ssize_t psl_revision_show(struct device *device, 28 struct device_attribute *attr, 29 char *buf) 30 { 31 struct cxl *adapter = to_cxl_adapter(device); 32 33 return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_rev); 34 } 35 36 static ssize_t base_image_show(struct device *device, 37 struct device_attribute *attr, 38 char *buf) 39 { 40 struct cxl *adapter = to_cxl_adapter(device); 41 42 return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->base_image); 43 } 44 45 static ssize_t image_loaded_show(struct device *device, 46 struct device_attribute *attr, 47 char *buf) 48 { 49 struct cxl *adapter = to_cxl_adapter(device); 50 51 if (adapter->user_image_loaded) 52 return scnprintf(buf, PAGE_SIZE, "user\n"); 53 return scnprintf(buf, PAGE_SIZE, "factory\n"); 54 } 55 56 static ssize_t psl_timebase_synced_show(struct device *device, 57 struct device_attribute *attr, 58 char *buf) 59 { 60 struct cxl *adapter = to_cxl_adapter(device); 61 u64 psl_tb, delta; 62 63 /* Recompute the status only in native mode */ 64 if (cpu_has_feature(CPU_FTR_HVMODE)) { 65 psl_tb = adapter->native->sl_ops->timebase_read(adapter); 66 delta = abs(mftb() - psl_tb); 67 68 /* CORE TB and PSL TB difference <= 16usecs ? */ 69 adapter->psl_timebase_synced = (tb_to_ns(delta) < 16000) ? true : false; 70 pr_devel("PSL timebase %s - delta: 0x%016llx\n", 71 (tb_to_ns(delta) < 16000) ? "synchronized" : 72 "not synchronized", tb_to_ns(delta)); 73 } 74 return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_timebase_synced); 75 } 76 77 static ssize_t tunneled_ops_supported_show(struct device *device, 78 struct device_attribute *attr, 79 char *buf) 80 { 81 struct cxl *adapter = to_cxl_adapter(device); 82 83 return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->tunneled_ops_supported); 84 } 85 86 static ssize_t reset_adapter_store(struct device *device, 87 struct device_attribute *attr, 88 const char *buf, size_t count) 89 { 90 struct cxl *adapter = to_cxl_adapter(device); 91 int rc; 92 int val; 93 94 rc = sscanf(buf, "%i", &val); 95 if ((rc != 1) || (val != 1 && val != -1)) 96 return -EINVAL; 97 98 /* 99 * See if we can lock the context mapping that's only allowed 100 * when there are no contexts attached to the adapter. Once 101 * taken this will also prevent any context from getting activated. 102 */ 103 if (val == 1) { 104 rc = cxl_adapter_context_lock(adapter); 105 if (rc) 106 goto out; 107 108 rc = cxl_ops->adapter_reset(adapter); 109 /* In case reset failed release context lock */ 110 if (rc) 111 cxl_adapter_context_unlock(adapter); 112 113 } else if (val == -1) { 114 /* Perform a forced adapter reset */ 115 rc = cxl_ops->adapter_reset(adapter); 116 } 117 118 out: 119 return rc ? rc : count; 120 } 121 122 static ssize_t load_image_on_perst_show(struct device *device, 123 struct device_attribute *attr, 124 char *buf) 125 { 126 struct cxl *adapter = to_cxl_adapter(device); 127 128 if (!adapter->perst_loads_image) 129 return scnprintf(buf, PAGE_SIZE, "none\n"); 130 131 if (adapter->perst_select_user) 132 return scnprintf(buf, PAGE_SIZE, "user\n"); 133 return scnprintf(buf, PAGE_SIZE, "factory\n"); 134 } 135 136 static ssize_t load_image_on_perst_store(struct device *device, 137 struct device_attribute *attr, 138 const char *buf, size_t count) 139 { 140 struct cxl *adapter = to_cxl_adapter(device); 141 int rc; 142 143 if (!strncmp(buf, "none", 4)) 144 adapter->perst_loads_image = false; 145 else if (!strncmp(buf, "user", 4)) { 146 adapter->perst_select_user = true; 147 adapter->perst_loads_image = true; 148 } else if (!strncmp(buf, "factory", 7)) { 149 adapter->perst_select_user = false; 150 adapter->perst_loads_image = true; 151 } else 152 return -EINVAL; 153 154 if ((rc = cxl_update_image_control(adapter))) 155 return rc; 156 157 return count; 158 } 159 160 static ssize_t perst_reloads_same_image_show(struct device *device, 161 struct device_attribute *attr, 162 char *buf) 163 { 164 struct cxl *adapter = to_cxl_adapter(device); 165 166 return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->perst_same_image); 167 } 168 169 static ssize_t perst_reloads_same_image_store(struct device *device, 170 struct device_attribute *attr, 171 const char *buf, size_t count) 172 { 173 struct cxl *adapter = to_cxl_adapter(device); 174 int rc; 175 int val; 176 177 rc = sscanf(buf, "%i", &val); 178 if ((rc != 1) || !(val == 1 || val == 0)) 179 return -EINVAL; 180 181 adapter->perst_same_image = (val == 1 ? true : false); 182 return count; 183 } 184 185 static struct device_attribute adapter_attrs[] = { 186 __ATTR_RO(caia_version), 187 __ATTR_RO(psl_revision), 188 __ATTR_RO(base_image), 189 __ATTR_RO(image_loaded), 190 __ATTR_RO(psl_timebase_synced), 191 __ATTR_RO(tunneled_ops_supported), 192 __ATTR_RW(load_image_on_perst), 193 __ATTR_RW(perst_reloads_same_image), 194 __ATTR(reset, S_IWUSR, NULL, reset_adapter_store), 195 }; 196 197 198 /********* AFU master specific attributes **********************************/ 199 200 static ssize_t mmio_size_show_master(struct device *device, 201 struct device_attribute *attr, 202 char *buf) 203 { 204 struct cxl_afu *afu = to_afu_chardev_m(device); 205 206 return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size); 207 } 208 209 static ssize_t pp_mmio_off_show(struct device *device, 210 struct device_attribute *attr, 211 char *buf) 212 { 213 struct cxl_afu *afu = to_afu_chardev_m(device); 214 215 return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->native->pp_offset); 216 } 217 218 static ssize_t pp_mmio_len_show(struct device *device, 219 struct device_attribute *attr, 220 char *buf) 221 { 222 struct cxl_afu *afu = to_afu_chardev_m(device); 223 224 return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size); 225 } 226 227 static struct device_attribute afu_master_attrs[] = { 228 __ATTR(mmio_size, S_IRUGO, mmio_size_show_master, NULL), 229 __ATTR_RO(pp_mmio_off), 230 __ATTR_RO(pp_mmio_len), 231 }; 232 233 234 /********* AFU attributes **************************************************/ 235 236 static ssize_t mmio_size_show(struct device *device, 237 struct device_attribute *attr, 238 char *buf) 239 { 240 struct cxl_afu *afu = to_cxl_afu(device); 241 242 if (afu->pp_size) 243 return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_size); 244 return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->adapter->ps_size); 245 } 246 247 static ssize_t reset_store_afu(struct device *device, 248 struct device_attribute *attr, 249 const char *buf, size_t count) 250 { 251 struct cxl_afu *afu = to_cxl_afu(device); 252 int rc; 253 254 /* Not safe to reset if it is currently in use */ 255 mutex_lock(&afu->contexts_lock); 256 if (!idr_is_empty(&afu->contexts_idr)) { 257 rc = -EBUSY; 258 goto err; 259 } 260 261 if ((rc = cxl_ops->afu_reset(afu))) 262 goto err; 263 264 rc = count; 265 err: 266 mutex_unlock(&afu->contexts_lock); 267 return rc; 268 } 269 270 static ssize_t irqs_min_show(struct device *device, 271 struct device_attribute *attr, 272 char *buf) 273 { 274 struct cxl_afu *afu = to_cxl_afu(device); 275 276 return scnprintf(buf, PAGE_SIZE, "%i\n", afu->pp_irqs); 277 } 278 279 static ssize_t irqs_max_show(struct device *device, 280 struct device_attribute *attr, 281 char *buf) 282 { 283 struct cxl_afu *afu = to_cxl_afu(device); 284 285 return scnprintf(buf, PAGE_SIZE, "%i\n", afu->irqs_max); 286 } 287 288 static ssize_t irqs_max_store(struct device *device, 289 struct device_attribute *attr, 290 const char *buf, size_t count) 291 { 292 struct cxl_afu *afu = to_cxl_afu(device); 293 ssize_t ret; 294 int irqs_max; 295 296 ret = sscanf(buf, "%i", &irqs_max); 297 if (ret != 1) 298 return -EINVAL; 299 300 if (irqs_max < afu->pp_irqs) 301 return -EINVAL; 302 303 if (cpu_has_feature(CPU_FTR_HVMODE)) { 304 if (irqs_max > afu->adapter->user_irqs) 305 return -EINVAL; 306 } else { 307 /* pHyp sets a per-AFU limit */ 308 if (irqs_max > afu->guest->max_ints) 309 return -EINVAL; 310 } 311 312 afu->irqs_max = irqs_max; 313 return count; 314 } 315 316 static ssize_t modes_supported_show(struct device *device, 317 struct device_attribute *attr, char *buf) 318 { 319 struct cxl_afu *afu = to_cxl_afu(device); 320 char *p = buf, *end = buf + PAGE_SIZE; 321 322 if (afu->modes_supported & CXL_MODE_DEDICATED) 323 p += scnprintf(p, end - p, "dedicated_process\n"); 324 if (afu->modes_supported & CXL_MODE_DIRECTED) 325 p += scnprintf(p, end - p, "afu_directed\n"); 326 return (p - buf); 327 } 328 329 static ssize_t prefault_mode_show(struct device *device, 330 struct device_attribute *attr, 331 char *buf) 332 { 333 struct cxl_afu *afu = to_cxl_afu(device); 334 335 switch (afu->prefault_mode) { 336 case CXL_PREFAULT_WED: 337 return scnprintf(buf, PAGE_SIZE, "work_element_descriptor\n"); 338 case CXL_PREFAULT_ALL: 339 return scnprintf(buf, PAGE_SIZE, "all\n"); 340 default: 341 return scnprintf(buf, PAGE_SIZE, "none\n"); 342 } 343 } 344 345 static ssize_t prefault_mode_store(struct device *device, 346 struct device_attribute *attr, 347 const char *buf, size_t count) 348 { 349 struct cxl_afu *afu = to_cxl_afu(device); 350 enum prefault_modes mode = -1; 351 352 if (!strncmp(buf, "none", 4)) 353 mode = CXL_PREFAULT_NONE; 354 else { 355 if (!radix_enabled()) { 356 357 /* only allowed when not in radix mode */ 358 if (!strncmp(buf, "work_element_descriptor", 23)) 359 mode = CXL_PREFAULT_WED; 360 if (!strncmp(buf, "all", 3)) 361 mode = CXL_PREFAULT_ALL; 362 } else { 363 dev_err(device, "Cannot prefault with radix enabled\n"); 364 } 365 } 366 367 if (mode == -1) 368 return -EINVAL; 369 370 afu->prefault_mode = mode; 371 return count; 372 } 373 374 static ssize_t mode_show(struct device *device, 375 struct device_attribute *attr, 376 char *buf) 377 { 378 struct cxl_afu *afu = to_cxl_afu(device); 379 380 if (afu->current_mode == CXL_MODE_DEDICATED) 381 return scnprintf(buf, PAGE_SIZE, "dedicated_process\n"); 382 if (afu->current_mode == CXL_MODE_DIRECTED) 383 return scnprintf(buf, PAGE_SIZE, "afu_directed\n"); 384 return scnprintf(buf, PAGE_SIZE, "none\n"); 385 } 386 387 static ssize_t mode_store(struct device *device, struct device_attribute *attr, 388 const char *buf, size_t count) 389 { 390 struct cxl_afu *afu = to_cxl_afu(device); 391 int old_mode, mode = -1; 392 int rc = -EBUSY; 393 394 /* can't change this if we have a user */ 395 mutex_lock(&afu->contexts_lock); 396 if (!idr_is_empty(&afu->contexts_idr)) 397 goto err; 398 399 if (!strncmp(buf, "dedicated_process", 17)) 400 mode = CXL_MODE_DEDICATED; 401 if (!strncmp(buf, "afu_directed", 12)) 402 mode = CXL_MODE_DIRECTED; 403 if (!strncmp(buf, "none", 4)) 404 mode = 0; 405 406 if (mode == -1) { 407 rc = -EINVAL; 408 goto err; 409 } 410 411 /* 412 * afu_deactivate_mode needs to be done outside the lock, prevent 413 * other contexts coming in before we are ready: 414 */ 415 old_mode = afu->current_mode; 416 afu->current_mode = 0; 417 afu->num_procs = 0; 418 419 mutex_unlock(&afu->contexts_lock); 420 421 if ((rc = cxl_ops->afu_deactivate_mode(afu, old_mode))) 422 return rc; 423 if ((rc = cxl_ops->afu_activate_mode(afu, mode))) 424 return rc; 425 426 return count; 427 err: 428 mutex_unlock(&afu->contexts_lock); 429 return rc; 430 } 431 432 static ssize_t api_version_show(struct device *device, 433 struct device_attribute *attr, 434 char *buf) 435 { 436 return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION); 437 } 438 439 static ssize_t api_version_compatible_show(struct device *device, 440 struct device_attribute *attr, 441 char *buf) 442 { 443 return scnprintf(buf, PAGE_SIZE, "%i\n", CXL_API_VERSION_COMPATIBLE); 444 } 445 446 static ssize_t afu_eb_read(struct file *filp, struct kobject *kobj, 447 struct bin_attribute *bin_attr, char *buf, 448 loff_t off, size_t count) 449 { 450 struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj)); 451 452 return cxl_ops->afu_read_err_buffer(afu, buf, off, count); 453 } 454 455 static struct device_attribute afu_attrs[] = { 456 __ATTR_RO(mmio_size), 457 __ATTR_RO(irqs_min), 458 __ATTR_RW(irqs_max), 459 __ATTR_RO(modes_supported), 460 __ATTR_RW(mode), 461 __ATTR_RW(prefault_mode), 462 __ATTR_RO(api_version), 463 __ATTR_RO(api_version_compatible), 464 __ATTR(reset, S_IWUSR, NULL, reset_store_afu), 465 }; 466 467 int cxl_sysfs_adapter_add(struct cxl *adapter) 468 { 469 struct device_attribute *dev_attr; 470 int i, rc; 471 472 for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) { 473 dev_attr = &adapter_attrs[i]; 474 if (cxl_ops->support_attributes(dev_attr->attr.name, 475 CXL_ADAPTER_ATTRS)) { 476 if ((rc = device_create_file(&adapter->dev, dev_attr))) 477 goto err; 478 } 479 } 480 return 0; 481 err: 482 for (i--; i >= 0; i--) { 483 dev_attr = &adapter_attrs[i]; 484 if (cxl_ops->support_attributes(dev_attr->attr.name, 485 CXL_ADAPTER_ATTRS)) 486 device_remove_file(&adapter->dev, dev_attr); 487 } 488 return rc; 489 } 490 491 void cxl_sysfs_adapter_remove(struct cxl *adapter) 492 { 493 struct device_attribute *dev_attr; 494 int i; 495 496 for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) { 497 dev_attr = &adapter_attrs[i]; 498 if (cxl_ops->support_attributes(dev_attr->attr.name, 499 CXL_ADAPTER_ATTRS)) 500 device_remove_file(&adapter->dev, dev_attr); 501 } 502 } 503 504 struct afu_config_record { 505 struct kobject kobj; 506 struct bin_attribute config_attr; 507 struct list_head list; 508 int cr; 509 u16 device; 510 u16 vendor; 511 u32 class; 512 }; 513 514 #define to_cr(obj) container_of(obj, struct afu_config_record, kobj) 515 516 static ssize_t vendor_show(struct kobject *kobj, 517 struct kobj_attribute *attr, char *buf) 518 { 519 struct afu_config_record *cr = to_cr(kobj); 520 521 return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->vendor); 522 } 523 524 static ssize_t device_show(struct kobject *kobj, 525 struct kobj_attribute *attr, char *buf) 526 { 527 struct afu_config_record *cr = to_cr(kobj); 528 529 return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->device); 530 } 531 532 static ssize_t class_show(struct kobject *kobj, 533 struct kobj_attribute *attr, char *buf) 534 { 535 struct afu_config_record *cr = to_cr(kobj); 536 537 return scnprintf(buf, PAGE_SIZE, "0x%.6x\n", cr->class); 538 } 539 540 static ssize_t afu_read_config(struct file *filp, struct kobject *kobj, 541 struct bin_attribute *bin_attr, char *buf, 542 loff_t off, size_t count) 543 { 544 struct afu_config_record *cr = to_cr(kobj); 545 struct cxl_afu *afu = to_cxl_afu(kobj_to_dev(kobj->parent)); 546 547 u64 i, j, val, rc; 548 549 for (i = 0; i < count;) { 550 rc = cxl_ops->afu_cr_read64(afu, cr->cr, off & ~0x7, &val); 551 if (rc) 552 val = ~0ULL; 553 for (j = off & 0x7; j < 8 && i < count; i++, j++, off++) 554 buf[i] = (val >> (j * 8)) & 0xff; 555 } 556 557 return count; 558 } 559 560 static struct kobj_attribute vendor_attribute = 561 __ATTR_RO(vendor); 562 static struct kobj_attribute device_attribute = 563 __ATTR_RO(device); 564 static struct kobj_attribute class_attribute = 565 __ATTR_RO(class); 566 567 static struct attribute *afu_cr_attrs[] = { 568 &vendor_attribute.attr, 569 &device_attribute.attr, 570 &class_attribute.attr, 571 NULL, 572 }; 573 574 static void release_afu_config_record(struct kobject *kobj) 575 { 576 struct afu_config_record *cr = to_cr(kobj); 577 578 kfree(cr); 579 } 580 581 static struct kobj_type afu_config_record_type = { 582 .sysfs_ops = &kobj_sysfs_ops, 583 .release = release_afu_config_record, 584 .default_attrs = afu_cr_attrs, 585 }; 586 587 static struct afu_config_record *cxl_sysfs_afu_new_cr(struct cxl_afu *afu, int cr_idx) 588 { 589 struct afu_config_record *cr; 590 int rc; 591 592 cr = kzalloc(sizeof(struct afu_config_record), GFP_KERNEL); 593 if (!cr) 594 return ERR_PTR(-ENOMEM); 595 596 cr->cr = cr_idx; 597 598 rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_DEVICE_ID, &cr->device); 599 if (rc) 600 goto err; 601 rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_VENDOR_ID, &cr->vendor); 602 if (rc) 603 goto err; 604 rc = cxl_ops->afu_cr_read32(afu, cr_idx, PCI_CLASS_REVISION, &cr->class); 605 if (rc) 606 goto err; 607 cr->class >>= 8; 608 609 /* 610 * Export raw AFU PCIe like config record. For now this is read only by 611 * root - we can expand that later to be readable by non-root and maybe 612 * even writable provided we have a good use-case. Once we support 613 * exposing AFUs through a virtual PHB they will get that for free from 614 * Linux' PCI infrastructure, but until then it's not clear that we 615 * need it for anything since the main use case is just identifying 616 * AFUs, which can be done via the vendor, device and class attributes. 617 */ 618 sysfs_bin_attr_init(&cr->config_attr); 619 cr->config_attr.attr.name = "config"; 620 cr->config_attr.attr.mode = S_IRUSR; 621 cr->config_attr.size = afu->crs_len; 622 cr->config_attr.read = afu_read_config; 623 624 rc = kobject_init_and_add(&cr->kobj, &afu_config_record_type, 625 &afu->dev.kobj, "cr%i", cr->cr); 626 if (rc) 627 goto err; 628 629 rc = sysfs_create_bin_file(&cr->kobj, &cr->config_attr); 630 if (rc) 631 goto err1; 632 633 rc = kobject_uevent(&cr->kobj, KOBJ_ADD); 634 if (rc) 635 goto err2; 636 637 return cr; 638 err2: 639 sysfs_remove_bin_file(&cr->kobj, &cr->config_attr); 640 err1: 641 kobject_put(&cr->kobj); 642 return ERR_PTR(rc); 643 err: 644 kfree(cr); 645 return ERR_PTR(rc); 646 } 647 648 void cxl_sysfs_afu_remove(struct cxl_afu *afu) 649 { 650 struct device_attribute *dev_attr; 651 struct afu_config_record *cr, *tmp; 652 int i; 653 654 /* remove the err buffer bin attribute */ 655 if (afu->eb_len) 656 device_remove_bin_file(&afu->dev, &afu->attr_eb); 657 658 for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) { 659 dev_attr = &afu_attrs[i]; 660 if (cxl_ops->support_attributes(dev_attr->attr.name, 661 CXL_AFU_ATTRS)) 662 device_remove_file(&afu->dev, &afu_attrs[i]); 663 } 664 665 list_for_each_entry_safe(cr, tmp, &afu->crs, list) { 666 sysfs_remove_bin_file(&cr->kobj, &cr->config_attr); 667 kobject_put(&cr->kobj); 668 } 669 } 670 671 int cxl_sysfs_afu_add(struct cxl_afu *afu) 672 { 673 struct device_attribute *dev_attr; 674 struct afu_config_record *cr; 675 int i, rc; 676 677 INIT_LIST_HEAD(&afu->crs); 678 679 for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) { 680 dev_attr = &afu_attrs[i]; 681 if (cxl_ops->support_attributes(dev_attr->attr.name, 682 CXL_AFU_ATTRS)) { 683 if ((rc = device_create_file(&afu->dev, &afu_attrs[i]))) 684 goto err; 685 } 686 } 687 688 /* conditionally create the add the binary file for error info buffer */ 689 if (afu->eb_len) { 690 sysfs_attr_init(&afu->attr_eb.attr); 691 692 afu->attr_eb.attr.name = "afu_err_buff"; 693 afu->attr_eb.attr.mode = S_IRUGO; 694 afu->attr_eb.size = afu->eb_len; 695 afu->attr_eb.read = afu_eb_read; 696 697 rc = device_create_bin_file(&afu->dev, &afu->attr_eb); 698 if (rc) { 699 dev_err(&afu->dev, 700 "Unable to create eb attr for the afu. Err(%d)\n", 701 rc); 702 goto err; 703 } 704 } 705 706 for (i = 0; i < afu->crs_num; i++) { 707 cr = cxl_sysfs_afu_new_cr(afu, i); 708 if (IS_ERR(cr)) { 709 rc = PTR_ERR(cr); 710 goto err1; 711 } 712 list_add(&cr->list, &afu->crs); 713 } 714 715 return 0; 716 717 err1: 718 cxl_sysfs_afu_remove(afu); 719 return rc; 720 err: 721 /* reset the eb_len as we havent created the bin attr */ 722 afu->eb_len = 0; 723 724 for (i--; i >= 0; i--) { 725 dev_attr = &afu_attrs[i]; 726 if (cxl_ops->support_attributes(dev_attr->attr.name, 727 CXL_AFU_ATTRS)) 728 device_remove_file(&afu->dev, &afu_attrs[i]); 729 } 730 return rc; 731 } 732 733 int cxl_sysfs_afu_m_add(struct cxl_afu *afu) 734 { 735 struct device_attribute *dev_attr; 736 int i, rc; 737 738 for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) { 739 dev_attr = &afu_master_attrs[i]; 740 if (cxl_ops->support_attributes(dev_attr->attr.name, 741 CXL_AFU_MASTER_ATTRS)) { 742 if ((rc = device_create_file(afu->chardev_m, &afu_master_attrs[i]))) 743 goto err; 744 } 745 } 746 747 return 0; 748 749 err: 750 for (i--; i >= 0; i--) { 751 dev_attr = &afu_master_attrs[i]; 752 if (cxl_ops->support_attributes(dev_attr->attr.name, 753 CXL_AFU_MASTER_ATTRS)) 754 device_remove_file(afu->chardev_m, &afu_master_attrs[i]); 755 } 756 return rc; 757 } 758 759 void cxl_sysfs_afu_m_remove(struct cxl_afu *afu) 760 { 761 struct device_attribute *dev_attr; 762 int i; 763 764 for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) { 765 dev_attr = &afu_master_attrs[i]; 766 if (cxl_ops->support_attributes(dev_attr->attr.name, 767 CXL_AFU_MASTER_ATTRS)) 768 device_remove_file(afu->chardev_m, &afu_master_attrs[i]); 769 } 770 } 771