Skip to content

Commit 04ad63f

Browse files
committed
cxl/region: Introduce cxl_pmem_region objects
The LIBNVDIMM subsystem is a platform agnostic representation of system NVDIMM / persistent memory resources. To date, the CXL subsystem's interaction with LIBNVDIMM has been to register an nvdimm-bridge device and cxl_nvdimm objects to proxy CXL capabilities into existing LIBNVDIMM subsystem mechanics. With regions the approach is the same. Create a new cxl_pmem_region object to proxy CXL region details into a LIBNVDIMM definition. With this enabling LIBNVDIMM can partition CXL persistent memory regions with legacy namespace labels. A follow-on patch will add CXL region label and CXL namespace label support to persist region configurations across driver reload / system-reset events. Co-developed-by: Ben Widawsky <[email protected]> Signed-off-by: Ben Widawsky <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Link: https://lore.kernel.org/r/165784340111.1758207.3036498385188290968.stgit@dwillia2-xfh.jf.intel.com Signed-off-by: Dan Williams <[email protected]>
1 parent 99183d2 commit 04ad63f

File tree

8 files changed

+446
-12
lines changed

8 files changed

+446
-12
lines changed

drivers/cxl/core/core.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ extern struct attribute_group cxl_base_attribute_group;
1313
extern struct device_attribute dev_attr_create_pmem_region;
1414
extern struct device_attribute dev_attr_delete_region;
1515
extern struct device_attribute dev_attr_region;
16+
extern const struct device_type cxl_pmem_region_type;
1617
extern const struct device_type cxl_region_type;
1718
void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled);
1819
#define CXL_REGION_ATTR(x) (&dev_attr_##x.attr)
1920
#define CXL_REGION_TYPE(x) (&cxl_region_type)
2021
#define SET_CXL_REGION_ATTR(x) (&dev_attr_##x.attr),
22+
#define CXL_PMEM_REGION_TYPE(x) (&cxl_pmem_region_type)
2123
int cxl_region_init(void);
2224
void cxl_region_exit(void);
2325
#else
@@ -34,6 +36,7 @@ static inline void cxl_region_exit(void)
3436
#define CXL_REGION_ATTR(x) NULL
3537
#define CXL_REGION_TYPE(x) NULL
3638
#define SET_CXL_REGION_ATTR(x)
39+
#define CXL_PMEM_REGION_TYPE(x) NULL
3740
#endif
3841

3942
struct cxl_send_command;

drivers/cxl/core/pmem.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ static int match_nvdimm_bridge(struct device *dev, void *data)
6262
return is_cxl_nvdimm_bridge(dev);
6363
}
6464

