772 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*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 17static 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 27static 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 36static 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 45static 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 56static 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 77static 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 86static 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 allowed100 * when there are no contexts attached to the adapter. Once101 * 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 118out:119 return rc ? rc : count;120}121 122static 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 136static 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 } else152 return -EINVAL;153 154 if ((rc = cxl_update_image_control(adapter)))155 return rc;156 157 return count;158}159 160static 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 169static 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);182 return count;183}184 185static 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 200static 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 209static 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 218static 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 227static 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 236static 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 247static 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;265err:266 mutex_unlock(&afu->contexts_lock);267 return rc;268}269 270static 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 279static 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 288static 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 316static 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 329static 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 345static 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 374static 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 387static 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, prevent413 * 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;427err:428 mutex_unlock(&afu->contexts_lock);429 return rc;430}431 432static 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 439static 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 446static 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 455static 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 467int 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;481err: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 491void 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 504struct 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 516static 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 524static 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 532static 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 540static 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 560static struct kobj_attribute vendor_attribute =561 __ATTR_RO(vendor);562static struct kobj_attribute device_attribute =563 __ATTR_RO(device);564static struct kobj_attribute class_attribute =565 __ATTR_RO(class);566 567static struct attribute *afu_cr_attrs[] = {568 &vendor_attribute.attr,569 &device_attribute.attr,570 &class_attribute.attr,571 NULL,572};573ATTRIBUTE_GROUPS(afu_cr);574 575static void release_afu_config_record(struct kobject *kobj)576{577 struct afu_config_record *cr = to_cr(kobj);578 579 kfree(cr);580}581 582static const struct kobj_type afu_config_record_type = {583 .sysfs_ops = &kobj_sysfs_ops,584 .release = release_afu_config_record,585 .default_groups = afu_cr_groups,586};587 588static struct afu_config_record *cxl_sysfs_afu_new_cr(struct cxl_afu *afu, int cr_idx)589{590 struct afu_config_record *cr;591 int rc;592 593 cr = kzalloc(sizeof(struct afu_config_record), GFP_KERNEL);594 if (!cr)595 return ERR_PTR(-ENOMEM);596 597 cr->cr = cr_idx;598 599 rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_DEVICE_ID, &cr->device);600 if (rc)601 goto err;602 rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_VENDOR_ID, &cr->vendor);603 if (rc)604 goto err;605 rc = cxl_ops->afu_cr_read32(afu, cr_idx, PCI_CLASS_REVISION, &cr->class);606 if (rc)607 goto err;608 cr->class >>= 8;609 610 /*611 * Export raw AFU PCIe like config record. For now this is read only by612 * root - we can expand that later to be readable by non-root and maybe613 * even writable provided we have a good use-case. Once we support614 * exposing AFUs through a virtual PHB they will get that for free from615 * Linux' PCI infrastructure, but until then it's not clear that we616 * need it for anything since the main use case is just identifying617 * AFUs, which can be done via the vendor, device and class attributes.618 */619 sysfs_bin_attr_init(&cr->config_attr);620 cr->config_attr.attr.name = "config";621 cr->config_attr.attr.mode = S_IRUSR;622 cr->config_attr.size = afu->crs_len;623 cr->config_attr.read = afu_read_config;624 625 rc = kobject_init_and_add(&cr->kobj, &afu_config_record_type,626 &afu->dev.kobj, "cr%i", cr->cr);627 if (rc)628 goto err1;629 630 rc = sysfs_create_bin_file(&cr->kobj, &cr->config_attr);631 if (rc)632 goto err1;633 634 rc = kobject_uevent(&cr->kobj, KOBJ_ADD);635 if (rc)636 goto err2;637 638 return cr;639err2:640 sysfs_remove_bin_file(&cr->kobj, &cr->config_attr);641err1:642 kobject_put(&cr->kobj);643 return ERR_PTR(rc);644err:645 kfree(cr);646 return ERR_PTR(rc);647}648 649void cxl_sysfs_afu_remove(struct cxl_afu *afu)650{651 struct device_attribute *dev_attr;652 struct afu_config_record *cr, *tmp;653 int i;654 655 /* remove the err buffer bin attribute */656 if (afu->eb_len)657 device_remove_bin_file(&afu->dev, &afu->attr_eb);658 659 for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {660 dev_attr = &afu_attrs[i];661 if (cxl_ops->support_attributes(dev_attr->attr.name,662 CXL_AFU_ATTRS))663 device_remove_file(&afu->dev, &afu_attrs[i]);664 }665 666 list_for_each_entry_safe(cr, tmp, &afu->crs, list) {667 sysfs_remove_bin_file(&cr->kobj, &cr->config_attr);668 kobject_put(&cr->kobj);669 }670}671 672int cxl_sysfs_afu_add(struct cxl_afu *afu)673{674 struct device_attribute *dev_attr;675 struct afu_config_record *cr;676 int i, rc;677 678 INIT_LIST_HEAD(&afu->crs);679 680 for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {681 dev_attr = &afu_attrs[i];682 if (cxl_ops->support_attributes(dev_attr->attr.name,683 CXL_AFU_ATTRS)) {684 if ((rc = device_create_file(&afu->dev, &afu_attrs[i])))685 goto err;686 }687 }688 689 /* conditionally create the add the binary file for error info buffer */690 if (afu->eb_len) {691 sysfs_attr_init(&afu->attr_eb.attr);692 693 afu->attr_eb.attr.name = "afu_err_buff";694 afu->attr_eb.attr.mode = S_IRUGO;695 afu->attr_eb.size = afu->eb_len;696 afu->attr_eb.read = afu_eb_read;697 698 rc = device_create_bin_file(&afu->dev, &afu->attr_eb);699 if (rc) {700 dev_err(&afu->dev,701 "Unable to create eb attr for the afu. Err(%d)\n",702 rc);703 goto err;704 }705 }706 707 for (i = 0; i < afu->crs_num; i++) {708 cr = cxl_sysfs_afu_new_cr(afu, i);709 if (IS_ERR(cr)) {710 rc = PTR_ERR(cr);711 goto err1;712 }713 list_add(&cr->list, &afu->crs);714 }715 716 return 0;717 718err1:719 cxl_sysfs_afu_remove(afu);720 return rc;721err:722 /* reset the eb_len as we havent created the bin attr */723 afu->eb_len = 0;724 725 for (i--; i >= 0; i--) {726 dev_attr = &afu_attrs[i];727 if (cxl_ops->support_attributes(dev_attr->attr.name,728 CXL_AFU_ATTRS))729 device_remove_file(&afu->dev, &afu_attrs[i]);730 }731 return rc;732}733 734int cxl_sysfs_afu_m_add(struct cxl_afu *afu)735{736 struct device_attribute *dev_attr;737 int i, rc;738 739 for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) {740 dev_attr = &afu_master_attrs[i];741 if (cxl_ops->support_attributes(dev_attr->attr.name,742 CXL_AFU_MASTER_ATTRS)) {743 if ((rc = device_create_file(afu->chardev_m, &afu_master_attrs[i])))744 goto err;745 }746 }747 748 return 0;749 750err:751 for (i--; i >= 0; i--) {752 dev_attr = &afu_master_attrs[i];753 if (cxl_ops->support_attributes(dev_attr->attr.name,754 CXL_AFU_MASTER_ATTRS))755 device_remove_file(afu->chardev_m, &afu_master_attrs[i]);756 }757 return rc;758}759 760void cxl_sysfs_afu_m_remove(struct cxl_afu *afu)761{762 struct device_attribute *dev_attr;763 int i;764 765 for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) {766 dev_attr = &afu_master_attrs[i];767 if (cxl_ops->support_attributes(dev_attr->attr.name,768 CXL_AFU_MASTER_ATTRS))769 device_remove_file(afu->chardev_m, &afu_master_attrs[i]);770 }771}772