linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Dan Williams <dan.j.williams@intel.com>
To: linux-cxl@vger.kernel.org
Cc: nvdimm@lists.linux.dev, linux-pci@vger.kernel.org,
	patches@lists.linux.dev, hch@lst.de,
	Dan Williams <dan.j.williams@intel.com>,
	Ben Widawsky <bwidawsk@kernel.org>
Subject: [PATCH 46/46] cxl/region: Introduce cxl_pmem_region objects
Date: Thu, 23 Jun 2022 21:19:50 -0700	[thread overview]
Message-ID: <20220624041950.559155-21-dan.j.williams@intel.com> (raw)
In-Reply-To: <165603869943.551046.3498980330327696732.stgit@dwillia2-xfh>

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 <bwidawsk@kernel.org>
Signed-off-by: Ben Widawsky <bwidawsk@kernel.org>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/cxl/core/core.h      |   3 +
 drivers/cxl/core/pmem.c      |   4 +-
 drivers/cxl/core/port.c      |   2 +
 drivers/cxl/core/region.c    | 139 ++++++++++++++++++++-
 drivers/cxl/cxl.h            |  36 +++++-
 drivers/cxl/pmem.c           | 235 ++++++++++++++++++++++++++++++++++-
 drivers/nvdimm/region_devs.c |  28 +++--
 include/linux/libnvdimm.h    |   5 +
 8 files changed, 440 insertions(+), 12 deletions(-)

diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index be5198ab8f3b..f5c5b041e8a5 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -13,6 +13,7 @@ extern struct attribute_group cxl_base_attribute_group;
 extern struct device_attribute dev_attr_create_pmem_region;
 extern struct device_attribute dev_attr_delete_region;
 extern struct device_attribute dev_attr_region;
+extern const struct device_type cxl_pmem_region_type;
 extern const struct device_type cxl_region_type;
 void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled);
 int cxl_region_init(void);
@@ -23,6 +24,7 @@ void cxl_region_exit(void);
  */
 #define CXL_REGION_ATTR(x) (&dev_attr_##x.attr)
 #define CXL_REGION_TYPE(x) (&cxl_region_type)
+#define CXL_PMEM_REGION_TYPE(x) (&cxl_pmem_region_type)
 #else
 static inline void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled)
 {
@@ -36,6 +38,7 @@ static inline void cxl_region_exit(void)
 }
 #define CXL_REGION_ATTR(x) NULL
 #define CXL_REGION_TYPE(x) NULL
+#define CXL_PMEM_REGION_TYPE(x) NULL
 #endif
 
 struct cxl_send_command;
diff --git a/drivers/cxl/core/pmem.c b/drivers/cxl/core/pmem.c
index bec7cfb54ebf..1d12a8206444 100644
--- a/drivers/cxl/core/pmem.c
+++ b/drivers/cxl/core/pmem.c
@@ -62,9 +62,9 @@ static int match_nvdimm_bridge(struct device *dev, void *data)
 	return is_cxl_nvdimm_bridge(dev);
 }
 
-struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd)
+struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *start)
 {
-	struct cxl_port *port = find_cxl_root(&cxl_nvd->dev);
+	struct cxl_port *port = find_cxl_root(start);
 	struct device *dev;
 
 	if (!port)
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 00add9e0b192..e13cd012ed22 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -44,6 +44,8 @@ static int cxl_device_id(struct device *dev)
 		return CXL_DEVICE_NVDIMM_BRIDGE;
 	if (dev->type == &cxl_nvdimm_type)
 		return CXL_DEVICE_NVDIMM;
+	if (dev->type == CXL_PMEM_REGION_TYPE())
+		return CXL_DEVICE_PMEM_REGION;
 	if (is_cxl_port(dev)) {
 		if (is_cxl_root(to_cxl_port(dev)))
 			return CXL_DEVICE_ROOT;
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index cd1848d4c8fe..70e9baef95f7 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -1614,6 +1614,136 @@ static ssize_t delete_region_store(struct device *dev,
 }
 DEVICE_ATTR_WO(delete_region);
 
+static void cxl_pmem_region_release(struct device *dev)
+{
+	struct cxl_pmem_region *cxlr_pmem = to_cxl_pmem_region(dev);
+	int i;
+
+	for (i = 0; i < cxlr_pmem->nr_mappings; i++) {
+		struct cxl_memdev *cxlmd = cxlr_pmem->mapping[i].cxlmd;
+
+		put_device(&cxlmd->dev);
+	}
+
+	kfree(cxlr_pmem);
+}
+
+static const struct attribute_group *cxl_pmem_region_attribute_groups[] = {
+	&cxl_base_attribute_group,
+	NULL,
+};
+
+const struct device_type cxl_pmem_region_type = {
+	.name = "cxl_pmem_region",
+	.release = cxl_pmem_region_release,
+	.groups = cxl_pmem_region_attribute_groups,
+};
+
+bool is_cxl_pmem_region(struct device *dev)
+{
+	return dev->type == &cxl_pmem_region_type;
+}
+EXPORT_SYMBOL_NS_GPL(is_cxl_pmem_region, CXL);
+
+struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev)
+{
+	if (dev_WARN_ONCE(dev, !is_cxl_pmem_region(dev),
+			  "not a cxl_pmem_region device\n"))
+		return NULL;
+	return container_of(dev, struct cxl_pmem_region, dev);
+}
+EXPORT_SYMBOL_NS_GPL(to_cxl_pmem_region, CXL);
+
+static struct lock_class_key cxl_pmem_region_key;
+
+static struct cxl_pmem_region *cxl_pmem_region_alloc(struct cxl_region *cxlr)
+{
+	struct cxl_pmem_region *cxlr_pmem = ERR_PTR(-ENXIO);
+	struct cxl_region_params *p = &cxlr->params;
+	struct device *dev;
+	int i;
+
+	down_read(&cxl_region_rwsem);
+	if (p->state != CXL_CONFIG_COMMIT)
+		goto out;
+	cxlr_pmem = kzalloc(struct_size(cxlr_pmem, mapping, p->nr_targets),
+			    GFP_KERNEL);
+	if (!cxlr_pmem) {
+		cxlr_pmem = ERR_PTR(-ENOMEM);
+		goto out;
+	}
+
+	cxlr_pmem->hpa_range.start = p->res->start;
+	cxlr_pmem->hpa_range.end = p->res->end;
+
+	/* Snapshot the region configuration underneath the cxl_region_rwsem */
+	cxlr_pmem->nr_mappings = p->nr_targets;
+	for (i = 0; i < p->nr_targets; i++) {
+		struct cxl_endpoint_decoder *cxled = p->targets[i];
+		struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
+		struct cxl_pmem_region_mapping *m = &cxlr_pmem->mapping[i];
+
+		m->cxlmd = cxlmd;
+		get_device(&cxlmd->dev);
+		m->start = cxled->dpa_res->start;
+		m->size = resource_size(cxled->dpa_res);
+		m->position = i;
+	}
+
+	dev = &cxlr_pmem->dev;
+	cxlr_pmem->cxlr = cxlr;
+	device_initialize(dev);
+	lockdep_set_class(&dev->mutex, &cxl_pmem_region_key);
+	device_set_pm_not_required(dev);
+	dev->parent = &cxlr->dev;
+	dev->bus = &cxl_bus_type;
+	dev->type = &cxl_pmem_region_type;
+out:
+	up_read(&cxl_region_rwsem);
+
+	return cxlr_pmem;
+}
+
+static void cxlr_pmem_unregister(void *dev)
+{
+	device_unregister(dev);
+}
+
+/**
+ * devm_cxl_add_pmem_region() - add a cxl_region to nd_region bridge
+ * @host: same host as @cxlmd
+ *
+ * Return: 0 on success negative error code on failure.
+ */
+static int devm_cxl_add_pmem_region(struct cxl_region *cxlr)
+{
+	struct cxl_pmem_region *cxlr_pmem;
+	struct device *dev;
+	int rc;
+
+	cxlr_pmem = cxl_pmem_region_alloc(cxlr);
+	if (IS_ERR(cxlr_pmem))
+		return PTR_ERR(cxlr_pmem);
+
+	dev = &cxlr_pmem->dev;
+	rc = dev_set_name(dev, "pmem_region%d", cxlr->id);
+	if (rc)
+		goto err;
+
+	rc = device_add(dev);
+	if (rc)
+		goto err;
+
+	dev_dbg(&cxlr->dev, "%s: register %s\n", dev_name(dev->parent),
+		dev_name(dev));
+
+	return devm_add_action_or_reset(&cxlr->dev, cxlr_pmem_unregister, dev);
+
+err:
+	put_device(dev);
+	return rc;
+}
+
 static int cxl_region_probe(struct device *dev)
 {
 	struct cxl_region *cxlr = to_cxl_region(dev);
@@ -1637,7 +1767,14 @@ static int cxl_region_probe(struct device *dev)
 	 */
 	up_read(&cxl_region_rwsem);
 
-	return rc;
+	switch (cxlr->mode) {
+	case CXL_DECODER_PMEM:
+		return devm_cxl_add_pmem_region(cxlr);
+	default:
+		dev_dbg(&cxlr->dev, "unsupported region mode: %d\n",
+			cxlr->mode);
+		return -ENXIO;
+	}
 }
 
 static struct cxl_driver cxl_region_driver = {
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 95f486bc1b41..bf878509bed4 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -412,6 +412,25 @@ struct cxl_nvdimm {
 	struct device dev;
 	struct cxl_memdev *cxlmd;
 	struct cxl_nvdimm_bridge *bridge;
+	struct cxl_pmem_region *region;
+};
+
+struct cxl_pmem_region_mapping {
+	struct cxl_memdev *cxlmd;
+	struct cxl_nvdimm *cxl_nvd;
+	u64 start;
+	u64 size;
+	int position;
+};
+
+struct cxl_pmem_region {
+	struct device dev;
+	struct cxl_region *cxlr;
+	struct nd_region *nd_region;
+	struct cxl_nvdimm_bridge *bridge;
+	struct range hpa_range;
+	int nr_mappings;
+	struct cxl_pmem_region_mapping mapping[];
 };
 
 /**
@@ -587,6 +606,7 @@ void cxl_driver_unregister(struct cxl_driver *cxl_drv);
 #define CXL_DEVICE_ROOT			4
 #define CXL_DEVICE_MEMORY_EXPANDER	5
 #define CXL_DEVICE_REGION		6
+#define CXL_DEVICE_PMEM_REGION		7
 
 #define MODULE_ALIAS_CXL(type) MODULE_ALIAS("cxl:t" __stringify(type) "*")
 #define CXL_MODALIAS_FMT "cxl:t%d"
@@ -598,7 +618,21 @@ struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev);
 bool is_cxl_nvdimm(struct device *dev);
 bool is_cxl_nvdimm_bridge(struct device *dev);
 int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd);
-struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd);
+struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *dev);
+
+#ifdef CONFIG_CXL_REGION
+bool is_cxl_pmem_region(struct device *dev);
+struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev);
+#else
+static inline bool is_cxl_pmem_region(struct device *dev)
+{
+	return false;
+}
+static inline struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev)
+{
+	return NULL;
+}
+#endif
 
 /*
  * Unit test builds overrides this to __weak, find the 'strong' version
diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c
index b271f6e90b91..4ba7248275ac 100644
--- a/drivers/cxl/pmem.c
+++ b/drivers/cxl/pmem.c
@@ -7,6 +7,7 @@
 #include <linux/ndctl.h>
 #include <linux/async.h>
 #include <linux/slab.h>
+#include <linux/nd.h>
 #include "cxlmem.h"
 #include "cxl.h"
 
@@ -27,6 +28,19 @@ static void clear_exclusive(void *cxlds)
 static void unregister_nvdimm(void *nvdimm)
 {
 	struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
+	struct cxl_nvdimm_bridge *cxl_nvb = cxl_nvd->bridge;
+	struct cxl_pmem_region *cxlr_pmem;
+
+	device_lock(&cxl_nvb->dev);
+	cxlr_pmem = cxl_nvd->region;
+	dev_set_drvdata(&cxl_nvd->dev, NULL);
+	cxl_nvd->region = NULL;
+	device_unlock(&cxl_nvb->dev);
+
+	if (cxlr_pmem) {
+		device_release_driver(&cxlr_pmem->dev);
+		put_device(&cxlr_pmem->dev);
+	}
 
 	nvdimm_delete(nvdimm);
 	cxl_nvd->bridge = NULL;
@@ -42,7 +56,7 @@ static int cxl_nvdimm_probe(struct device *dev)
 	struct nvdimm *nvdimm;
 	int rc;
 
-	cxl_nvb = cxl_find_nvdimm_bridge(cxl_nvd);
+	cxl_nvb = cxl_find_nvdimm_bridge(dev);
 	if (!cxl_nvb)
 		return -ENXIO;
 
@@ -223,6 +237,21 @@ static int cxl_nvdimm_release_driver(struct device *dev, void *cxl_nvb)
 	return 0;
 }
 
+static int cxl_pmem_region_release_driver(struct device *dev, void *cxl_nvb)
+{
+	struct cxl_pmem_region *cxlr_pmem;
+
+	if (!is_cxl_pmem_region(dev))
+		return 0;
+
+	cxlr_pmem = to_cxl_pmem_region(dev);
+	if (cxlr_pmem->bridge != cxl_nvb)
+		return 0;
+
+	device_release_driver(dev);
+	return 0;
+}
+
 static void offline_nvdimm_bus(struct cxl_nvdimm_bridge *cxl_nvb,
 			       struct nvdimm_bus *nvdimm_bus)
 {
@@ -234,6 +263,8 @@ static void offline_nvdimm_bus(struct cxl_nvdimm_bridge *cxl_nvb,
 	 * nvdimm_bus_unregister() rips the nvdimm objects out from
 	 * underneath them.
 	 */
+	bus_for_each_dev(&cxl_bus_type, NULL, cxl_nvb,
+			 cxl_pmem_region_release_driver);
 	bus_for_each_dev(&cxl_bus_type, NULL, cxl_nvb,
 			 cxl_nvdimm_release_driver);
 	nvdimm_bus_unregister(nvdimm_bus);
@@ -328,6 +359,200 @@ static struct cxl_driver cxl_nvdimm_bridge_driver = {
 	.id = CXL_DEVICE_NVDIMM_BRIDGE,
 };
 
+static int match_cxl_nvdimm(struct device *dev, void *data)
+{
+	return is_cxl_nvdimm(dev);
+}
+
+static void unregister_region(void *nd_region)
+{
+	struct cxl_nvdimm_bridge *cxl_nvb;
+	struct cxl_pmem_region *cxlr_pmem;
+	int i;
+
+	cxlr_pmem = nd_region_provider_data(nd_region);
+	cxl_nvb = cxlr_pmem->bridge;
+	device_lock(&cxl_nvb->dev);
+	for (i = 0; i < cxlr_pmem->nr_mappings; i++) {
+		struct cxl_pmem_region_mapping *m = &cxlr_pmem->mapping[i];
+		struct cxl_nvdimm *cxl_nvd = m->cxl_nvd;
+
+		if (cxl_nvd->region) {
+			put_device(&cxlr_pmem->dev);
+			cxl_nvd->region = NULL;
+		}
+	}
+	device_unlock(&cxl_nvb->dev);
+
+	nvdimm_region_delete(nd_region);
+}
+
+static void cxlr_pmem_remove_resource(void *res)
+{
+	remove_resource(res);
+}
+
+struct cxl_pmem_region_info {
+	u64 offset;
+	u64 serial;
+};
+
+static int cxl_pmem_region_probe(struct device *dev)
+{
+	struct nd_mapping_desc mappings[CXL_DECODER_MAX_INTERLEAVE];
+	struct cxl_pmem_region *cxlr_pmem = to_cxl_pmem_region(dev);
+	struct cxl_region *cxlr = cxlr_pmem->cxlr;
+	struct cxl_pmem_region_info *info = NULL;
+	struct cxl_nvdimm_bridge *cxl_nvb;
+	struct nd_interleave_set *nd_set;
+	struct nd_region_desc ndr_desc;
+	struct cxl_nvdimm *cxl_nvd;
+	struct nvdimm *nvdimm;
+	struct resource *res;
+	int rc = 0, i;
+
+	cxl_nvb = cxl_find_nvdimm_bridge(&cxlr_pmem->mapping[0].cxlmd->dev);
+	if (!cxl_nvb) {
+		dev_dbg(dev, "bridge not found\n");
+		return -ENXIO;
+	}
+	cxlr_pmem->bridge = cxl_nvb;
+
+	device_lock(&cxl_nvb->dev);
+	if (!cxl_nvb->nvdimm_bus) {
+		dev_dbg(dev, "nvdimm bus not found\n");
+		rc = -ENXIO;
+		goto out;
+	}
+
+	memset(&mappings, 0, sizeof(mappings));
+	memset(&ndr_desc, 0, sizeof(ndr_desc));
+
+	res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
+	if (!res) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	res->name = "Persistent Memory";
+	res->start = cxlr_pmem->hpa_range.start;
+	res->end = cxlr_pmem->hpa_range.end;
+	res->flags = IORESOURCE_MEM;
+	res->desc = IORES_DESC_PERSISTENT_MEMORY;
+
+	rc = insert_resource(&iomem_resource, res);
+	if (rc)
+		goto out;
+
+	rc = devm_add_action_or_reset(dev, cxlr_pmem_remove_resource, res);
+	if (rc)
+		goto out;
+
+	ndr_desc.res = res;
+	ndr_desc.provider_data = cxlr_pmem;
+
+	ndr_desc.numa_node = memory_add_physaddr_to_nid(res->start);
+	ndr_desc.target_node = phys_to_target_node(res->start);
+	if (ndr_desc.target_node == NUMA_NO_NODE) {
+		ndr_desc.target_node = ndr_desc.numa_node;
+		dev_dbg(&cxlr->dev, "changing target node from %d to %d",
+			NUMA_NO_NODE, ndr_desc.target_node);
+	}
+
+	nd_set = devm_kzalloc(dev, sizeof(*nd_set), GFP_KERNEL);
+	if (!nd_set) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	ndr_desc.memregion = cxlr->id;
+	set_bit(ND_REGION_CXL, &ndr_desc.flags);
+	set_bit(ND_REGION_PERSIST_MEMCTRL, &ndr_desc.flags);
+
+	info = kmalloc_array(cxlr_pmem->nr_mappings, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		goto out;
+
+	rc = -ENODEV;
+	for (i = 0; i < cxlr_pmem->nr_mappings; i++) {
+		struct cxl_pmem_region_mapping *m = &cxlr_pmem->mapping[i];
+		struct cxl_memdev *cxlmd = m->cxlmd;
+		struct cxl_dev_state *cxlds = cxlmd->cxlds;
+		struct device *d;
+
+		d = device_find_child(&cxlmd->dev, NULL, match_cxl_nvdimm);
+		if (!d) {
+			dev_dbg(dev, "[%d]: %s: no cxl_nvdimm found\n", i,
+				dev_name(&cxlmd->dev));
+			goto err;
+		}
+
+		/* safe to drop ref now with bridge lock held */
+		put_device(d);
+
+		cxl_nvd = to_cxl_nvdimm(d);
+		nvdimm = dev_get_drvdata(&cxl_nvd->dev);
+		if (!nvdimm) {
+			dev_dbg(dev, "[%d]: %s: no nvdimm found\n", i,
+				dev_name(&cxlmd->dev));
+			goto err;
+		}
+		cxl_nvd->region = cxlr_pmem;
+		get_device(&cxlr_pmem->dev);
+		m->cxl_nvd = cxl_nvd;
+		mappings[i] = (struct nd_mapping_desc) {
+			.nvdimm = nvdimm,
+			.start = m->start,
+			.size = m->size,
+			.position = i,
+		};
+		info[i].offset = m->start;
+		info[i].serial = cxlds->serial;
+	}
+	ndr_desc.num_mappings = cxlr_pmem->nr_mappings;
+	ndr_desc.mapping = mappings;
+
+	/*
+	 * TODO enable CXL labels which skip the need for 'interleave-set cookie'
+	 */
+	nd_set->cookie1 =
+		nd_fletcher64(info, sizeof(*info) * cxlr_pmem->nr_mappings, 0);
+	nd_set->cookie2 = nd_set->cookie1;
+	ndr_desc.nd_set = nd_set;
+
+	cxlr_pmem->nd_region =
+		nvdimm_pmem_region_create(cxl_nvb->nvdimm_bus, &ndr_desc);
+	if (IS_ERR(cxlr_pmem->nd_region)) {
+		rc = PTR_ERR(cxlr_pmem->nd_region);
+		goto err;
+	} else
+		rc = devm_add_action_or_reset(dev, unregister_region,
+					      cxlr_pmem->nd_region);
+out:
+	device_unlock(&cxl_nvb->dev);
+	put_device(&cxl_nvb->dev);
+	kfree(info);
+
+	if (rc)
+		dev_dbg(dev, "failed to create nvdimm region\n");
+	return rc;
+
+err:
+	for (i--; i >= 0; i--) {
+		nvdimm = mappings[i].nvdimm;
+		cxl_nvd = nvdimm_provider_data(nvdimm);
+		put_device(&cxl_nvd->region->dev);
+		cxl_nvd->region = NULL;
+	}
+	goto out;
+}
+
+static struct cxl_driver cxl_pmem_region_driver = {
+	.name = "cxl_pmem_region",
+	.probe = cxl_pmem_region_probe,
+	.id = CXL_DEVICE_PMEM_REGION,
+};
+
 /*
  * Return all bridges to the CXL_NVB_NEW state to invalidate any
  * ->state_work referring to the now destroyed cxl_pmem_wq.
@@ -372,8 +597,14 @@ static __init int cxl_pmem_init(void)
 	if (rc)
 		goto err_nvdimm;
 
+	rc = cxl_driver_register(&cxl_pmem_region_driver);
+	if (rc)
+		goto err_region;
+
 	return 0;
 
+err_region:
+	cxl_driver_unregister(&cxl_nvdimm_driver);
 err_nvdimm:
 	cxl_driver_unregister(&cxl_nvdimm_bridge_driver);
 err_bridge:
@@ -383,6 +614,7 @@ static __init int cxl_pmem_init(void)
 
 static __exit void cxl_pmem_exit(void)
 {
+	cxl_driver_unregister(&cxl_pmem_region_driver);
 	cxl_driver_unregister(&cxl_nvdimm_driver);
 	cxl_driver_unregister(&cxl_nvdimm_bridge_driver);
 	destroy_cxl_pmem_wq();
@@ -394,3 +626,4 @@ module_exit(cxl_pmem_exit);
 MODULE_IMPORT_NS(CXL);
 MODULE_ALIAS_CXL(CXL_DEVICE_NVDIMM_BRIDGE);
 MODULE_ALIAS_CXL(CXL_DEVICE_NVDIMM);
+MODULE_ALIAS_CXL(CXL_DEVICE_PMEM_REGION);
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index d976260eca7a..473a71bbd9c9 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -133,7 +133,8 @@ static void nd_region_release(struct device *dev)
 		put_device(&nvdimm->dev);
 	}
 	free_percpu(nd_region->lane);
-	memregion_free(nd_region->id);
+	if (!test_bit(ND_REGION_CXL, &nd_region->flags))
+		memregion_free(nd_region->id);
 	kfree(nd_region);
 }
 
@@ -982,9 +983,14 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
 
 	if (!nd_region)
 		return NULL;
-	nd_region->id = memregion_alloc(GFP_KERNEL);
-	if (nd_region->id < 0)
-		goto err_id;
+	/* CXL pre-assigns memregion ids before creating nvdimm regions */
+	if (test_bit(ND_REGION_CXL, &ndr_desc->flags)) {
+		nd_region->id = ndr_desc->memregion;
+	} else {
+		nd_region->id = memregion_alloc(GFP_KERNEL);
+		if (nd_region->id < 0)
+			goto err_id;
+	}
 
 	nd_region->lane = alloc_percpu(struct nd_percpu_lane);
 	if (!nd_region->lane)
@@ -1043,9 +1049,10 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
 
 	return nd_region;
 
- err_percpu:
-	memregion_free(nd_region->id);
- err_id:
+err_percpu:
+	if (!test_bit(ND_REGION_CXL, &ndr_desc->flags))
+		memregion_free(nd_region->id);
+err_id:
 	kfree(nd_region);
 	return NULL;
 }
@@ -1068,6 +1075,13 @@ struct nd_region *nvdimm_volatile_region_create(struct nvdimm_bus *nvdimm_bus,
 }
 EXPORT_SYMBOL_GPL(nvdimm_volatile_region_create);
 
+void nvdimm_region_delete(struct nd_region *nd_region)
+{
+	if (nd_region)
+		nd_device_unregister(&nd_region->dev, ND_SYNC);
+}
+EXPORT_SYMBOL_GPL(nvdimm_region_delete);
+
 int nvdimm_flush(struct nd_region *nd_region, struct bio *bio)
 {
 	int rc = 0;
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index 0d61e07b6827..c74acfa1a3fe 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -59,6 +59,9 @@ enum {
 	/* Platform provides asynchronous flush mechanism */
 	ND_REGION_ASYNC = 3,
 
+	/* Region was created by CXL subsystem */
+	ND_REGION_CXL = 4,
+
 	/* mark newly adjusted resources as requiring a label update */
 	DPA_RESOURCE_ADJUSTED = 1 << 0,
 };
@@ -122,6 +125,7 @@ struct nd_region_desc {
 	int numa_node;
 	int target_node;
 	unsigned long flags;
+	int memregion;
 	struct device_node *of_node;
 	int (*flush)(struct nd_region *nd_region, struct bio *bio);
 };
@@ -259,6 +263,7 @@ static inline struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus,
 			cmd_mask, num_flush, flush_wpq, NULL, NULL, NULL);
 }
 void nvdimm_delete(struct nvdimm *nvdimm);
+void nvdimm_region_delete(struct nd_region *nd_region);
 
 const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd);
 const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd);
