cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sysfs.c (19184B)


      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
     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 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
    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	} else
    152		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, 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;
    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 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 by
    612	 * root - we can expand that later to be readable by non-root and maybe
    613	 * even writable provided we have a good use-case. Once we support
    614	 * exposing AFUs through a virtual PHB they will get that for free from
    615	 * Linux' PCI infrastructure, but until then it's not clear that we
    616	 * need it for anything since the main use case is just identifying
    617	 * 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}