65-
struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd)
65+
struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *start)
6666
{
67-
struct cxl_port *port = find_cxl_root(&cxl_nvd->dev);
67+
struct cxl_port *port = find_cxl_root(start);
6868
struct device *dev;
6969

7070
if (!port)

drivers/cxl/core/port.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ static int cxl_device_id(struct device *dev)
4444
return CXL_DEVICE_NVDIMM_BRIDGE;
4545
if (dev->type == &cxl_nvdimm_type)
4646
return CXL_DEVICE_NVDIMM;
47+
if (dev->type == CXL_PMEM_REGION_TYPE())
48+
return CXL_DEVICE_PMEM_REGION;
4749
if (is_cxl_port(dev)) {
4850
if (is_cxl_root(to_cxl_port(dev)))
4951
return CXL_DEVICE_ROOT;

drivers/cxl/core/region.c

Lines changed: 141 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1650,6 +1650,139 @@ static ssize_t delete_region_store(struct device *dev,
16501650
}
16511651
DEVICE_ATTR_WO(delete_region);
16521652

1653+
static void cxl_pmem_region_release(struct device *dev)
1654+
{
1655+
struct cxl_pmem_region *cxlr_pmem = to_cxl_pmem_region(dev);
1656+
int i;
1657+
1658+
for (i = 0; i < cxlr_pmem->nr_mappings; i++) {
1659+
struct cxl_memdev *cxlmd = cxlr_pmem->mapping[i].cxlmd;
1660+
1661+
put_device(&cxlmd->dev);
1662+
}
1663+
1664+
kfree(cxlr_pmem);
1665+
}
1666+
1667+
static const struct attribute_group *cxl_pmem_region_attribute_groups[] = {
1668+
&cxl_base_attribute_group,
1669+
NULL,
1670+
};
1671+
1672+
const struct device_type cxl_pmem_region_type = {
1673+
.name = "cxl_pmem_region",
1674+
.release = cxl_pmem_region_release,
1675+
.groups = cxl_pmem_region_attribute_groups,
1676+
};
1677+
1678+
bool is_cxl_pmem_region(struct device *dev)
1679+
{
1680+
return dev->type == &cxl_pmem_region_type;
1681+
}
1682+
EXPORT_SYMBOL_NS_GPL(is_cxl_pmem_region, CXL);
1683+
1684+
struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev)
1685+
{
1686+
if (dev_WARN_ONCE(dev, !is_cxl_pmem_region(dev),
1687+
"not a cxl_pmem_region device\n"))
1688+
return NULL;
1689+
return container_of(dev, struct cxl_pmem_region, dev);
1690+
}
1691+
EXPORT_SYMBOL_NS_GPL(to_cxl_pmem_region, CXL);
1692+
1693+
static struct lock_class_key cxl_pmem_region_key;
1694+
1695+
static struct cxl_pmem_region *cxl_pmem_region_alloc(struct cxl_region *cxlr)
1696+
{
1697+
struct cxl_region_params *p = &cxlr->params;
1698+
struct cxl_pmem_region *cxlr_pmem;
1699+
struct device *dev;
1700+
int i;
1701+
1702+
down_read(&cxl_region_rwsem);
1703+
if (p->state != CXL_CONFIG_COMMIT) {
1704+
cxlr_pmem = ERR_PTR(-ENXIO);
1705+
goto out;
1706+
}
1707+
1708+
cxlr_pmem = kzalloc(struct_size(cxlr_pmem, mapping, p->nr_targets),
1709+
GFP_KERNEL);
1710+
if (!cxlr_pmem) {
1711+
cxlr_pmem = ERR_PTR(-ENOMEM);
1712+
goto out;
1713+
}
1714+
1715+
cxlr_pmem->hpa_range.start = p->res->start;
1716+
cxlr_pmem->hpa_range.end = p->res->end;
1717+
1718+
/* Snapshot the region configuration underneath the cxl_region_rwsem */
1719+
cxlr_pmem->nr_mappings = p->nr_targets;
1720+
for (i = 0; i < p->nr_targets; i++) {
1721+
struct cxl_endpoint_decoder *cxled = p->targets[i];
1722+
struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
1723+
struct cxl_pmem_region_mapping *m = &cxlr_pmem->mapping[i];
1724+
1725+
m->cxlmd = cxlmd;
1726+
get_device(&cxlmd->dev);
1727+
m->start = cxled->dpa_res->start;
1728+
m->size = resource_size(cxled->dpa_res);
1729+
m->position = i;
1730+
}
1731+
1732+
dev = &cxlr_pmem->dev;
1733+
cxlr_pmem->cxlr = cxlr;
1734+
device_initialize(dev);
1735+
lockdep_set_class(&dev->mutex, &cxl_pmem_region_key);
1736+
device_set_pm_not_required(dev);
1737+
dev->parent = &cxlr->dev;
1738+
dev->bus = &cxl_bus_type;
1739+
dev->type = &cxl_pmem_region_type;
1740+
out:
1741+
up_read(&cxl_region_rwsem);
1742+
1743+
return cxlr_pmem;
1744+
}
1745+
1746+
static void cxlr_pmem_unregister(void *dev)
1747+
{
1748+
device_unregister(dev);
1749+
}
1750+
1751+
/**
1752+
* devm_cxl_add_pmem_region() - add a cxl_region-to-nd_region bridge
1753+
* @cxlr: parent CXL region for this pmem region bridge device
1754+
*
1755+
* Return: 0 on success negative error code on failure.
1756+
*/
1757+
static int devm_cxl_add_pmem_region(struct cxl_region *cxlr)
1758+
{
1759+
struct cxl_pmem_region *cxlr_pmem;
1760+
struct device *dev;
1761+
int rc;
1762+
1763+
cxlr_pmem = cxl_pmem_region_alloc(cxlr);
1764+
if (IS_ERR(cxlr_pmem))
1765+
return PTR_ERR(cxlr_pmem);
1766+
1767+
dev = &cxlr_pmem->dev;
1768+
rc = dev_set_name(dev, "pmem_region%d", cxlr->id);
1769+
if (rc)
1770+
goto err;
1771+
1772+
rc = device_add(dev);
1773+
if (rc)
1774+
goto err;
1775+
1776+
dev_dbg(&cxlr->dev, "%s: register %s\n", dev_name(dev->parent),
1777+
dev_name(dev));
1778+
1779+
return devm_add_action_or_reset(&cxlr->dev, cxlr_pmem_unregister, dev);
1780+
1781+
err:
1782+
put_device(dev);
1783+
return rc;
1784+
}
1785+
16531786
static int cxl_region_probe(struct device *dev)
16541787
{
16551788
struct cxl_region *cxlr = to_cxl_region(dev);
@@ -1673,7 +1806,14 @@ static int cxl_region_probe(struct device *dev)
16731806
*/
16741807
up_read(&cxl_region_rwsem);
16751808

1676-
return rc;
1809+
switch (cxlr->mode) {
1810+
case CXL_DECODER_PMEM:
1811+
return devm_cxl_add_pmem_region(cxlr);
1812+
default:
1813+
dev_dbg(&cxlr->dev, "unsupported region mode: %d\n",
1814+
cxlr->mode);
1815+
return -ENXIO;
1816+
}
16771817
}
16781818

16791819
static struct cxl_driver cxl_region_driver = {

drivers/cxl/cxl.h

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,25 @@ struct cxl_nvdimm {
419419
struct device dev;
420420
struct cxl_memdev *cxlmd;
421421
struct cxl_nvdimm_bridge *bridge;
422+
struct cxl_pmem_region *region;
423+
};
424+
425+
struct cxl_pmem_region_mapping {
426+
struct cxl_memdev *cxlmd;
427+
struct cxl_nvdimm *cxl_nvd;
428+
u64 start;
429+
u64 size;
430+
int position;
431+
};
432+
433+
struct cxl_pmem_region {
434+
struct device dev;
435+
struct cxl_region *cxlr;
436+
struct nd_region *nd_region;
437+
struct cxl_nvdimm_bridge *bridge;
438+
struct range hpa_range;
439+
int nr_mappings;
440+
struct cxl_pmem_region_mapping mapping[];
422441
};
423442

424443
/**
@@ -601,6 +620,7 @@ void cxl_driver_unregister(struct cxl_driver *cxl_drv);
601620
#define CXL_DEVICE_ROOT 4
602621
#define CXL_DEVICE_MEMORY_EXPANDER 5
603622
#define CXL_DEVICE_REGION 6
623+
#define CXL_DEVICE_PMEM_REGION 7
604624

605625
#define MODULE_ALIAS_CXL(type) MODULE_ALIAS("cxl:t" __stringify(type) "*")
606626
#define CXL_MODALIAS_FMT "cxl:t%d"
@@ -612,7 +632,21 @@ struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev);
612632
bool is_cxl_nvdimm(struct device *dev);
613633
bool is_cxl_nvdimm_bridge(struct device *dev);
614634
int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd);
615-
struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd);
635+
struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *dev);
636+
637+
#ifdef CONFIG_CXL_REGION
638+
bool is_cxl_pmem_region(struct device *dev);
639+
struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev);
640+
#else
641+
static inline bool is_cxl_pmem_region(struct device *dev)
642+
{
643+
return false;
644+
}
645+
static inline struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev)
646+
{
647+
return NULL;
648+
}
649+
#endif
616650

617651
/*
618652
* Unit test builds overrides this to __weak, find the 'strong' version

0 commit comments

Comments
 (0)