-- 
2.36.1


  parent reply	other threads:[~2022-06-24  4:20 UTC|newest]

Thread overview: 157+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-24  2:45 [PATCH 00/46] CXL PMEM Region Provisioning Dan Williams
2022-06-24  2:45 ` [PATCH 01/46] tools/testing/cxl: Fix cxl_hdm_decode_init() calling convention Dan Williams
2022-06-28 10:37   ` Jonathan Cameron
     [not found]   ` <CGME20220629174147uscas1p211384ae262e099484440ef285be26c75@uscas1p2.samsung.com>
2022-06-29 17:41     ` Adam Manzanares
2022-07-09 20:06       ` Dan Williams
2022-07-12 22:11         ` Adam Manzanares
2022-06-24  2:45 ` [PATCH 02/46] cxl/port: Keep port->uport valid for the entire life of a port Dan Williams
2022-06-24  3:37   ` Alison Schofield
2022-06-28 11:47   ` Jonathan Cameron
2022-06-28 14:27     ` Dan Williams
     [not found]   ` <CGME20220629174622uscas1p2236a084ce25771a3ab57c6f006632f35@uscas1p2.samsung.com>
2022-06-29 17:46     ` Adam Manzanares
2022-06-24  2:45 ` [PATCH 03/46] cxl/hdm: Use local hdm variable Dan Williams
2022-06-24  3:38   ` Alison Schofield
2022-06-28 15:16   ` Jonathan Cameron
     [not found]   ` <CGME20220629200312uscas1p292303b9325dcbfe59293f002dc9e6b03@uscas1p2.samsung.com>
