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);
}
}
mutex_init(&cxlrd->regions_lock);
+ xa_init(&cxlrd->regions);
cxld = &cxlsd->cxld;
cxld->dev.type = &cxl_decoder_root_type;
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);
}
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);
/*
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
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);
{
int rc;
+ if (cxlrd->dead)
+ return ERR_PTR(-ENXIO);
+
switch (mode) {
case CXL_PARTMODE_RAM:
case CXL_PARTMODE_PMEM:
}
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;
+ int rc, id;
ACQUIRE(mutex_intr, regions_lock)(&cxlrd->regions_lock);
if ((rc = ACQUIRE_ERR(mutex_intr, ®ions_lock)))
return rc;
- cxlr = cxl_find_region_by_name(cxlrd, buf);
- if (IS_ERR(cxlr))
- return PTR_ERR(cxlr);
+ rc = sscanf(buf, "region%d\n", &id);
+ if (rc != 1)
+ return -EINVAL;
- devm_release_action(port->uport_dev, unregister_region, cxlr);
- put_device(&cxlr->dev);
+ cxlr = xa_load(&cxlrd->regions, id);
+ if (!cxlr || !sysfs_streq(buf, dev_name(&cxlr->dev)))
+ return -ENODEV;
+
+ unregister_region(cxlr);
return len;
}
{
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;
rc = __construct_region(cxlr, ctx);
if (rc) {
- devm_release_action(port->uport_dev, unregister_region, cxlr);
+ unregister_region(cxlr);
return ERR_PTR(rc);
}