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
This commit is contained in:
Dave Jiang 2026-06-12 13:47:53 -07:00
commit f72af41a43
10 changed files with 304 additions and 63 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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);
}

View File

@ -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, &regions_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, &regions_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);

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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__ */

View File

@ -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);