2022-06-29 20:03     ` Adam Manzanares
2022-06-24  2:45 ` [PATCH 04/46] cxl/core: Rename ->decoder_range ->hpa_range Dan Williams
2022-06-24  3:39   ` Alison Schofield
2022-06-28 15:17   ` Jonathan Cameron
     [not found]   ` <CGME20220629200652uscas1p2c1da644ea63a5de69e14e046379779b1@uscas1p2.samsung.com>
2022-06-29 20:06     ` Adam Manzanares
2022-06-24  2:45 ` [PATCH 05/46] cxl/core: Drop ->platform_res attribute for root decoders Dan Williams
2022-06-28 15:24   ` Jonathan Cameron
2022-07-09 23:33     ` Dan Williams
     [not found]   ` <CGME20220629202117uscas1p2892fb68ae60c4754e2f7d26882a92ae5@uscas1p2.samsung.com>
2022-06-29 20:21     ` Adam Manzanares
2022-07-09 23:38       ` Dan Williams
2022-06-24  2:45 ` [PATCH 06/46] cxl/core: Drop is_cxl_decoder() Dan Williams
2022-06-24  3:48   ` Alison Schofield
2022-06-28 15:25   ` Jonathan Cameron
     [not found]   ` <CGME20220629203448uscas1p264a7f79a1ed7f9257eefcb3064c7d943@uscas1p2.samsung.com>
