Commit 6e099264 authored by Dan Williams's avatar Dan Williams

cxl/region: Add volatile region creation support

Expand the region creation infrastructure to enable 'ram'
(volatile-memory) regions. The internals of create_pmem_region_store()
and create_pmem_region_show() are factored out into helpers
__create_region() and __create_region_show() for the 'ram' case to
reuse.
Reviewed-by: default avatarVishal Verma <vishal.l.verma@intel.com>
Reviewed-by: default avatarGregory Price <gregory.price@memverge.com>
Reviewed-by: default avatarDave Jiang <dave.jiang@intel.com>
Reviewed-by: default avatarIra Weiny <ira.weiny@intel.com>
Reviewed-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
Tested-by: default avatarFan Ni <fan.ni@samsung.com>
Link: https://lore.kernel.org/r/167601995775.1924368.352616146815830591.stgit@dwillia2-xfh.jf.intel.comSigned-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 1b9b7a6f
...@@ -285,20 +285,20 @@ Description: ...@@ -285,20 +285,20 @@ Description:
interleave_granularity). interleave_granularity).
What: /sys/bus/cxl/devices/decoderX.Y/create_pmem_region What: /sys/bus/cxl/devices/decoderX.Y/create_{pmem,ram}_region
Date: May, 2022 Date: May, 2022, January, 2023
KernelVersion: v6.0 KernelVersion: v6.0 (pmem), v6.3 (ram)
Contact: linux-cxl@vger.kernel.org Contact: linux-cxl@vger.kernel.org
Description: Description:
(RW) Write a string in the form 'regionZ' to start the process (RW) Write a string in the form 'regionZ' to start the process
of defining a new persistent memory region (interleave-set) of defining a new persistent, or volatile memory region
within the decode range bounded by root decoder 'decoderX.Y'. (interleave-set) within the decode range bounded by root decoder
The value written must match the current value returned from 'decoderX.Y'. The value written must match the current value
reading this attribute. An atomic compare exchange operation is returned from reading this attribute. An atomic compare exchange
done on write to assign the requested id to a region and operation is done on write to assign the requested id to a
allocate the region-id for the next creation attempt. EBUSY is region and allocate the region-id for the next creation attempt.
returned if the region name written does not match the current EBUSY is returned if the region name written does not match the
cached value. current cached value.
What: /sys/bus/cxl/devices/decoderX.Y/delete_region What: /sys/bus/cxl/devices/decoderX.Y/delete_region
......
...@@ -11,6 +11,7 @@ extern struct attribute_group cxl_base_attribute_group; ...@@ -11,6 +11,7 @@ extern struct attribute_group cxl_base_attribute_group;
#ifdef CONFIG_CXL_REGION #ifdef CONFIG_CXL_REGION
extern struct device_attribute dev_attr_create_pmem_region; extern struct device_attribute dev_attr_create_pmem_region;
extern struct device_attribute dev_attr_create_ram_region;
extern struct device_attribute dev_attr_delete_region; extern struct device_attribute dev_attr_delete_region;
extern struct device_attribute dev_attr_region; extern struct device_attribute dev_attr_region;
extern const struct device_type cxl_pmem_region_type; extern const struct device_type cxl_pmem_region_type;
......
...@@ -294,6 +294,7 @@ static struct attribute *cxl_decoder_root_attrs[] = { ...@@ -294,6 +294,7 @@ static struct attribute *cxl_decoder_root_attrs[] = {
&dev_attr_cap_type3.attr, &dev_attr_cap_type3.attr,
&dev_attr_target_list.attr, &dev_attr_target_list.attr,
SET_CXL_REGION_ATTR(create_pmem_region) SET_CXL_REGION_ATTR(create_pmem_region)
SET_CXL_REGION_ATTR(create_ram_region)
SET_CXL_REGION_ATTR(delete_region) SET_CXL_REGION_ATTR(delete_region)
NULL, NULL,
}; };
...@@ -305,6 +306,13 @@ static bool can_create_pmem(struct cxl_root_decoder *cxlrd) ...@@ -305,6 +306,13 @@ static bool can_create_pmem(struct cxl_root_decoder *cxlrd)
return (cxlrd->cxlsd.cxld.flags & flags) == flags; return (cxlrd->cxlsd.cxld.flags & flags) == flags;
} }
static bool can_create_ram(struct cxl_root_decoder *cxlrd)
{
unsigned long flags = CXL_DECODER_F_TYPE3 | CXL_DECODER_F_RAM;
return (cxlrd->cxlsd.cxld.flags & flags) == flags;
}
static umode_t cxl_root_decoder_visible(struct kobject *kobj, struct attribute *a, int n) static umode_t cxl_root_decoder_visible(struct kobject *kobj, struct attribute *a, int n)
{ {
struct device *dev = kobj_to_dev(kobj); struct device *dev = kobj_to_dev(kobj);
...@@ -313,7 +321,11 @@ static umode_t cxl_root_decoder_visible(struct kobject *kobj, struct attribute * ...@@ -313,7 +321,11 @@ static umode_t cxl_root_decoder_visible(struct kobject *kobj, struct attribute *
if (a == CXL_REGION_ATTR(create_pmem_region) && !can_create_pmem(cxlrd)) if (a == CXL_REGION_ATTR(create_pmem_region) && !can_create_pmem(cxlrd))
return 0; return 0;
if (a == CXL_REGION_ATTR(delete_region) && !can_create_pmem(cxlrd)) if (a == CXL_REGION_ATTR(create_ram_region) && !can_create_ram(cxlrd))
return 0;
if (a == CXL_REGION_ATTR(delete_region) &&
!(can_create_pmem(cxlrd) || can_create_ram(cxlrd)))
return 0; return 0;
return a->mode; return a->mode;
......
...@@ -1689,6 +1689,15 @@ static struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd, ...@@ -1689,6 +1689,15 @@ static struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd,
struct device *dev; struct device *dev;
int rc; int rc;
switch (mode) {
case CXL_DECODER_RAM:
case CXL_DECODER_PMEM:
break;
default:
dev_err(&cxlrd->cxlsd.cxld.dev, "unsupported mode %d\n", mode);
return ERR_PTR(-EINVAL);
}
cxlr = cxl_region_alloc(cxlrd, id); cxlr = cxl_region_alloc(cxlrd, id);
if (IS_ERR(cxlr)) if (IS_ERR(cxlr))
return cxlr; return cxlr;
...@@ -1717,12 +1726,38 @@ static struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd, ...@@ -1717,12 +1726,38 @@ static struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd,
return ERR_PTR(rc); return ERR_PTR(rc);
} }
static ssize_t __create_region_show(struct cxl_root_decoder *cxlrd, char *buf)
{
return sysfs_emit(buf, "region%u\n", atomic_read(&cxlrd->region_id));
}
static ssize_t create_pmem_region_show(struct device *dev, static ssize_t create_pmem_region_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev); return __create_region_show(to_cxl_root_decoder(dev), buf);
}
return sysfs_emit(buf, "region%u\n", atomic_read(&cxlrd->region_id)); static ssize_t create_ram_region_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return __create_region_show(to_cxl_root_decoder(dev), buf);
}
static struct cxl_region *__create_region(struct cxl_root_decoder *cxlrd,
enum cxl_decoder_mode mode, int id)
{
int rc;
rc = memregion_alloc(GFP_KERNEL);
if (rc < 0)
return ERR_PTR(rc);
if (atomic_cmpxchg(&cxlrd->region_id, id, rc) != id) {
memregion_free(rc);
return ERR_PTR(-EBUSY);
}
return devm_cxl_add_region(cxlrd, id, mode, CXL_DECODER_EXPANDER);
} }
static ssize_t create_pmem_region_store(struct device *dev, static ssize_t create_pmem_region_store(struct device *dev,
...@@ -1731,29 +1766,39 @@ static ssize_t create_pmem_region_store(struct device *dev, ...@@ -1731,29 +1766,39 @@ static ssize_t create_pmem_region_store(struct device *dev,
{ {
struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev); struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
struct cxl_region *cxlr; struct cxl_region *cxlr;
int id, rc; int rc, id;
rc = sscanf(buf, "region%d\n", &id); rc = sscanf(buf, "region%d\n", &id);
if (rc != 1) if (rc != 1)
return -EINVAL; return -EINVAL;
rc = memregion_alloc(GFP_KERNEL); cxlr = __create_region(cxlrd, CXL_DECODER_PMEM, id);
if (rc < 0) if (IS_ERR(cxlr))
return rc; return PTR_ERR(cxlr);
if (atomic_cmpxchg(&cxlrd->region_id, id, rc) != id) { return len;
memregion_free(rc); }
return -EBUSY; DEVICE_ATTR_RW(create_pmem_region);
}
static ssize_t create_ram_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_region *cxlr;
int rc, id;
cxlr = devm_cxl_add_region(cxlrd, id, CXL_DECODER_PMEM, rc = sscanf(buf, "region%d\n", &id);
CXL_DECODER_EXPANDER); if (rc != 1)
return -EINVAL;
cxlr = __create_region(cxlrd, CXL_DECODER_RAM, id);
if (IS_ERR(cxlr)) if (IS_ERR(cxlr))
return PTR_ERR(cxlr); return PTR_ERR(cxlr);
return len; return len;
} }
DEVICE_ATTR_RW(create_pmem_region); DEVICE_ATTR_RW(create_ram_region);
static ssize_t region_show(struct device *dev, struct device_attribute *attr, static ssize_t region_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment