mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
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:
commit
f72af41a43
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user