--- v14
+++ v23
@@ -1,90 +1,204 @@
From: Alejandro Lucero <alucerop@amd.com>
-By definition a type2 cxl device will use the host managed memory for
-specific functionality, therefore it should not be available to other
-uses. However, a dax interface could be just good enough in some cases.
-
-Add a flag to a cxl region for specifically state to not create a dax
-device. Allow a Type2 driver to set that flag at region creation time.
+Creating a CXL region requires userspace intervention through the cxl
+sysfs files. Type2 support should allow accelerator drivers to create
+such cxl region from kernel code.
+
+Adding that functionality and integrating it with current support for
+memory expanders.
+
+Based on https://lore.kernel.org/linux-cxl/168592159835.1948938.1647215579839222774.stgit@dwillia2-xfh.jf.intel.com/
Signed-off-by: Alejandro Lucero <alucerop@amd.com>
-Reviewed-by: Zhi Wang <zhiw@nvidia.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
-Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
---
- drivers/cxl/core/region.c | 10 +++++++++-
- drivers/cxl/cxl.h | 3 +++
- include/cxl/cxl.h | 3 ++-
- 3 files changed, 14 insertions(+), 2 deletions(-)
+ drivers/cxl/core/region.c | 131 ++++++++++++++++++++++++++++++++++++--
+ include/cxl/cxl.h | 3 +
+ 2 files changed, 127 insertions(+), 7 deletions(-)
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
-index f55fb253ecde..cec168a26efb 100644
+index 63c2aeb2ee1f..293e63dfef22 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
-@@ -3649,12 +3649,14 @@ __construct_new_region(struct cxl_root_decoder *cxlrd,
- * @cxlrd: root decoder to allocate HPA
- * @cxled: endpoint decoder with reserved DPA capacity
- * @ways: interleave ways required
-+ * @no_dax: if true no DAX device should be created
- *
- * Returns a fully formed region in the commit state and attached to the
- * cxl_region driver.
- */
- struct cxl_region *cxl_create_region(struct cxl_root_decoder *cxlrd,
-- struct cxl_endpoint_decoder *cxled, int ways)
-+ struct cxl_endpoint_decoder *cxled, int ways,
-+ bool no_dax)
+@@ -2944,6 +2944,14 @@ cxl_find_region_by_name(struct cxl_root_decoder *cxlrd, const char *name)
+ return to_cxl_region(region_dev);
+ }
+
++static void drop_region(struct cxl_region *cxlr)
++{
++ struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent);
++ struct cxl_port *port = cxlrd_to_port(cxlrd);
++
++ devm_release_action(port->uport_dev, __unregister_region, cxlr);
++}
++
+ static ssize_t delete_region_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+@@ -4047,14 +4055,12 @@ static int __construct_region(struct cxl_region *cxlr,
+ return 0;
+ }
+
+-/* Establish an empty region covering the given HPA range */
+-static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd,
+- struct cxl_endpoint_decoder *cxled)
++static struct cxl_region *construct_region_begin(struct cxl_root_decoder *cxlrd,
++ struct cxl_endpoint_decoder *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);
++ int part = READ_ONCE(cxled->part);
struct cxl_region *cxlr;
-@@ -3670,6 +3672,9 @@ struct cxl_region *cxl_create_region(struct cxl_root_decoder *cxlrd,
- return ERR_PTR(-ENODEV);
- }
-
-+ if (no_dax)
-+ set_bit(CXL_REGION_F_NO_DAX, &cxlr->flags);
-+
+ do {
+@@ -4063,13 +4069,26 @@ static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd,
+ cxled->cxld.target_type);
+ } while (IS_ERR(cxlr) && PTR_ERR(cxlr) == -EBUSY);
+
+- if (IS_ERR(cxlr)) {
++ if (IS_ERR(cxlr))
+ dev_err(cxlmd->dev.parent,
+ "%s:%s: %s failed assign region: %ld\n",
+ dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
+ __func__, PTR_ERR(cxlr));
++
++ return cxlr;
++}
++
++/* Establish an empty region covering the given HPA range */
++static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd,
++ struct cxl_endpoint_decoder *cxled)
++{
++ struct cxl_port *port = cxlrd_to_port(cxlrd);
++ struct cxl_region *cxlr;
++ int rc;
++
++ cxlr = construct_region_begin(cxlrd, cxled);
++ if (IS_ERR(cxlr))
+ return cxlr;
+- }
+
+ rc = __construct_region(cxlr, cxlrd, cxled);
+ if (rc) {
+@@ -4080,6 +4099,104 @@ static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd,
return cxlr;
}
- EXPORT_SYMBOL_NS_GPL(cxl_create_region, "CXL");
-@@ -3833,6 +3838,9 @@ static int cxl_region_probe(struct device *dev)
- if (rc)
- return rc;
-
-+ if (test_bit(CXL_REGION_F_NO_DAX, &cxlr->flags))
-+ return 0;
-+
- switch (cxlr->mode) {
- case CXL_PARTMODE_PMEM:
- return devm_cxl_add_pmem_region(cxlr);
-diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
-index c35620c24c8f..2eb927c9229c 100644
---- a/drivers/cxl/cxl.h
-+++ b/drivers/cxl/cxl.h
-@@ -405,6 +405,9 @@ struct cxl_region_params {
- */
- #define CXL_REGION_F_NEEDS_RESET 1
-
-+/* Allow Type2 drivers to specify if a dax region should not be created. */
-+#define CXL_REGION_F_NO_DAX 2
-+
- /**
- * struct cxl_region - CXL region
- * @dev: This region's device
+
++DEFINE_FREE(cxl_region_drop, struct cxl_region *, if (_T) drop_region(_T))
++
++static struct cxl_region *
++__construct_new_region(struct cxl_root_decoder *cxlrd,
++ struct cxl_endpoint_decoder **cxled, int ways)
++{
++ struct cxl_memdev *cxlmd = cxled_to_memdev(cxled[0]);
++ struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
++ struct cxl_region_params *p;
++ resource_size_t size = 0;
++ int rc, i;
++
++ struct cxl_region *cxlr __free(cxl_region_drop) =
++ construct_region_begin(cxlrd, cxled[0]);
++ if (IS_ERR(cxlr))
++ return cxlr;
++
++ guard(rwsem_write)(&cxl_rwsem.region);
++
++ /*
++ * Sanity check. This should not happen with an accel driver handling
++ * the region creation.
++ */
++ p = &cxlr->params;
++ if (p->state >= CXL_CONFIG_INTERLEAVE_ACTIVE) {
++ dev_err(cxlmd->dev.parent,
++ "%s:%s: %s unexpected region state\n",
++ dev_name(&cxlmd->dev), dev_name(&cxled[0]->cxld.dev),
++ __func__);
++ return ERR_PTR(-EBUSY);
++ }
++
++ rc = set_interleave_ways(cxlr, ways);
++ if (rc)
++ return ERR_PTR(rc);
++
++ rc = set_interleave_granularity(cxlr, cxld->interleave_granularity);
++ if (rc)
++ return ERR_PTR(rc);
++
++ scoped_guard(rwsem_read, &cxl_rwsem.dpa) {
++ for (i = 0; i < ways; i++) {
++ if (!cxled[i]->dpa_res)
++ return ERR_PTR(-EINVAL);
++ size += resource_size(cxled[i]->dpa_res);
++ }
++
++ rc = alloc_hpa(cxlr, size);
++ if (rc)
++ return ERR_PTR(rc);
++
++ for (i = 0; i < ways; i++) {
++ rc = cxl_region_attach(cxlr, cxled[i], 0);
++ if (rc)
++ return ERR_PTR(rc);
++ }
++ }
++
++ rc = cxl_region_decode_commit(cxlr);
++ if (rc)
++ return ERR_PTR(rc);
++
++ p->state = CXL_CONFIG_COMMIT;
++
++ return no_free_ptr(cxlr);
++}
++
++/**
++ * cxl_create_region - Establish a region given an endpoint decoder
++ * @cxlrd: root decoder to allocate HPA
++ * @cxled: endpoint decoders with reserved DPA capacity
++ * @ways: interleave ways required
++ *
++ * Returns a fully formed region in the commit state and attached to the
++ * cxl_region driver.
++ */
++struct cxl_region *cxl_create_region(struct cxl_root_decoder *cxlrd,
++ struct cxl_endpoint_decoder **cxled,
++ int ways)
++{
++ struct cxl_region *cxlr;
++
++ mutex_lock(&cxlrd->range_lock);
++ cxlr = __construct_new_region(cxlrd, cxled, ways);
++ mutex_unlock(&cxlrd->range_lock);
++ if (IS_ERR(cxlr))
++ return cxlr;
++
++ if (device_attach(&cxlr->dev) <= 0) {
++ dev_err(&cxlr->dev, "failed to create region\n");
++ drop_region(cxlr);
++ return ERR_PTR(-ENODEV);
++ }
++
++ return cxlr;
++}
++EXPORT_SYMBOL_NS_GPL(cxl_create_region, "CXL");
++
+ static struct cxl_region *
+ cxl_find_region_by_range(struct cxl_root_decoder *cxlrd, struct range *hpa)
+ {
diff --git a/include/cxl/cxl.h b/include/cxl/cxl.h
-index ca8dd6aed455..5d30d775966b 100644
+index 4802371db00e..50acbd13bcf8 100644
--- a/include/cxl/cxl.h
+++ b/include/cxl/cxl.h
-@@ -267,7 +267,8 @@ struct cxl_endpoint_decoder *cxl_request_dpa(struct cxl_memdev *cxlmd,
+@@ -281,4 +281,7 @@ struct cxl_endpoint_decoder *cxl_request_dpa(struct cxl_memdev *cxlmd,
+ enum cxl_partition_mode mode,
resource_size_t alloc);
int cxl_dpa_free(struct cxl_endpoint_decoder *cxled);
- struct cxl_region *cxl_create_region(struct cxl_root_decoder *cxlrd,
-- struct cxl_endpoint_decoder *cxled, int ways);
-+ struct cxl_endpoint_decoder *cxled, int ways,
-+ bool no_dax);
-
- int cxl_accel_region_detach(struct cxl_endpoint_decoder *cxled);
++struct cxl_region *cxl_create_region(struct cxl_root_decoder *cxlrd,
++ struct cxl_endpoint_decoder **cxled,
++ int ways);
#endif /* __CXL_CXL_H__ */
--
2.34.1