cxl/pmem: Add support for multiple nvdimm-bridge objects

In preparation for a mocked unit test environment for CXL objects, allow
for multiple unique nvdimm-bridge objects.

For now, just allow multiple bridges to be registered. Later, when there
are multiple present, further updates are needed to
cxl_find_nvdimm_bridge() to identify which bridge is associated with
which CXL hierarchy for nvdimm registration.

Note that this does change the kernel device-name for the bridge object.
User space should not have any attachment to the device name at this
point as it is still early days in the CXL driver development.

Acked-by: Ben Widawsky <ben.widawsky@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Link: https://lore.kernel.org/r/163164647007.2831228.2150246954620721526.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
Dan Williams 2021-09-14 12:08:40 -07:00
parent 60b8f17215
commit 2e52b6256b
3 changed files with 33 additions and 16 deletions

View file

@ -2,6 +2,7 @@
/* Copyright(c) 2020 Intel Corporation. */
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/idr.h>
#include <cxlmem.h>
#include <cxl.h>
#include "core.h"
@ -20,10 +21,13 @@
* operations, for example, namespace label access commands.
*/
static DEFINE_IDA(cxl_nvdimm_bridge_ida);
static void cxl_nvdimm_bridge_release(struct device *dev)
{
struct cxl_nvdimm_bridge *cxl_nvb = to_cxl_nvdimm_bridge(dev);
ida_free(&cxl_nvdimm_bridge_ida, cxl_nvb->id);
kfree(cxl_nvb);
}
@ -47,16 +51,38 @@ struct cxl_nvdimm_bridge *to_cxl_nvdimm_bridge(struct device *dev)
}
EXPORT_SYMBOL_GPL(to_cxl_nvdimm_bridge);
static int match_nvdimm_bridge(struct device *dev, const void *data)
{
return dev->type == &cxl_nvdimm_bridge_type;
}
struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(void)
{
struct device *dev;
dev = bus_find_device(&cxl_bus_type, NULL, NULL, match_nvdimm_bridge);
if (!dev)
return NULL;
return to_cxl_nvdimm_bridge(dev);
}
EXPORT_SYMBOL_GPL(cxl_find_nvdimm_bridge);
static struct cxl_nvdimm_bridge *
cxl_nvdimm_bridge_alloc(struct cxl_port *port)
{
struct cxl_nvdimm_bridge *cxl_nvb;
struct device *dev;
int rc;
cxl_nvb = kzalloc(sizeof(*cxl_nvb), GFP_KERNEL);
if (!cxl_nvb)
return ERR_PTR(-ENOMEM);
rc = ida_alloc(&cxl_nvdimm_bridge_ida, GFP_KERNEL);
if (rc < 0)
goto err;
cxl_nvb->id = rc;
dev = &cxl_nvb->dev;
cxl_nvb->port = port;
cxl_nvb->state = CXL_NVB_NEW;
@ -67,6 +93,10 @@ cxl_nvdimm_bridge_alloc(struct cxl_port *port)
dev->type = &cxl_nvdimm_bridge_type;
return cxl_nvb;
err:
kfree(cxl_nvb);
return ERR_PTR(rc);
}
static void unregister_nvb(void *_cxl_nvb)
@ -119,7 +149,7 @@ struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host,
return cxl_nvb;
dev = &cxl_nvb->dev;
rc = dev_set_name(dev, "nvdimm-bridge");
rc = dev_set_name(dev, "nvdimm-bridge%d", cxl_nvb->id);
if (rc)
goto err;

View file

@ -211,6 +211,7 @@ enum cxl_nvdimm_brige_state {
};
struct cxl_nvdimm_bridge {
int id;
struct device dev;
struct cxl_port *port;
struct nvdimm_bus *nvdimm_bus;
@ -323,4 +324,5 @@ struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host,
struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev);
bool is_cxl_nvdimm(struct device *dev);
int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd);
struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(void);
#endif /* __CXL_H__ */

View file

@ -29,21 +29,6 @@ static void unregister_nvdimm(void *nvdimm)
nvdimm_delete(nvdimm);
}
static int match_nvdimm_bridge(struct device *dev, const void *data)
{
return strcmp(dev_name(dev), "nvdimm-bridge") == 0;
}
static struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(void)
{
struct device *dev;
dev = bus_find_device(&cxl_bus_type, NULL, NULL, match_nvdimm_bridge);
if (!dev)
return NULL;
return to_cxl_nvdimm_bridge(dev);
}
static int cxl_nvdimm_probe(struct device *dev)
{
struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev);