diff options
| author | Dave Jiang <dave.jiang@intel.com> | 2026-06-12 13:47:53 -0700 |
|---|---|---|
| committer | Dave Jiang <dave.jiang@intel.com> | 2026-06-12 13:47:53 -0700 |
| commit | f72af41a43e16276c46d44cf8a833cc0f9ba9d48 (patch) | |
| tree | 1ccba38b40fc491fc85ce84a3c7b2d8bf41b1e94 | |
| parent | e53ef72033b30f8ff0bf76adf956d4a27d1a2675 (diff) | |
| parent | 383f69656359191d2236ef5ec259984c844fde9a (diff) | |
| download | lwn-f72af41a43e16276c46d44cf8a833cc0f9ba9d48.tar.gz lwn-f72af41a43e16276c46d44cf8a833cc0f9ba9d48.zip | |
Merge branch 'for-7.2/cxl-type2-attach-region' into cxl-for-next
cxl: Add dummy function for cxl_memdev_attach_region for !CONFIG_CXL_REGION
cxl/region: Introduce devm_cxl_probe_mem()
cxl/memdev: Introduce cxl_class_memdev_type
cxl/memdev: Pin parents for entire memdev lifetime
cxl/region: Resolve region deletion races
cxl/region: Block region delete during region creation
| -rw-r--r-- | drivers/cxl/core/core.h | 2 | ||||
| -rw-r--r-- | drivers/cxl/core/memdev.c | 20 | ||||
| -rw-r--r-- | drivers/cxl/core/port.c | 7 | ||||
| -rw-r--r-- | drivers/cxl/core/region.c | 194 | ||||
| -rw-r--r-- | drivers/cxl/cxl.h | 8 | ||||
| -rw-r--r-- | drivers/cxl/cxlmem.h | 34 | ||||
| -rw-r--r-- | drivers/cxl/mem.c | 95 | ||||
| -rw-r--r-- | drivers/cxl/pci.c | 2 | ||||
| -rw-r--r-- | include/cxl/cxl.h | 3 | ||||
| -rw-r--r-- | tools/testing/cxl/test/mem.c | 2 |
10 files changed, 304 insertions, 63 deletions
diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index 82ca3a476708..07555ae63859 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -52,6 +52,7 @@ u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, u64 dpa); int devm_cxl_add_dax_region(struct cxl_region *cxlr); int devm_cxl_add_pmem_region(struct cxl_region *cxlr); +void kill_regions(struct cxl_root_decoder *cxlrd); #else static inline u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, @@ -81,6 +82,7 @@ static inline int cxl_region_init(void) static inline void cxl_region_exit(void) { } +static inline void kill_regions(struct cxl_root_decoder *cxlrd) { }; #define CXL_REGION_ATTR(x) NULL #define CXL_REGION_TYPE(x) NULL #define SET_CXL_REGION_ATTR(x) diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c index 80e65690eb77..33a3d2e7b13a 100644 --- a/drivers/cxl/core/memdev.c +++ b/drivers/cxl/core/memdev.c @@ -25,9 +25,11 @@ static DEFINE_IDA(cxl_memdev_ida); static void cxl_memdev_release(struct device *dev) { struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + struct device *parent = dev->parent; ida_free(&cxl_memdev_ida, cxlmd->id); kfree(cxlmd); + put_device(parent); } static char *cxl_memdev_devnode(const struct device *dev, umode_t *mode, kuid_t *uid, @@ -572,16 +574,23 @@ void cxl_memdev_update_perf(struct cxl_memdev *cxlmd) } EXPORT_SYMBOL_NS_GPL(cxl_memdev_update_perf, "CXL"); -static const struct device_type cxl_memdev_type = { +static const struct device_type cxl_class_memdev_type = { .name = "cxl_memdev", .release = cxl_memdev_release, .devnode = cxl_memdev_devnode, .groups = cxl_memdev_attribute_groups, }; +static const struct device_type cxl_memdev_type = { + .name = "cxl_memdev", + .release = cxl_memdev_release, + .devnode = cxl_memdev_devnode, +}; + bool is_cxl_memdev(const struct device *dev) { - return dev->type == &cxl_memdev_type; + return (dev->type == &cxl_class_memdev_type || + dev->type == &cxl_memdev_type); } EXPORT_SYMBOL_NS_GPL(is_cxl_memdev, "CXL"); @@ -707,10 +716,13 @@ static struct cxl_memdev *cxl_memdev_alloc(struct cxl_dev_state *cxlds, dev = &cxlmd->dev; device_initialize(dev); lockdep_set_class(&dev->mutex, &cxl_memdev_key); - dev->parent = cxlds->dev; + dev->parent = get_device(cxlds->dev); dev->bus = &cxl_bus_type; dev->devt = MKDEV(cxl_mem_major, cxlmd->id); - dev->type = &cxl_memdev_type; + if (cxlds->type == CXL_DEVTYPE_DEVMEM) + dev->type = &cxl_memdev_type; + else + dev->type = &cxl_class_memdev_type; device_set_pm_not_required(dev); INIT_WORK(&cxlmd->detach_work, detach_memdev); diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index c5aacd7054f1..1215ee4f4035 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -458,6 +458,8 @@ static void cxl_root_decoder_release(struct device *dev) if (atomic_read(&cxlrd->region_id) >= 0) memregion_free(atomic_read(&cxlrd->region_id)); + mutex_destroy(&cxlrd->regions_lock); + xa_destroy(&cxlrd->regions); __cxl_decoder_release(&cxlrd->cxlsd.cxld); kfree(cxlrd); } @@ -2016,7 +2018,8 @@ struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port, return ERR_PTR(rc); } - mutex_init(&cxlrd->range_lock); + mutex_init(&cxlrd->regions_lock); + xa_init(&cxlrd->regions); cxld = &cxlsd->cxld; cxld->dev.type = &cxl_decoder_root_type; @@ -2192,6 +2195,8 @@ static void cxld_unregister(void *dev) if (is_endpoint_decoder(dev)) cxl_decoder_detach(NULL, to_cxl_endpoint_decoder(dev), -1, DETACH_INVALIDATE); + if (is_root_decoder(dev)) + kill_regions(to_cxl_root_decoder(dev)); device_unregister(dev); } diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 66c328d1c14e..1e211542b6b6 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -1148,6 +1148,19 @@ static int cxl_rr_assign_decoder(struct cxl_port *port, struct cxl_region *cxlr, static void cxl_region_setup_flags(struct cxl_region *cxlr, struct cxl_decoder *cxld) { + if (is_endpoint_decoder(&cxld->dev)) { + struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(&cxld->dev); + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); + + /* + * When a region's memdevs specify an @attach method the attach + * provider is responsible for dispositioning the region for + * both probe and userspace management + */ + if (cxlmd->attach) + set_bit(CXL_REGION_F_LOCK, &cxlr->flags); + } + if (cxld->flags & CXL_DECODER_F_LOCK) { set_bit(CXL_REGION_F_LOCK, &cxlr->flags); clear_bit(CXL_REGION_F_NEEDS_RESET, &cxlr->flags); @@ -2546,12 +2559,13 @@ static struct cxl_region *to_cxl_region(struct device *dev) return container_of(dev, struct cxl_region, dev); } -static void unregister_region(void *_cxlr) +static void unregister_region(struct cxl_region *cxlr) { - struct cxl_region *cxlr = _cxlr; + struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent); struct cxl_region_params *p = &cxlr->params; int i; + xa_erase(&cxlrd->regions, cxlr->id); device_del(&cxlr->dev); /* @@ -2568,6 +2582,17 @@ static void unregister_region(void *_cxlr) put_device(&cxlr->dev); } +static void endpoint_unregister_region(void *_cxlr) +{ + struct cxl_region *cxlr = _cxlr; + struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent); + + guard(mutex)(&cxlrd->regions_lock); + if (xa_load(&cxlrd->regions, cxlr->id)) + unregister_region(cxlr); + put_device(&cxlr->dev); +} + static struct lock_class_key cxl_region_key; static struct cxl_region *cxl_region_alloc(struct cxl_root_decoder *cxlrd, int id) @@ -2682,6 +2707,19 @@ static int cxl_region_calculate_adistance(struct notifier_block *nb, return NOTIFY_STOP; } +/* unwind all remaining regions */ +void kill_regions(struct cxl_root_decoder *cxlrd) +{ + unsigned long index; + struct cxl_region *cxlr; + + guard(mutex)(&cxlrd->regions_lock); + /* no more region creation */ + cxlrd->dead = true; + xa_for_each(&cxlrd->regions, index, cxlr) + unregister_region(cxlr); +} + /** * devm_cxl_add_region - Adds a region to a decoder * @cxlrd: root decoder @@ -2720,14 +2758,15 @@ static struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd, if (rc) goto err; - rc = devm_add_action_or_reset(port->uport_dev, unregister_region, cxlr); - if (rc) + rc = xa_insert(&cxlrd->regions, cxlr->id, cxlr, GFP_KERNEL); + if (rc) { + unregister_region(cxlr); return ERR_PTR(rc); + } dev_dbg(port->uport_dev, "%s: created %s\n", dev_name(&cxlrd->cxlsd.cxld.dev), dev_name(dev)); return cxlr; - err: put_device(dev); return ERR_PTR(rc); @@ -2756,6 +2795,9 @@ static struct cxl_region *__create_region(struct cxl_root_decoder *cxlrd, { int rc; + if (cxlrd->dead) + return ERR_PTR(-ENXIO); + switch (mode) { case CXL_PARTMODE_RAM: case CXL_PARTMODE_PMEM: @@ -2788,6 +2830,10 @@ static ssize_t create_region_store(struct device *dev, const char *buf, if (rc != 1) return -EINVAL; + ACQUIRE(mutex_intr, regions_lock)(&cxlrd->regions_lock); + if ((rc = ACQUIRE_ERR(mutex_intr, ®ions_lock))) + return rc; + cxlr = __create_region(cxlrd, mode, id, CXL_DECODER_HOSTONLYMEM); if (IS_ERR(cxlr)) return PTR_ERR(cxlr); @@ -2827,33 +2873,27 @@ static ssize_t region_show(struct device *dev, struct device_attribute *attr, } DEVICE_ATTR_RO(region); -static struct cxl_region * -cxl_find_region_by_name(struct cxl_root_decoder *cxlrd, const char *name) -{ - struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld; - struct device *region_dev; - - region_dev = device_find_child_by_name(&cxld->dev, name); - if (!region_dev) - return ERR_PTR(-ENODEV); - - return to_cxl_region(region_dev); -} - static ssize_t delete_region_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev); - struct cxl_port *port = to_cxl_port(dev->parent); struct cxl_region *cxlr; + int rc, id; - cxlr = cxl_find_region_by_name(cxlrd, buf); - if (IS_ERR(cxlr)) - return PTR_ERR(cxlr); + ACQUIRE(mutex_intr, regions_lock)(&cxlrd->regions_lock); + if ((rc = ACQUIRE_ERR(mutex_intr, ®ions_lock))) + return rc; - devm_release_action(port->uport_dev, unregister_region, cxlr); - put_device(&cxlr->dev); + rc = sscanf(buf, "region%d\n", &id); + if (rc != 1) + return -EINVAL; + + cxlr = xa_load(&cxlrd->regions, id); + if (!cxlr || !sysfs_streq(buf, dev_name(&cxlr->dev))) + return -ENODEV; + + unregister_region(cxlr); return len; } @@ -3718,7 +3758,6 @@ static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd, { struct cxl_endpoint_decoder *cxled = ctx->cxled; struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); - struct cxl_port *port = cxlrd_to_port(cxlrd); struct cxl_dev_state *cxlds = cxlmd->cxlds; int rc, part = READ_ONCE(cxled->part); struct cxl_region *cxlr; @@ -3742,7 +3781,7 @@ static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd, rc = __construct_region(cxlr, ctx); if (rc) { - devm_release_action(port->uport_dev, unregister_region, cxlr); + unregister_region(cxlr); return ERR_PTR(rc); } @@ -3788,12 +3827,11 @@ int cxl_add_to_region(struct cxl_endpoint_decoder *cxled) * for the HPA range, one does the construction and the others * add to that. */ - mutex_lock(&cxlrd->range_lock); + guard(mutex)(&cxlrd->regions_lock); struct cxl_region *cxlr __free(put_cxl_region) = cxl_find_region_by_range(cxlrd, &ctx.hpa_range); if (!cxlr) cxlr = construct_region(cxlrd, &ctx); - mutex_unlock(&cxlrd->range_lock); rc = PTR_ERR_OR_ZERO(cxlr); if (rc) @@ -4055,6 +4093,103 @@ static int cxl_region_can_probe(struct cxl_region *cxlr) return 0; } +static int first_mapped_decoder(struct device *dev, const void *data) +{ + struct cxl_endpoint_decoder *cxled; + + if (!is_endpoint_decoder(dev)) + return 0; + + cxled = to_cxl_endpoint_decoder(dev); + if (cxled->cxld.region) + return 1; + + return 0; +} + +/* + * Runs in cxl_mem_probe context after successful endpoint probe, assumes the + * simple case of single mapped decoder per memdev. + */ +int cxl_memdev_attach_region(struct cxl_memdev *cxlmd) +{ + struct cxl_attach_region *attach = + container_of(cxlmd->attach, typeof(*attach), attach); + struct cxl_port *endpoint = cxlmd->endpoint; + struct cxl_endpoint_decoder *cxled; + struct cxl_region *cxlr; + int rc; + + /* hold endpoint lock to setup autoremove of the region */ + guard(device)(&endpoint->dev); + if (!endpoint->dev.driver) + return -ENXIO; + guard(rwsem_read)(&cxl_rwsem.region); + guard(rwsem_read)(&cxl_rwsem.dpa); + + /* + * TODO auto-instantiate a region, for now assume this will find an + * auto-region + */ + struct device *dev __free(put_device) = + device_find_child(&endpoint->dev, NULL, first_mapped_decoder); + + if (!dev) { + dev_dbg(cxlmd->cxlds->dev, "no region found for memdev %s\n", + dev_name(&cxlmd->dev)); + return -ENXIO; + } + + cxled = to_cxl_endpoint_decoder(dev); + cxlr = cxled->cxld.region; + + if (cxlr->params.state < CXL_CONFIG_COMMIT) { + dev_dbg(cxlmd->cxlds->dev, + "region %s not committed for memdev %s\n", + dev_name(&cxlr->dev), dev_name(&cxlmd->dev)); + return -ENXIO; + } + + if (cxlr->params.nr_targets > 1) { + dev_dbg(cxlmd->cxlds->dev, + "Only attach to local non-interleaved region\n"); + return -ENXIO; + } + + /* Only teardown regions that pass validation, ignore the rest */ + get_device(&cxlr->dev); + rc = devm_add_action_or_reset(&endpoint->dev, + endpoint_unregister_region, cxlr); + if (rc) + return rc; + + attach->hpa_range = (struct range) { + .start = cxlr->params.res->start, + .end = cxlr->params.res->end, + }; + return 0; +} +EXPORT_SYMBOL_FOR_MODULES(cxl_memdev_attach_region, "cxl_mem"); + +/* + * The presence of an attach method indicates that the region is designated for + * a purpose outside of CXL core memory expansion defaults. + */ +static bool cxl_region_has_memdev_attach(struct cxl_region *cxlr) +{ + struct cxl_region_params *p = &cxlr->params; + + for (int i = 0; i < p->nr_targets; i++) { + struct cxl_endpoint_decoder *cxled = p->targets[i]; + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); + + if (cxlmd->attach) + return true; + } + + return false; +} + static int cxl_region_probe(struct device *dev) { struct cxl_region *cxlr = to_cxl_region(dev); @@ -4086,6 +4221,9 @@ static int cxl_region_probe(struct device *dev) if (rc) return rc; + if (cxl_region_has_memdev_attach(cxlr)) + return 0; + switch (cxlr->mode) { case CXL_PARTMODE_PMEM: rc = devm_cxl_region_edac_register(cxlr); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 4a884821ff7c..c0e5308e4d1b 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -371,7 +371,9 @@ struct cxl_rd_ops { * @cache_size: extended linear cache size if exists, otherwise zero. * @region_id: region id for next region provisioning event * @platform_data: platform specific configuration data - * @range_lock: sync region autodiscovery by address range + * @regions_lock: sync region discovery, construction, and deletion + * @regions: regions to remove at root decoder destruct time + * @dead: root decoder dead to region creation * @qos_class: QoS performance class cookie * @ops: CXL root decoder operations * @cxlsd: base cxl switch decoder @@ -381,7 +383,9 @@ struct cxl_root_decoder { resource_size_t cache_size; atomic_t region_id; void *platform_data; - struct mutex range_lock; + struct mutex regions_lock; + struct xarray regions; + bool dead; int qos_class; struct cxl_rd_ops ops; struct cxl_switch_decoder cxlsd; diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index 776c50d1db51..ed419d0c59f2 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -34,10 +34,6 @@ (FIELD_GET(CXLMDEV_RESET_NEEDED_MASK, status) != \ CXLMDEV_RESET_NEEDED_NOT) -struct cxl_memdev_attach { - int (*probe)(struct cxl_memdev *cxlmd); -}; - /** * struct cxl_memdev - CXL bus object representing a Type-3 Memory Device * @dev: driver core device object @@ -101,10 +97,36 @@ static inline bool is_cxl_endpoint(struct cxl_port *port) return is_cxl_memdev(port->uport_dev); } +struct cxl_memdev_attach { + int (*probe)(struct cxl_memdev *cxlmd); +}; + +/** + * struct cxl_attach_region - coordinate mapping a region at memdev registration + * @attach: common core attachment descriptor + * @hpa_range: physical address range of the region + * + * For the common simple case of a CXL device with private (non-general purpose + * / "accelerator") memory, enumerate firmware instantiated region, or + * instantiate a region for the device's capacity. Destroy the region on detach. + */ +struct cxl_attach_region { + struct cxl_memdev_attach attach; + struct range hpa_range; +}; + +#ifdef CONFIG_CXL_REGION +int cxl_memdev_attach_region(struct cxl_memdev *cxlmd); +#else +static inline int cxl_memdev_attach_region(struct cxl_memdev *cxlmd) +{ + return -EOPNOTSUPP; +} +#endif + +struct cxl_memdev *devm_cxl_add_classdev(struct cxl_dev_state *cxlds); struct cxl_memdev *__devm_cxl_add_memdev(struct cxl_dev_state *cxlds, const struct cxl_memdev_attach *attach); -struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds, - const struct cxl_memdev_attach *attach); int devm_cxl_sanitize_setup_notifier(struct device *host, struct cxl_memdev *cxlmd); struct cxl_memdev_state; diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c index ab88eaa31d1d..798e5c369cfc 100644 --- a/drivers/cxl/mem.c +++ b/drivers/cxl/mem.c @@ -75,6 +75,26 @@ static int cxl_debugfs_poison_clear(void *data, u64 dpa) DEFINE_DEBUGFS_ATTRIBUTE(cxl_poison_clear_fops, NULL, cxl_debugfs_poison_clear, "%llx\n"); +static void cxl_memdev_poison_enable(struct cxl_memdev_state *mds, + struct cxl_memdev *cxlmd, + struct dentry *dentry) +{ + /* + * Avoid poison debugfs for DEVMEM aka accelerators as they rely on + * cxl_memdev_state. + */ + if (!mds) + return; + + if (test_bit(CXL_POISON_ENABLED_INJECT, mds->poison.enabled_cmds)) + debugfs_create_file("inject_poison", 0200, dentry, cxlmd, + &cxl_poison_inject_fops); + + if (test_bit(CXL_POISON_ENABLED_CLEAR, mds->poison.enabled_cmds)) + debugfs_create_file("clear_poison", 0200, dentry, cxlmd, + &cxl_poison_clear_fops); +} + static int cxl_mem_probe(struct device *dev) { struct cxl_memdev *cxlmd = to_cxl_memdev(dev); @@ -102,12 +122,7 @@ static int cxl_mem_probe(struct device *dev) dentry = cxl_debugfs_create_dir(dev_name(dev)); debugfs_create_devm_seqfile(dev, "dpamem", dentry, cxl_mem_dpa_show); - if (test_bit(CXL_POISON_ENABLED_INJECT, mds->poison.enabled_cmds)) - debugfs_create_file("inject_poison", 0200, dentry, cxlmd, - &cxl_poison_inject_fops); - if (test_bit(CXL_POISON_ENABLED_CLEAR, mds->poison.enabled_cmds)) - debugfs_create_file("clear_poison", 0200, dentry, cxlmd, - &cxl_poison_clear_fops); + cxl_memdev_poison_enable(mds, cxlmd, dentry); rc = devm_add_action_or_reset(dev, remove_debugfs, dentry); if (rc) @@ -178,27 +193,59 @@ static int cxl_mem_probe(struct device *dev) } /** - * devm_cxl_add_memdev - Add a CXL memory device + * devm_cxl_add_classdev - Add a CXL memory class-code device * @cxlds: CXL device state to associate with the memdev - * @attach: Caller depends on CXL topology attachment * * Upon return the device will have had a chance to attach to the * cxl_mem driver, but may fail to attach if the CXL topology is not ready * (hardware CXL link down, or software platform CXL root not attached). * - * When @attach is NULL it indicates the caller wants the memdev to remain - * registered even if it does not immediately attach to the CXL hierarchy. When - * @attach is provided a cxl_mem_probe() failure leads to failure of this routine. + * The parent of the resulting device and the devm context for allocations is + * @cxlds->dev. + */ +struct cxl_memdev *devm_cxl_add_classdev(struct cxl_dev_state *cxlds) +{ + return __devm_cxl_add_memdev(cxlds, NULL); +} +EXPORT_SYMBOL_NS_GPL(devm_cxl_add_classdev, "CXL"); + +/** + * devm_cxl_probe_mem - Add a CXL memory device and probe its region + * @cxlds: CXL device state to associate with the memdev + * @hpa_range: CXL.mem physical address range result + * + * Upon return the device will have had a chance to attach to the + * cxl_mem driver, but may fail to attach if the CXL topology is not ready + * (hardware CXL link down, or software platform CXL root not attached). + * + * Failure to probe the memdev and/or setup a region for the memdev + * results in this function failing. * * The parent of the resulting device and the devm context for allocations is * @cxlds->dev. */ -struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds, - const struct cxl_memdev_attach *attach) +struct cxl_memdev *devm_cxl_probe_mem(struct cxl_dev_state *cxlds, + struct range *hpa_range) { - return __devm_cxl_add_memdev(cxlds, attach); + struct cxl_attach_region *attach = + devm_kmalloc(cxlds->dev, sizeof(*attach), GFP_KERNEL); + struct cxl_memdev *cxlmd; + + if (!attach) + return ERR_PTR(-ENOMEM); + + *attach = (struct cxl_attach_region) { + .attach = { + .probe = cxl_memdev_attach_region, + }, + .hpa_range = { 0, -1 }, + }; + + cxlmd = __devm_cxl_add_memdev(cxlds, &attach->attach); + *hpa_range = attach->hpa_range; + return cxlmd; } -EXPORT_SYMBOL_NS_GPL(devm_cxl_add_memdev, "CXL"); +EXPORT_SYMBOL_NS_GPL(devm_cxl_probe_mem, "CXL"); static ssize_t trigger_poison_list_store(struct device *dev, struct device_attribute *attr, @@ -216,16 +263,24 @@ static ssize_t trigger_poison_list_store(struct device *dev, } static DEVICE_ATTR_WO(trigger_poison_list); -static umode_t cxl_mem_visible(struct kobject *kobj, struct attribute *a, int n) +static bool cxl_poison_attr_visible(struct kobject *kobj, struct attribute *a) { struct device *dev = kobj_to_dev(kobj); struct cxl_memdev *cxlmd = to_cxl_memdev(dev); struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); - if (a == &dev_attr_trigger_poison_list.attr) - if (!test_bit(CXL_POISON_ENABLED_LIST, - mds->poison.enabled_cmds)) - return 0; + if (!mds || + !test_bit(CXL_POISON_ENABLED_LIST, mds->poison.enabled_cmds)) + return false; + + return true; +} + +static umode_t cxl_mem_visible(struct kobject *kobj, struct attribute *a, int n) +{ + if (a == &dev_attr_trigger_poison_list.attr && + !cxl_poison_attr_visible(kobj, a)) + return 0; return a->mode; } diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index bace662dc988..267c679b0b3c 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -878,7 +878,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (rc) dev_dbg(&pdev->dev, "No CXL Features discovered\n"); - cxlmd = devm_cxl_add_memdev(cxlds, NULL); + cxlmd = devm_cxl_add_classdev(cxlds); if (IS_ERR(cxlmd)) return PTR_ERR(cxlmd); diff --git a/include/cxl/cxl.h b/include/cxl/cxl.h index fa7269154620..016c74fb747c 100644 --- a/include/cxl/cxl.h +++ b/include/cxl/cxl.h @@ -223,4 +223,7 @@ struct cxl_dev_state *_devm_cxl_dev_state_create(struct device *dev, (drv_struct *)_devm_cxl_dev_state_create(parent, type, serial, dvsec, \ sizeof(drv_struct), mbox); \ }) + +struct cxl_memdev *devm_cxl_probe_mem(struct cxl_dev_state *cxlds, + struct range *range); #endif /* __CXL_CXL_H__ */ diff --git a/tools/testing/cxl/test/mem.c b/tools/testing/cxl/test/mem.c index 739343cd5802..a1d170f88fee 100644 --- a/tools/testing/cxl/test/mem.c +++ b/tools/testing/cxl/test/mem.c @@ -1790,7 +1790,7 @@ static int cxl_mock_mem_probe(struct platform_device *pdev) cxl_mock_add_event_logs(&mdata->mes); - cxlmd = devm_cxl_add_memdev(cxlds, NULL); + cxlmd = devm_cxl_add_classdev(cxlds); if (IS_ERR(cxlmd)) return PTR_ERR(cxlmd); |