2022-06-29 20:34     ` Adam Manzanares
2022-06-24  2:45 ` [PATCH 07/46] cxl: Introduce cxl_to_{ways,granularity} Dan Williams
2022-06-28 15:36   ` Jonathan Cameron
2022-07-09 23:52     ` Dan Williams
2022-06-24  2:45 ` [PATCH 08/46] cxl/core: Define a 'struct cxl_switch_decoder' Dan Williams
2022-06-28 16:12   ` Jonathan Cameron
2022-06-30 10:56     ` Jonathan Cameron
2022-07-10  0:49       ` Dan Williams
2022-07-10  0:33     ` Dan Williams
2022-06-24  2:46 ` [PATCH 09/46] cxl/acpi: Track CXL resources in iomem_resource Dan Williams
2022-06-28 16:43   ` Jonathan Cameron
2022-07-10  2:12     ` Dan Williams
2022-07-19 14:24       ` Jonathan Cameron
2022-06-24  2:46 ` [PATCH 10/46] cxl/core: Define a 'struct cxl_root_decoder' for tracking CXL window resources Dan Williams
2022-06-28 16:49   ` Jonathan Cameron
2022-07-10  2:20     ` Dan Williams
2022-06-28 16:53   ` Jonathan Cameron
2022-06-24  2:46 ` [PATCH 11/46] cxl/core: Define a 'struct cxl_endpoint_decoder' for tracking DPA resources Dan Williams
2022-06-28 16:55   ` Jonathan Cameron
2022-07-10  2:40     ` Dan Williams
2022-06-24  2:46 ` [PATCH 12/46] cxl/mem: Convert partition-info to resources Dan Williams
2022-06-28 17:02   ` Jonathan Cameron
2022-06-24  2:46 ` [PATCH 13/46] cxl/hdm: Require all decoders to be enumerated Dan Williams
2022-06-28 17:04   ` Jonathan Cameron
2022-06-24  2:46 ` [PATCH 14/46] cxl/hdm: Enumerate allocated DPA Dan Williams
2022-06-29 14:43   ` Jonathan Cameron
2022-07-10  3:03     ` Dan Williams
2022-07-19 14:25       ` Jonathan Cameron
2022-06-24  2:46 ` [PATCH 15/46] cxl/Documentation: List attribute permissions Dan Williams
2022-06-28  3:16   ` Alison Schofield
2022-06-29 14:59   ` Jonathan Cameron
2022-06-24  2:46 ` [PATCH 16/46] cxl/hdm: Add 'mode' attribute to decoder objects Dan Williams
2022-06-29 15:28   ` Jonathan Cameron
2022-07-10  3:45     ` Dan Williams
2022-06-24  2:47 ` [PATCH 17/46] cxl/hdm: Track next decoder to allocate Dan Williams
2022-06-29 15:31   ` Jonathan Cameron
2022-07-10  3:55     ` Dan Williams
2022-07-19 14:27       ` Jonathan Cameron
2022-07-10 16:34     ` Dan Williams
2022-06-24  2:47 ` [PATCH 18/46] cxl/hdm: Add support for allocating DPA to an endpoint decoder Dan Williams
2022-06-29 15:56   ` Jonathan Cameron
2022-07-10 16:53     ` Dan Williams
2022-06-24  2:47 ` [PATCH 19/46] cxl/debug: Move debugfs init to cxl_core_init() Dan Williams
2022-06-29 15:58   ` Jonathan Cameron
2022-06-24  2:47 ` [PATCH 20/46] cxl/mem: Add a debugfs version of 'iomem' for DPA, 'dpamem' Dan Williams
2022-06-29 16:08   ` Jonathan Cameron
2022-07-10 17:09     ` Dan Williams
2022-06-24  2:47 ` [PATCH 21/46] tools/testing/cxl: Move cxl_test resources to the top of memory Dan Williams
2022-06-29 16:11   ` Jonathan Cameron
2022-07-10 17:19     ` Dan Williams
2022-06-24  2:47 ` [PATCH 22/46] tools/testing/cxl: Expand CFMWS windows Dan Williams
2022-06-29 16:14   ` Jonathan Cameron
2022-06-24  2:47 ` [PATCH 23/46] tools/testing/cxl: Add partition support Dan Williams
2022-06-29 16:20   ` Jonathan Cameron
2022-06-24  2:48 ` [PATCH 24/46] tools/testing/cxl: Fix decoder default state Dan Williams
2022-06-29 16:22   ` Jonathan Cameron
2022-07-10 17:33     ` Dan Williams
2022-06-24  2:48 ` [PATCH 25/46] cxl/port: Record dport in endpoint references Dan Williams
2022-06-29 16:49   ` Jonathan Cameron
2022-07-10 18:40     ` Dan Williams
2022-06-24  4:19 ` [PATCH 26/46] cxl/port: Record parent dport when adding ports Dan Williams
2022-06-29 17:02   ` Jonathan Cameron
2022-06-24  4:19 ` [PATCH 27/46] cxl/port: Move 'cxl_ep' references to an xarray per port Dan Williams
2022-06-29 17:19   ` Jonathan Cameron
2022-06-24  4:19 ` [PATCH 28/46] cxl/port: Move dport tracking to an xarray Dan Williams
2022-06-30  9:18   ` Jonathan Cameron
2022-07-10 19:06     ` Dan Williams
2022-06-24  4:19 ` [PATCH 29/46] cxl/port: Cache CXL host bridge data Dan Williams
2022-06-30  9:21   ` Jonathan Cameron
2022-07-10 19:09     ` Dan Williams
2022-06-24  4:19 ` [PATCH 30/46] cxl/hdm: Add sysfs attributes for interleave ways + granularity Dan Williams
2022-06-30  9:26   ` Jonathan Cameron
2022-07-10 20:40     ` Dan Williams
2022-07-19 14:32       ` Jonathan Cameron
2022-06-24  4:19 ` [PATCH 31/46] cxl/hdm: Initialize decoder type for memory expander devices Dan Williams
2022-06-30  9:33   ` Jonathan Cameron
2022-06-24  4:19 ` [PATCH 32/46] cxl/mem: Enumerate port targets before adding endpoints Dan Williams
2022-06-30  9:48   ` Jonathan Cameron
2022-07-10 21:01     ` Dan Williams
2022-06-24  4:19 ` [PATCH 33/46] resource: Introduce alloc_free_mem_region() Dan Williams
2022-06-30 10:35   ` Jonathan Cameron
2022-07-10 21:58     ` Dan Williams
2022-06-24  4:19 ` [PATCH 34/46] cxl/region: Add region creation support Dan Williams
2022-06-30 13:17   ` Jonathan Cameron
2022-07-11  0:08     ` Dan Williams
2022-07-19 14:42       ` Jonathan Cameron
2022-06-24  4:19 ` [PATCH 35/46] cxl/region: Add a 'uuid' attribute Dan Williams
2022-06-28 10:29   ` Jonathan Cameron
2022-06-28 14:24     ` Dan Williams
2022-06-24  4:19 ` [PATCH 36/46] cxl/region: Add interleave ways attribute Dan Williams
2022-06-30 13:44   ` Jonathan Cameron
2022-07-11  0:32     ` Dan Williams
2022-07-19 14:47       ` Jonathan Cameron
2022-07-19 22:15         ` Dan Williams
2022-07-20  9:59           ` Jonathan Cameron
2022-06-30 13:45   ` Jonathan Cameron
2022-06-24  4:19 ` [PATCH 37/46] cxl/region: Allocate host physical address (HPA) capacity to new regions Dan Williams
2022-06-30 13:56   ` Jonathan Cameron
2022-07-11  0:47     ` Dan Williams
2022-06-24  4:19 ` [PATCH 38/46] cxl/region: Enable the assignment of endpoint decoders to regions Dan Williams
2022-06-30 14:31   ` Jonathan Cameron
2022-07-11  1:12     ` Dan Williams
2022-06-24  4:19 ` [PATCH 39/46] cxl/acpi: Add a host-bridge index lookup mechanism Dan Williams
2022-06-30 15:48   ` Jonathan Cameron
2022-06-24  4:19 ` [PATCH 40/46] cxl/region: Attach endpoint decoders Dan Williams
2022-06-24 18:25   ` Jonathan Cameron
2022-06-24 18:49     ` Dan Williams
2022-06-24 20:51     ` Dan Williams
2022-06-24 23:21       ` Dan Williams
2022-06-30 16:34   ` Jonathan Cameron
2022-07-11  2:02     ` Dan Williams
2022-06-24  4:19 ` [PATCH 41/46] cxl/region: Program target lists Dan Williams
2022-06-24  4:19 ` [PATCH 42/46] cxl/hdm: Commit decoder state to hardware Dan Williams
2022-06-30 17:05   ` Jonathan Cameron
2022-07-11  3:02     ` Dan Williams
2022-06-24  4:19 ` [PATCH 43/46] cxl/region: Add region driver boiler plate Dan Williams
2022-06-30 17:09   ` Jonathan Cameron
2022-06-24  4:19 ` [PATCH 44/46] cxl/pmem: Delete unused nvdimm attribute Dan Williams
2022-06-30 17:10   ` Jonathan Cameron
2022-06-24  4:19 ` [PATCH 45/46] cxl/pmem: Fix offline_nvdimm_bus() to offline by bridge Dan Williams
2022-06-30 17:14   ` Jonathan Cameron
2022-07-11 19:49     ` Dan Williams
2022-06-24  4:19 ` Dan Williams [this message]
2022-06-30 17:34   ` [PATCH 46/46] cxl/region: Introduce cxl_pmem_region objects Jonathan Cameron
2022-07-11 20:05     ` Dan Williams
2022-06-24 15:13 ` [PATCH 00/46] CXL PMEM Region Provisioning Jonathan Cameron
2022-06-24 15:32   ` Dan Williams
2022-06-28  3:12 ` Alison Schofield
2022-06-28  3:34   ` Dan Williams
2022-07-02  2:26 ` Alison Schofield

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220624041950.559155-21-dan.j.williams@intel.com \
    --to=dan.j.williams@intel.com \
    --cc=bwidawsk@kernel.org \
    --cc=hch@lst.de \
    --cc=linux-cxl@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=nvdimm@lists.linux.dev \
    --cc=patches@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).