From 5be587b1110132b4f05e0bc3515a145365e910fe Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Fri, 4 Mar 2016 12:26:28 +0100 Subject: cxl: Introduce implementation-specific API The backend API (in cxl.h) lists some low-level functions whose implementation is different on bare-metal and in a guest. Each environment implements its own functions, and the common code uses them through function pointers, defined in cxl_backend_ops Co-authored-by: Christophe Lombard Signed-off-by: Frederic Barrat Signed-off-by: Christophe Lombard Reviewed-by: Manoj Kumar Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/sysfs.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) (limited to 'drivers/misc/cxl/sysfs.c') diff --git a/drivers/misc/cxl/sysfs.c b/drivers/misc/cxl/sysfs.c index 02006f7109a8..300eafe4ed43 100644 --- a/drivers/misc/cxl/sysfs.c +++ b/drivers/misc/cxl/sysfs.c @@ -69,7 +69,7 @@ static ssize_t reset_adapter_store(struct device *device, if ((rc != 1) || (val != 1)) return -EINVAL; - if ((rc = cxl_reset(adapter))) + if ((rc = cxl_ops->adapter_reset(adapter))) return rc; return count; } @@ -211,7 +211,7 @@ static ssize_t reset_store_afu(struct device *device, goto err; } - if ((rc = __cxl_afu_reset(afu))) + if ((rc = cxl_ops->afu_reset(afu))) goto err; rc = count; @@ -348,7 +348,7 @@ static ssize_t mode_store(struct device *device, struct device_attribute *attr, } /* - * cxl_afu_deactivate_mode needs to be done outside the lock, prevent + * afu_deactivate_mode needs to be done outside the lock, prevent * other contexts coming in before we are ready: */ old_mode = afu->current_mode; @@ -357,9 +357,9 @@ static ssize_t mode_store(struct device *device, struct device_attribute *attr, mutex_unlock(&afu->contexts_lock); - if ((rc = _cxl_afu_deactivate_mode(afu, old_mode))) + if ((rc = cxl_ops->afu_deactivate_mode(afu, old_mode))) return rc; - if ((rc = cxl_afu_activate_mode(afu, mode))) + if ((rc = cxl_ops->afu_activate_mode(afu, mode))) return rc; return count; @@ -389,7 +389,7 @@ static ssize_t afu_eb_read(struct file *filp, struct kobject *kobj, struct cxl_afu *afu = to_cxl_afu(container_of(kobj, struct device, kobj)); - return cxl_afu_read_err_buffer(afu, buf, off, count); + return cxl_ops->afu_read_err_buffer(afu, buf, off, count); } static struct device_attribute afu_attrs[] = { @@ -469,10 +469,12 @@ static ssize_t afu_read_config(struct file *filp, struct kobject *kobj, struct afu_config_record *cr = to_cr(kobj); struct cxl_afu *afu = to_cxl_afu(container_of(kobj->parent, struct device, kobj)); - u64 i, j, val; + u64 i, j, val, rc; for (i = 0; i < count;) { - val = cxl_afu_cr_read64(afu, cr->cr, off & ~0x7); + rc = cxl_ops->afu_cr_read64(afu, cr->cr, off & ~0x7, &val); + if (rc) + val = ~0ULL; for (j = off & 0x7; j < 8 && i < count; i++, j++, off++) buf[i] = (val >> (j * 8)) & 0xff; } @@ -517,9 +519,17 @@ static struct afu_config_record *cxl_sysfs_afu_new_cr(struct cxl_afu *afu, int c return ERR_PTR(-ENOMEM); cr->cr = cr_idx; - cr->device = cxl_afu_cr_read16(afu, cr_idx, PCI_DEVICE_ID); - cr->vendor = cxl_afu_cr_read16(afu, cr_idx, PCI_VENDOR_ID); - cr->class = cxl_afu_cr_read32(afu, cr_idx, PCI_CLASS_REVISION) >> 8; + + rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_DEVICE_ID, &cr->device); + if (rc) + goto err; + rc = cxl_ops->afu_cr_read16(afu, cr_idx, PCI_VENDOR_ID, &cr->vendor); + if (rc) + goto err; + rc = cxl_ops->afu_cr_read32(afu, cr_idx, PCI_CLASS_REVISION, &cr->class); + if (rc) + goto err; + cr->class >>= 8; /* * Export raw AFU PCIe like config record. For now this is read only by -- cgit v1.2.3 From cbffa3a5146a90f46806cef3a98b8be5833727e8 Mon Sep 17 00:00:00 2001 From: Christophe Lombard Date: Fri, 4 Mar 2016 12:26:35 +0100 Subject: cxl: Separate bare-metal fields in adapter and AFU data structures Introduce sub-structures containing the bare-metal specific fields in the structures describing the adapter (struct cxl) and AFU (struct cxl_afu). Update all their references. Co-authored-by: Frederic Barrat Signed-off-by: Frederic Barrat Signed-off-by: Christophe Lombard Reviewed-by: Manoj Kumar Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/context.c | 2 +- drivers/misc/cxl/cxl.h | 84 +++++++++++++++++++++++++++------------- drivers/misc/cxl/irq.c | 2 +- drivers/misc/cxl/main.c | 1 - drivers/misc/cxl/native.c | 85 +++++++++++++++++++++-------------------- drivers/misc/cxl/pci.c | 95 +++++++++++++++++++++++++++------------------- drivers/misc/cxl/sysfs.c | 2 +- drivers/misc/cxl/vphb.c | 4 +- 8 files changed, 164 insertions(+), 111 deletions(-) (limited to 'drivers/misc/cxl/sysfs.c') diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c index 46f98441d7a1..200837f7612b 100644 --- a/drivers/misc/cxl/context.c +++ b/drivers/misc/cxl/context.c @@ -96,7 +96,7 @@ int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master, ctx->pe = i; if (cpu_has_feature(CPU_FTR_HVMODE)) - ctx->elem = &ctx->afu->spa[i]; + ctx->elem = &ctx->afu->native->spa[i]; ctx->pe_inserted = false; /* diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index ac655a698e41..3a1fabd41072 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -344,18 +344,44 @@ struct cxl_sste { #define to_cxl_adapter(d) container_of(d, struct cxl, dev) #define to_cxl_afu(d) container_of(d, struct cxl_afu, dev) -struct cxl_afu { +struct cxl_afu_native { + void __iomem *p1n_mmio; + void __iomem *afu_desc_mmio; irq_hw_number_t psl_hwirq; + unsigned int psl_virq; + struct mutex spa_mutex; + /* + * Only the first part of the SPA is used for the process element + * linked list. The only other part that software needs to worry about + * is sw_command_status, which we store a separate pointer to. + * Everything else in the SPA is only used by hardware + */ + struct cxl_process_element *spa; + __be64 *sw_command_status; + unsigned int spa_size; + int spa_order; + int spa_max_procs; + u64 pp_offset; +}; + +struct cxl_afu_guest { + u64 handle; + phys_addr_t p2n_phys; + u64 p2n_size; + int max_ints; +}; + +struct cxl_afu { + struct cxl_afu_native *native; + struct cxl_afu_guest *guest; irq_hw_number_t serr_hwirq; - char *err_irq_name; - char *psl_irq_name; unsigned int serr_virq; - void __iomem *p1n_mmio; + char *psl_irq_name; + char *err_irq_name; void __iomem *p2n_mmio; phys_addr_t psn_phys; - u64 pp_offset; u64 pp_size; - void __iomem *afu_desc_mmio; + struct cxl *adapter; struct device dev; struct cdev afu_cdev_s, afu_cdev_m, afu_cdev_d; @@ -363,26 +389,12 @@ struct cxl_afu { struct idr contexts_idr; struct dentry *debugfs; struct mutex contexts_lock; - struct mutex spa_mutex; spinlock_t afu_cntl_lock; /* AFU error buffer fields and bin attribute for sysfs */ u64 eb_len, eb_offset; struct bin_attribute attr_eb; - /* - * Only the first part of the SPA is used for the process element - * linked list. The only other part that software needs to worry about - * is sw_command_status, which we store a separate pointer to. - * Everything else in the SPA is only used by hardware - */ - struct cxl_process_element *spa; - __be64 *sw_command_status; - unsigned int spa_size; - int spa_order; - int spa_max_procs; - unsigned int psl_virq; - /* pointer to the vphb */ struct pci_controller *phb; @@ -488,11 +500,34 @@ struct cxl_context { struct rcu_head rcu; }; -struct cxl { +struct cxl_native { + u64 afu_desc_off; + u64 afu_desc_size; void __iomem *p1_mmio; void __iomem *p2_mmio; irq_hw_number_t err_hwirq; unsigned int err_virq; + u64 ps_off; +}; + +struct cxl_guest { + struct platform_device *pdev; + int irq_nranges; + struct cdev cdev; + irq_hw_number_t irq_base_offset; + struct irq_avail *irq_avail; + spinlock_t irq_alloc_lock; + u64 handle; + char *status; + u16 vendor; + u16 device; + u16 subsystem_vendor; + u16 subsystem; +}; + +struct cxl { + struct cxl_native *native; + struct cxl_guest *guest; spinlock_t afu_list_lock; struct cxl_afu *afu[CXL_MAX_SLICES]; struct device dev; @@ -503,9 +538,6 @@ struct cxl { struct bin_attribute cxl_attr; int adapter_num; int user_irqs; - u64 afu_desc_off; - u64 afu_desc_size; - u64 ps_off; u64 ps_size; u16 psl_rev; u16 base_image; @@ -570,7 +602,7 @@ static inline bool cxl_adapter_link_ok(struct cxl *cxl) static inline void __iomem *_cxl_p1_addr(struct cxl *cxl, cxl_p1_reg_t reg) { WARN_ON(!cpu_has_feature(CPU_FTR_HVMODE)); - return cxl->p1_mmio + cxl_reg_off(reg); + return cxl->native->p1_mmio + cxl_reg_off(reg); } static inline void cxl_p1_write(struct cxl *cxl, cxl_p1_reg_t reg, u64 val) @@ -590,7 +622,7 @@ static inline u64 cxl_p1_read(struct cxl *cxl, cxl_p1_reg_t reg) static inline void __iomem *_cxl_p1n_addr(struct cxl_afu *afu, cxl_p1n_reg_t reg) { WARN_ON(!cpu_has_feature(CPU_FTR_HVMODE)); - return afu->p1n_mmio + cxl_reg_off(reg); + return afu->native->p1n_mmio + cxl_reg_off(reg); } static inline void cxl_p1n_write(struct cxl_afu *afu, cxl_p1n_reg_t reg, u64 val) diff --git a/drivers/misc/cxl/irq.c b/drivers/misc/cxl/irq.c index 3c04c14d1c60..be646dc41a2c 100644 --- a/drivers/misc/cxl/irq.c +++ b/drivers/misc/cxl/irq.c @@ -270,7 +270,7 @@ int afu_allocate_irqs(struct cxl_context *ctx, u32 count) if (cpu_has_feature(CPU_FTR_HVMODE)) { /* Multiplexed PSL Interrupt */ - ctx->irqs.offset[0] = ctx->afu->psl_hwirq; + ctx->irqs.offset[0] = ctx->afu->native->psl_hwirq; ctx->irqs.range[0] = 1; } diff --git a/drivers/misc/cxl/main.c b/drivers/misc/cxl/main.c index 814257b44534..927ba5a954f6 100644 --- a/drivers/misc/cxl/main.c +++ b/drivers/misc/cxl/main.c @@ -261,7 +261,6 @@ struct cxl_afu *cxl_alloc_afu(struct cxl *adapter, int slice) idr_init(&afu->contexts_idr); mutex_init(&afu->contexts_lock); spin_lock_init(&afu->afu_cntl_lock); - mutex_init(&afu->spa_mutex); afu->prefault_mode = CXL_PREFAULT_NONE; afu->irqs_max = afu->adapter->user_irqs; diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index 7d526294112d..c0bca59a12aa 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c @@ -186,22 +186,22 @@ static int spa_max_procs(int spa_size) int cxl_alloc_spa(struct cxl_afu *afu) { /* Work out how many pages to allocate */ - afu->spa_order = 0; + afu->native->spa_order = 0; do { - afu->spa_order++; - afu->spa_size = (1 << afu->spa_order) * PAGE_SIZE; - afu->spa_max_procs = spa_max_procs(afu->spa_size); - } while (afu->spa_max_procs < afu->num_procs); + afu->native->spa_order++; + afu->native->spa_size = (1 << afu->native->spa_order) * PAGE_SIZE; + afu->native->spa_max_procs = spa_max_procs(afu->native->spa_size); + } while (afu->native->spa_max_procs < afu->num_procs); - WARN_ON(afu->spa_size > 0x100000); /* Max size supported by the hardware */ + WARN_ON(afu->native->spa_size > 0x100000); /* Max size supported by the hardware */ - if (!(afu->spa = (struct cxl_process_element *) - __get_free_pages(GFP_KERNEL | __GFP_ZERO, afu->spa_order))) { + if (!(afu->native->spa = (struct cxl_process_element *) + __get_free_pages(GFP_KERNEL | __GFP_ZERO, afu->native->spa_order))) { pr_err("cxl_alloc_spa: Unable to allocate scheduled process area\n"); return -ENOMEM; } pr_devel("spa pages: %i afu->spa_max_procs: %i afu->num_procs: %i\n", - 1<spa_order, afu->spa_max_procs, afu->num_procs); + 1<native->spa_order, afu->native->spa_max_procs, afu->num_procs); return 0; } @@ -210,13 +210,15 @@ static void attach_spa(struct cxl_afu *afu) { u64 spap; - afu->sw_command_status = (__be64 *)((char *)afu->spa + - ((afu->spa_max_procs + 3) * 128)); + afu->native->sw_command_status = (__be64 *)((char *)afu->native->spa + + ((afu->native->spa_max_procs + 3) * 128)); - spap = virt_to_phys(afu->spa) & CXL_PSL_SPAP_Addr; - spap |= ((afu->spa_size >> (12 - CXL_PSL_SPAP_Size_Shift)) - 1) & CXL_PSL_SPAP_Size; + spap = virt_to_phys(afu->native->spa) & CXL_PSL_SPAP_Addr; + spap |= ((afu->native->spa_size >> (12 - CXL_PSL_SPAP_Size_Shift)) - 1) & CXL_PSL_SPAP_Size; spap |= CXL_PSL_SPAP_V; - pr_devel("cxl: SPA allocated at 0x%p. Max processes: %i, sw_command_status: 0x%p CXL_PSL_SPAP_An=0x%016llx\n", afu->spa, afu->spa_max_procs, afu->sw_command_status, spap); + pr_devel("cxl: SPA allocated at 0x%p. Max processes: %i, sw_command_status: 0x%p CXL_PSL_SPAP_An=0x%016llx\n", + afu->native->spa, afu->native->spa_max_procs, + afu->native->sw_command_status, spap); cxl_p1n_write(afu, CXL_PSL_SPAP_An, spap); } @@ -227,9 +229,10 @@ static inline void detach_spa(struct cxl_afu *afu) void cxl_release_spa(struct cxl_afu *afu) { - if (afu->spa) { - free_pages((unsigned long) afu->spa, afu->spa_order); - afu->spa = NULL; + if (afu->native->spa) { + free_pages((unsigned long) afu->native->spa, + afu->native->spa_order); + afu->native->spa = NULL; } } @@ -291,7 +294,7 @@ static void slb_invalid(struct cxl_context *ctx) struct cxl *adapter = ctx->afu->adapter; u64 slbia; - WARN_ON(!mutex_is_locked(&ctx->afu->spa_mutex)); + WARN_ON(!mutex_is_locked(&ctx->afu->native->spa_mutex)); cxl_p1_write(adapter, CXL_PSL_LBISEL, ((u64)be32_to_cpu(ctx->elem->common.pid) << 32) | @@ -321,7 +324,7 @@ static int do_process_element_cmd(struct cxl_context *ctx, ctx->elem->software_state = cpu_to_be32(pe_state); smp_wmb(); - *(ctx->afu->sw_command_status) = cpu_to_be64(cmd | 0 | ctx->pe); + *(ctx->afu->native->sw_command_status) = cpu_to_be64(cmd | 0 | ctx->pe); smp_mb(); cxl_p1n_write(ctx->afu, CXL_PSL_LLCMD_An, cmd | ctx->pe); while (1) { @@ -335,7 +338,7 @@ static int do_process_element_cmd(struct cxl_context *ctx, rc = -EIO; goto out; } - state = be64_to_cpup(ctx->afu->sw_command_status); + state = be64_to_cpup(ctx->afu->native->sw_command_status); if (state == ~0ULL) { pr_err("cxl: Error adding process element to AFU\n"); rc = -1; @@ -363,12 +366,12 @@ static int add_process_element(struct cxl_context *ctx) { int rc = 0; - mutex_lock(&ctx->afu->spa_mutex); + mutex_lock(&ctx->afu->native->spa_mutex); pr_devel("%s Adding pe: %i started\n", __func__, ctx->pe); if (!(rc = do_process_element_cmd(ctx, CXL_SPA_SW_CMD_ADD, CXL_PE_SOFTWARE_STATE_V))) ctx->pe_inserted = true; pr_devel("%s Adding pe: %i finished\n", __func__, ctx->pe); - mutex_unlock(&ctx->afu->spa_mutex); + mutex_unlock(&ctx->afu->native->spa_mutex); return rc; } @@ -380,7 +383,7 @@ static int terminate_process_element(struct cxl_context *ctx) if (!(ctx->elem->software_state & cpu_to_be32(CXL_PE_SOFTWARE_STATE_V))) return rc; - mutex_lock(&ctx->afu->spa_mutex); + mutex_lock(&ctx->afu->native->spa_mutex); pr_devel("%s Terminate pe: %i started\n", __func__, ctx->pe); /* We could be asked to terminate when the hw is down. That * should always succeed: it's not running if the hw has gone @@ -391,7 +394,7 @@ static int terminate_process_element(struct cxl_context *ctx) CXL_PE_SOFTWARE_STATE_V | CXL_PE_SOFTWARE_STATE_T); ctx->elem->software_state = 0; /* Remove Valid bit */ pr_devel("%s Terminate pe: %i finished\n", __func__, ctx->pe); - mutex_unlock(&ctx->afu->spa_mutex); + mutex_unlock(&ctx->afu->native->spa_mutex); return rc; } @@ -399,7 +402,7 @@ static int remove_process_element(struct cxl_context *ctx) { int rc = 0; - mutex_lock(&ctx->afu->spa_mutex); + mutex_lock(&ctx->afu->native->spa_mutex); pr_devel("%s Remove pe: %i started\n", __func__, ctx->pe); /* We could be asked to remove when the hw is down. Again, if @@ -412,7 +415,7 @@ static int remove_process_element(struct cxl_context *ctx) ctx->pe_inserted = false; slb_invalid(ctx); pr_devel("%s Remove pe: %i finished\n", __func__, ctx->pe); - mutex_unlock(&ctx->afu->spa_mutex); + mutex_unlock(&ctx->afu->native->spa_mutex); return rc; } @@ -425,7 +428,7 @@ void cxl_assign_psn_space(struct cxl_context *ctx) ctx->psn_size = ctx->afu->adapter->ps_size; } else { ctx->psn_phys = ctx->afu->psn_phys + - (ctx->afu->pp_offset + ctx->afu->pp_size * ctx->pe); + (ctx->afu->native->pp_offset + ctx->afu->pp_size * ctx->pe); ctx->psn_size = ctx->afu->pp_size; } } @@ -437,7 +440,7 @@ static int activate_afu_directed(struct cxl_afu *afu) dev_info(&afu->dev, "Activating AFU directed mode\n"); afu->num_procs = afu->max_procs_virtualised; - if (afu->spa == NULL) { + if (afu->native->spa == NULL) { if (cxl_alloc_spa(afu)) return -ENOMEM; } @@ -846,27 +849,27 @@ int cxl_native_register_psl_err_irq(struct cxl *adapter) return -ENOMEM; if ((rc = cxl_register_one_irq(adapter, native_irq_err, adapter, - &adapter->err_hwirq, - &adapter->err_virq, + &adapter->native->err_hwirq, + &adapter->native->err_virq, adapter->irq_name))) { kfree(adapter->irq_name); adapter->irq_name = NULL; return rc; } - cxl_p1_write(adapter, CXL_PSL_ErrIVTE, adapter->err_hwirq & 0xffff); + cxl_p1_write(adapter, CXL_PSL_ErrIVTE, adapter->native->err_hwirq & 0xffff); return 0; } void cxl_native_release_psl_err_irq(struct cxl *adapter) { - if (adapter->err_virq != irq_find_mapping(NULL, adapter->err_hwirq)) + if (adapter->native->err_virq != irq_find_mapping(NULL, adapter->native->err_hwirq)) return; cxl_p1_write(adapter, CXL_PSL_ErrIVTE, 0x0000000000000000); - cxl_unmap_irq(adapter->err_virq, adapter); - cxl_ops->release_one_irq(adapter, adapter->err_hwirq); + cxl_unmap_irq(adapter->native->err_virq, adapter); + cxl_ops->release_one_irq(adapter, adapter->native->err_hwirq); kfree(adapter->irq_name); } @@ -915,8 +918,8 @@ int cxl_native_register_psl_irq(struct cxl_afu *afu) if (!afu->psl_irq_name) return -ENOMEM; - if ((rc = cxl_register_one_irq(afu->adapter, native_irq_multiplexed, afu, - &afu->psl_hwirq, &afu->psl_virq, + if ((rc = cxl_register_one_irq(afu->adapter, native_irq_multiplexed, + afu, &afu->native->psl_hwirq, &afu->native->psl_virq, afu->psl_irq_name))) { kfree(afu->psl_irq_name); afu->psl_irq_name = NULL; @@ -926,11 +929,11 @@ int cxl_native_register_psl_irq(struct cxl_afu *afu) void cxl_native_release_psl_irq(struct cxl_afu *afu) { - if (afu->psl_virq != irq_find_mapping(NULL, afu->psl_hwirq)) + if (afu->native->psl_virq != irq_find_mapping(NULL, afu->native->psl_hwirq)) return; - cxl_unmap_irq(afu->psl_virq, afu); - cxl_ops->release_one_irq(afu->adapter, afu->psl_hwirq); + cxl_unmap_irq(afu->native->psl_virq, afu); + cxl_ops->release_one_irq(afu->adapter, afu->native->psl_hwirq); kfree(afu->psl_irq_name); } @@ -970,7 +973,7 @@ static int native_afu_cr_read64(struct cxl_afu *afu, int cr, u64 off, u64 *out) return -EIO; if (unlikely(off >= afu->crs_len)) return -ERANGE; - *out = in_le64(afu->afu_desc_mmio + afu->crs_offset + + *out = in_le64(afu->native->afu_desc_mmio + afu->crs_offset + (cr * afu->crs_len) + off); return 0; } @@ -981,7 +984,7 @@ static int native_afu_cr_read32(struct cxl_afu *afu, int cr, u64 off, u32 *out) return -EIO; if (unlikely(off >= afu->crs_len)) return -ERANGE; - *out = in_le32(afu->afu_desc_mmio + afu->crs_offset + + *out = in_le32(afu->native->afu_desc_mmio + afu->crs_offset + (cr * afu->crs_len) + off); return 0; } diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 23b84c5d9453..fb4fd45e8744 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -90,8 +90,8 @@ /* This works a little different than the p1/p2 register accesses to make it * easier to pull out individual fields */ -#define AFUD_READ(afu, off) in_be64(afu->afu_desc_mmio + off) -#define AFUD_READ_LE(afu, off) in_le64(afu->afu_desc_mmio + off) +#define AFUD_READ(afu, off) in_be64(afu->native->afu_desc_mmio + off) +#define AFUD_READ_LE(afu, off) in_le64(afu->native->afu_desc_mmio + off) #define EXTRACT_PPC_BIT(val, bit) (!!(val & PPC_BIT(bit))) #define EXTRACT_PPC_BITS(val, bs, be) ((val & PPC_BITMASK(bs, be)) >> PPC_BITLSHIFT(be)) @@ -550,15 +550,15 @@ static int pci_map_slice_regs(struct cxl_afu *afu, struct cxl *adapter, struct p p1n_base = p1_base(dev) + 0x10000 + (afu->slice * p1n_size); p2n_base = p2_base(dev) + (afu->slice * p2n_size); - afu->psn_phys = p2_base(dev) + (adapter->ps_off + (afu->slice * adapter->ps_size)); - afu_desc = p2_base(dev) + adapter->afu_desc_off + (afu->slice * adapter->afu_desc_size); + afu->psn_phys = p2_base(dev) + (adapter->native->ps_off + (afu->slice * adapter->ps_size)); + afu_desc = p2_base(dev) + adapter->native->afu_desc_off + (afu->slice * adapter->native->afu_desc_size); - if (!(afu->p1n_mmio = ioremap(p1n_base, p1n_size))) + if (!(afu->native->p1n_mmio = ioremap(p1n_base, p1n_size))) goto err; if (!(afu->p2n_mmio = ioremap(p2n_base, p2n_size))) goto err1; if (afu_desc) { - if (!(afu->afu_desc_mmio = ioremap(afu_desc, adapter->afu_desc_size))) + if (!(afu->native->afu_desc_mmio = ioremap(afu_desc, adapter->native->afu_desc_size))) goto err2; } @@ -566,7 +566,7 @@ static int pci_map_slice_regs(struct cxl_afu *afu, struct cxl *adapter, struct p err2: iounmap(afu->p2n_mmio); err1: - iounmap(afu->p1n_mmio); + iounmap(afu->native->p1n_mmio); err: dev_err(&afu->dev, "Error mapping AFU MMIO regions\n"); return -ENOMEM; @@ -578,13 +578,13 @@ static void pci_unmap_slice_regs(struct cxl_afu *afu) iounmap(afu->p2n_mmio); afu->p2n_mmio = NULL; } - if (afu->p1n_mmio) { - iounmap(afu->p1n_mmio); - afu->p1n_mmio = NULL; + if (afu->native->p1n_mmio) { + iounmap(afu->native->p1n_mmio); + afu->native->p1n_mmio = NULL; } - if (afu->afu_desc_mmio) { - iounmap(afu->afu_desc_mmio); - afu->afu_desc_mmio = NULL; + if (afu->native->afu_desc_mmio) { + iounmap(afu->native->afu_desc_mmio); + afu->native->afu_desc_mmio = NULL; } } @@ -597,6 +597,7 @@ void cxl_pci_release_afu(struct device *dev) idr_destroy(&afu->contexts_idr); cxl_release_spa(afu); + kfree(afu->native); kfree(afu); } @@ -621,7 +622,7 @@ static int cxl_read_afu_descriptor(struct cxl_afu *afu) afu->pp_size = AFUD_PPPSA_LEN(val) * 4096; afu->psa = AFUD_PPPSA_PSA(val); if ((afu->pp_psa = AFUD_PPPSA_PP(val))) - afu->pp_offset = AFUD_READ_PPPSA_OFF(afu); + afu->native->pp_offset = AFUD_READ_PPPSA_OFF(afu); val = AFUD_READ_CR(afu); afu->crs_len = AFUD_CR_LEN(val) * 256; @@ -652,7 +653,7 @@ static int cxl_afu_descriptor_looks_ok(struct cxl_afu *afu) u32 val; if (afu->psa && afu->adapter->ps_size < - (afu->pp_offset + afu->pp_size*afu->max_procs_virtualised)) { + (afu->native->pp_offset + afu->pp_size*afu->max_procs_virtualised)) { dev_err(&afu->dev, "per-process PSA can't fit inside the PSA!\n"); return -ENODEV; } @@ -737,7 +738,7 @@ ssize_t cxl_pci_afu_read_err_buffer(struct cxl_afu *afu, char *buf, loff_t aligned_start, aligned_end; size_t aligned_length; void *tbuf; - const void __iomem *ebuf = afu->afu_desc_mmio + afu->eb_offset; + const void __iomem *ebuf = afu->native->afu_desc_mmio + afu->eb_offset; if (count == 0 || off < 0 || (size_t)off >= afu->eb_len) return 0; @@ -819,19 +820,25 @@ static void pci_deconfigure_afu(struct cxl_afu *afu) static int pci_init_afu(struct cxl *adapter, int slice, struct pci_dev *dev) { struct cxl_afu *afu; - int rc; + int rc = -ENOMEM; afu = cxl_alloc_afu(adapter, slice); if (!afu) return -ENOMEM; + afu->native = kzalloc(sizeof(struct cxl_afu_native), GFP_KERNEL); + if (!afu->native) + goto err_free_afu; + + mutex_init(&afu->native->spa_mutex); + rc = dev_set_name(&afu->dev, "afu%i.%i", adapter->adapter_num, slice); if (rc) - goto err_free; + goto err_free_native; rc = pci_configure_afu(afu, adapter, dev); if (rc) - goto err_free; + goto err_free_native; /* Don't care if this fails */ cxl_debugfs_afu_add(afu); @@ -859,7 +866,9 @@ err_put1: device_unregister(&afu->dev); return rc; -err_free: +err_free_native: + kfree(afu->native); +err_free_afu: kfree(afu); return rc; @@ -920,17 +929,17 @@ static int cxl_map_adapter_regs(struct cxl *adapter, struct pci_dev *dev) pr_devel("cxl_map_adapter_regs: p1: %#016llx %#llx, p2: %#016llx %#llx", p1_base(dev), p1_size(dev), p2_base(dev), p2_size(dev)); - if (!(adapter->p1_mmio = ioremap(p1_base(dev), p1_size(dev)))) + if (!(adapter->native->p1_mmio = ioremap(p1_base(dev), p1_size(dev)))) goto err3; - if (!(adapter->p2_mmio = ioremap(p2_base(dev), p2_size(dev)))) + if (!(adapter->native->p2_mmio = ioremap(p2_base(dev), p2_size(dev)))) goto err4; return 0; err4: - iounmap(adapter->p1_mmio); - adapter->p1_mmio = NULL; + iounmap(adapter->native->p1_mmio); + adapter->native->p1_mmio = NULL; err3: pci_release_region(dev, 0); err2: @@ -941,14 +950,14 @@ err1: static void cxl_unmap_adapter_regs(struct cxl *adapter) { - if (adapter->p1_mmio) { - iounmap(adapter->p1_mmio); - adapter->p1_mmio = NULL; + if (adapter->native->p1_mmio) { + iounmap(adapter->native->p1_mmio); + adapter->native->p1_mmio = NULL; pci_release_region(to_pci_dev(adapter->dev.parent), 2); } - if (adapter->p2_mmio) { - iounmap(adapter->p2_mmio); - adapter->p2_mmio = NULL; + if (adapter->native->p2_mmio) { + iounmap(adapter->native->p2_mmio); + adapter->native->p2_mmio = NULL; pci_release_region(to_pci_dev(adapter->dev.parent), 0); } } @@ -989,10 +998,10 @@ static int cxl_read_vsec(struct cxl *adapter, struct pci_dev *dev) /* Convert everything to bytes, because there is NO WAY I'd look at the * code a month later and forget what units these are in ;-) */ - adapter->ps_off = ps_off * 64 * 1024; + adapter->native->ps_off = ps_off * 64 * 1024; adapter->ps_size = ps_size * 64 * 1024; - adapter->afu_desc_off = afu_desc_off * 64 * 1024; - adapter->afu_desc_size = afu_desc_size *64 * 1024; + adapter->native->afu_desc_off = afu_desc_off * 64 * 1024; + adapter->native->afu_desc_size = afu_desc_size * 64 * 1024; /* Total IRQs - 1 PSL ERROR - #AFU*(1 slice error + 1 DSI) */ adapter->user_irqs = pnv_cxl_get_irq_count(dev) - 1 - 2*adapter->slices; @@ -1043,15 +1052,15 @@ static int cxl_vsec_looks_ok(struct cxl *adapter, struct pci_dev *dev) return -EINVAL; } - if (!adapter->afu_desc_off || !adapter->afu_desc_size) { + if (!adapter->native->afu_desc_off || !adapter->native->afu_desc_size) { dev_err(&dev->dev, "ABORTING: VSEC shows no AFU descriptors\n"); return -EINVAL; } - if (adapter->ps_size > p2_size(dev) - adapter->ps_off) { + if (adapter->ps_size > p2_size(dev) - adapter->native->ps_off) { dev_err(&dev->dev, "ABORTING: Problem state size larger than " "available in BAR2: 0x%llx > 0x%llx\n", - adapter->ps_size, p2_size(dev) - adapter->ps_off); + adapter->ps_size, p2_size(dev) - adapter->native->ps_off); return -EINVAL; } @@ -1066,6 +1075,7 @@ static void cxl_release_adapter(struct device *dev) cxl_remove_adapter_nr(adapter); + kfree(adapter->native); kfree(adapter); } @@ -1162,6 +1172,12 @@ static struct cxl *cxl_pci_init_adapter(struct pci_dev *dev) if (!adapter) return ERR_PTR(-ENOMEM); + adapter->native = kzalloc(sizeof(struct cxl_native), GFP_KERNEL); + if (!adapter->native) { + rc = -ENOMEM; + goto err_release; + } + /* Set defaults for parameters which need to persist over * configure/reconfigure */ @@ -1171,8 +1187,7 @@ static struct cxl *cxl_pci_init_adapter(struct pci_dev *dev) rc = cxl_configure_adapter(adapter, dev); if (rc) { pci_disable_device(dev); - cxl_release_adapter(&adapter->dev); - return ERR_PTR(rc); + goto err_release; } /* Don't care if this one fails: */ @@ -1198,6 +1213,10 @@ err_put1: cxl_deconfigure_adapter(adapter); device_unregister(&adapter->dev); return ERR_PTR(rc); + +err_release: + cxl_release_adapter(&adapter->dev); + return ERR_PTR(rc); } static void cxl_pci_remove_adapter(struct cxl *adapter) diff --git a/drivers/misc/cxl/sysfs.c b/drivers/misc/cxl/sysfs.c index 300eafe4ed43..1a1409cb1652 100644 --- a/drivers/misc/cxl/sysfs.c +++ b/drivers/misc/cxl/sysfs.c @@ -165,7 +165,7 @@ static ssize_t pp_mmio_off_show(struct device *device, { struct cxl_afu *afu = to_afu_chardev_m(device); - return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->pp_offset); + return scnprintf(buf, PAGE_SIZE, "%llu\n", afu->native->pp_offset); } static ssize_t pp_mmio_len_show(struct device *device, diff --git a/drivers/misc/cxl/vphb.c b/drivers/misc/cxl/vphb.c index e8a8eed6f006..baa408748300 100644 --- a/drivers/misc/cxl/vphb.c +++ b/drivers/misc/cxl/vphb.c @@ -248,7 +248,7 @@ int cxl_pci_vphb_add(struct cxl_afu *afu) /* Setup the PHB using arch provided callback */ phb->ops = &cxl_pcie_pci_ops; - phb->cfg_addr = afu->afu_desc_mmio + afu->crs_offset; + phb->cfg_addr = afu->native->afu_desc_mmio + afu->crs_offset; phb->cfg_data = (void *)(u64)afu->crs_len; phb->private_data = afu; phb->controller_ops = cxl_pci_controller_ops; @@ -278,7 +278,7 @@ void cxl_pci_vphb_reconfigure(struct cxl_afu *afu) * and remapped. We need to reflect this in the PHB's view of * the world. */ - afu->phb->cfg_addr = afu->afu_desc_mmio + afu->crs_offset; + afu->phb->cfg_addr = afu->native->afu_desc_mmio + afu->crs_offset; } void cxl_pci_vphb_remove(struct cxl_afu *afu) -- cgit v1.2.3 From 4752876c71701b7663a5ded789058ab2c05f7d0f Mon Sep 17 00:00:00 2001 From: Christophe Lombard Date: Fri, 4 Mar 2016 12:26:37 +0100 Subject: cxl: sysfs support for guests Filter out a few adapter parameters which don't make sense in a guest. Document the changes. Co-authored-by: Frederic Barrat Signed-off-by: Frederic Barrat Signed-off-by: Christophe Lombard Reviewed-by: Manoj Kumar Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- Documentation/ABI/testing/sysfs-class-cxl | 10 ++-- drivers/misc/cxl/cxl.h | 7 +++ drivers/misc/cxl/guest.c | 25 +++++++++ drivers/misc/cxl/native.c | 7 +++ drivers/misc/cxl/sysfs.c | 89 ++++++++++++++++++++++++------- 5 files changed, 113 insertions(+), 25 deletions(-) (limited to 'drivers/misc/cxl/sysfs.c') diff --git a/Documentation/ABI/testing/sysfs-class-cxl b/Documentation/ABI/testing/sysfs-class-cxl index b07e86d4597f..7fd737eed38a 100644 --- a/Documentation/ABI/testing/sysfs-class-cxl +++ b/Documentation/ABI/testing/sysfs-class-cxl @@ -159,7 +159,7 @@ Description: read only Decimal value of the Per Process MMIO space length. Users: https://github.com/ibm-capi/libcxl -What: /sys/class/cxl/m/pp_mmio_off +What: /sys/class/cxl/m/pp_mmio_off (not in a guest) Date: September 2014 Contact: linuxppc-dev@lists.ozlabs.org Description: read only @@ -183,7 +183,7 @@ Description: read only Identifies the revision level of the PSL. Users: https://github.com/ibm-capi/libcxl -What: /sys/class/cxl//base_image +What: /sys/class/cxl//base_image (not in a guest) Date: September 2014 Contact: linuxppc-dev@lists.ozlabs.org Description: read only @@ -193,7 +193,7 @@ Description: read only during the initial program load. Users: https://github.com/ibm-capi/libcxl -What: /sys/class/cxl//image_loaded +What: /sys/class/cxl//image_loaded (not in a guest) Date: September 2014 Contact: linuxppc-dev@lists.ozlabs.org Description: read only @@ -201,7 +201,7 @@ Description: read only onto the card. Users: https://github.com/ibm-capi/libcxl -What: /sys/class/cxl//load_image_on_perst +What: /sys/class/cxl//load_image_on_perst (not in a guest) Date: December 2014 Contact: linuxppc-dev@lists.ozlabs.org Description: read/write @@ -224,7 +224,7 @@ Description: write only to reload the FPGA depending on load_image_on_perst. Users: https://github.com/ibm-capi/libcxl -What: /sys/class/cxl//perst_reloads_same_image +What: /sys/class/cxl//perst_reloads_same_image (not in a guest) Date: July 2015 Contact: linuxppc-dev@lists.ozlabs.org Description: read/write diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index 4372a87ff3aa..a7e75f1cc903 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -336,6 +336,12 @@ enum prefault_modes { CXL_PREFAULT_ALL, }; +enum cxl_attrs { + CXL_ADAPTER_ATTRS, + CXL_AFU_MASTER_ATTRS, + CXL_AFU_ATTRS, +}; + struct cxl_sste { __be64 esid_data; __be64 vsid_data; @@ -844,6 +850,7 @@ struct cxl_backend_ops { int (*attach_process)(struct cxl_context *ctx, bool kernel, u64 wed, u64 amr); int (*detach_process)(struct cxl_context *ctx); + bool (*support_attributes)(const char *attr_name, enum cxl_attrs type); bool (*link_ok)(struct cxl *cxl); void (*release_afu)(struct device *dev); ssize_t (*afu_read_err_buffer)(struct cxl_afu *afu, char *buf, diff --git a/drivers/misc/cxl/guest.c b/drivers/misc/cxl/guest.c index d7d53d869283..b1b8ac5195e7 100644 --- a/drivers/misc/cxl/guest.c +++ b/drivers/misc/cxl/guest.c @@ -596,6 +596,30 @@ static int guest_afu_check_and_enable(struct cxl_afu *afu) return 0; } +static bool guest_support_attributes(const char *attr_name, + enum cxl_attrs type) +{ + switch (type) { + case CXL_ADAPTER_ATTRS: + if ((strcmp(attr_name, "base_image") == 0) || + (strcmp(attr_name, "load_image_on_perst") == 0) || + (strcmp(attr_name, "perst_reloads_same_image") == 0) || + (strcmp(attr_name, "image_loaded") == 0)) + return false; + break; + case CXL_AFU_MASTER_ATTRS: + if ((strcmp(attr_name, "pp_mmio_off") == 0)) + return false; + break; + case CXL_AFU_ATTRS: + break; + default: + break; + } + + return true; +} + static int activate_afu_directed(struct cxl_afu *afu) { int rc; @@ -936,6 +960,7 @@ const struct cxl_backend_ops cxl_guest_ops = { .ack_irq = guest_ack_irq, .attach_process = guest_attach_process, .detach_process = guest_detach_process, + .support_attributes = guest_support_attributes, .link_ok = guest_link_ok, .release_afu = guest_release_afu, .afu_read_err_buffer = guest_afu_read_err_buffer, diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index c0bca59a12aa..0e289c22cdec 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c @@ -967,6 +967,12 @@ int cxl_check_error(struct cxl_afu *afu) return (cxl_p1n_read(afu, CXL_PSL_SCNTL_An) == ~0ULL); } +static bool native_support_attributes(const char *attr_name, + enum cxl_attrs type) +{ + return true; +} + static int native_afu_cr_read64(struct cxl_afu *afu, int cr, u64 off, u64 *out) { if (unlikely(!cxl_ops->link_ok(afu->adapter))) @@ -1026,6 +1032,7 @@ const struct cxl_backend_ops cxl_native_ops = { .ack_irq = native_ack_irq, .attach_process = native_attach_process, .detach_process = native_detach_process, + .support_attributes = native_support_attributes, .link_ok = cxl_adapter_link_ok, .release_afu = cxl_pci_release_afu, .afu_read_err_buffer = cxl_pci_afu_read_err_buffer, diff --git a/drivers/misc/cxl/sysfs.c b/drivers/misc/cxl/sysfs.c index 1a1409cb1652..907c99b9f5af 100644 --- a/drivers/misc/cxl/sysfs.c +++ b/drivers/misc/cxl/sysfs.c @@ -253,8 +253,14 @@ static ssize_t irqs_max_store(struct device *device, if (irqs_max < afu->pp_irqs) return -EINVAL; - if (irqs_max > afu->adapter->user_irqs) - return -EINVAL; + if (cpu_has_feature(CPU_FTR_HVMODE)) { + if (irqs_max > afu->adapter->user_irqs) + return -EINVAL; + } else { + /* pHyp sets a per-AFU limit */ + if (irqs_max > afu->guest->max_ints) + return -EINVAL; + } afu->irqs_max = irqs_max; return count; @@ -406,24 +412,39 @@ static struct device_attribute afu_attrs[] = { int cxl_sysfs_adapter_add(struct cxl *adapter) { + struct device_attribute *dev_attr; int i, rc; for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) { - if ((rc = device_create_file(&adapter->dev, &adapter_attrs[i]))) - goto err; + dev_attr = &adapter_attrs[i]; + if (cxl_ops->support_attributes(dev_attr->attr.name, + CXL_ADAPTER_ATTRS)) { + if ((rc = device_create_file(&adapter->dev, dev_attr))) + goto err; + } } return 0; err: - for (i--; i >= 0; i--) - device_remove_file(&adapter->dev, &adapter_attrs[i]); + for (i--; i >= 0; i--) { + dev_attr = &adapter_attrs[i]; + if (cxl_ops->support_attributes(dev_attr->attr.name, + CXL_ADAPTER_ATTRS)) + device_remove_file(&adapter->dev, dev_attr); + } return rc; } + void cxl_sysfs_adapter_remove(struct cxl *adapter) { + struct device_attribute *dev_attr; int i; - for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) - device_remove_file(&adapter->dev, &adapter_attrs[i]); + for (i = 0; i < ARRAY_SIZE(adapter_attrs); i++) { + dev_attr = &adapter_attrs[i]; + if (cxl_ops->support_attributes(dev_attr->attr.name, + CXL_ADAPTER_ATTRS)) + device_remove_file(&adapter->dev, dev_attr); + } } struct afu_config_record { @@ -534,7 +555,7 @@ static struct afu_config_record *cxl_sysfs_afu_new_cr(struct cxl_afu *afu, int c /* * Export raw AFU PCIe like config record. For now this is read only by * root - we can expand that later to be readable by non-root and maybe - * even writable provided we have a good use-case. Once we suport + * even writable provided we have a good use-case. Once we support * exposing AFUs through a virtual PHB they will get that for free from * Linux' PCI infrastructure, but until then it's not clear that we * need it for anything since the main use case is just identifying @@ -572,6 +593,7 @@ err: void cxl_sysfs_afu_remove(struct cxl_afu *afu) { + struct device_attribute *dev_attr; struct afu_config_record *cr, *tmp; int i; @@ -579,8 +601,12 @@ void cxl_sysfs_afu_remove(struct cxl_afu *afu) if (afu->eb_len) device_remove_bin_file(&afu->dev, &afu->attr_eb); - for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) - device_remove_file(&afu->dev, &afu_attrs[i]); + for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) { + dev_attr = &afu_attrs[i]; + if (cxl_ops->support_attributes(dev_attr->attr.name, + CXL_AFU_ATTRS)) + device_remove_file(&afu->dev, &afu_attrs[i]); + } list_for_each_entry_safe(cr, tmp, &afu->crs, list) { sysfs_remove_bin_file(&cr->kobj, &cr->config_attr); @@ -590,14 +616,19 @@ void cxl_sysfs_afu_remove(struct cxl_afu *afu) int cxl_sysfs_afu_add(struct cxl_afu *afu) { + struct device_attribute *dev_attr; struct afu_config_record *cr; int i, rc; INIT_LIST_HEAD(&afu->crs); for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) { - if ((rc = device_create_file(&afu->dev, &afu_attrs[i]))) - goto err; + dev_attr = &afu_attrs[i]; + if (cxl_ops->support_attributes(dev_attr->attr.name, + CXL_AFU_ATTRS)) { + if ((rc = device_create_file(&afu->dev, &afu_attrs[i]))) + goto err; + } } /* conditionally create the add the binary file for error info buffer */ @@ -636,32 +667,50 @@ err: /* reset the eb_len as we havent created the bin attr */ afu->eb_len = 0; - for (i--; i >= 0; i--) + for (i--; i >= 0; i--) { + dev_attr = &afu_attrs[i]; + if (cxl_ops->support_attributes(dev_attr->attr.name, + CXL_AFU_ATTRS)) device_remove_file(&afu->dev, &afu_attrs[i]); + } return rc; } int cxl_sysfs_afu_m_add(struct cxl_afu *afu) { + struct device_attribute *dev_attr; int i, rc; for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) { - if ((rc = device_create_file(afu->chardev_m, &afu_master_attrs[i]))) - goto err; + dev_attr = &afu_master_attrs[i]; + if (cxl_ops->support_attributes(dev_attr->attr.name, + CXL_AFU_MASTER_ATTRS)) { + if ((rc = device_create_file(afu->chardev_m, &afu_master_attrs[i]))) + goto err; + } } return 0; err: - for (i--; i >= 0; i--) - device_remove_file(afu->chardev_m, &afu_master_attrs[i]); + for (i--; i >= 0; i--) { + dev_attr = &afu_master_attrs[i]; + if (cxl_ops->support_attributes(dev_attr->attr.name, + CXL_AFU_MASTER_ATTRS)) + device_remove_file(afu->chardev_m, &afu_master_attrs[i]); + } return rc; } void cxl_sysfs_afu_m_remove(struct cxl_afu *afu) { + struct device_attribute *dev_attr; int i; - for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) - device_remove_file(afu->chardev_m, &afu_master_attrs[i]); + for (i = 0; i < ARRAY_SIZE(afu_master_attrs); i++) { + dev_attr = &afu_master_attrs[i]; + if (cxl_ops->support_attributes(dev_attr->attr.name, + CXL_AFU_MASTER_ATTRS)) + device_remove_file(afu->chardev_m, &afu_master_attrs[i]); + } } -- cgit v1.2.3