* [RFC PATCH 01/20] nvdimm/label: Introduce NDD_CXL_LABEL flag to set cxl label format
[not found] ` <CGME20250617124008epcas5p2e702f786645d44ceb1cdd980a914ce8e@epcas5p2.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
2025-06-20 16:40 ` Jonathan Cameron
` (2 more replies)
0 siblings, 3 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
NDD_CXL_LABEL is introduced to set cxl LSA 2.1 label format
Accordingly updated label index version
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/nvdimm/dimm.c | 1 +
drivers/nvdimm/dimm_devs.c | 10 ++++++++++
drivers/nvdimm/label.c | 16 ++++++++++++----
drivers/nvdimm/nd.h | 1 +
include/linux/libnvdimm.h | 3 +++
5 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c
index 91d9163ee303..8753b5cd91cc 100644
--- a/drivers/nvdimm/dimm.c
+++ b/drivers/nvdimm/dimm.c
@@ -62,6 +62,7 @@ static int nvdimm_probe(struct device *dev)
if (rc < 0)
dev_dbg(dev, "failed to unlock dimm: %d\n", rc);
+ ndd->cxl = nvdimm_check_cxl_label_format(ndd->dev);
/*
* EACCES failures reading the namespace label-area-properties
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
index 21498d461fde..e8f545f889fd 100644
--- a/drivers/nvdimm/dimm_devs.c
+++ b/drivers/nvdimm/dimm_devs.c
@@ -18,6 +18,16 @@
static DEFINE_IDA(dimm_ida);
+bool nvdimm_check_cxl_label_format(struct device *dev)
+{
+ struct nvdimm *nvdimm = to_nvdimm(dev);
+
+ if (test_bit(NDD_CXL_LABEL, &nvdimm->flags))
+ return true;
+
+ return false;
+}
+
/*
* Retrieve bus and dimm handle and return if this bus supports
* get_config_data commands
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
index 082253a3a956..48b5ba90216d 100644
--- a/drivers/nvdimm/label.c
+++ b/drivers/nvdimm/label.c
@@ -687,11 +687,19 @@ static int nd_label_write_index(struct nvdimm_drvdata *ndd, int index, u32 seq,
- (unsigned long) to_namespace_index(ndd, 0);
nsindex->labeloff = __cpu_to_le64(offset);
nsindex->nslot = __cpu_to_le32(nslot);
- nsindex->major = __cpu_to_le16(1);
- if (sizeof_namespace_label(ndd) < 256)
+
+ /* Support CXL LSA 2.1 label format */
+ if (ndd->cxl) {
+ nsindex->major = __cpu_to_le16(2);
nsindex->minor = __cpu_to_le16(1);
- else
- nsindex->minor = __cpu_to_le16(2);
+ } else {
+ nsindex->major = __cpu_to_le16(1);
+ if (sizeof_namespace_label(ndd) < 256)
+ nsindex->minor = __cpu_to_le16(1);
+ else
+ nsindex->minor = __cpu_to_le16(2);
+ }
+
nsindex->checksum = __cpu_to_le64(0);
if (flags & ND_NSINDEX_INIT) {
unsigned long *free = (unsigned long *) nsindex->free;
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 5ca06e9a2d29..304f0e9904f1 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -522,6 +522,7 @@ void nvdimm_set_labeling(struct device *dev);
void nvdimm_set_locked(struct device *dev);
void nvdimm_clear_locked(struct device *dev);
int nvdimm_security_setup_events(struct device *dev);
+bool nvdimm_check_cxl_label_format(struct device *dev);
#if IS_ENABLED(CONFIG_NVDIMM_KEYS)
int nvdimm_security_unlock(struct device *dev);
#else
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index e772aae71843..0a55900842c8 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -44,6 +44,9 @@ enum {
/* dimm provider wants synchronous registration by __nvdimm_create() */
NDD_REGISTER_SYNC = 8,
+ /* dimm supports region labels (LSA Format 2.1) */
+ NDD_CXL_LABEL = 9,
+
/* need to set a limit somewhere, but yes, this is likely overkill */
ND_IOCTL_MAX_BUFLEN = SZ_4M,
ND_CMD_MAX_ELEM = 5,
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH 02/20] nvdimm/label: Prep patch to accommodate cxl lsa 2.1 support
[not found] ` <CGME20250617124011epcas5p2264e30ec58977907f80d311083265641@epcas5p2.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
2025-06-23 10:53 ` Jonathan Cameron
2025-07-02 17:55 ` Ira Weiny
0 siblings, 2 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
In order to accommodate cxl lsa 2.1 format region label, renamed
nd_namespace_label to nd_lsa_label.
No functional change introduced.
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/nvdimm/label.c | 79 ++++++++++++++++++---------------
drivers/nvdimm/label.h | 12 ++++-
drivers/nvdimm/namespace_devs.c | 74 +++++++++++++++---------------
drivers/nvdimm/nd.h | 2 +-
4 files changed, 92 insertions(+), 75 deletions(-)
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
index 48b5ba90216d..30bccad98939 100644
--- a/drivers/nvdimm/label.c
+++ b/drivers/nvdimm/label.c
@@ -271,7 +271,7 @@ static void nd_label_copy(struct nvdimm_drvdata *ndd,
memcpy(dst, src, sizeof_namespace_index(ndd));
}
-static struct nd_namespace_label *nd_label_base(struct nvdimm_drvdata *ndd)
+static struct nd_lsa_label *nd_label_base(struct nvdimm_drvdata *ndd)
{
void *base = to_namespace_index(ndd, 0);
@@ -279,7 +279,7 @@ static struct nd_namespace_label *nd_label_base(struct nvdimm_drvdata *ndd)
}
static int to_slot(struct nvdimm_drvdata *ndd,
- struct nd_namespace_label *nd_label)
+ struct nd_lsa_label *nd_label)
{
unsigned long label, base;
@@ -289,14 +289,14 @@ static int to_slot(struct nvdimm_drvdata *ndd,
return (label - base) / sizeof_namespace_label(ndd);
}
-static struct nd_namespace_label *to_label(struct nvdimm_drvdata *ndd, int slot)
+static struct nd_lsa_label *to_label(struct nvdimm_drvdata *ndd, int slot)
{
unsigned long label, base;
base = (unsigned long) nd_label_base(ndd);
label = base + sizeof_namespace_label(ndd) * slot;
- return (struct nd_namespace_label *) label;
+ return (struct nd_lsa_label *) label;
}
#define for_each_clear_bit_le(bit, addr, size) \
@@ -382,14 +382,14 @@ static void nsl_calculate_checksum(struct nvdimm_drvdata *ndd,
}
static bool slot_valid(struct nvdimm_drvdata *ndd,
- struct nd_namespace_label *nd_label, u32 slot)
+ struct nd_lsa_label *nd_label, u32 slot)
{
bool valid;
/* check that we are written where we expect to be written */
- if (slot != nsl_get_slot(ndd, nd_label))
+ if (slot != nsl_get_slot(ndd, &nd_label->ns_label))
return false;
- valid = nsl_validate_checksum(ndd, nd_label);
+ valid = nsl_validate_checksum(ndd, &nd_label->ns_label);
if (!valid)
dev_dbg(ndd->dev, "fail checksum. slot: %d\n", slot);
return valid;
@@ -405,7 +405,8 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd)
return 0; /* no label, nothing to reserve */
for_each_clear_bit_le(slot, free, nslot) {
- struct nd_namespace_label *nd_label;
+ struct nd_lsa_label *nd_label;
+ struct nd_namespace_label *ns_label;
struct nd_region *nd_region = NULL;
struct nd_label_id label_id;
struct resource *res;
@@ -413,16 +414,17 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd)
u32 flags;
nd_label = to_label(ndd, slot);
+ ns_label = &nd_label->ns_label;
if (!slot_valid(ndd, nd_label, slot))
continue;
- nsl_get_uuid(ndd, nd_label, &label_uuid);
- flags = nsl_get_flags(ndd, nd_label);
+ nsl_get_uuid(ndd, ns_label, &label_uuid);
+ flags = nsl_get_flags(ndd, ns_label);
nd_label_gen_id(&label_id, &label_uuid, flags);
res = nvdimm_allocate_dpa(ndd, &label_id,
- nsl_get_dpa(ndd, nd_label),
- nsl_get_rawsize(ndd, nd_label));
+ nsl_get_dpa(ndd, ns_label),
+ nsl_get_rawsize(ndd, ns_label));
nd_dbg_dpa(nd_region, ndd, res, "reserve\n");
if (!res)
return -EBUSY;
@@ -564,14 +566,14 @@ int nd_label_active_count(struct nvdimm_drvdata *ndd)
return 0;
for_each_clear_bit_le(slot, free, nslot) {
- struct nd_namespace_label *nd_label;
+ struct nd_lsa_label *nd_label;
nd_label = to_label(ndd, slot);
if (!slot_valid(ndd, nd_label, slot)) {
- u32 label_slot = nsl_get_slot(ndd, nd_label);
- u64 size = nsl_get_rawsize(ndd, nd_label);
- u64 dpa = nsl_get_dpa(ndd, nd_label);
+ u32 label_slot = nsl_get_slot(ndd, &nd_label->ns_label);
+ u64 size = nsl_get_rawsize(ndd, &nd_label->ns_label);
+ u64 dpa = nsl_get_dpa(ndd, &nd_label->ns_label);
dev_dbg(ndd->dev,
"slot%d invalid slot: %d dpa: %llx size: %llx\n",
@@ -583,7 +585,7 @@ int nd_label_active_count(struct nvdimm_drvdata *ndd)
return count;
}
-struct nd_namespace_label *nd_label_active(struct nvdimm_drvdata *ndd, int n)
+struct nd_lsa_label *nd_label_active(struct nvdimm_drvdata *ndd, int n)
{
struct nd_namespace_index *nsindex;
unsigned long *free;
@@ -593,7 +595,7 @@ struct nd_namespace_label *nd_label_active(struct nvdimm_drvdata *ndd, int n)
return NULL;
for_each_clear_bit_le(slot, free, nslot) {
- struct nd_namespace_label *nd_label;
+ struct nd_lsa_label *nd_label;
nd_label = to_label(ndd, slot);
if (!slot_valid(ndd, nd_label, slot))
@@ -731,7 +733,7 @@ static int nd_label_write_index(struct nvdimm_drvdata *ndd, int index, u32 seq,
}
static unsigned long nd_label_offset(struct nvdimm_drvdata *ndd,
- struct nd_namespace_label *nd_label)
+ struct nd_lsa_label *nd_label)
{
return (unsigned long) nd_label
- (unsigned long) to_namespace_index(ndd, 0);
@@ -885,7 +887,8 @@ static int __pmem_label_update(struct nd_region *nd_region,
struct nd_namespace_common *ndns = &nspm->nsio.common;
struct nd_interleave_set *nd_set = nd_region->nd_set;
struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
- struct nd_namespace_label *nd_label;
+ struct nd_lsa_label *nd_label;
+ struct nd_namespace_label *ns_label;
struct nd_namespace_index *nsindex;
struct nd_label_ent *label_ent;
struct nd_label_id label_id;
@@ -918,20 +921,22 @@ static int __pmem_label_update(struct nd_region *nd_region,
nd_label = to_label(ndd, slot);
memset(nd_label, 0, sizeof_namespace_label(ndd));
- nsl_set_uuid(ndd, nd_label, nspm->uuid);
- nsl_set_name(ndd, nd_label, nspm->alt_name);
- nsl_set_flags(ndd, nd_label, flags);
- nsl_set_nlabel(ndd, nd_label, nd_region->ndr_mappings);
- nsl_set_nrange(ndd, nd_label, 1);
- nsl_set_position(ndd, nd_label, pos);
- nsl_set_isetcookie(ndd, nd_label, cookie);
- nsl_set_rawsize(ndd, nd_label, resource_size(res));
- nsl_set_lbasize(ndd, nd_label, nspm->lbasize);
- nsl_set_dpa(ndd, nd_label, res->start);
- nsl_set_slot(ndd, nd_label, slot);
- nsl_set_type_guid(ndd, nd_label, &nd_set->type_guid);
- nsl_set_claim_class(ndd, nd_label, ndns->claim_class);
- nsl_calculate_checksum(ndd, nd_label);
+
+ ns_label = &nd_label->ns_label;
+ nsl_set_uuid(ndd, ns_label, nspm->uuid);
+ nsl_set_name(ndd, ns_label, nspm->alt_name);
+ nsl_set_flags(ndd, ns_label, flags);
+ nsl_set_nlabel(ndd, ns_label, nd_region->ndr_mappings);
+ nsl_set_nrange(ndd, ns_label, 1);
+ nsl_set_position(ndd, ns_label, pos);
+ nsl_set_isetcookie(ndd, ns_label, cookie);
+ nsl_set_rawsize(ndd, ns_label, resource_size(res));
+ nsl_set_lbasize(ndd, ns_label, nspm->lbasize);
+ nsl_set_dpa(ndd, ns_label, res->start);
+ nsl_set_slot(ndd, ns_label, slot);
+ nsl_set_type_guid(ndd, ns_label, &nd_set->type_guid);
+ nsl_set_claim_class(ndd, ns_label, ndns->claim_class);
+ nsl_calculate_checksum(ndd, ns_label);
nd_dbg_dpa(nd_region, ndd, res, "\n");
/* update label */
@@ -947,7 +952,7 @@ static int __pmem_label_update(struct nd_region *nd_region,
if (!label_ent->label)
continue;
if (test_and_clear_bit(ND_LABEL_REAP, &label_ent->flags) ||
- nsl_uuid_equal(ndd, label_ent->label, nspm->uuid))
+ nsl_uuid_equal(ndd, &label_ent->label->ns_label, nspm->uuid))
reap_victim(nd_mapping, label_ent);
}
@@ -1035,12 +1040,12 @@ static int del_labels(struct nd_mapping *nd_mapping, uuid_t *uuid)
mutex_lock(&nd_mapping->lock);
list_for_each_entry_safe(label_ent, e, &nd_mapping->labels, list) {
- struct nd_namespace_label *nd_label = label_ent->label;
+ struct nd_lsa_label *nd_label = label_ent->label;
if (!nd_label)
continue;
active++;
- if (!nsl_uuid_equal(ndd, nd_label, uuid))
+ if (!nsl_uuid_equal(ndd, &nd_label->ns_label, uuid))
continue;
active--;
slot = to_slot(ndd, nd_label);
diff --git a/drivers/nvdimm/label.h b/drivers/nvdimm/label.h
index 0650fb4b9821..4883b3a1320f 100644
--- a/drivers/nvdimm/label.h
+++ b/drivers/nvdimm/label.h
@@ -183,6 +183,16 @@ struct nd_namespace_label {
};
};
+/*
+ * LSA 2.1 format introduces region label, which can also reside
+ * into LSA along with only namespace label as per v1.1 and v1.2
+ */
+struct nd_lsa_label {
+ union {
+ struct nd_namespace_label ns_label;
+ };
+};
+
#define NVDIMM_BTT_GUID "8aed63a2-29a2-4c66-8b12-f05d15d3922a"
#define NVDIMM_BTT2_GUID "18633bfc-1735-4217-8ac9-17239282d3f8"
#define NVDIMM_PFN_GUID "266400ba-fb9f-4677-bcb0-968f11d0d225"
@@ -215,7 +225,7 @@ struct nvdimm_drvdata;
int nd_label_data_init(struct nvdimm_drvdata *ndd);
size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd);
int nd_label_active_count(struct nvdimm_drvdata *ndd);
-struct nd_namespace_label *nd_label_active(struct nvdimm_drvdata *ndd, int n);
+struct nd_lsa_label *nd_label_active(struct nvdimm_drvdata *ndd, int n);
u32 nd_label_alloc_slot(struct nvdimm_drvdata *ndd);
bool nd_label_free_slot(struct nvdimm_drvdata *ndd, u32 slot);
u32 nd_label_nfree(struct nvdimm_drvdata *ndd);
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index 55cfbf1e0a95..f180f0068c15 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -1009,15 +1009,15 @@ static int namespace_update_uuid(struct nd_region *nd_region,
mutex_lock(&nd_mapping->lock);
list_for_each_entry(label_ent, &nd_mapping->labels, list) {
- struct nd_namespace_label *nd_label = label_ent->label;
+ struct nd_lsa_label *nd_label = label_ent->label;
struct nd_label_id label_id;
uuid_t uuid;
if (!nd_label)
continue;
- nsl_get_uuid(ndd, nd_label, &uuid);
+ nsl_get_uuid(ndd, &nd_label->ns_label, &uuid);
nd_label_gen_id(&label_id, &uuid,
- nsl_get_flags(ndd, nd_label));
+ nsl_get_flags(ndd, &nd_label->ns_label));
if (strcmp(old_label_id.id, label_id.id) == 0)
set_bit(ND_LABEL_REAP, &label_ent->flags);
}
@@ -1562,7 +1562,7 @@ static struct device **create_namespace_io(struct nd_region *nd_region)
static bool has_uuid_at_pos(struct nd_region *nd_region, const uuid_t *uuid,
u64 cookie, u16 pos)
{
- struct nd_namespace_label *found = NULL;
+ struct nd_lsa_label *found = NULL;
int i;
for (i = 0; i < nd_region->ndr_mappings; i++) {
@@ -1573,20 +1573,21 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, const uuid_t *uuid,
bool found_uuid = false;
list_for_each_entry(label_ent, &nd_mapping->labels, list) {
- struct nd_namespace_label *nd_label = label_ent->label;
+ struct nd_lsa_label *nd_label = label_ent->label;
u16 position;
if (!nd_label)
continue;
- position = nsl_get_position(ndd, nd_label);
+ position = nsl_get_position(ndd, &nd_label->ns_label);
- if (!nsl_validate_isetcookie(ndd, nd_label, cookie))
+ if (!nsl_validate_isetcookie(ndd, &nd_label->ns_label,
+ cookie))
continue;
- if (!nsl_uuid_equal(ndd, nd_label, uuid))
+ if (!nsl_uuid_equal(ndd, &nd_label->ns_label, uuid))
continue;
- if (!nsl_validate_type_guid(ndd, nd_label,
+ if (!nsl_validate_type_guid(ndd, &nd_label->ns_label,
&nd_set->type_guid))
continue;
@@ -1595,7 +1596,8 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, const uuid_t *uuid,
return false;
}
found_uuid = true;
- if (!nsl_validate_nlabel(nd_region, ndd, nd_label))
+ if (!nsl_validate_nlabel(nd_region,
+ ndd, &nd_label->ns_label))
continue;
if (position != pos)
continue;
@@ -1615,7 +1617,7 @@ static int select_pmem_id(struct nd_region *nd_region, const uuid_t *pmem_id)
for (i = 0; i < nd_region->ndr_mappings; i++) {
struct nd_mapping *nd_mapping = &nd_region->mapping[i];
struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
- struct nd_namespace_label *nd_label = NULL;
+ struct nd_lsa_label *nd_label = NULL;
u64 hw_start, hw_end, pmem_start, pmem_end;
struct nd_label_ent *label_ent;
@@ -1624,7 +1626,7 @@ static int select_pmem_id(struct nd_region *nd_region, const uuid_t *pmem_id)
nd_label = label_ent->label;
if (!nd_label)
continue;
- if (nsl_uuid_equal(ndd, nd_label, pmem_id))
+ if (nsl_uuid_equal(ndd, &nd_label->ns_label, pmem_id))
break;
nd_label = NULL;
}
@@ -1640,15 +1642,15 @@ static int select_pmem_id(struct nd_region *nd_region, const uuid_t *pmem_id)
*/
hw_start = nd_mapping->start;
hw_end = hw_start + nd_mapping->size;
- pmem_start = nsl_get_dpa(ndd, nd_label);
- pmem_end = pmem_start + nsl_get_rawsize(ndd, nd_label);
+ pmem_start = nsl_get_dpa(ndd, &nd_label->ns_label);
+ pmem_end = pmem_start + nsl_get_rawsize(ndd, &nd_label->ns_label);
if (pmem_start >= hw_start && pmem_start < hw_end
&& pmem_end <= hw_end && pmem_end > hw_start)
/* pass */;
else {
dev_dbg(&nd_region->dev, "%s invalid label for %pUb\n",
dev_name(ndd->dev),
- nsl_uuid_raw(ndd, nd_label));
+ nsl_uuid_raw(ndd, &nd_label->ns_label));
return -EINVAL;
}
@@ -1668,7 +1670,7 @@ static int select_pmem_id(struct nd_region *nd_region, const uuid_t *pmem_id)
*/
static struct device *create_namespace_pmem(struct nd_region *nd_region,
struct nd_mapping *nd_mapping,
- struct nd_namespace_label *nd_label)
+ struct nd_lsa_label *nd_label)
{
struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
struct nd_namespace_index *nsindex =
@@ -1689,14 +1691,14 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region,
return ERR_PTR(-ENXIO);
}
- if (!nsl_validate_isetcookie(ndd, nd_label, cookie)) {
+ if (!nsl_validate_isetcookie(ndd, &nd_label->ns_label, cookie)) {
dev_dbg(&nd_region->dev, "invalid cookie in label: %pUb\n",
- nsl_uuid_raw(ndd, nd_label));
- if (!nsl_validate_isetcookie(ndd, nd_label, altcookie))
+ nsl_uuid_raw(ndd, &nd_label->ns_label));
+ if (!nsl_validate_isetcookie(ndd, &nd_label->ns_label, altcookie))
return ERR_PTR(-EAGAIN);
dev_dbg(&nd_region->dev, "valid altcookie in label: %pUb\n",
- nsl_uuid_raw(ndd, nd_label));
+ nsl_uuid_raw(ndd, &nd_label->ns_label));
}
nspm = kzalloc(sizeof(*nspm), GFP_KERNEL);
@@ -1712,7 +1714,7 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region,
res->flags = IORESOURCE_MEM;
for (i = 0; i < nd_region->ndr_mappings; i++) {
- nsl_get_uuid(ndd, nd_label, &uuid);
+ nsl_get_uuid(ndd, &nd_label->ns_label, &uuid);
if (has_uuid_at_pos(nd_region, &uuid, cookie, i))
continue;
if (has_uuid_at_pos(nd_region, &uuid, altcookie, i))
@@ -1729,7 +1731,7 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region,
* find a dimm with two instances of the same uuid.
*/
dev_err(&nd_region->dev, "%s missing label for %pUb\n",
- nvdimm_name(nvdimm), nsl_uuid_raw(ndd, nd_label));
+ nvdimm_name(nvdimm), nsl_uuid_raw(ndd, &nd_label->ns_label));
rc = -EINVAL;
goto err;
}
@@ -1739,14 +1741,14 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region,
* that position at labels[0], and NULL at labels[1]. In the process,
* check that the namespace aligns with interleave-set.
*/
- nsl_get_uuid(ndd, nd_label, &uuid);
+ nsl_get_uuid(ndd, &nd_label->ns_label, &uuid);
rc = select_pmem_id(nd_region, &uuid);
if (rc)
goto err;
/* Calculate total size and populate namespace properties from label0 */
for (i = 0; i < nd_region->ndr_mappings; i++) {
- struct nd_namespace_label *label0;
+ struct nd_lsa_label *label0;
struct nvdimm_drvdata *ndd;
nd_mapping = &nd_region->mapping[i];
@@ -1760,17 +1762,17 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region,
}
ndd = to_ndd(nd_mapping);
- size += nsl_get_rawsize(ndd, label0);
- if (nsl_get_position(ndd, label0) != 0)
+ size += nsl_get_rawsize(ndd, &label0->ns_label);
+ if (nsl_get_position(ndd, &label0->ns_label) != 0)
continue;
WARN_ON(nspm->alt_name || nspm->uuid);
- nspm->alt_name = kmemdup(nsl_ref_name(ndd, label0),
+ nspm->alt_name = kmemdup(nsl_ref_name(ndd, &label0->ns_label),
NSLABEL_NAME_LEN, GFP_KERNEL);
- nsl_get_uuid(ndd, label0, &uuid);
+ nsl_get_uuid(ndd, &label0->ns_label, &uuid);
nspm->uuid = kmemdup(&uuid, sizeof(uuid_t), GFP_KERNEL);
- nspm->lbasize = nsl_get_lbasize(ndd, label0);
+ nspm->lbasize = nsl_get_lbasize(ndd, &label0->ns_label);
nspm->nsio.common.claim_class =
- nsl_get_claim_class(ndd, label0);
+ nsl_get_claim_class(ndd, &label0->ns_label);
}
if (!nspm->alt_name || !nspm->uuid) {
@@ -1887,7 +1889,7 @@ void nd_region_create_btt_seed(struct nd_region *nd_region)
}
static int add_namespace_resource(struct nd_region *nd_region,
- struct nd_namespace_label *nd_label, struct device **devs,
+ struct nd_lsa_label *nd_label, struct device **devs,
int count)
{
struct nd_mapping *nd_mapping = &nd_region->mapping[0];
@@ -1902,7 +1904,7 @@ static int add_namespace_resource(struct nd_region *nd_region,
continue;
}
- if (!nsl_uuid_equal(ndd, nd_label, uuid))
+ if (!nsl_uuid_equal(ndd, &nd_label->ns_label, uuid))
continue;
dev_err(&nd_region->dev,
"error: conflicting extents for uuid: %pUb\n", uuid);
@@ -1943,15 +1945,15 @@ static struct device **scan_labels(struct nd_region *nd_region)
/* "safe" because create_namespace_pmem() might list_move() label_ent */
list_for_each_entry_safe(label_ent, e, &nd_mapping->labels, list) {
- struct nd_namespace_label *nd_label = label_ent->label;
+ struct nd_lsa_label *nd_label = label_ent->label;
struct device **__devs;
if (!nd_label)
continue;
/* skip labels that describe extents outside of the region */
- if (nsl_get_dpa(ndd, nd_label) < nd_mapping->start ||
- nsl_get_dpa(ndd, nd_label) > map_end)
+ if (nsl_get_dpa(ndd, &nd_label->ns_label) < nd_mapping->start ||
+ nsl_get_dpa(ndd, &nd_label->ns_label) > map_end)
continue;
i = add_namespace_resource(nd_region, nd_label, devs, count);
@@ -2122,7 +2124,7 @@ static int init_active_labels(struct nd_region *nd_region)
if (!count)
continue;
for (j = 0; j < count; j++) {
- struct nd_namespace_label *label;
+ struct nd_lsa_label *label;
label_ent = kzalloc(sizeof(*label_ent), GFP_KERNEL);
if (!label_ent)
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 304f0e9904f1..2ead96ac598b 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -376,7 +376,7 @@ enum nd_label_flags {
struct nd_label_ent {
struct list_head list;
unsigned long flags;
- struct nd_namespace_label *label;
+ struct nd_lsa_label *label;
};
enum nd_mapping_lock_class {
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH 03/20] nvdimm/namespace_label: Add namespace label changes as per CXL LSA v2.1
[not found] ` <CGME20250617124013epcas5p3c241c626448fcf7851a100fdf2816160@epcas5p3.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
CXL 3.2 Spec mentions CXL LSA 2.1 Namespace Labels at section 9.13.2.5
Modified __pmem_label_update function using setter functions to update
namespace label as per CXL LSA 2.1
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/nvdimm/label.c | 3 +++
drivers/nvdimm/nd.h | 27 +++++++++++++++++++++++++++
2 files changed, 30 insertions(+)
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
index 30bccad98939..d5cfaa99f976 100644
--- a/drivers/nvdimm/label.c
+++ b/drivers/nvdimm/label.c
@@ -923,6 +923,7 @@ static int __pmem_label_update(struct nd_region *nd_region,
memset(nd_label, 0, sizeof_namespace_label(ndd));
ns_label = &nd_label->ns_label;
+ nsl_set_type(ndd, ns_label);
nsl_set_uuid(ndd, ns_label, nspm->uuid);
nsl_set_name(ndd, ns_label, nspm->alt_name);
nsl_set_flags(ndd, ns_label, flags);
@@ -934,7 +935,9 @@ static int __pmem_label_update(struct nd_region *nd_region,
nsl_set_lbasize(ndd, ns_label, nspm->lbasize);
nsl_set_dpa(ndd, ns_label, res->start);
nsl_set_slot(ndd, ns_label, slot);
+ nsl_set_alignment(ndd, ns_label, 0);
nsl_set_type_guid(ndd, ns_label, &nd_set->type_guid);
+ nsl_set_region_uuid(ndd, ns_label, NULL);
nsl_set_claim_class(ndd, ns_label, ndns->claim_class);
nsl_calculate_checksum(ndd, ns_label);
nd_dbg_dpa(nd_region, ndd, res, "\n");
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 2ead96ac598b..07d665f18bf6 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -295,6 +295,33 @@ static inline const u8 *nsl_uuid_raw(struct nvdimm_drvdata *ndd,
return nd_label->efi.uuid;
}
+static inline void nsl_set_type(struct nvdimm_drvdata *ndd,
+ struct nd_namespace_label *ns_label)
+{
+ uuid_t tmp;
+
+ if (ndd->cxl) {
+ uuid_parse(CXL_NAMESPACE_UUID, &tmp);
+ export_uuid(ns_label->cxl.type, &tmp);
+ }
+}
+
+static inline void nsl_set_alignment(struct nvdimm_drvdata *ndd,
+ struct nd_namespace_label *ns_label,
+ u32 align)
+{
+ if (ndd->cxl)
+ ns_label->cxl.align = __cpu_to_le16(align);
+}
+
+static inline void nsl_set_region_uuid(struct nvdimm_drvdata *ndd,
+ struct nd_namespace_label *ns_label,
+ const uuid_t *uuid)
+{
+ if (ndd->cxl)
+ export_uuid(ns_label->cxl.region_uuid, uuid);
+}
+
bool nsl_validate_type_guid(struct nvdimm_drvdata *ndd,
struct nd_namespace_label *nd_label, guid_t *guid);
enum nvdimm_claim_class nsl_get_claim_class(struct nvdimm_drvdata *ndd,
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH 04/20] nvdimm/label: CXL labels skip the need for 'interleave-set cookie'
[not found] ` <CGME20250617124016epcas5p20b04482f41a58c7f83484aa2b8b0c33c@epcas5p2.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
CXL LSA v2.1 utilizes the region labels stored in the LSA for interleave
set configuration instead of interleave-set cookie used in previous LSA
versions. As interleave-set cookie is not required for CXL LSA v2.1 format
so skip its usage for CXL LSA 2.1 format
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/nvdimm/namespace_devs.c | 3 ++-
drivers/nvdimm/region_devs.c | 5 +++++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index f180f0068c15..23b9def71012 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -1686,7 +1686,8 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region,
int rc = 0;
u16 i;
- if (cookie == 0) {
+ /* CXL labels skip the need for 'interleave-set cookie' */
+ if (!ndd->cxl && cookie == 0) {
dev_dbg(&nd_region->dev, "invalid interleave-set-cookie\n");
return ERR_PTR(-ENXIO);
}
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index 37417ce5ec7b..0481fc3fb627 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -858,6 +858,11 @@ u64 nd_region_interleave_set_cookie(struct nd_region *nd_region,
if (!nd_set)
return 0;
+ /* CXL labels skip the need for 'interleave-set cookie' */
+ if (nsindex && __le16_to_cpu(nsindex->major) == 2
+ && __le16_to_cpu(nsindex->minor) == 1)
+ return 0;
+
if (nsindex && __le16_to_cpu(nsindex->major) == 1
&& __le16_to_cpu(nsindex->minor) == 1)
return nd_set->cookie1;
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH 05/20] nvdimm/region_label: Add region label updation routine
[not found] ` <CGME20250617124019epcas5p39815cc0f2b175aee40c194625166695c@epcas5p3.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
2025-06-23 9:05 ` Jonathan Cameron
2025-07-17 22:53 ` Fabio M. De Francesco
0 siblings, 2 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
Added __pmem_region_label_update region label update routine to update
region label
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/nvdimm/label.c | 142 ++++++++++++++++++++++++++++++++
drivers/nvdimm/label.h | 2 +
drivers/nvdimm/namespace_devs.c | 12 +++
drivers/nvdimm/nd.h | 20 +++++
include/linux/libnvdimm.h | 8 ++
5 files changed, 184 insertions(+)
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
index d5cfaa99f976..7f33d14ce0ef 100644
--- a/drivers/nvdimm/label.c
+++ b/drivers/nvdimm/label.c
@@ -381,6 +381,16 @@ static void nsl_calculate_checksum(struct nvdimm_drvdata *ndd,
nsl_set_checksum(ndd, nd_label, sum);
}
+static void rgl_calculate_checksum(struct nvdimm_drvdata *ndd,
+ struct cxl_region_label *rg_label)
+{
+ u64 sum;
+
+ rgl_set_checksum(rg_label, 0);
+ sum = nd_fletcher64(rg_label, sizeof_namespace_label(ndd), 1);
+ rgl_set_checksum(rg_label, sum);
+}
+
static bool slot_valid(struct nvdimm_drvdata *ndd,
struct nd_lsa_label *nd_label, u32 slot)
{
@@ -1117,6 +1127,138 @@ int nd_pmem_namespace_label_update(struct nd_region *nd_region,
return 0;
}
+static int __pmem_region_label_update(struct nd_region *nd_region,
+ struct nd_mapping *nd_mapping, int pos, unsigned long flags)
+{
+ struct nd_interleave_set *nd_set = nd_region->nd_set;
+ struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
+ struct nd_lsa_label *nd_label;
+ struct cxl_region_label *rg_label;
+ struct nd_namespace_index *nsindex;
+ struct nd_label_ent *label_ent;
+ unsigned long *free;
+ u32 nslot, slot;
+ size_t offset;
+ int rc;
+ uuid_t tmp;
+
+ if (!preamble_next(ndd, &nsindex, &free, &nslot))
+ return -ENXIO;
+
+ /* allocate and write the label to the staging (next) index */
+ slot = nd_label_alloc_slot(ndd);
+ if (slot == UINT_MAX)
+ return -ENXIO;
+ dev_dbg(ndd->dev, "allocated: %d\n", slot);
+
+ nd_label = to_label(ndd, slot);
+
+ memset(nd_label, 0, sizeof_namespace_label(ndd));
+ rg_label = &nd_label->rg_label;
+
+ /* Set Region Label Format identification UUID */
+ uuid_parse(CXL_REGION_UUID, &tmp);
+ export_uuid(nd_label->rg_label.type, &tmp);
+
+ /* Set Current Region Label UUID */
+ export_uuid(nd_label->rg_label.uuid, &nd_set->uuid);
+
+ rg_label->flags = __cpu_to_le32(flags);
+ rg_label->nlabel = __cpu_to_le16(nd_region->ndr_mappings);
+ rg_label->position = __cpu_to_le16(pos);
+ rg_label->dpa = __cpu_to_le64(nd_mapping->start);
+ rg_label->rawsize = __cpu_to_le64(nd_mapping->size);
+ rg_label->hpa = __cpu_to_le64(nd_set->res->start);
+ rg_label->slot = __cpu_to_le32(slot);
+ rg_label->ig = __cpu_to_le32(nd_set->interleave_granularity);
+ rg_label->align = __cpu_to_le16(0);
+
+ /* Update fletcher64 Checksum */
+ rgl_calculate_checksum(ndd, rg_label);
+
+ /* update label */
+ offset = nd_label_offset(ndd, nd_label);
+ rc = nvdimm_set_config_data(ndd, offset, nd_label,
+ sizeof_namespace_label(ndd));
+ if (rc < 0) {
+ nd_label_free_slot(ndd, slot);
+ return rc;
+ }
+
+ /* Garbage collect the previous label */
+ mutex_lock(&nd_mapping->lock);
+ list_for_each_entry(label_ent, &nd_mapping->labels, list) {
+ if (!label_ent->label)
+ continue;
+ if (rgl_uuid_equal(&label_ent->label->rg_label, &nd_set->uuid))
+ reap_victim(nd_mapping, label_ent);
+ }
+
+ /* update index */
+ rc = nd_label_write_index(ndd, ndd->ns_next,
+ nd_inc_seq(__le32_to_cpu(nsindex->seq)), 0);
+
+ if (rc == 0) {
+ list_for_each_entry(label_ent, &nd_mapping->labels, list)
+ if (!label_ent->label) {
+ label_ent->label = nd_label;
+ nd_label = NULL;
+ break;
+ }
+ dev_WARN_ONCE(&nd_region->dev, nd_label,
+ "failed to track label: %d\n",
+ to_slot(ndd, nd_label));
+ if (nd_label)
+ rc = -ENXIO;
+ }
+ mutex_unlock(&nd_mapping->lock);
+
+ return rc;
+}
+
+int nd_pmem_region_label_update(struct nd_region *nd_region)
+{
+ int i, rc;
+
+ for (i = 0; i < nd_region->ndr_mappings; i++) {
+ struct nd_mapping *nd_mapping = &nd_region->mapping[i];
+ struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
+
+ /* No need to update region label for non cxl format */
+ if (!ndd->cxl)
+ continue;
+
+ /* Init labels to include region label */
+ rc = init_labels(nd_mapping, 1);
+
+ if (rc < 0)
+ return rc;
+
+ rc = __pmem_region_label_update(nd_region, nd_mapping, i,
+ NSLABEL_FLAG_UPDATING);
+
+ if (rc)
+ return rc;
+ }
+
+ /* Clear the UPDATING flag per UEFI 2.7 expectations */
+ for (i = 0; i < nd_region->ndr_mappings; i++) {
+ struct nd_mapping *nd_mapping = &nd_region->mapping[i];
+ struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
+
+ /* No need to update region label for non cxl format */
+ if (!ndd->cxl)
+ continue;
+
+ rc = __pmem_region_label_update(nd_region, nd_mapping, i, 0);
+
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
int __init nd_label_init(void)
{
WARN_ON(guid_parse(NVDIMM_BTT_GUID, &nvdimm_btt_guid));
diff --git a/drivers/nvdimm/label.h b/drivers/nvdimm/label.h
index 4883b3a1320f..0f428695017d 100644
--- a/drivers/nvdimm/label.h
+++ b/drivers/nvdimm/label.h
@@ -190,6 +190,7 @@ struct nd_namespace_label {
struct nd_lsa_label {
union {
struct nd_namespace_label ns_label;
+ struct cxl_region_label rg_label;
};
};
@@ -233,4 +234,5 @@ struct nd_region;
struct nd_namespace_pmem;
int nd_pmem_namespace_label_update(struct nd_region *nd_region,
struct nd_namespace_pmem *nspm, resource_size_t size);
+int nd_pmem_region_label_update(struct nd_region *nd_region);
#endif /* __LABEL_H__ */
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index 23b9def71012..6cccb4d2fc7b 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -232,6 +232,18 @@ static ssize_t __alt_name_store(struct device *dev, const char *buf,
return rc;
}
+int nd_region_label_update(struct nd_region *nd_region)
+{
+ int rc;
+
+ nvdimm_bus_lock(&nd_region->dev);
+ rc = nd_pmem_region_label_update(nd_region);
+ nvdimm_bus_unlock(&nd_region->dev);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(nd_region_label_update);
+
static int nd_namespace_label_update(struct nd_region *nd_region,
struct device *dev)
{
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 07d665f18bf6..2fdc92b29e8a 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -322,6 +322,26 @@ static inline void nsl_set_region_uuid(struct nvdimm_drvdata *ndd,
export_uuid(ns_label->cxl.region_uuid, uuid);
}
+static inline bool rgl_uuid_equal(struct cxl_region_label *rg_label,
+ const uuid_t *uuid)
+{
+ uuid_t tmp;
+
+ import_uuid(&tmp, rg_label->uuid);
+ return uuid_equal(&tmp, uuid);
+}
+
+static inline u64 rgl_get_checksum(struct cxl_region_label *rg_label)
+{
+ return __le64_to_cpu(rg_label->checksum);
+}
+
+static inline void rgl_set_checksum(struct cxl_region_label *rg_label,
+ u64 checksum)
+{
+ rg_label->checksum = __cpu_to_le64(checksum);
+}
+
bool nsl_validate_type_guid(struct nvdimm_drvdata *ndd,
struct nd_namespace_label *nd_label, guid_t *guid);
enum nvdimm_claim_class nsl_get_claim_class(struct nvdimm_drvdata *ndd,
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index 0a55900842c8..b06bd45373f4 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -115,6 +115,13 @@ struct nd_interleave_set {
u64 altcookie;
guid_t type_guid;
+
+ /* v2.1 region label info */
+ uuid_t uuid;
+ int interleave_ways;
+ int interleave_granularity;
+ struct resource *res;
+ int nr_targets;
};
struct nd_mapping_desc {
@@ -302,6 +309,7 @@ int nvdimm_has_flush(struct nd_region *nd_region);
int nvdimm_has_cache(struct nd_region *nd_region);
int nvdimm_in_overwrite(struct nvdimm *nvdimm);
bool is_nvdimm_sync(struct nd_region *nd_region);
+int nd_region_label_update(struct nd_region *nd_region);
static inline int nvdimm_ctl(struct nvdimm *nvdimm, unsigned int cmd, void *buf,
unsigned int buf_len, int *cmd_rc)
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH 06/20] nvdimm/region_label: Add region label deletion routine
[not found] ` <CGME20250617124022epcas5p2441d6c5dfaeceb744b5fc00add7ceae0@epcas5p2.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
2025-06-23 9:09 ` Jonathan Cameron
0 siblings, 1 reply; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
Added cxl v2.1 format region label deletion routine. This function is
used to delete region label from LSA
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/nvdimm/label.c | 75 ++++++++++++++++++++++++++++++---
drivers/nvdimm/label.h | 6 +++
drivers/nvdimm/namespace_devs.c | 12 ++++++
drivers/nvdimm/nd.h | 9 ++++
include/linux/libnvdimm.h | 1 +
5 files changed, 98 insertions(+), 5 deletions(-)
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
index 7f33d14ce0ef..9381c50086fc 100644
--- a/drivers/nvdimm/label.c
+++ b/drivers/nvdimm/label.c
@@ -1034,7 +1034,8 @@ static int init_labels(struct nd_mapping *nd_mapping, int num_labels)
return max(num_labels, old_num_labels);
}
-static int del_labels(struct nd_mapping *nd_mapping, uuid_t *uuid)
+static int del_labels(struct nd_mapping *nd_mapping, uuid_t *uuid,
+ enum label_type ltype)
{
struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
struct nd_label_ent *label_ent, *e;
@@ -1058,8 +1059,18 @@ static int del_labels(struct nd_mapping *nd_mapping, uuid_t *uuid)
if (!nd_label)
continue;
active++;
- if (!nsl_uuid_equal(ndd, &nd_label->ns_label, uuid))
- continue;
+
+ if (ltype == NS_LABEL_TYPE) {
+ if (!nsl_uuid_equal(ndd, &nd_label->ns_label, uuid))
+ continue;
+ } else if (ltype == RG_LABEL_TYPE) {
+ if (!nsl_uuid_equal(ndd, &nd_label->ns_label, uuid))
+ continue;
+ } else {
+ dev_err(ndd->dev, "Invalid label type\n");
+ return 0;
+ }
+
active--;
slot = to_slot(ndd, nd_label);
nd_label_free_slot(ndd, slot);
@@ -1069,7 +1080,7 @@ static int del_labels(struct nd_mapping *nd_mapping, uuid_t *uuid)
}
list_splice_tail_init(&list, &nd_mapping->labels);
- if (active == 0) {
+ if ((ltype == NS_LABEL_TYPE) && (active == 0)) {
nd_mapping_free_labels(nd_mapping);
dev_dbg(ndd->dev, "no more active labels\n");
}
@@ -1091,7 +1102,8 @@ int nd_pmem_namespace_label_update(struct nd_region *nd_region,
int count = 0;
if (size == 0) {
- rc = del_labels(nd_mapping, nspm->uuid);
+ rc = del_labels(nd_mapping, nspm->uuid,
+ NS_LABEL_TYPE);
if (rc)
return rc;
continue;
@@ -1259,6 +1271,59 @@ int nd_pmem_region_label_update(struct nd_region *nd_region)
return 0;
}
+int nd_pmem_region_label_delete(struct nd_region *nd_region)
+{
+ int i, rc;
+ struct nd_interleave_set *nd_set = nd_region->nd_set;
+ struct nd_label_ent *label_ent;
+ bool is_non_rgl = false;
+ int ns_region_cnt = 0;
+
+ for (i = 0; i < nd_region->ndr_mappings; i++) {
+ struct nd_mapping *nd_mapping = &nd_region->mapping[i];
+ struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
+
+ /* Find non cxl format supported ndr_mappings */
+ if (!ndd->cxl)
+ is_non_rgl = true;
+
+ /* Find if any NS label using this region */
+ mutex_lock(&nd_mapping->lock);
+ list_for_each_entry(label_ent, &nd_mapping->labels, list) {
+ if (!label_ent->label)
+ continue;
+
+ /* Check if any available NS labels has same
+ * region_uuid in LSA
+ */
+ if (nsl_region_uuid_equal(&label_ent->label->ns_label,
+ &nd_set->uuid))
+ ns_region_cnt++;
+ }
+ mutex_unlock(&nd_mapping->lock);
+ }
+
+ if (is_non_rgl) {
+ dev_dbg(&nd_region->dev, "Region label deletion unsupported\n");
+ return -EINVAL;
+ }
+
+ if (ns_region_cnt) {
+ dev_dbg(&nd_region->dev, "Region/Namespace label in use\n");
+ return -EBUSY;
+ }
+
+ for (i = 0; i < nd_region->ndr_mappings; i++) {
+ struct nd_mapping *nd_mapping = &nd_region->mapping[i];
+
+ rc = del_labels(nd_mapping, &nd_set->uuid, RG_LABEL_TYPE);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
int __init nd_label_init(void)
{
WARN_ON(guid_parse(NVDIMM_BTT_GUID, &nvdimm_btt_guid));
diff --git a/drivers/nvdimm/label.h b/drivers/nvdimm/label.h
index 0f428695017d..cc14068511cf 100644
--- a/drivers/nvdimm/label.h
+++ b/drivers/nvdimm/label.h
@@ -30,6 +30,11 @@ enum {
ND_NSINDEX_INIT = 0x1,
};
+enum label_type {
+ RG_LABEL_TYPE,
+ NS_LABEL_TYPE,
+};
+
/**
* struct nd_namespace_index - label set superblock
* @sig: NAMESPACE_INDEX\0
@@ -235,4 +240,5 @@ struct nd_namespace_pmem;
int nd_pmem_namespace_label_update(struct nd_region *nd_region,
struct nd_namespace_pmem *nspm, resource_size_t size);
int nd_pmem_region_label_update(struct nd_region *nd_region);
+int nd_pmem_region_label_delete(struct nd_region *nd_region);
#endif /* __LABEL_H__ */
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index 6cccb4d2fc7b..b081661b7aaa 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -244,6 +244,18 @@ int nd_region_label_update(struct nd_region *nd_region)
}
EXPORT_SYMBOL_GPL(nd_region_label_update);
+int nd_region_label_delete(struct nd_region *nd_region)
+{
+ int rc;
+
+ nvdimm_bus_lock(&nd_region->dev);
+ rc = nd_pmem_region_label_delete(nd_region);
+ nvdimm_bus_unlock(&nd_region->dev);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(nd_region_label_delete);
+
static int nd_namespace_label_update(struct nd_region *nd_region,
struct device *dev)
{
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 2fdc92b29e8a..1e5a68013735 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -322,6 +322,15 @@ static inline void nsl_set_region_uuid(struct nvdimm_drvdata *ndd,
export_uuid(ns_label->cxl.region_uuid, uuid);
}
+static inline bool nsl_region_uuid_equal(struct nd_namespace_label *ns_label,
+ const uuid_t *uuid)
+{
+ uuid_t tmp;
+
+ import_uuid(&tmp, ns_label->cxl.region_uuid);
+ return uuid_equal(&tmp, uuid);
+}
+
static inline bool rgl_uuid_equal(struct cxl_region_label *rg_label,
const uuid_t *uuid)
{
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index b06bd45373f4..b2e16914ab52 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -310,6 +310,7 @@ int nvdimm_has_cache(struct nd_region *nd_region);
int nvdimm_in_overwrite(struct nvdimm *nvdimm);
bool is_nvdimm_sync(struct nd_region *nd_region);
int nd_region_label_update(struct nd_region *nd_region);
+int nd_region_label_delete(struct nd_region *nd_region);
static inline int nvdimm_ctl(struct nvdimm *nvdimm, unsigned int cmd, void *buf,
unsigned int buf_len, int *cmd_rc)
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH 07/20] nvdimm/namespace_label: Update namespace init_labels and its region_uuid
[not found] ` <CGME20250617124025epcas5p1ce6656fed9ef1175812f80574048cd7a@epcas5p1.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
2025-06-23 9:11 ` Jonathan Cameron
0 siblings, 1 reply; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
nd_mapping->labels maintains the list of labels present into LSA.
init_labels function prepares this list while adding new label
into LSA and updates nd_mapping->labels accordingly. During cxl
region creation nd_mapping->labels list and LSA was updated with
one region label. Therefore during new namespace label creation
pre-include the previously created region label, so increase
num_labels count by 1.
Also updated nsl_set_region_uuid with region uuid with which
namespace is associated with.
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/nvdimm/label.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
index 9381c50086fc..108100c4bf44 100644
--- a/drivers/nvdimm/label.c
+++ b/drivers/nvdimm/label.c
@@ -947,7 +947,7 @@ static int __pmem_label_update(struct nd_region *nd_region,
nsl_set_slot(ndd, ns_label, slot);
nsl_set_alignment(ndd, ns_label, 0);
nsl_set_type_guid(ndd, ns_label, &nd_set->type_guid);
- nsl_set_region_uuid(ndd, ns_label, NULL);
+ nsl_set_region_uuid(ndd, ns_label, &nd_set->uuid);
nsl_set_claim_class(ndd, ns_label, ndns->claim_class);
nsl_calculate_checksum(ndd, ns_label);
nd_dbg_dpa(nd_region, ndd, res, "\n");
@@ -1114,7 +1114,8 @@ int nd_pmem_namespace_label_update(struct nd_region *nd_region,
count++;
WARN_ON_ONCE(!count);
- rc = init_labels(nd_mapping, count);
+ /* Adding 1 to pre include the already added region label */
+ rc = init_labels(nd_mapping, count + 1);
if (rc < 0)
return rc;
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH 08/20] nvdimm/label: Include region label in slot validation
[not found] ` <CGME20250617124028epcas5p2bb45182c91359a16efc5b1561927abce@epcas5p2.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
2025-06-23 9:13 ` Jonathan Cameron
0 siblings, 1 reply; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
slot validation routine validates label slot by calculating label
checksum. It was only validating namespace label. This changeset also
validates region label if present.
Also validate and calculate lsa v2.1 namespace label checksum
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/nvdimm/label.c | 52 ++++++++++++++++++++++++++++++++++--------
drivers/nvdimm/nd.h | 21 +++++++++++++++++
2 files changed, 63 insertions(+), 10 deletions(-)
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
index 108100c4bf44..22e13db1ca20 100644
--- a/drivers/nvdimm/label.c
+++ b/drivers/nvdimm/label.c
@@ -359,7 +359,7 @@ static bool nsl_validate_checksum(struct nvdimm_drvdata *ndd,
{
u64 sum, sum_save;
- if (!ndd->cxl && !efi_namespace_label_has(ndd, checksum))
+ if (!efi_namespace_label_has(ndd, checksum))
return true;
sum_save = nsl_get_checksum(ndd, nd_label);
@@ -374,13 +374,25 @@ static void nsl_calculate_checksum(struct nvdimm_drvdata *ndd,
{
u64 sum;
- if (!ndd->cxl && !efi_namespace_label_has(ndd, checksum))
+ if (!efi_namespace_label_has(ndd, checksum))
return;
nsl_set_checksum(ndd, nd_label, 0);
sum = nd_fletcher64(nd_label, sizeof_namespace_label(ndd), 1);
nsl_set_checksum(ndd, nd_label, sum);
}
+static bool rgl_validate_checksum(struct nvdimm_drvdata *ndd,
+ struct cxl_region_label *rg_label)
+{
+ u64 sum, sum_save;
+
+ sum_save = rgl_get_checksum(rg_label);
+ rgl_set_checksum(rg_label, 0);
+ sum = nd_fletcher64(rg_label, sizeof_namespace_label(ndd), 1);
+ rgl_set_checksum(rg_label, sum_save);
+ return sum == sum_save;
+}
+
static void rgl_calculate_checksum(struct nvdimm_drvdata *ndd,
struct cxl_region_label *rg_label)
{
@@ -395,13 +407,25 @@ static bool slot_valid(struct nvdimm_drvdata *ndd,
struct nd_lsa_label *nd_label, u32 slot)
{
bool valid;
+ char *label_name;
/* check that we are written where we expect to be written */
- if (slot != nsl_get_slot(ndd, &nd_label->ns_label))
- return false;
- valid = nsl_validate_checksum(ndd, &nd_label->ns_label);
+ if (is_region_label(ndd, nd_label)) {
+ label_name = "rg";
+ if (slot != rgl_get_slot(&nd_label->rg_label))
+ return false;
+ valid = rgl_validate_checksum(ndd, &nd_label->rg_label);
+ } else {
+ label_name = "ns";
+ if (slot != nsl_get_slot(ndd, &nd_label->ns_label))
+ return false;
+ valid = nsl_validate_checksum(ndd, &nd_label->ns_label);
+ }
+
if (!valid)
- dev_dbg(ndd->dev, "fail checksum. slot: %d\n", slot);
+ dev_dbg(ndd->dev, "%s label checksum fail. slot: %d\n",
+ label_name, slot);
+
return valid;
}
@@ -577,17 +601,25 @@ int nd_label_active_count(struct nvdimm_drvdata *ndd)
for_each_clear_bit_le(slot, free, nslot) {
struct nd_lsa_label *nd_label;
+ u32 lslot;
+ u64 size, dpa;
nd_label = to_label(ndd, slot);
if (!slot_valid(ndd, nd_label, slot)) {
- u32 label_slot = nsl_get_slot(ndd, &nd_label->ns_label);
- u64 size = nsl_get_rawsize(ndd, &nd_label->ns_label);
- u64 dpa = nsl_get_dpa(ndd, &nd_label->ns_label);
+ if (is_region_label(ndd, nd_label)) {
+ lslot = __le32_to_cpu(nd_label->rg_label.slot);
+ size = __le64_to_cpu(nd_label->rg_label.rawsize);
+ dpa = __cpu_to_le64(nd_label->rg_label.dpa);
+ } else {
+ lslot = nsl_get_slot(ndd, &nd_label->ns_label);
+ size = nsl_get_rawsize(ndd, &nd_label->ns_label);
+ dpa = nsl_get_dpa(ndd, &nd_label->ns_label);
+ }
dev_dbg(ndd->dev,
"slot%d invalid slot: %d dpa: %llx size: %llx\n",
- slot, label_slot, dpa, size);
+ slot, lslot, dpa, size);
continue;
}
count++;
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 1e5a68013735..ca8256b31472 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -331,6 +331,22 @@ static inline bool nsl_region_uuid_equal(struct nd_namespace_label *ns_label,
return uuid_equal(&tmp, uuid);
}
+static inline bool is_region_label(struct nvdimm_drvdata *ndd,
+ struct nd_lsa_label *nd_label)
+{
+ uuid_t ns_type, region_type;
+
+ if (ndd->cxl) {
+ uuid_parse(CXL_REGION_UUID, ®ion_type);
+ import_uuid(&ns_type, nd_label->ns_label.cxl.type);
+ if (uuid_equal(®ion_type, &ns_type))
+ return true;
+ else
+ return false;
+ } else
+ return false;
+}
+
static inline bool rgl_uuid_equal(struct cxl_region_label *rg_label,
const uuid_t *uuid)
{
@@ -340,6 +356,11 @@ static inline bool rgl_uuid_equal(struct cxl_region_label *rg_label,
return uuid_equal(&tmp, uuid);
}
+static inline u32 rgl_get_slot(struct cxl_region_label *rg_label)
+{
+ return __le32_to_cpu(rg_label->slot);
+}
+
static inline u64 rgl_get_checksum(struct cxl_region_label *rg_label)
{
return __le64_to_cpu(rg_label->checksum);
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH 09/20] nvdimm/namespace_label: Skip region label during ns label DPA reservation
[not found] ` <CGME20250617124031epcas5p3542c2fc6d946f3cdcbc06dbfc65743e2@epcas5p3.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
If Namespace label is present in LSA during nvdimm_probe then DPA
reservation is required. But this reservation is not required by region
label. Therefore if LSA scanning finds any region label, skip it.
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/nvdimm/label.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
index 22e13db1ca20..3a870798a90c 100644
--- a/drivers/nvdimm/label.c
+++ b/drivers/nvdimm/label.c
@@ -450,6 +450,10 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd)
nd_label = to_label(ndd, slot);
ns_label = &nd_label->ns_label;
+ /* skip region label, dpa reservation for ns label only */
+ if (is_region_label(ndd, nd_label))
+ continue;
+
if (!slot_valid(ndd, nd_label, slot))
continue;
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH 10/20] nvdimm/region_label: Preserve cxl region information from region label
[not found] ` <CGME20250617124034epcas5p2f53c3cc21c51b7c176ad580d5d954c64@epcas5p2.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
Preserve region information from region label during nvdimm_probe. This
preserved region information is used for creating cxl region to achieve
region persistency across reboot.
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/nvdimm/dimm.c | 4 ++++
drivers/nvdimm/label.c | 41 +++++++++++++++++++++++++++++++++++++++
drivers/nvdimm/nd-core.h | 2 ++
drivers/nvdimm/nd.h | 1 +
include/linux/libnvdimm.h | 14 +++++++++++++
5 files changed, 62 insertions(+)
diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c
index 8753b5cd91cc..da4f37f0ae3b 100644
--- a/drivers/nvdimm/dimm.c
+++ b/drivers/nvdimm/dimm.c
@@ -107,6 +107,10 @@ static int nvdimm_probe(struct device *dev)
if (rc)
goto err;
+ /* Preserve cxl region info if available */
+ if (ndd->cxl)
+ nvdimm_cxl_region_preserve(ndd);
+
return 0;
err:
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
index 3a870798a90c..6a94175e6bb6 100644
--- a/drivers/nvdimm/label.c
+++ b/drivers/nvdimm/label.c
@@ -471,6 +471,47 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd)
return 0;
}
+int nvdimm_cxl_region_preserve(struct nvdimm_drvdata *ndd)
+{
+ struct nvdimm *nvdimm = to_nvdimm(ndd->dev);
+ struct cxl_pmem_region_params *params = &nvdimm->cxl_region_params;
+ struct nd_namespace_index *nsindex;
+ unsigned long *free;
+ u32 nslot, slot;
+
+ if (!preamble_current(ndd, &nsindex, &free, &nslot))
+ return 0; /* no label, nothing to preserve */
+
+ for_each_clear_bit_le(slot, free, nslot) {
+ struct nd_lsa_label *nd_label;
+ struct cxl_region_label *rg_label;
+ uuid_t rg_type, region_type;
+
+ nd_label = to_label(ndd, slot);
+ rg_label = &nd_label->rg_label;
+ uuid_parse(CXL_REGION_UUID, ®ion_type);
+ import_uuid(&rg_type, nd_label->rg_label.type);
+
+ /* REVISIT: Currently preserving only one region */
+ if (uuid_equal(®ion_type, &rg_type)) {
+ nvdimm->is_region_label = true;
+ import_uuid(¶ms->uuid, rg_label->uuid);
+ params->flags = __le32_to_cpu(rg_label->flags);
+ params->nlabel = __le16_to_cpu(rg_label->nlabel);
+ params->position = __le16_to_cpu(rg_label->position);
+ params->dpa = __le64_to_cpu(rg_label->dpa);
+ params->rawsize = __le64_to_cpu(rg_label->rawsize);
+ params->hpa = __le64_to_cpu(rg_label->hpa);
+ params->slot = __le32_to_cpu(rg_label->slot);
+ params->ig = __le32_to_cpu(rg_label->ig);
+ params->align = __le32_to_cpu(rg_label->align);
+ break;
+ }
+ }
+
+ return 0;
+}
+
int nd_label_data_init(struct nvdimm_drvdata *ndd)
{
size_t config_size, read_size, max_xfer, offset;
diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h
index 86976a9e8a15..71eabf2db389 100644
--- a/drivers/nvdimm/nd-core.h
+++ b/drivers/nvdimm/nd-core.h
@@ -46,6 +46,8 @@ struct nvdimm {
} sec;
struct delayed_work dwork;
const struct nvdimm_fw_ops *fw_ops;
+ bool is_region_label;
+ struct cxl_pmem_region_params cxl_region_params;
};
static inline unsigned long nvdimm_security_flags(
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index ca8256b31472..33a87924dfee 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -600,6 +600,7 @@ void nvdimm_set_locked(struct device *dev);
void nvdimm_clear_locked(struct device *dev);
int nvdimm_security_setup_events(struct device *dev);
bool nvdimm_check_cxl_label_format(struct device *dev);
+int nvdimm_cxl_region_preserve(struct nvdimm_drvdata *ndd);
#if IS_ENABLED(CONFIG_NVDIMM_KEYS)
int nvdimm_security_unlock(struct device *dev);
#else
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index b2e16914ab52..cdabb43a8a7f 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -106,6 +106,20 @@ struct nd_cmd_desc {
int out_sizes[ND_CMD_MAX_ELEM];
};
+struct cxl_pmem_region_params {
+ uuid_t uuid;
+ u32 flags;
+ u16 nlabel;
+ u16 position;
+ u64 dpa;
+ u64 rawsize;
+ u64 hpa;
+ u32 slot;
+ u32 ig;
+ u32 align;
+ int nr_targets;
+};
+
struct nd_interleave_set {
/* v1.1 definition of the interleave-set-cookie algorithm */
u64 cookie1;
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH 11/20] nvdimm/region_label: Export routine to fetch region information
[not found] ` <CGME20250617124037epcas5p2efa5e8ac19df70cdeb7330404eed385f@epcas5p2.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
cxl region information preserved from LSA need to be exported so as to
use by cxl driver for cxl region re-creation
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/nvdimm/dimm_devs.c | 18 ++++++++++++++++++
include/linux/libnvdimm.h | 2 ++
2 files changed, 20 insertions(+)
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
index e8f545f889fd..0edcb6b558e5 100644
--- a/drivers/nvdimm/dimm_devs.c
+++ b/drivers/nvdimm/dimm_devs.c
@@ -283,6 +283,24 @@ void *nvdimm_provider_data(struct nvdimm *nvdimm)
}
EXPORT_SYMBOL_GPL(nvdimm_provider_data);
+bool nvdimm_has_cxl_region(struct nvdimm *nvdimm)
+{
+ if (nvdimm)
+ return nvdimm->is_region_label;
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(nvdimm_has_cxl_region);
+
+void *nvdimm_get_cxl_region_param(struct nvdimm *nvdimm)
+{
+ if (nvdimm)
+ return &nvdimm->cxl_region_params;
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(nvdimm_get_cxl_region_param);
+
static ssize_t commands_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index cdabb43a8a7f..9a5d17c4b89b 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -325,6 +325,8 @@ int nvdimm_in_overwrite(struct nvdimm *nvdimm);
bool is_nvdimm_sync(struct nd_region *nd_region);
int nd_region_label_update(struct nd_region *nd_region);
int nd_region_label_delete(struct nd_region *nd_region);
+bool nvdimm_has_cxl_region(struct nvdimm *nvdimm);
+void *nvdimm_get_cxl_region_param(struct nvdimm *nvdimm);
static inline int nvdimm_ctl(struct nvdimm *nvdimm, unsigned int cmd, void *buf,
unsigned int buf_len, int *cmd_rc)
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH 12/20] nvdimm/namespace_label: Skip region label during namespace creation
[not found] ` <CGME20250617124040epcas5p3be044cbdc5b33b0b8465d84870a5b280@epcas5p3.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
2025-06-23 9:17 ` Jonathan Cameron
0 siblings, 1 reply; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
During namespace creation skip presence of region label if present.
Also preserve region label into labels list if present.
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/nvdimm/namespace_devs.c | 48 +++++++++++++++++++++++++++++----
1 file changed, 43 insertions(+), 5 deletions(-)
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index b081661b7aaa..ca8f8546170c 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -1976,6 +1976,10 @@ static struct device **scan_labels(struct nd_region *nd_region)
if (!nd_label)
continue;
+ /* skip region labels if present */
+ if (is_region_label(ndd, nd_label))
+ continue;
+
/* skip labels that describe extents outside of the region */
if (nsl_get_dpa(ndd, &nd_label->ns_label) < nd_mapping->start ||
nsl_get_dpa(ndd, &nd_label->ns_label) > map_end)
@@ -2014,9 +2018,29 @@ static struct device **scan_labels(struct nd_region *nd_region)
if (count == 0) {
struct nd_namespace_pmem *nspm;
+ for (i = 0; i < nd_region->ndr_mappings; i++) {
+ struct nd_label_ent *le, *e;
+ LIST_HEAD(list);
- /* Publish a zero-sized namespace for userspace to configure. */
- nd_mapping_free_labels(nd_mapping);
+ nd_mapping = &nd_region->mapping[i];
+ if (list_empty(&nd_mapping->labels))
+ continue;
+
+ list_for_each_entry_safe(le, e, &nd_mapping->labels,
+ list) {
+ struct nd_lsa_label *nd_label = le->label;
+
+ /* preserve region labels if present */
+ if (is_region_label(ndd, nd_label))
+ list_move_tail(&le->list, &list);
+ }
+
+ /* Publish a zero-sized namespace for userspace
+ * to configure.
+ */
+ nd_mapping_free_labels(nd_mapping);
+ list_splice_init(&list, &nd_mapping->labels);
+ }
nspm = kzalloc(sizeof(*nspm), GFP_KERNEL);
if (!nspm)
goto err;
@@ -2028,7 +2052,7 @@ static struct device **scan_labels(struct nd_region *nd_region)
} else if (is_memory(&nd_region->dev)) {
/* clean unselected labels */
for (i = 0; i < nd_region->ndr_mappings; i++) {
- struct list_head *l, *e;
+ struct nd_label_ent *le, *e;
LIST_HEAD(list);
int j;
@@ -2039,10 +2063,24 @@ static struct device **scan_labels(struct nd_region *nd_region)
}
j = count;
- list_for_each_safe(l, e, &nd_mapping->labels) {
+ list_for_each_entry_safe(le, e, &nd_mapping->labels,
+ list) {
+ struct nd_lsa_label *nd_label = le->label;
+
+ /* preserve region labels */
+ if (is_region_label(ndd, nd_label)) {
+ list_move_tail(&le->list, &list);
+ continue;
+ }
+
+ /* Once preserving selected ns label done
+ * break out of loop
+ */
if (!j--)
break;
- list_move_tail(l, &list);
+
+ /* preserve selected ns label */
+ list_move_tail(&le->list, &list);
}
nd_mapping_free_labels(nd_mapping);
list_splice_init(&list, &nd_mapping->labels);
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH 13/20] cxl/mem: Refactor cxl pmem region auto-assembling
[not found] ` <CGME20250617124043epcas5p21e5b77aa3a6acfa7e01847ffd58350ed@epcas5p2.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
2025-06-23 9:20 ` Jonathan Cameron
2025-07-10 0:38 ` Dave Jiang
0 siblings, 2 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
In 84ec985944ef3, For cxl pmem region auto-assembly after endpoint port
probing, cxl_nvd presence was required. And for cxl region persistency,
region creation happens during nvdimm_probe which need the completion
of endpoint probe.
It is therefore refactored cxl pmem region auto-assembly after endpoint
probing to cxl mem probing
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/cxl/core/port.c | 38 ++++++++++++++++++++++++++++++++++++++
drivers/cxl/cxl.h | 1 +
drivers/cxl/mem.c | 27 ++++++++++++++++++---------
drivers/cxl/port.c | 38 --------------------------------------
4 files changed, 57 insertions(+), 47 deletions(-)
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 78a5c2c25982..bca668193c49 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -1038,6 +1038,44 @@ void put_cxl_root(struct cxl_root *cxl_root)
}
EXPORT_SYMBOL_NS_GPL(put_cxl_root, "CXL");
+static int discover_region(struct device *dev, void *root)
+{
+ struct cxl_endpoint_decoder *cxled;
+ int rc;
+
+ if (!is_endpoint_decoder(dev))
+ return 0;
+
+ cxled = to_cxl_endpoint_decoder(dev);
+ if ((cxled->cxld.flags & CXL_DECODER_F_ENABLE) == 0)
+ return 0;
+
+ if (cxled->state != CXL_DECODER_STATE_AUTO)
+ return 0;
+
+ /*
+ * Region enumeration is opportunistic, if this add-event fails,
+ * continue to the next endpoint decoder.
+ */
+ rc = cxl_add_to_region(root, cxled);
+ if (rc)
+ dev_dbg(dev, "failed to add to region: %#llx-%#llx\n",
+ cxled->cxld.hpa_range.start, cxled->cxld.hpa_range.end);
+
+ return 0;
+}
+
+void cxl_region_discovery(struct cxl_port *port)
+{
+ struct cxl_port *root;
+ struct cxl_root *cxl_root __free(put_cxl_root) = find_cxl_root(port);
+
+ root = &cxl_root->port;
+
+ device_for_each_child(&port->dev, root, discover_region);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_region_discovery, "CXL");
+
static struct cxl_dport *find_dport(struct cxl_port *port, int id)
{
struct cxl_dport *dport;
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index dcf2a127efc7..9423ea3509ad 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -869,6 +869,7 @@ bool is_cxl_nvdimm(struct device *dev);
bool is_cxl_nvdimm_bridge(struct device *dev);
int devm_cxl_add_nvdimm(struct cxl_port *parent_port, struct cxl_memdev *cxlmd);
struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_port *port);
+void cxl_region_discovery(struct cxl_port *port);
#ifdef CONFIG_CXL_REGION
bool is_cxl_pmem_region(struct device *dev);
diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
index 2f03a4d5606e..aaea4eb178ef 100644
--- a/drivers/cxl/mem.c
+++ b/drivers/cxl/mem.c
@@ -152,15 +152,6 @@ static int cxl_mem_probe(struct device *dev)
return -ENXIO;
}
- if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM)) {
- rc = devm_cxl_add_nvdimm(parent_port, cxlmd);
- if (rc) {
- if (rc == -ENODEV)
- dev_info(dev, "PMEM disabled by platform\n");
- return rc;
- }
- }
-
if (dport->rch)
endpoint_parent = parent_port->uport_dev;
else
@@ -180,6 +171,24 @@ static int cxl_mem_probe(struct device *dev)
return rc;
}
+ if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM)) {
+ rc = devm_cxl_add_nvdimm(parent_port, cxlmd);
+ if (rc) {
+ if (rc == -ENODEV)
+ dev_info(dev, "PMEM disabled by platform\n");
+ return rc;
+ }
+ }
+
+ /*
+ * Now that all endpoint decoders are successfully enumerated, try to
+ * assemble region autodiscovery from committed decoders.
+ * Earlier it was part of cxl_endpoint_port_probe, So moved it here
+ * as cxl_nvd of the memdev needs to be available during the pmem
+ * region auto-assembling
+ */
+ cxl_region_discovery(cxlmd->endpoint);
+
/*
* The kernel may be operating out of CXL memory on this device,
* there is no spec defined way to determine whether this device
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index d2bfd1ff5492..361544760a4c 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -30,33 +30,6 @@ static void schedule_detach(void *cxlmd)
schedule_cxl_memdev_detach(cxlmd);
}
-static int discover_region(struct device *dev, void *root)
-{
- struct cxl_endpoint_decoder *cxled;
- int rc;
-
- if (!is_endpoint_decoder(dev))
- return 0;
-
- cxled = to_cxl_endpoint_decoder(dev);
- if ((cxled->cxld.flags & CXL_DECODER_F_ENABLE) == 0)
- return 0;
-
- if (cxled->state != CXL_DECODER_STATE_AUTO)
- return 0;
-
- /*
- * Region enumeration is opportunistic, if this add-event fails,
- * continue to the next endpoint decoder.
- */
- rc = cxl_add_to_region(root, cxled);
- if (rc)
- dev_dbg(dev, "failed to add to region: %#llx-%#llx\n",
- cxled->cxld.hpa_range.start, cxled->cxld.hpa_range.end);
-
- return 0;
-}
-
static int cxl_switch_port_probe(struct cxl_port *port)
{
struct cxl_hdm *cxlhdm;
@@ -95,7 +68,6 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
struct cxl_dev_state *cxlds = cxlmd->cxlds;
struct cxl_hdm *cxlhdm;
- struct cxl_port *root;
int rc;
rc = cxl_dvsec_rr_decode(cxlds, &info);
@@ -125,20 +97,10 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
rc = devm_cxl_enumerate_decoders(cxlhdm, &info);
if (rc)
return rc;
-
/*
* This can't fail in practice as CXL root exit unregisters all
* descendant ports and that in turn synchronizes with cxl_port_probe()
*/
- struct cxl_root *cxl_root __free(put_cxl_root) = find_cxl_root(port);
-
- root = &cxl_root->port;
-
- /*
- * Now that all endpoint decoders are successfully enumerated, try to
- * assemble regions from committed decoders
- */
- device_for_each_child(&port->dev, root, discover_region);
return 0;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH 14/20] cxl/region: Add cxl pmem region creation routine for region persistency
[not found] ` <CGME20250617124046epcas5p16a45d2afe3b41ca08994a5cca09bfb68@epcas5p1.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
2025-06-23 9:43 ` Jonathan Cameron
2025-07-10 15:59 ` Dave Jiang
0 siblings, 2 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
Added exported cxl_create_pmem_region routine to create cxl pmem region
from LSA parsed cxl region information.
Inspirition for the function is taken from ndctl device attribute
(_store) call. It allocates cxlr and fills information parsed from LSA
and calls device_add(&cxlr->dev) to initiates further region creation
porbes
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/cxl/core/port.c | 6 ++
drivers/cxl/core/region.c | 208 ++++++++++++++++++++++++++++++++++++++
drivers/cxl/cxl.h | 11 ++
3 files changed, 225 insertions(+)
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index bca668193c49..2452f7c15b2d 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -2150,6 +2150,12 @@ void cxl_bus_drain(void)
}
EXPORT_SYMBOL_NS_GPL(cxl_bus_drain, "CXL");
+void cxl_wq_flush(void)
+{
+ flush_workqueue(cxl_bus_wq);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_wq_flush, "CXL");
+
bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd)
{
return queue_work(cxl_bus_wq, &cxlmd->detach_work);
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index b98b1ccffd1c..8990e3c3474d 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -2522,6 +2522,214 @@ static ssize_t create_ram_region_show(struct device *dev,
return __create_region_show(to_cxl_root_decoder(dev), buf);
}
+static ssize_t update_region_size(struct cxl_region *cxlr, u64 val)
+{
+ int rc;
+
+ rc = down_write_killable(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+
+ if (val)
+ rc = alloc_hpa(cxlr, val);
+ else
+ rc = free_hpa(cxlr);
+ up_write(&cxl_region_rwsem);
+
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static ssize_t update_region_dpa_size(struct cxl_region *cxlr,
+ struct cxl_decoder *cxld,
+ unsigned long long size)
+{
+ int rc;
+ struct cxl_endpoint_decoder *cxled =
+ to_cxl_endpoint_decoder(&cxld->dev);
+
+ if (!IS_ALIGNED(size, SZ_256M))
+ return -EINVAL;
+
+ rc = cxl_dpa_free(cxled);
+ if (rc)
+ return rc;
+
+ if (size == 0)
+ return 0;
+
+ rc = cxl_dpa_alloc(cxled, size);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static ssize_t update_region_dpa_mode(struct cxl_region *cxlr,
+ struct cxl_decoder *cxld)
+{
+ int rc;
+ struct cxl_endpoint_decoder *cxled =
+ to_cxl_endpoint_decoder(&cxld->dev);
+
+ rc = cxl_dpa_set_mode(cxled, CXL_DECODER_PMEM);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static size_t attach_region_target(struct cxl_region *cxlr,
+ struct cxl_decoder *cxld, int pos)
+{
+ int rc;
+ struct cxl_endpoint_decoder *cxled =
+ to_cxl_endpoint_decoder(&cxld->dev);
+
+ rc = attach_target(cxlr, cxled, pos, TASK_INTERRUPTIBLE);
+
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static ssize_t commit_region(struct cxl_region *cxlr)
+{
+ struct cxl_region_params *p = &cxlr->params;
+ ssize_t rc;
+
+ rc = down_write_killable(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+
+ /* Already in the requested state? */
+ if (p->state >= CXL_CONFIG_COMMIT)
+ goto out;
+
+ /* Not ready to commit? */
+ if (p->state < CXL_CONFIG_ACTIVE) {
+ rc = -ENXIO;
+ goto out;
+ }
+
+ /*
+ * Invalidate caches before region setup to drop any speculative
+ * consumption of this address space
+ */
+ rc = cxl_region_invalidate_memregion(cxlr);
+ if (rc)
+ goto out;
+
+ rc = cxl_region_decode_commit(cxlr);
+ if (rc == 0)
+ p->state = CXL_CONFIG_COMMIT;
+out:
+ up_write(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+ return 0;
+}
+
+static struct cxl_region *
+devm_cxl_pmem_add_region(struct cxl_root_decoder *cxlrd,
+ struct cxl_decoder *cxld,
+ struct cxl_pmem_region_params *params, int id,
+ enum cxl_decoder_mode mode, enum cxl_decoder_type type)
+{
+ struct cxl_port *port;
+ struct cxl_region *cxlr;
+ struct cxl_region_params *p;
+ struct device *dev;
+ int rc;
+
+ if (!cxlrd)
+ return ERR_PTR(-EINVAL);
+
+ port = to_cxl_port(cxlrd->cxlsd.cxld.dev.parent);
+
+ cxlr = cxl_region_alloc(cxlrd, id);
+ if (IS_ERR(cxlr))
+ return cxlr;
+ cxlr->mode = mode;
+ cxlr->type = type;
+
+ dev = &cxlr->dev;
+ rc = dev_set_name(dev, "region%d", id);
+ if (rc)
+ goto err;
+
+ p = &cxlr->params;
+ p->uuid = params->uuid;
+ p->interleave_ways = params->nlabel;
+ p->interleave_granularity = params->ig;
+
+ /* Update region size */
+ if (update_region_size(cxlr, params->rawsize))
+ goto err;
+
+ /* Flush cxl wq */
+ cxl_wq_flush();
+
+ /* Clear DPA Size */
+ if (update_region_dpa_size(cxlr, cxld, 0))
+ goto err;
+
+ /* Update DPA mode */
+ if (update_region_dpa_mode(cxlr, cxld))
+ goto err;
+
+ /* Update DPA Size */
+ if (update_region_dpa_size(cxlr, cxld, params->rawsize))
+ goto err;
+
+ /* Attach region targets */
+ if (attach_region_target(cxlr, cxld, params->position))
+ goto err;
+
+ /* Commit Region */
+ if (commit_region(cxlr))
+ goto err;
+
+ rc = device_add(dev);
+ if (rc)
+ goto err;
+
+ rc = devm_add_action_or_reset(port->uport_dev, unregister_region, cxlr);
+ if (rc)
+ return ERR_PTR(rc);
+
+ dev_dbg(port->uport_dev, "%s: created %s\n",
+ dev_name(&cxlrd->cxlsd.cxld.dev), dev_name(dev));
+ return cxlr;
+
+err:
+ put_device(dev);
+ return ERR_PTR(rc);
+}
+
+struct cxl_region *cxl_create_pmem_region(struct cxl_root_decoder *cxlrd,
+ struct cxl_decoder *cxld,
+ struct cxl_pmem_region_params *params, 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_pmem_add_region(cxlrd, cxld, params, id,
+ CXL_DECODER_PMEM, CXL_DECODER_HOSTONLYMEM);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_create_pmem_region, "CXL");
+
static struct cxl_region *__create_region(struct cxl_root_decoder *cxlrd,
enum cxl_decoder_mode mode, int id)
{
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 9423ea3509ad..30c80e04cb27 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -759,6 +759,7 @@ DEFINE_FREE(put_cxl_port, struct cxl_port *, if (!IS_ERR_OR_NULL(_T)) put_device
int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd);
void cxl_bus_rescan(void);
void cxl_bus_drain(void);
+void cxl_wq_flush(void);
struct cxl_port *cxl_pci_find_port(struct pci_dev *pdev,
struct cxl_dport **dport);
struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd,
@@ -877,6 +878,9 @@ struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev);
int cxl_add_to_region(struct cxl_port *root,
struct cxl_endpoint_decoder *cxled);
struct cxl_dax_region *to_cxl_dax_region(struct device *dev);
+struct cxl_region *cxl_create_pmem_region(struct cxl_root_decoder *cxlrd,
+ struct cxl_decoder *cxld,
+ struct cxl_pmem_region_params *params, int id);
#else
static inline bool is_cxl_pmem_region(struct device *dev)
{
@@ -895,6 +899,13 @@ static inline struct cxl_dax_region *to_cxl_dax_region(struct device *dev)
{
return NULL;
}
+static inline struct cxl_region *cxl_create_pmem_region(
+ struct cxl_root_decoder *cxlrd,
+ struct cxl_decoder *cxld,
+ struct cxl_pmem_region_params *params, int id)
+{
+ return NULL;
+}
#endif
void cxl_endpoint_parse_cdat(struct cxl_port *port);
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH 15/20] cxl: Add a routine to find cxl root decoder on cxl bus
[not found] ` <CGME20250617124049epcas5p1de7eeee3b5ddd12ea221ca3ebf22f6e8@epcas5p1.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
2025-06-23 9:44 ` Jonathan Cameron
` (2 more replies)
0 siblings, 3 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
Add cxl_find_root_decoder to find root decoder on cxl bus. It is used to
find root decoder during region creation
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/cxl/core/port.c | 26 ++++++++++++++++++++++++++
drivers/cxl/cxl.h | 1 +
2 files changed, 27 insertions(+)
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 2452f7c15b2d..94d9322b8e38 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -513,6 +513,32 @@ struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev)
}
EXPORT_SYMBOL_NS_GPL(to_cxl_switch_decoder, "CXL");
+static int match_root_decoder(struct device *dev, void *data)
+{
+ return is_root_decoder(dev);
+}
+
+/**
+ * cxl_find_root_decoder() - find a cxl root decoder on cxl bus
+ * @port: any descendant port in root-cxl-port topology
+ */
+struct cxl_root_decoder *cxl_find_root_decoder(struct cxl_port *port)
+{
+ struct cxl_root *cxl_root __free(put_cxl_root) = find_cxl_root(port);
+ struct device *dev;
+
+ if (!cxl_root)
+ return NULL;
+
+ dev = device_find_child(&cxl_root->port.dev, NULL, match_root_decoder);
+
+ if (!dev)
+ return NULL;
+
+ return to_cxl_root_decoder(dev);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_find_root_decoder, "CXL");
+
static void cxl_ep_release(struct cxl_ep *ep)
{
put_device(ep->ep);
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 30c80e04cb27..2c6a782d0941 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -871,6 +871,7 @@ bool is_cxl_nvdimm_bridge(struct device *dev);
int devm_cxl_add_nvdimm(struct cxl_port *parent_port, struct cxl_memdev *cxlmd);
struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_port *port);
void cxl_region_discovery(struct cxl_port *port);
+struct cxl_root_decoder *cxl_find_root_decoder(struct cxl_port *port);
#ifdef CONFIG_CXL_REGION
bool is_cxl_pmem_region(struct device *dev);
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH 16/20] cxl/mem: Preserve cxl root decoder during mem probe
[not found] ` <CGME20250617124052epcas5p24aace8321ed09af8bdd1e8c30c20cd84@epcas5p2.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
Saved root decoder info is required for cxl region persistency
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/cxl/cxlmem.h | 1 +
drivers/cxl/mem.c | 2 ++
2 files changed, 3 insertions(+)
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index 2a25d1957ddb..a14e82d4c9aa 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -54,6 +54,7 @@ struct cxl_memdev {
struct cxl_nvdimm_bridge *cxl_nvb;
struct cxl_nvdimm *cxl_nvd;
struct cxl_port *endpoint;
+ struct cxl_root_decoder *cxlrd;
int id;
int depth;
};
diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
index aaea4eb178ef..c2e5d0e6b96b 100644
--- a/drivers/cxl/mem.c
+++ b/drivers/cxl/mem.c
@@ -152,6 +152,8 @@ static int cxl_mem_probe(struct device *dev)
return -ENXIO;
}
+ cxlmd->cxlrd = cxl_find_root_decoder(parent_port);
+
if (dport->rch)
endpoint_parent = parent_port->uport_dev;
else
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH 17/20] cxl/pmem: Preserve region information into nd_set
[not found] ` <CGME20250617124055epcas5p4978a3c139128bf5873c60ca0a10f5199@epcas5p4.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
Save region information stored in cxlr to nd_set during
cxl_pmem_region_probe in nd_set. This saved region information is being
stored into LSA, which will be used for cxl region persistence
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/cxl/pmem.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c
index f9c95996e937..ffcebb8d382f 100644
--- a/drivers/cxl/pmem.c
+++ b/drivers/cxl/pmem.c
@@ -308,6 +308,7 @@ 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_region_params *p = &cxlr->params;
struct cxl_nvdimm_bridge *cxl_nvb = cxlr->cxl_nvb;
struct cxl_pmem_region_info *info = NULL;
struct nd_interleave_set *nd_set;
@@ -388,12 +389,12 @@ static int cxl_pmem_region_probe(struct device *dev)
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;
+ nd_set->uuid = p->uuid;
+ nd_set->interleave_ways = p->interleave_ways;
+ nd_set->interleave_granularity = p->interleave_granularity;
+ nd_set->res = p->res;
+ nd_set->nr_targets = p->nr_targets;
+
ndr_desc.nd_set = nd_set;
cxlr_pmem->nd_region =
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH 18/20] cxl/pmem: Add support of cxl lsa 2.1 support in cxl pmem
[not found] ` <CGME20250617124058epcas5p2324bd3b1bf95d47f553d90fdc727e50d@epcas5p2.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
2025-06-23 9:48 ` Jonathan Cameron
2025-07-10 17:18 ` Dave Jiang
0 siblings, 2 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
Add support of cxl lsa 2.1 using NDD_CXL_LABEL flag. It also creates cxl
region based on region information parsed from LSA.
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/cxl/pmem.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c
index ffcebb8d382f..2733d79b32d5 100644
--- a/drivers/cxl/pmem.c
+++ b/drivers/cxl/pmem.c
@@ -58,6 +58,63 @@ static const struct attribute_group *cxl_dimm_attribute_groups[] = {
NULL
};
+static int match_ep_decoder(struct device *dev, void *data)
+{
+ struct cxl_decoder *cxld = to_cxl_decoder(dev);
+
+ if (!cxld->region)
+ return 1;
+ else
+ return 0;
+}
+
+static struct cxl_decoder *cxl_find_free_decoder(struct cxl_port *port)
+{
+ struct device *dev;
+
+ dev = device_find_child(&port->dev, NULL, match_ep_decoder);
+ if (!dev)
+ return NULL;
+
+ return to_cxl_decoder(dev);
+}
+
+static int create_pmem_region(struct nvdimm *nvdimm)
+{
+ struct cxl_nvdimm *cxl_nvd;
+ struct cxl_memdev *cxlmd;
+ struct cxl_nvdimm_bridge *cxl_nvb;
+ struct cxl_pmem_region_params *params;
+ struct cxl_root_decoder *cxlrd;
+ struct cxl_decoder *cxld;
+ struct cxl_region *cxlr;
+
+ if (!nvdimm)
+ return -ENOTTY;
+
+ if (!nvdimm_has_cxl_region(nvdimm))
+ return 0;
+
+ cxl_nvd = nvdimm_provider_data(nvdimm);
+ params = nvdimm_get_cxl_region_param(nvdimm);
+ cxlmd = cxl_nvd->cxlmd;
+ cxl_nvb = cxlmd->cxl_nvb;
+ cxlrd = cxlmd->cxlrd;
+
+ /* FIXME: Limitation: Region creation only when interleave way == 1 */
+ if (params->nlabel == 1) {
+ cxld = cxl_find_free_decoder(cxlmd->endpoint);
+ cxlr = cxl_create_pmem_region(cxlrd, cxld, params,
+ atomic_read(&cxlrd->region_id));
+ if (IS_ERR(cxlr))
+ dev_dbg(&cxlmd->dev, "Region Creation failed\n");
+ } else {
+ dev_dbg(&cxlmd->dev, "Region Creation is not supported with iw > 1\n");
+ }
+
+ return 0;
+}
+
static int cxl_nvdimm_probe(struct device *dev)
{
struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev);
@@ -74,6 +131,7 @@ static int cxl_nvdimm_probe(struct device *dev)
return rc;
set_bit(NDD_LABELING, &flags);
+ set_bit(NDD_CXL_LABEL, &flags);
set_bit(NDD_REGISTER_SYNC, &flags);
set_bit(ND_CMD_GET_CONFIG_SIZE, &cmd_mask);
set_bit(ND_CMD_GET_CONFIG_DATA, &cmd_mask);
@@ -86,6 +144,7 @@ static int cxl_nvdimm_probe(struct device *dev)
return -ENOMEM;
dev_set_drvdata(dev, nvdimm);
+ create_pmem_region(nvdimm);
return devm_add_action_or_reset(dev, unregister_nvdimm, nvdimm);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH 19/20] cxl/pmem_region: Prep patch to accommodate pmem_region attributes
[not found] ` <CGME20250617124101epcas5p4d54f34ebc5161b7cb816e352d144d9a1@epcas5p4.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
2025-06-23 9:53 ` Jonathan Cameron
0 siblings, 1 reply; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
Created a separate file core/pmem_region.c along with CONFIG_PMEM_REGION
Moved pmem_region related code from core/region.c to core/pmem_region.c
For region label update, need to create device attribute, which calls
nvdimm exported function thus making pmem_region dependent on libnvdimm.
Because of this dependency of pmem region on libnvdimm, segregated pmem
region related code from core/region.c
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/cxl/Kconfig | 12 ++
drivers/cxl/core/Makefile | 1 +
drivers/cxl/core/core.h | 8 +-
drivers/cxl/core/pmem_region.c | 222 +++++++++++++++++++++++++++++++++
drivers/cxl/core/port.c | 2 +-
drivers/cxl/core/region.c | 217 ++------------------------------
drivers/cxl/cxl.h | 42 +++++--
tools/testing/cxl/Kbuild | 1 +
8 files changed, 283 insertions(+), 222 deletions(-)
create mode 100644 drivers/cxl/core/pmem_region.c
diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
index 876469e23f7a..f0cbb096bfe7 100644
--- a/drivers/cxl/Kconfig
+++ b/drivers/cxl/Kconfig
@@ -128,6 +128,18 @@ config CXL_REGION
If unsure say 'y'
+config CXL_PMEM_REGION
+ bool "CXL: Pmem Region Support"
+ default CXL_BUS
+ depends on CXL_REGION
+ select LIBNVDIMM if CXL_BUS = y
+ help
+ Enable the CXL core to enumerate and provision CXL pmem regions.
+ A CXL pmem region need to update region label into LSA. For LSA
+ updation/deletion libnvdimm is required.
+
+ If unsure say 'y'
+
config CXL_REGION_INVALIDATION_TEST
bool "CXL: Region Cache Management Bypass (TEST)"
depends on CXL_REGION
diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile
index 9259bcc6773c..0ef2f3dd6c13 100644
--- a/drivers/cxl/core/Makefile
+++ b/drivers/cxl/core/Makefile
@@ -16,3 +16,4 @@ cxl_core-y += pmu.o
cxl_core-y += cdat.o
cxl_core-$(CONFIG_TRACING) += trace.o
cxl_core-$(CONFIG_CXL_REGION) += region.o
+cxl_core-$(CONFIG_CXL_PMEM_REGION) += pmem_region.o
diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index 800466f96a68..8111da17dfb4 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -22,7 +22,6 @@ void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled);
#define CXL_REGION_ATTR(x) (&dev_attr_##x.attr)
#define CXL_REGION_TYPE(x) (&cxl_region_type)
#define SET_CXL_REGION_ATTR(x) (&dev_attr_##x.attr),
-#define CXL_PMEM_REGION_TYPE(x) (&cxl_pmem_region_type)
#define CXL_DAX_REGION_TYPE(x) (&cxl_dax_region_type)
int cxl_region_init(void);
void cxl_region_exit(void);
@@ -59,10 +58,15 @@ static inline void cxl_region_exit(void)
#define CXL_REGION_ATTR(x) NULL
#define CXL_REGION_TYPE(x) NULL
#define SET_CXL_REGION_ATTR(x)
-#define CXL_PMEM_REGION_TYPE(x) NULL
#define CXL_DAX_REGION_TYPE(x) NULL
#endif
+#ifdef CONFIG_CXL_PMEM_REGION
+#define CXL_PMEM_REGION_TYPE (&cxl_pmem_region_type)
+#else
+#define CXL_PMEM_REGION_TYPE NULL
+#endif
+
struct cxl_send_command;
struct cxl_mem_query_commands;
int cxl_query_cmd(struct cxl_memdev *cxlmd,
diff --git a/drivers/cxl/core/pmem_region.c b/drivers/cxl/core/pmem_region.c
new file mode 100644
index 000000000000..a29526c27d40
--- /dev/null
+++ b/drivers/cxl/core/pmem_region.c
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2020 Intel Corporation. */
+#include <linux/device.h>
+#include <linux/memregion.h>
+#include <cxlmem.h>
+#include <cxl.h>
+#include "core.h"
+
+/**
+ * DOC: cxl pmem region
+ *
+ * The core CXL PMEM region infrastructure supports persistent memory
+ * region creation using LIBNVDIMM subsystem. It has dependency on
+ * LIBNVDIMM, pmem region need updation of cxl region information into
+ * LSA. LIBNVDIMM dependency is only for pmem region, it is therefore
+ * need this separate file.
+ */
+
+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 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,
+};
+
+static struct lock_class_key cxl_pmem_region_key;
+
+static int cxl_pmem_region_alloc(struct cxl_region *cxlr)
+{
+ struct cxl_region_params *p = &cxlr->params;
+ struct cxl_nvdimm_bridge *cxl_nvb;
+ struct device *dev;
+ int i;
+
+ guard(rwsem_read)(&cxl_region_rwsem);
+ if (p->state != CXL_CONFIG_COMMIT)
+ return -ENXIO;
+
+ struct cxl_pmem_region *cxlr_pmem __free(kfree) =
+ kzalloc(struct_size(cxlr_pmem, mapping, p->nr_targets), GFP_KERNEL);
+ if (!cxlr_pmem)
+ return -ENOMEM;
+
+ 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];
+
+ /*
+ * Regions never span CXL root devices, so by definition the
+ * bridge for one device is the same for all.
+ */
+ if (i == 0) {
+ cxl_nvb = cxl_find_nvdimm_bridge(cxlmd->endpoint);
+ if (!cxl_nvb)
+ return -ENODEV;
+ cxlr->cxl_nvb = cxl_nvb;
+ }
+ 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;
+ 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;
+ cxlr_pmem->cxlr = cxlr;
+ cxlr->cxlr_pmem = no_free_ptr(cxlr_pmem);
+
+ return 0;
+}
+
+static void cxlr_pmem_unregister(void *_cxlr_pmem)
+{
+ struct cxl_pmem_region *cxlr_pmem = _cxlr_pmem;
+ struct cxl_region *cxlr = cxlr_pmem->cxlr;
+ struct cxl_nvdimm_bridge *cxl_nvb = cxlr->cxl_nvb;
+
+ /*
+ * Either the bridge is in ->remove() context under the device_lock(),
+ * or cxlr_release_nvdimm() is cancelling the bridge's release action
+ * for @cxlr_pmem and doing it itself (while manually holding the bridge
+ * lock).
+ */
+ device_lock_assert(&cxl_nvb->dev);
+ cxlr->cxlr_pmem = NULL;
+ cxlr_pmem->cxlr = NULL;
+ device_unregister(&cxlr_pmem->dev);
+}
+
+static void cxlr_release_nvdimm(void *_cxlr)
+{
+ struct cxl_region *cxlr = _cxlr;
+ struct cxl_nvdimm_bridge *cxl_nvb = cxlr->cxl_nvb;
+
+ scoped_guard(device, &cxl_nvb->dev) {
+ if (cxlr->cxlr_pmem)
+ devm_release_action(&cxl_nvb->dev, cxlr_pmem_unregister,
+ cxlr->cxlr_pmem);
+ }
+ cxlr->cxl_nvb = NULL;
+ put_device(&cxl_nvb->dev);
+}
+
+/**
+ * devm_cxl_add_pmem_region() - add a cxl_region-to-nd_region bridge
+ * @cxlr: parent CXL region for this pmem region bridge device
+ *
+ * Return: 0 on success negative error code on failure.
+ */
+int devm_cxl_add_pmem_region(struct cxl_region *cxlr)
+{
+ struct cxl_pmem_region *cxlr_pmem;
+ struct cxl_nvdimm_bridge *cxl_nvb;
+ struct device *dev;
+ int rc;
+
+ rc = cxl_pmem_region_alloc(cxlr);
+ if (rc)
+ return rc;
+ cxlr_pmem = cxlr->cxlr_pmem;
+ cxl_nvb = cxlr->cxl_nvb;
+
+ 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));
+
+ scoped_guard(device, &cxl_nvb->dev) {
+ if (cxl_nvb->dev.driver)
+ rc = devm_add_action_or_reset(&cxl_nvb->dev,
+ cxlr_pmem_unregister,
+ cxlr_pmem);
+ else
+ rc = -ENXIO;
+ }
+
+ if (rc)
+ goto err_bridge;
+
+ /* @cxlr carries a reference on @cxl_nvb until cxlr_release_nvdimm */
+ return devm_add_action_or_reset(&cxlr->dev, cxlr_release_nvdimm, cxlr);
+
+err:
+ put_device(dev);
+err_bridge:
+ put_device(&cxl_nvb->dev);
+ cxlr->cxl_nvb = NULL;
+ return rc;
+}
+EXPORT_SYMBOL_NS_GPL(devm_cxl_add_pmem_region, "CXL");
+
+struct cxl_region *cxl_create_pmem_region(struct cxl_root_decoder *cxlrd,
+ struct cxl_decoder *cxld,
+ struct cxl_pmem_region_params *params, 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_pmem_add_region(cxlrd, cxld, params, id,
+ CXL_DECODER_PMEM, CXL_DECODER_HOSTONLYMEM);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_create_pmem_region, "CXL");
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 94d9322b8e38..7a26a4703180 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -59,7 +59,7 @@ static int cxl_device_id(const 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())
+ if (dev->type == CXL_PMEM_REGION_TYPE)
return CXL_DEVICE_PMEM_REGION;
if (dev->type == CXL_DAX_REGION_TYPE())
return CXL_DEVICE_DAX_REGION;
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index 8990e3c3474d..e817d3f2d2df 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -30,8 +30,6 @@
* 3. Decoder targets
*/
-static struct cxl_region *to_cxl_region(struct device *dev);
-
#define __ACCESS_ATTR_RO(_level, _name) { \
.attr = { .name = __stringify(_name), .mode = 0444 }, \
.show = _name##_access##_level##_show, \
@@ -2312,7 +2310,7 @@ bool is_cxl_region(struct device *dev)
}
EXPORT_SYMBOL_NS_GPL(is_cxl_region, "CXL");
-static struct cxl_region *to_cxl_region(struct device *dev)
+struct cxl_region *to_cxl_region(struct device *dev)
{
if (dev_WARN_ONCE(dev, dev->type != &cxl_region_type,
"not a cxl_region device\n"))
@@ -2320,6 +2318,7 @@ static struct cxl_region *to_cxl_region(struct device *dev)
return container_of(dev, struct cxl_region, dev);
}
+EXPORT_SYMBOL_NS_GPL(to_cxl_region, "CXL");
static void unregister_region(void *_cxlr)
{
@@ -2633,7 +2632,7 @@ static ssize_t commit_region(struct cxl_region *cxlr)
return 0;
}
-static struct cxl_region *
+struct cxl_region *
devm_cxl_pmem_add_region(struct cxl_root_decoder *cxlrd,
struct cxl_decoder *cxld,
struct cxl_pmem_region_params *params, int id,
@@ -2709,26 +2708,7 @@ devm_cxl_pmem_add_region(struct cxl_root_decoder *cxlrd,
put_device(dev);
return ERR_PTR(rc);
}
-
-struct cxl_region *cxl_create_pmem_region(struct cxl_root_decoder *cxlrd,
- struct cxl_decoder *cxld,
- struct cxl_pmem_region_params *params, 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_pmem_add_region(cxlrd, cxld, params, id,
- CXL_DECODER_PMEM, CXL_DECODER_HOSTONLYMEM);
-}
-EXPORT_SYMBOL_NS_GPL(cxl_create_pmem_region, "CXL");
+EXPORT_SYMBOL_NS_GPL(devm_cxl_pmem_add_region, "CXL");
static struct cxl_region *__create_region(struct cxl_root_decoder *cxlrd,
enum cxl_decoder_mode mode, int id)
@@ -2842,46 +2822,6 @@ 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");
-
struct cxl_poison_context {
struct cxl_port *port;
enum cxl_decoder_mode mode;
@@ -3146,64 +3086,6 @@ u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd,
return hpa;
}
-static struct lock_class_key cxl_pmem_region_key;
-
-static int cxl_pmem_region_alloc(struct cxl_region *cxlr)
-{
- struct cxl_region_params *p = &cxlr->params;
- struct cxl_nvdimm_bridge *cxl_nvb;
- struct device *dev;
- int i;
-
- guard(rwsem_read)(&cxl_region_rwsem);
- if (p->state != CXL_CONFIG_COMMIT)
- return -ENXIO;
-
- struct cxl_pmem_region *cxlr_pmem __free(kfree) =
- kzalloc(struct_size(cxlr_pmem, mapping, p->nr_targets), GFP_KERNEL);
- if (!cxlr_pmem)
- return -ENOMEM;
-
- 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];
-
- /*
- * Regions never span CXL root devices, so by definition the
- * bridge for one device is the same for all.
- */
- if (i == 0) {
- cxl_nvb = cxl_find_nvdimm_bridge(cxlmd->endpoint);
- if (!cxl_nvb)
- return -ENODEV;
- cxlr->cxl_nvb = cxl_nvb;
- }
- 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;
- 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;
- cxlr_pmem->cxlr = cxlr;
- cxlr->cxlr_pmem = no_free_ptr(cxlr_pmem);
-
- return 0;
-}
-
static void cxl_dax_region_release(struct device *dev)
{
struct cxl_dax_region *cxlr_dax = to_cxl_dax_region(dev);
@@ -3273,92 +3155,6 @@ static struct cxl_dax_region *cxl_dax_region_alloc(struct cxl_region *cxlr)
return cxlr_dax;
}
-static void cxlr_pmem_unregister(void *_cxlr_pmem)
-{
- struct cxl_pmem_region *cxlr_pmem = _cxlr_pmem;
- struct cxl_region *cxlr = cxlr_pmem->cxlr;
- struct cxl_nvdimm_bridge *cxl_nvb = cxlr->cxl_nvb;
-
- /*
- * Either the bridge is in ->remove() context under the device_lock(),
- * or cxlr_release_nvdimm() is cancelling the bridge's release action
- * for @cxlr_pmem and doing it itself (while manually holding the bridge
- * lock).
- */
- device_lock_assert(&cxl_nvb->dev);
- cxlr->cxlr_pmem = NULL;
- cxlr_pmem->cxlr = NULL;
- device_unregister(&cxlr_pmem->dev);
-}
-
-static void cxlr_release_nvdimm(void *_cxlr)
-{
- struct cxl_region *cxlr = _cxlr;
- struct cxl_nvdimm_bridge *cxl_nvb = cxlr->cxl_nvb;
-
- scoped_guard(device, &cxl_nvb->dev) {
- if (cxlr->cxlr_pmem)
- devm_release_action(&cxl_nvb->dev, cxlr_pmem_unregister,
- cxlr->cxlr_pmem);
- }
- cxlr->cxl_nvb = NULL;
- put_device(&cxl_nvb->dev);
-}
-
-/**
- * devm_cxl_add_pmem_region() - add a cxl_region-to-nd_region bridge
- * @cxlr: parent CXL region for this pmem region bridge device
- *
- * 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 cxl_nvdimm_bridge *cxl_nvb;
- struct device *dev;
- int rc;
-
- rc = cxl_pmem_region_alloc(cxlr);
- if (rc)
- return rc;
- cxlr_pmem = cxlr->cxlr_pmem;
- cxl_nvb = cxlr->cxl_nvb;
-
- 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));
-
- scoped_guard(device, &cxl_nvb->dev) {
- if (cxl_nvb->dev.driver)
- rc = devm_add_action_or_reset(&cxl_nvb->dev,
- cxlr_pmem_unregister,
- cxlr_pmem);
- else
- rc = -ENXIO;
- }
-
- if (rc)
- goto err_bridge;
-
- /* @cxlr carries a reference on @cxl_nvb until cxlr_release_nvdimm */
- return devm_add_action_or_reset(&cxlr->dev, cxlr_release_nvdimm, cxlr);
-
-err:
- put_device(dev);
-err_bridge:
- put_device(&cxl_nvb->dev);
- cxlr->cxl_nvb = NULL;
- return rc;
-}
-
static void cxlr_dax_unregister(void *_cxlr_dax)
{
struct cxl_dax_region *cxlr_dax = _cxlr_dax;
@@ -3646,7 +3442,10 @@ static int cxl_region_probe(struct device *dev)
switch (cxlr->mode) {
case CXL_DECODER_PMEM:
- return devm_cxl_add_pmem_region(cxlr);
+ if (IS_ENABLED(CONFIG_CXL_PMEM_REGION))
+ return devm_cxl_add_pmem_region(cxlr);
+ else
+ return -EINVAL;
case CXL_DECODER_RAM:
/*
* The region can not be manged by CXL if any portion of
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 2c6a782d0941..c6cd0c8d78a1 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -828,6 +828,7 @@ int cxl_dvsec_rr_decode(struct cxl_dev_state *cxlds,
struct cxl_endpoint_dvsec_info *info);
bool is_cxl_region(struct device *dev);
+struct cxl_region *to_cxl_region(struct device *dev);
extern struct bus_type cxl_bus_type;
@@ -874,11 +875,37 @@ void cxl_region_discovery(struct cxl_port *port);
struct cxl_root_decoder *cxl_find_root_decoder(struct cxl_port *port);
#ifdef CONFIG_CXL_REGION
-bool is_cxl_pmem_region(struct device *dev);
-struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev);
int cxl_add_to_region(struct cxl_port *root,
struct cxl_endpoint_decoder *cxled);
struct cxl_dax_region *to_cxl_dax_region(struct device *dev);
+struct cxl_region *devm_cxl_pmem_add_region(struct cxl_root_decoder *cxlrd,
+ struct cxl_decoder *cxld,
+ struct cxl_pmem_region_params *params, int id,
+ enum cxl_decoder_mode mode, enum cxl_decoder_type type);
+#else
+static inline int cxl_add_to_region(struct cxl_port *root,
+ struct cxl_endpoint_decoder *cxled)
+{
+ return 0;
+}
+static inline struct cxl_dax_region *to_cxl_dax_region(struct device *dev)
+{
+ return NULL;
+}
+static inline struct cxl_region *
+ devm_cxl_pmem_add_region(struct cxl_root_decoder *cxlrd,
+ struct cxl_decoder *cxld,
+ struct cxl_pmem_region_params *params, int id,
+ enum cxl_decoder_mode mode, enum cxl_decoder_type type)
+{
+ return NULL;
+}
+#endif
+
+#ifdef CONFIG_CXL_PMEM_REGION
+bool is_cxl_pmem_region(struct device *dev);
+struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev);
+int devm_cxl_add_pmem_region(struct cxl_region *cxlr);
struct cxl_region *cxl_create_pmem_region(struct cxl_root_decoder *cxlrd,
struct cxl_decoder *cxld,
struct cxl_pmem_region_params *params, int id);
@@ -891,17 +918,12 @@ static inline struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev)
{
return NULL;
}
-static inline int cxl_add_to_region(struct cxl_port *root,
- struct cxl_endpoint_decoder *cxled)
+static inline int devm_cxl_add_pmem_region(struct cxl_region *cxlr)
{
return 0;
}
-static inline struct cxl_dax_region *to_cxl_dax_region(struct device *dev)
-{
- return NULL;
-}
-static inline struct cxl_region *cxl_create_pmem_region(
- struct cxl_root_decoder *cxlrd,
+static inline struct cxl_region *
+ cxl_create_pmem_region(struct cxl_root_decoder *cxlrd,
struct cxl_decoder *cxld,
struct cxl_pmem_region_params *params, int id)
{
diff --git a/tools/testing/cxl/Kbuild b/tools/testing/cxl/Kbuild
index b1256fee3567..91f3a9076413 100644
--- a/tools/testing/cxl/Kbuild
+++ b/tools/testing/cxl/Kbuild
@@ -63,6 +63,7 @@ cxl_core-y += $(CXL_CORE_SRC)/pmu.o
cxl_core-y += $(CXL_CORE_SRC)/cdat.o
cxl_core-$(CONFIG_TRACING) += $(CXL_CORE_SRC)/trace.o
cxl_core-$(CONFIG_CXL_REGION) += $(CXL_CORE_SRC)/region.o
+cxl_core-$(CONFIG_CXL_PMEM_REGION) += $(CXL_CORE_SRC)/pmem_region.o
cxl_core-y += config_check.o
cxl_core-y += cxl_core_test.o
cxl_core-y += cxl_core_exports.o
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* [RFC PATCH 20/20] cxl/pmem_region: Add cxl region label updation and deletion device attributes
[not found] ` <CGME20250617124104epcas5p41105ad63af456b5cdb041e174a99925e@epcas5p4.samsung.com>
@ 2025-06-17 12:39 ` Neeraj Kumar
2025-06-23 9:56 ` Jonathan Cameron
0 siblings, 1 reply; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-17 12:39 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
Using these attributes region label is added/deleted into LSA. These
attributes are called from userspace (ndctl) after region creation.
Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
---
drivers/cxl/core/pmem_region.c | 103 +++++++++++++++++++++++++++++++++
drivers/cxl/cxl.h | 1 +
2 files changed, 104 insertions(+)
diff --git a/drivers/cxl/core/pmem_region.c b/drivers/cxl/core/pmem_region.c
index a29526c27d40..f582d796c21b 100644
--- a/drivers/cxl/core/pmem_region.c
+++ b/drivers/cxl/core/pmem_region.c
@@ -45,8 +45,111 @@ static void cxl_pmem_region_release(struct device *dev)
kfree(cxlr_pmem);
}
+static ssize_t region_label_update_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct cxl_pmem_region *cxlr_pmem = to_cxl_pmem_region(dev);
+ struct cxl_region *cxlr = cxlr_pmem->cxlr;
+ struct cxl_region_params *p = &cxlr->params;
+ ssize_t rc;
+ bool update;
+
+ rc = kstrtobool(buf, &update);
+ if (rc)
+ return rc;
+
+ rc = down_write_killable(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+
+ /* Region not yet committed */
+ if (update && p->state != CXL_CONFIG_COMMIT) {
+ dev_dbg(dev, "region not committed, can't update into LSA\n");
+ rc = -ENXIO;
+ goto out;
+ }
+
+ if (cxlr && cxlr->cxlr_pmem && cxlr->cxlr_pmem->nd_region) {
+ rc = nd_region_label_update(cxlr->cxlr_pmem->nd_region);
+
+ if (!rc)
+ p->region_label_state = 1;
+ }
+
+out:
+ up_write(&cxl_region_rwsem);
+
+ if (rc)
+ return rc;
+
+ return len;
+}
+
+static ssize_t region_label_update_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct cxl_pmem_region *cxlr_pmem = to_cxl_pmem_region(dev);
+ struct cxl_region *cxlr = cxlr_pmem->cxlr;
+ struct cxl_region_params *p = &cxlr->params;
+ ssize_t rc;
+
+ rc = down_read_interruptible(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+ rc = sysfs_emit(buf, "%d\n", p->region_label_state);
+ up_read(&cxl_region_rwsem);
+
+ return rc;
+}
+static DEVICE_ATTR_RW(region_label_update);
+
+static ssize_t region_label_delete_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct cxl_pmem_region *cxlr_pmem = to_cxl_pmem_region(dev);
+ struct cxl_region *cxlr = cxlr_pmem->cxlr;
+ struct cxl_region_params *p = &cxlr->params;
+ ssize_t rc;
+
+ rc = down_write_killable(&cxl_region_rwsem);
+ if (rc)
+ return rc;
+
+ if (cxlr && cxlr->cxlr_pmem && cxlr->cxlr_pmem->nd_region) {
+ rc = nd_region_label_delete(cxlr->cxlr_pmem->nd_region);
+ if (rc)
+ goto out;
+ }
+
+ if (!rc)
+ p->region_label_state = 0;
+
+out:
+ up_write(&cxl_region_rwsem);
+
+ if (rc)
+ return rc;
+
+ return len;
+}
+DEVICE_ATTR_WO(region_label_delete);
+
+static struct attribute *cxl_pmem_region_attrs[] = {
+ &dev_attr_region_label_update.attr,
+ &dev_attr_region_label_delete.attr,
+ NULL,
+};
+
+struct attribute_group cxl_pmem_region_group = {
+ .attrs = cxl_pmem_region_attrs,
+};
+
static const struct attribute_group *cxl_pmem_region_attribute_groups[] = {
&cxl_base_attribute_group,
+ &cxl_pmem_region_group,
NULL,
};
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index c6cd0c8d78a1..f67bf7df287a 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -498,6 +498,7 @@ enum cxl_config_state {
*/
struct cxl_region_params {
enum cxl_config_state state;
+ int region_label_state;
uuid_t uuid;
int interleave_ways;
int interleave_granularity;
--
2.34.1
^ permalink raw reply related [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 01/20] nvdimm/label: Introduce NDD_CXL_LABEL flag to set cxl label format
2025-06-17 12:39 ` [RFC PATCH 01/20] nvdimm/label: Introduce NDD_CXL_LABEL flag to set cxl label format Neeraj Kumar
@ 2025-06-20 16:40 ` Jonathan Cameron
2025-06-26 9:48 ` Neeraj Kumar
2025-07-02 18:02 ` Ira Weiny
2025-07-09 22:57 ` Dave Jiang
2 siblings, 1 reply; 66+ messages in thread
From: Jonathan Cameron @ 2025-06-20 16:40 UTC (permalink / raw)
To: Neeraj Kumar
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
On Tue, 17 Jun 2025 18:09:25 +0530
Neeraj Kumar <s.neeraj@samsung.com> wrote:
> NDD_CXL_LABEL is introduced to set cxl LSA 2.1 label format
> Accordingly updated label index version
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
A few local comments. I'll need to read on to figure out how this
fits in generally.
> ---
> drivers/nvdimm/dimm.c | 1 +
> drivers/nvdimm/dimm_devs.c | 10 ++++++++++
> drivers/nvdimm/label.c | 16 ++++++++++++----
> drivers/nvdimm/nd.h | 1 +
> include/linux/libnvdimm.h | 3 +++
> 5 files changed, 27 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c
> index 91d9163ee303..8753b5cd91cc 100644
> --- a/drivers/nvdimm/dimm.c
> +++ b/drivers/nvdimm/dimm.c
> @@ -62,6 +62,7 @@ static int nvdimm_probe(struct device *dev)
> if (rc < 0)
> dev_dbg(dev, "failed to unlock dimm: %d\n", rc);
>
> + ndd->cxl = nvdimm_check_cxl_label_format(ndd->dev);
>
> /*
> * EACCES failures reading the namespace label-area-properties
> diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
> index 21498d461fde..e8f545f889fd 100644
> --- a/drivers/nvdimm/dimm_devs.c
> +++ b/drivers/nvdimm/dimm_devs.c
> @@ -18,6 +18,16 @@
>
> static DEFINE_IDA(dimm_ida);
>
> +bool nvdimm_check_cxl_label_format(struct device *dev)
> +{
> + struct nvdimm *nvdimm = to_nvdimm(dev);
> +
> + if (test_bit(NDD_CXL_LABEL, &nvdimm->flags))
> + return true;
> +
> + return false;
return test_bit(NDD_CXL_LABEL, &nvdimm->flags);
Unless this is going to get more complex in later patches, in which case
may be fine to ignore this comment.
> +}
> +
> /*
> * Retrieve bus and dimm handle and return if this bus supports
> * get_config_data commands
> diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
> index 082253a3a956..48b5ba90216d 100644
> --- a/drivers/nvdimm/label.c
> +++ b/drivers/nvdimm/label.c
> @@ -687,11 +687,19 @@ static int nd_label_write_index(struct nvdimm_drvdata *ndd, int index, u32 seq,
> - (unsigned long) to_namespace_index(ndd, 0);
> nsindex->labeloff = __cpu_to_le64(offset);
> nsindex->nslot = __cpu_to_le32(nslot);
> - nsindex->major = __cpu_to_le16(1);
> - if (sizeof_namespace_label(ndd) < 256)
> +
> + /* Support CXL LSA 2.1 label format */
Might be good to sprinkle some extra details in the references.
E.g. CXL r3.2 Table 9-9 Label Index Block Layout
> + if (ndd->cxl) {
> + nsindex->major = __cpu_to_le16(2);
> nsindex->minor = __cpu_to_le16(1);
> - else
> - nsindex->minor = __cpu_to_le16(2);
> + } else {
> + nsindex->major = __cpu_to_le16(1);
Same for these. Case of making reviewers jobs easier by
giving them breadcrumb trails to follow.
> + if (sizeof_namespace_label(ndd) < 256)
> + nsindex->minor = __cpu_to_le16(1);
> + else
> + nsindex->minor = __cpu_to_le16(2);
> + }
> +
> nsindex->checksum = __cpu_to_le64(0);
> if (flags & ND_NSINDEX_INIT) {
> unsigned long *free = (unsigned long *) nsindex->free;
> diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
> index 5ca06e9a2d29..304f0e9904f1 100644
> --- a/drivers/nvdimm/nd.h
> +++ b/drivers/nvdimm/nd.h
> @@ -522,6 +522,7 @@ void nvdimm_set_labeling(struct device *dev);
> void nvdimm_set_locked(struct device *dev);
> void nvdimm_clear_locked(struct device *dev);
> int nvdimm_security_setup_events(struct device *dev);
> +bool nvdimm_check_cxl_label_format(struct device *dev);
> #if IS_ENABLED(CONFIG_NVDIMM_KEYS)
> int nvdimm_security_unlock(struct device *dev);
> #else
> diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
> index e772aae71843..0a55900842c8 100644
> --- a/include/linux/libnvdimm.h
> +++ b/include/linux/libnvdimm.h
> @@ -44,6 +44,9 @@ enum {
> /* dimm provider wants synchronous registration by __nvdimm_create() */
> NDD_REGISTER_SYNC = 8,
>
> + /* dimm supports region labels (LSA Format 2.1) */
> + NDD_CXL_LABEL = 9,
> +
> /* need to set a limit somewhere, but yes, this is likely overkill */
> ND_IOCTL_MAX_BUFLEN = SZ_4M,
> ND_CMD_MAX_ELEM = 5,
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 05/20] nvdimm/region_label: Add region label updation routine
2025-06-17 12:39 ` [RFC PATCH 05/20] nvdimm/region_label: Add region label updation routine Neeraj Kumar
@ 2025-06-23 9:05 ` Jonathan Cameron
2025-06-26 9:54 ` Neeraj Kumar
2025-07-17 22:53 ` Fabio M. De Francesco
1 sibling, 1 reply; 66+ messages in thread
From: Jonathan Cameron @ 2025-06-23 9:05 UTC (permalink / raw)
To: Neeraj Kumar
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
On Tue, 17 Jun 2025 18:09:29 +0530
Neeraj Kumar <s.neeraj@samsung.com> wrote:
Add region label update routine
> Added __pmem_region_label_update region label update routine to update
> region label
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
A few trivial comments inline.
Jonathan
> ---
> drivers/nvdimm/label.c | 142 ++++++++++++++++++++++++++++++++
> drivers/nvdimm/label.h | 2 +
> drivers/nvdimm/namespace_devs.c | 12 +++
> drivers/nvdimm/nd.h | 20 +++++
> include/linux/libnvdimm.h | 8 ++
> 5 files changed, 184 insertions(+)
>
> diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
> index d5cfaa99f976..7f33d14ce0ef 100644
> --- a/drivers/nvdimm/label.c
> +++ b/drivers/nvdimm/label.c
> @@ -381,6 +381,16 @@ static void nsl_calculate_checksum(struct nvdimm_drvdata *ndd,
> nsl_set_checksum(ndd, nd_label, sum);
> }
>
> +static void rgl_calculate_checksum(struct nvdimm_drvdata *ndd,
> + struct cxl_region_label *rg_label)
> +{
> + u64 sum;
> +
> + rgl_set_checksum(rg_label, 0);
> + sum = nd_fletcher64(rg_label, sizeof_namespace_label(ndd), 1);
> + rgl_set_checksum(rg_label, sum);
> +}
> +
> static bool slot_valid(struct nvdimm_drvdata *ndd,
> struct nd_lsa_label *nd_label, u32 slot)
> {
> @@ -1117,6 +1127,138 @@ int nd_pmem_namespace_label_update(struct nd_region *nd_region,
> return 0;
> }
>
> +static int __pmem_region_label_update(struct nd_region *nd_region,
> + struct nd_mapping *nd_mapping, int pos, unsigned long flags)
> +{
> + struct nd_interleave_set *nd_set = nd_region->nd_set;
> + struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
> + struct nd_lsa_label *nd_label;
> + struct cxl_region_label *rg_label;
> + struct nd_namespace_index *nsindex;
> + struct nd_label_ent *label_ent;
> + unsigned long *free;
> + u32 nslot, slot;
> + size_t offset;
> + int rc;
> + uuid_t tmp;
> +
> + if (!preamble_next(ndd, &nsindex, &free, &nslot))
> + return -ENXIO;
> +
> + /* allocate and write the label to the staging (next) index */
> + slot = nd_label_alloc_slot(ndd);
> + if (slot == UINT_MAX)
> + return -ENXIO;
> + dev_dbg(ndd->dev, "allocated: %d\n", slot);
> +
> + nd_label = to_label(ndd, slot);
> +
> + memset(nd_label, 0, sizeof_namespace_label(ndd));
> + rg_label = &nd_label->rg_label;
> +
> + /* Set Region Label Format identification UUID */
> + uuid_parse(CXL_REGION_UUID, &tmp);
> + export_uuid(nd_label->rg_label.type, &tmp);
> +
> + /* Set Current Region Label UUID */
> + export_uuid(nd_label->rg_label.uuid, &nd_set->uuid);
> +
> + rg_label->flags = __cpu_to_le32(flags);
> + rg_label->nlabel = __cpu_to_le16(nd_region->ndr_mappings);
> + rg_label->position = __cpu_to_le16(pos);
> + rg_label->dpa = __cpu_to_le64(nd_mapping->start);
> + rg_label->rawsize = __cpu_to_le64(nd_mapping->size);
> + rg_label->hpa = __cpu_to_le64(nd_set->res->start);
> + rg_label->slot = __cpu_to_le32(slot);
> + rg_label->ig = __cpu_to_le32(nd_set->interleave_granularity);
> + rg_label->align = __cpu_to_le16(0);
> +
> + /* Update fletcher64 Checksum */
> + rgl_calculate_checksum(ndd, rg_label);
> +
> + /* update label */
> + offset = nd_label_offset(ndd, nd_label);
> + rc = nvdimm_set_config_data(ndd, offset, nd_label,
> + sizeof_namespace_label(ndd));
> + if (rc < 0) {
> + nd_label_free_slot(ndd, slot);
> + return rc;
> + }
> +
> + /* Garbage collect the previous label */
> + mutex_lock(&nd_mapping->lock);
Perhaps use
guard(mutex)(&nd_mapping->lock);
so you can directly return in the error path below and simplify the flow
a tiny bit.
> + list_for_each_entry(label_ent, &nd_mapping->labels, list) {
> + if (!label_ent->label)
> + continue;
> + if (rgl_uuid_equal(&label_ent->label->rg_label, &nd_set->uuid))
> + reap_victim(nd_mapping, label_ent);
> + }
> +
> + /* update index */
> + rc = nd_label_write_index(ndd, ndd->ns_next,
> + nd_inc_seq(__le32_to_cpu(nsindex->seq)), 0);
> +
With guard this can be
if (rc)
return rec;
list_for_each...
> + if (rc == 0) {
> + list_for_each_entry(label_ent, &nd_mapping->labels, list)
> + if (!label_ent->label) {
> + label_ent->label = nd_label;
> + nd_label = NULL;
> + break;
> + }
> + dev_WARN_ONCE(&nd_region->dev, nd_label,
> + "failed to track label: %d\n",
> + to_slot(ndd, nd_label));
> + if (nd_label)
> + rc = -ENXIO;
> + }
> + mutex_unlock(&nd_mapping->lock);
> +
> + return rc;
> +}
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 06/20] nvdimm/region_label: Add region label deletion routine
2025-06-17 12:39 ` [RFC PATCH 06/20] nvdimm/region_label: Add region label deletion routine Neeraj Kumar
@ 2025-06-23 9:09 ` Jonathan Cameron
2025-06-26 9:55 ` Neeraj Kumar
0 siblings, 1 reply; 66+ messages in thread
From: Jonathan Cameron @ 2025-06-23 9:09 UTC (permalink / raw)
To: Neeraj Kumar
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
On Tue, 17 Jun 2025 18:09:30 +0530
Neeraj Kumar <s.neeraj@samsung.com> wrote:
> Added cxl v2.1 format region label deletion routine. This function is
> used to delete region label from LSA
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
> ---
> drivers/nvdimm/label.c | 75 ++++++++++++++++++++++++++++++---
> drivers/nvdimm/label.h | 6 +++
> drivers/nvdimm/namespace_devs.c | 12 ++++++
> drivers/nvdimm/nd.h | 9 ++++
> include/linux/libnvdimm.h | 1 +
> 5 files changed, 98 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
> index 7f33d14ce0ef..9381c50086fc 100644
> --- a/drivers/nvdimm/label.c
> +++ b/drivers/nvdimm/label.c
> @@ -1034,7 +1034,8 @@ static int init_labels(struct nd_mapping *nd_mapping, int num_labels)
> return max(num_labels, old_num_labels);
> }
>
> -static int del_labels(struct nd_mapping *nd_mapping, uuid_t *uuid)
> +static int del_labels(struct nd_mapping *nd_mapping, uuid_t *uuid,
> + enum label_type ltype)
> {
> struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
> struct nd_label_ent *label_ent, *e;
> @@ -1058,8 +1059,18 @@ static int del_labels(struct nd_mapping *nd_mapping, uuid_t *uuid)
> if (!nd_label)
> continue;
> active++;
> - if (!nsl_uuid_equal(ndd, &nd_label->ns_label, uuid))
> - continue;
> +
> + if (ltype == NS_LABEL_TYPE) {
Perhaps a switch is more appropriate here.
> + if (!nsl_uuid_equal(ndd, &nd_label->ns_label, uuid))
> + continue;
> + } else if (ltype == RG_LABEL_TYPE) {
> + if (!nsl_uuid_equal(ndd, &nd_label->ns_label, uuid))
> + continue;
> + } else {
> + dev_err(ndd->dev, "Invalid label type\n");
> + return 0;
> + }
> +
> active--;
> slot = to_slot(ndd, nd_label);
> nd_label_free_slot(ndd, slot);
> @@ -1259,6 +1271,59 @@ int nd_pmem_region_label_update(struct nd_region *nd_region)
> return 0;
> }
>
> +int nd_pmem_region_label_delete(struct nd_region *nd_region)
> +{
> + int i, rc;
> + struct nd_interleave_set *nd_set = nd_region->nd_set;
> + struct nd_label_ent *label_ent;
> + bool is_non_rgl = false;
> + int ns_region_cnt = 0;
> +
> + for (i = 0; i < nd_region->ndr_mappings; i++) {
> + struct nd_mapping *nd_mapping = &nd_region->mapping[i];
> + struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
> +
> + /* Find non cxl format supported ndr_mappings */
> + if (!ndd->cxl)
> + is_non_rgl = true;
> +
> + /* Find if any NS label using this region */
> + mutex_lock(&nd_mapping->lock);
> + list_for_each_entry(label_ent, &nd_mapping->labels, list) {
> + if (!label_ent->label)
> + continue;
> +
> + /* Check if any available NS labels has same
Looks like wrong style for multiline comments in this file.
/*
* Check ...
> + * region_uuid in LSA
> + */
> + if (nsl_region_uuid_equal(&label_ent->label->ns_label,
> + &nd_set->uuid))
> + ns_region_cnt++;
> + }
> + mutex_unlock(&nd_mapping->lock);
> + }
> +
> + if (is_non_rgl) {
> + dev_dbg(&nd_region->dev, "Region label deletion unsupported\n");
> + return -EINVAL;
Why not bail out where you originally detect that above?
> + }
> +
> + if (ns_region_cnt) {
> + dev_dbg(&nd_region->dev, "Region/Namespace label in use\n");
> + return -EBUSY;
> + }
> +
> + for (i = 0; i < nd_region->ndr_mappings; i++) {
> + struct nd_mapping *nd_mapping = &nd_region->mapping[i];
> +
> + rc = del_labels(nd_mapping, &nd_set->uuid, RG_LABEL_TYPE);
> + if (rc)
> + return rc;
> + }
> +
> + return 0;
> +}
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 07/20] nvdimm/namespace_label: Update namespace init_labels and its region_uuid
2025-06-17 12:39 ` [RFC PATCH 07/20] nvdimm/namespace_label: Update namespace init_labels and its region_uuid Neeraj Kumar
@ 2025-06-23 9:11 ` Jonathan Cameron
2025-06-26 9:58 ` Neeraj Kumar
0 siblings, 1 reply; 66+ messages in thread
From: Jonathan Cameron @ 2025-06-23 9:11 UTC (permalink / raw)
To: Neeraj Kumar
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
On Tue, 17 Jun 2025 18:09:31 +0530
Neeraj Kumar <s.neeraj@samsung.com> wrote:
> nd_mapping->labels maintains the list of labels present into LSA.
> init_labels function prepares this list while adding new label
init_labels() prepares
> into LSA and updates nd_mapping->labels accordingly. During cxl
> region creation nd_mapping->labels list and LSA was updated with
> one region label. Therefore during new namespace label creation
> pre-include the previously created region label, so increase
> num_labels count by 1.
>
> Also updated nsl_set_region_uuid with region uuid with which
> namespace is associated with.
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
> ---
> drivers/nvdimm/label.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
> index 9381c50086fc..108100c4bf44 100644
> --- a/drivers/nvdimm/label.c
> +++ b/drivers/nvdimm/label.c
> @@ -947,7 +947,7 @@ static int __pmem_label_update(struct nd_region *nd_region,
> nsl_set_slot(ndd, ns_label, slot);
> nsl_set_alignment(ndd, ns_label, 0);
> nsl_set_type_guid(ndd, ns_label, &nd_set->type_guid);
> - nsl_set_region_uuid(ndd, ns_label, NULL);
> + nsl_set_region_uuid(ndd, ns_label, &nd_set->uuid);
> nsl_set_claim_class(ndd, ns_label, ndns->claim_class);
> nsl_calculate_checksum(ndd, ns_label);
> nd_dbg_dpa(nd_region, ndd, res, "\n");
> @@ -1114,7 +1114,8 @@ int nd_pmem_namespace_label_update(struct nd_region *nd_region,
> count++;
> WARN_ON_ONCE(!count);
>
> - rc = init_labels(nd_mapping, count);
> + /* Adding 1 to pre include the already added region label */
> + rc = init_labels(nd_mapping, count + 1);
> if (rc < 0)
> return rc;
>
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 08/20] nvdimm/label: Include region label in slot validation
2025-06-17 12:39 ` [RFC PATCH 08/20] nvdimm/label: Include region label in slot validation Neeraj Kumar
@ 2025-06-23 9:13 ` Jonathan Cameron
2025-06-26 10:00 ` Neeraj Kumar
0 siblings, 1 reply; 66+ messages in thread
From: Jonathan Cameron @ 2025-06-23 9:13 UTC (permalink / raw)
To: Neeraj Kumar
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
On Tue, 17 Jun 2025 18:09:32 +0530
Neeraj Kumar <s.neeraj@samsung.com> wrote:
> slot validation routine validates label slot by calculating label
> checksum. It was only validating namespace label. This changeset also
> validates region label if present.
>
> Also validate and calculate lsa v2.1 namespace label checksum
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
> diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
> index 1e5a68013735..ca8256b31472 100644
> --- a/drivers/nvdimm/nd.h
> +++ b/drivers/nvdimm/nd.h
> @@ -331,6 +331,22 @@ static inline bool nsl_region_uuid_equal(struct nd_namespace_label *ns_label,
> return uuid_equal(&tmp, uuid);
> }
>
> +static inline bool is_region_label(struct nvdimm_drvdata *ndd,
> + struct nd_lsa_label *nd_label)
> +{
> + uuid_t ns_type, region_type;
> +
> + if (ndd->cxl) {
> + uuid_parse(CXL_REGION_UUID, ®ion_type);
> + import_uuid(&ns_type, nd_label->ns_label.cxl.type);
> + if (uuid_equal(®ion_type, &ns_type))
> + return true;
> + else
> + return false;
return uuid_equal(®_type, &ns_type);
> + } else
{}
for all legs if one needs it.
However, if you aren't going to add more code here later, just flip the condition
and exit early.
if (!ndd->cxl)
return false;
uuid_parse...
> + return false;
> +}
> +
> static inline bool rgl_uuid_equal(struct cxl_region_label *rg_label,
> const uuid_t *uuid)
> {
> @@ -340,6 +356,11 @@ static inline bool rgl_uuid_equal(struct cxl_region_label *rg_label,
> return uuid_equal(&tmp, uuid);
> }
>
> +static inline u32 rgl_get_slot(struct cxl_region_label *rg_label)
> +{
> + return __le32_to_cpu(rg_label->slot);
> +}
> +
> static inline u64 rgl_get_checksum(struct cxl_region_label *rg_label)
> {
> return __le64_to_cpu(rg_label->checksum);
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 12/20] nvdimm/namespace_label: Skip region label during namespace creation
2025-06-17 12:39 ` [RFC PATCH 12/20] nvdimm/namespace_label: Skip region label during namespace creation Neeraj Kumar
@ 2025-06-23 9:17 ` Jonathan Cameron
2025-06-26 10:02 ` Neeraj Kumar
0 siblings, 1 reply; 66+ messages in thread
From: Jonathan Cameron @ 2025-06-23 9:17 UTC (permalink / raw)
To: Neeraj Kumar
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
On Tue, 17 Jun 2025 18:09:36 +0530
Neeraj Kumar <s.neeraj@samsung.com> wrote:
> During namespace creation skip presence of region label if present.
> Also preserve region label into labels list if present.
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
> ---
> drivers/nvdimm/namespace_devs.c | 48 +++++++++++++++++++++++++++++----
> 1 file changed, 43 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
> index b081661b7aaa..ca8f8546170c 100644
> --- a/drivers/nvdimm/namespace_devs.c
> +++ b/drivers/nvdimm/namespace_devs.c
> @@ -1976,6 +1976,10 @@ static struct device **scan_labels(struct nd_region *nd_region)
> if (!nd_label)
> continue;
>
> + /* skip region labels if present */
> + if (is_region_label(ndd, nd_label))
> + continue;
> +
> /* skip labels that describe extents outside of the region */
> if (nsl_get_dpa(ndd, &nd_label->ns_label) < nd_mapping->start ||
> nsl_get_dpa(ndd, &nd_label->ns_label) > map_end)
> @@ -2014,9 +2018,29 @@ static struct device **scan_labels(struct nd_region *nd_region)
>
> if (count == 0) {
> struct nd_namespace_pmem *nspm;
> + for (i = 0; i < nd_region->ndr_mappings; i++) {
> + struct nd_label_ent *le, *e;
> + LIST_HEAD(list);
>
> - /* Publish a zero-sized namespace for userspace to configure. */
> - nd_mapping_free_labels(nd_mapping);
> + nd_mapping = &nd_region->mapping[i];
> + if (list_empty(&nd_mapping->labels))
> + continue;
> +
> + list_for_each_entry_safe(le, e, &nd_mapping->labels,
> + list) {
> + struct nd_lsa_label *nd_label = le->label;
> +
> + /* preserve region labels if present */
> + if (is_region_label(ndd, nd_label))
> + list_move_tail(&le->list, &list);
> + }
> +
> + /* Publish a zero-sized namespace for userspace
Comment syntax as before looks to be inconsistent with file.
> + * to configure.
> + */
> + nd_mapping_free_labels(nd_mapping);
> + list_splice_init(&list, &nd_mapping->labels);
> + }
> nspm = kzalloc(sizeof(*nspm), GFP_KERNEL);
> if (!nspm)
> goto err;
> @@ -2028,7 +2052,7 @@ static struct device **scan_labels(struct nd_region *nd_region)
> } else if (is_memory(&nd_region->dev)) {
> /* clean unselected labels */
> for (i = 0; i < nd_region->ndr_mappings; i++) {
> - struct list_head *l, *e;
> + struct nd_label_ent *le, *e;
> LIST_HEAD(list);
> int j;
>
> @@ -2039,10 +2063,24 @@ static struct device **scan_labels(struct nd_region *nd_region)
> }
>
> j = count;
> - list_for_each_safe(l, e, &nd_mapping->labels) {
> + list_for_each_entry_safe(le, e, &nd_mapping->labels,
> + list) {
> + struct nd_lsa_label *nd_label = le->label;
> +
> + /* preserve region labels */
> + if (is_region_label(ndd, nd_label)) {
> + list_move_tail(&le->list, &list);
> + continue;
> + }
> +
> + /* Once preserving selected ns label done
Comment syntax.
> + * break out of loop
> + */
> if (!j--)
> break;
> - list_move_tail(l, &list);
> +
> + /* preserve selected ns label */
> + list_move_tail(&le->list, &list);
> }
> nd_mapping_free_labels(nd_mapping);
> list_splice_init(&list, &nd_mapping->labels);
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 13/20] cxl/mem: Refactor cxl pmem region auto-assembling
2025-06-17 12:39 ` [RFC PATCH 13/20] cxl/mem: Refactor cxl pmem region auto-assembling Neeraj Kumar
@ 2025-06-23 9:20 ` Jonathan Cameron
2025-06-26 10:03 ` Neeraj Kumar
2025-07-10 0:38 ` Dave Jiang
1 sibling, 1 reply; 66+ messages in thread
From: Jonathan Cameron @ 2025-06-23 9:20 UTC (permalink / raw)
To: Neeraj Kumar
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
On Tue, 17 Jun 2025 18:09:37 +0530
Neeraj Kumar <s.neeraj@samsung.com> wrote:
> In 84ec985944ef3, For cxl pmem region auto-assembly after endpoint port
> probing, cxl_nvd presence was required. And for cxl region persistency,
> region creation happens during nvdimm_probe which need the completion
> of endpoint probe.
>
> It is therefore refactored cxl pmem region auto-assembly after endpoint
> probing to cxl mem probing
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
For ordering requirements this needs more eyes. I've never cared that
much about he persistency and auto assembly code so not something I have
a good mental model of!
> ---
> drivers/cxl/core/port.c | 38 ++++++++++++++++++++++++++++++++++++++
> drivers/cxl/cxl.h | 1 +
> drivers/cxl/mem.c | 27 ++++++++++++++++++---------
> drivers/cxl/port.c | 38 --------------------------------------
> 4 files changed, 57 insertions(+), 47 deletions(-)
> diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
> index 2f03a4d5606e..aaea4eb178ef 100644
> --- a/drivers/cxl/mem.c
> +++ b/drivers/cxl/mem.c
> @@ -180,6 +171,24 @@ static int cxl_mem_probe(struct device *dev)
> return rc;
> }
>
> + if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM)) {
> + rc = devm_cxl_add_nvdimm(parent_port, cxlmd);
> + if (rc) {
> + if (rc == -ENODEV)
> + dev_info(dev, "PMEM disabled by platform\n");
> + return rc;
> + }
> + }
> +
> + /*
> + * Now that all endpoint decoders are successfully enumerated, try to
> + * assemble region autodiscovery from committed decoders.
> + * Earlier it was part of cxl_endpoint_port_probe, So moved it here
I would drop this history statement. Good to have in the patch description
but no point in keeping it in the code. Just state what the requirements
are now.
> + * as cxl_nvd of the memdev needs to be available during the pmem
> + * region auto-assembling
> + */
> + cxl_region_discovery(cxlmd->endpoint);
> +
> /*
> * The kernel may be operating out of CXL memory on this device,
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 14/20] cxl/region: Add cxl pmem region creation routine for region persistency
2025-06-17 12:39 ` [RFC PATCH 14/20] cxl/region: Add cxl pmem region creation routine for region persistency Neeraj Kumar
@ 2025-06-23 9:43 ` Jonathan Cameron
2025-06-26 10:23 ` Neeraj Kumar
2025-07-10 15:59 ` Dave Jiang
1 sibling, 1 reply; 66+ messages in thread
From: Jonathan Cameron @ 2025-06-23 9:43 UTC (permalink / raw)
To: Neeraj Kumar
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
On Tue, 17 Jun 2025 18:09:38 +0530
Neeraj Kumar <s.neeraj@samsung.com> wrote:
> Added exported cxl_create_pmem_region routine to create cxl pmem region
For function names always add () after and drop 'function/routine' etc.
Ends up shorter and easier to read.
> from LSA parsed cxl region information.
> Inspirition for the function is taken from ndctl device attribute
> (_store) call. It allocates cxlr and fills information parsed from LSA
> and calls device_add(&cxlr->dev) to initiates further region creation
> porbes
Spell check.
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
> ---
> drivers/cxl/core/port.c | 6 ++
> drivers/cxl/core/region.c | 208 ++++++++++++++++++++++++++++++++++++++
> drivers/cxl/cxl.h | 11 ++
> 3 files changed, 225 insertions(+)
>
> diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
> index b98b1ccffd1c..8990e3c3474d 100644
> --- a/drivers/cxl/core/region.c
> +++ b/drivers/cxl/core/region.c
> @@ -2522,6 +2522,214 @@ static ssize_t create_ram_region_show(struct device *dev,
> return __create_region_show(to_cxl_root_decoder(dev), buf);
> }
>
> +static ssize_t update_region_size(struct cxl_region *cxlr, u64 val)
> +{
> + int rc;
> +
> + rc = down_write_killable(&cxl_region_rwsem);
ACQUIRE() as mentioned below.
> + if (rc)
> + return rc;
> +
> + if (val)
> + rc = alloc_hpa(cxlr, val);
> + else
> + rc = free_hpa(cxlr);
> + up_write(&cxl_region_rwsem);
> +
> + if (rc)
> + return rc;
return rc;
> +
> + return 0;
> +}
> +
> +static ssize_t update_region_dpa_size(struct cxl_region *cxlr,
> + struct cxl_decoder *cxld,
> + unsigned long long size)
> +{
> + int rc;
> + struct cxl_endpoint_decoder *cxled =
> + to_cxl_endpoint_decoder(&cxld->dev);
> +
> + if (!IS_ALIGNED(size, SZ_256M))
> + return -EINVAL;
> +
> + rc = cxl_dpa_free(cxled);
> + if (rc)
> + return rc;
> +
> + if (size == 0)
> + return 0;
> +
> + rc = cxl_dpa_alloc(cxled, size);
return cxl_dpa_alloc()
Unless something more is getting added here in later patches in which case
you can ignore this comment.
> + if (rc)
> + return rc;
> +
> + return 0;
> +}
> +
> +static ssize_t update_region_dpa_mode(struct cxl_region *cxlr,
> + struct cxl_decoder *cxld)
> +{
> + int rc;
> + struct cxl_endpoint_decoder *cxled =
> + to_cxl_endpoint_decoder(&cxld->dev);
Maybe don't bother with local variable and just put this
below as the parameter.
> +
> + rc = cxl_dpa_set_mode(cxled, CXL_DECODER_PMEM);
return cxl_dpa_set_mode()
> + if (rc)
> + return rc;
> +
> + return 0;
> +}
> +
> +static size_t attach_region_target(struct cxl_region *cxlr,
> + struct cxl_decoder *cxld, int pos)
> +{
> + int rc;
> + struct cxl_endpoint_decoder *cxled =
> + to_cxl_endpoint_decoder(&cxld->dev);
> +
> + rc = attach_target(cxlr, cxled, pos, TASK_INTERRUPTIBLE);
> +
No blank line here
> + if (rc < 0)
Can it ever be > 0 ?
If not, return attach_target() should be fine.
> + return rc;
> +
> + return 0;
> +}
> +
> +static ssize_t commit_region(struct cxl_region *cxlr)
> +{
> + struct cxl_region_params *p = &cxlr->params;
> + ssize_t rc;
> +
> + rc = down_write_killable(&cxl_region_rwsem);
Maybe look at Dan's new ACQUIRE() series. The last patch in there
is targeting code similar to this.
> + if (rc)
> + return rc;
> +
> + /* Already in the requested state? */
> + if (p->state >= CXL_CONFIG_COMMIT)
> + goto out;
> +
> + /* Not ready to commit? */
> + if (p->state < CXL_CONFIG_ACTIVE) {
> + rc = -ENXIO;
> + goto out;
> + }
> +
> + /*
> + * Invalidate caches before region setup to drop any speculative
> + * consumption of this address space
> + */
> + rc = cxl_region_invalidate_memregion(cxlr);
> + if (rc)
> + goto out;
> +
> + rc = cxl_region_decode_commit(cxlr);
> + if (rc == 0)
With AQUIRE() stuff you can just do
if (rc)
return rc;
here
> + p->state = CXL_CONFIG_COMMIT;
> +out:
> + up_write(&cxl_region_rwsem);
> + if (rc)
> + return rc;
> + return 0;
> +}
> +
> +static struct cxl_region *
> +devm_cxl_pmem_add_region(struct cxl_root_decoder *cxlrd,
> + struct cxl_decoder *cxld,
> + struct cxl_pmem_region_params *params, int id,
> + enum cxl_decoder_mode mode, enum cxl_decoder_type type)
> +{
> + struct cxl_port *port;
> + struct cxl_region *cxlr;
> + struct cxl_region_params *p;
> + struct device *dev;
> + int rc;
> +
> + if (!cxlrd)
> + return ERR_PTR(-EINVAL);
For a check like this, add a comment on why it might be NULL.
If it can't be, then drop the check.
> +
> + port = to_cxl_port(cxlrd->cxlsd.cxld.dev.parent);
Maybe add a comment on which port this actually is. These long indirections
can make that hard to figure out!
> +
> + cxlr = cxl_region_alloc(cxlrd, id);
> + if (IS_ERR(cxlr))
> + return cxlr;
> + cxlr->mode = mode;
> + cxlr->type = type;
> +
> + dev = &cxlr->dev;
> + rc = dev_set_name(dev, "region%d", id);
> + if (rc)
> + goto err;
> +
> + p = &cxlr->params;
> + p->uuid = params->uuid;
> + p->interleave_ways = params->nlabel;
> + p->interleave_granularity = params->ig;
> +
> + /* Update region size */
> + if (update_region_size(cxlr, params->rawsize))
> + goto err;
> +
> + /* Flush cxl wq */
Much more useful to say 'why' you are flushing it. It's obvious
from the code that you are.
> + cxl_wq_flush();
> +
> + /* Clear DPA Size */
I'd look at all these comments and where they are obvious, drop the comment
and let the code speak for itself.
> + if (update_region_dpa_size(cxlr, cxld, 0))
> + goto err;
> +
> + /* Update DPA mode */
> + if (update_region_dpa_mode(cxlr, cxld))
> + goto err;
> +
> + /* Update DPA Size */
> + if (update_region_dpa_size(cxlr, cxld, params->rawsize))
> + goto err;
> +
> + /* Attach region targets */
It's attaching just one by the look of it. I'd just drop the comment.
> + if (attach_region_target(cxlr, cxld, params->position))
> + goto err;
> +
> + /* Commit Region */
> + if (commit_region(cxlr))
> + goto err;
> +
> + rc = device_add(dev);
> + if (rc)
> + goto err;
> +
> + rc = devm_add_action_or_reset(port->uport_dev, unregister_region, cxlr);
> + if (rc)
> + return ERR_PTR(rc);
> +
> + dev_dbg(port->uport_dev, "%s: created %s\n",
> + dev_name(&cxlrd->cxlsd.cxld.dev), dev_name(dev));
> + return cxlr;
> +
> +err:
> + put_device(dev);
> + return ERR_PTR(rc);
> +}
> +
> +struct cxl_region *cxl_create_pmem_region(struct cxl_root_decoder *cxlrd,
> + struct cxl_decoder *cxld,
> + struct cxl_pmem_region_params *params, 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);
> + }
I'm a little surprised not to see cleanup of the memregion via
devm somewhere here.
> +
> + return devm_cxl_pmem_add_region(cxlrd, cxld, params, id,
> + CXL_DECODER_PMEM, CXL_DECODER_HOSTONLYMEM);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_create_pmem_region, "CXL");
> +
> static struct cxl_region *__create_region(struct cxl_root_decoder *cxlrd,
> enum cxl_decoder_mode mode, int id)
> {
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 15/20] cxl: Add a routine to find cxl root decoder on cxl bus
2025-06-17 12:39 ` [RFC PATCH 15/20] cxl: Add a routine to find cxl root decoder on cxl bus Neeraj Kumar
@ 2025-06-23 9:44 ` Jonathan Cameron
2025-06-26 10:38 ` Neeraj Kumar
2025-06-26 19:19 ` Alison Schofield
2025-07-10 16:23 ` Dave Jiang
2 siblings, 1 reply; 66+ messages in thread
From: Jonathan Cameron @ 2025-06-23 9:44 UTC (permalink / raw)
To: Neeraj Kumar
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
On Tue, 17 Jun 2025 18:09:39 +0530
Neeraj Kumar <s.neeraj@samsung.com> wrote:
> Add cxl_find_root_decoder to find root decoder on cxl bus. It is used to
> find root decoder during region creation
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
> ---
> drivers/cxl/core/port.c | 26 ++++++++++++++++++++++++++
> drivers/cxl/cxl.h | 1 +
> 2 files changed, 27 insertions(+)
>
> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
> index 2452f7c15b2d..94d9322b8e38 100644
> --- a/drivers/cxl/core/port.c
> +++ b/drivers/cxl/core/port.c
> @@ -513,6 +513,32 @@ struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev)
> }
> EXPORT_SYMBOL_NS_GPL(to_cxl_switch_decoder, "CXL");
>
> +static int match_root_decoder(struct device *dev, void *data)
> +{
> + return is_root_decoder(dev);
> +}
> +
> +/**
> + * cxl_find_root_decoder() - find a cxl root decoder on cxl bus
> + * @port: any descendant port in root-cxl-port topology
> + */
> +struct cxl_root_decoder *cxl_find_root_decoder(struct cxl_port *port)
> +{
> + struct cxl_root *cxl_root __free(put_cxl_root) = find_cxl_root(port);
> + struct device *dev;
> +
> + if (!cxl_root)
> + return NULL;
> +
> + dev = device_find_child(&cxl_root->port.dev, NULL, match_root_decoder);
> +
No blank line here. Generally when we have a call then an error check
it is easier to see how they are related if we keep them in one block.
> + if (!dev)
> + return NULL;
> +
> + return to_cxl_root_decoder(dev);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_find_root_decoder, "CXL");
> +
> static void cxl_ep_release(struct cxl_ep *ep)
> {
> put_device(ep->ep);
> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> index 30c80e04cb27..2c6a782d0941 100644
> --- a/drivers/cxl/cxl.h
> +++ b/drivers/cxl/cxl.h
> @@ -871,6 +871,7 @@ bool is_cxl_nvdimm_bridge(struct device *dev);
> int devm_cxl_add_nvdimm(struct cxl_port *parent_port, struct cxl_memdev *cxlmd);
> struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_port *port);
> void cxl_region_discovery(struct cxl_port *port);
> +struct cxl_root_decoder *cxl_find_root_decoder(struct cxl_port *port);
>
> #ifdef CONFIG_CXL_REGION
> bool is_cxl_pmem_region(struct device *dev);
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 18/20] cxl/pmem: Add support of cxl lsa 2.1 support in cxl pmem
2025-06-17 12:39 ` [RFC PATCH 18/20] cxl/pmem: Add support of cxl lsa 2.1 support in cxl pmem Neeraj Kumar
@ 2025-06-23 9:48 ` Jonathan Cameron
2025-06-26 10:41 ` Neeraj Kumar
2025-07-10 17:18 ` Dave Jiang
1 sibling, 1 reply; 66+ messages in thread
From: Jonathan Cameron @ 2025-06-23 9:48 UTC (permalink / raw)
To: Neeraj Kumar
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
On Tue, 17 Jun 2025 18:09:42 +0530
Neeraj Kumar <s.neeraj@samsung.com> wrote:
> Add support of cxl lsa 2.1 using NDD_CXL_LABEL flag. It also creates cxl
> region based on region information parsed from LSA.
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
> ---
> drivers/cxl/pmem.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 59 insertions(+)
>
> diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c
> index ffcebb8d382f..2733d79b32d5 100644
> --- a/drivers/cxl/pmem.c
> +++ b/drivers/cxl/pmem.c
> @@ -58,6 +58,63 @@ static const struct attribute_group *cxl_dimm_attribute_groups[] = {
> NULL
> };
>
> +static int match_ep_decoder(struct device *dev, void *data)
> +{
> + struct cxl_decoder *cxld = to_cxl_decoder(dev);
> +
> + if (!cxld->region)
> + return 1;
> + else
> + return 0;
> +}
> +
> +static struct cxl_decoder *cxl_find_free_decoder(struct cxl_port *port)
> +{
> + struct device *dev;
> +
> + dev = device_find_child(&port->dev, NULL, match_ep_decoder);
> + if (!dev)
> + return NULL;
> +
> + return to_cxl_decoder(dev);
> +}
> +
> +static int create_pmem_region(struct nvdimm *nvdimm)
> +{
> + struct cxl_nvdimm *cxl_nvd;
> + struct cxl_memdev *cxlmd;
> + struct cxl_nvdimm_bridge *cxl_nvb;
> + struct cxl_pmem_region_params *params;
> + struct cxl_root_decoder *cxlrd;
> + struct cxl_decoder *cxld;
> + struct cxl_region *cxlr;
> +
> + if (!nvdimm)
> + return -ENOTTY;
As with other checks like this, it is useful to add a comment on when you can
call this function with a null parameter.
> +
> + if (!nvdimm_has_cxl_region(nvdimm))
> + return 0;
> +
> + cxl_nvd = nvdimm_provider_data(nvdimm);
> + params = nvdimm_get_cxl_region_param(nvdimm);
> + cxlmd = cxl_nvd->cxlmd;
> + cxl_nvb = cxlmd->cxl_nvb;
> + cxlrd = cxlmd->cxlrd;
> +
> + /* FIXME: Limitation: Region creation only when interleave way == 1 */
> + if (params->nlabel == 1) {
> + cxld = cxl_find_free_decoder(cxlmd->endpoint);
> + cxlr = cxl_create_pmem_region(cxlrd, cxld, params,
> + atomic_read(&cxlrd->region_id));
> + if (IS_ERR(cxlr))
> + dev_dbg(&cxlmd->dev, "Region Creation failed\n");
> + } else {
> + dev_dbg(&cxlmd->dev, "Region Creation is not supported with iw > 1\n");
> + }
Flip logic to check for unhandled case first and also return an error if this happens
rather than silently carrying on. dev_info() is appropriate here.
> +
> + return 0;
> +}
> +
> static int cxl_nvdimm_probe(struct device *dev)
> {
> struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev);
> @@ -74,6 +131,7 @@ static int cxl_nvdimm_probe(struct device *dev)
> return rc;
>
> set_bit(NDD_LABELING, &flags);
> + set_bit(NDD_CXL_LABEL, &flags);
> set_bit(NDD_REGISTER_SYNC, &flags);
> set_bit(ND_CMD_GET_CONFIG_SIZE, &cmd_mask);
> set_bit(ND_CMD_GET_CONFIG_DATA, &cmd_mask);
> @@ -86,6 +144,7 @@ static int cxl_nvdimm_probe(struct device *dev)
> return -ENOMEM;
>
> dev_set_drvdata(dev, nvdimm);
> + create_pmem_region(nvdimm);
> return devm_add_action_or_reset(dev, unregister_nvdimm, nvdimm);
> }
>
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 19/20] cxl/pmem_region: Prep patch to accommodate pmem_region attributes
2025-06-17 12:39 ` [RFC PATCH 19/20] cxl/pmem_region: Prep patch to accommodate pmem_region attributes Neeraj Kumar
@ 2025-06-23 9:53 ` Jonathan Cameron
2025-06-26 10:45 ` Neeraj Kumar
0 siblings, 1 reply; 66+ messages in thread
From: Jonathan Cameron @ 2025-06-23 9:53 UTC (permalink / raw)
To: Neeraj Kumar
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
On Tue, 17 Jun 2025 18:09:43 +0530
Neeraj Kumar <s.neeraj@samsung.com> wrote:
> Created a separate file core/pmem_region.c along with CONFIG_PMEM_REGION
> Moved pmem_region related code from core/region.c to core/pmem_region.c
> For region label update, need to create device attribute, which calls
> nvdimm exported function thus making pmem_region dependent on libnvdimm.
> Because of this dependency of pmem region on libnvdimm, segregated pmem
segregate
> region related code from core/region.c
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
> ---
> drivers/cxl/Kconfig | 12 ++
> drivers/cxl/core/Makefile | 1 +
> drivers/cxl/core/core.h | 8 +-
> drivers/cxl/core/pmem_region.c | 222 +++++++++++++++++++++++++++++++++
> drivers/cxl/core/port.c | 2 +-
> drivers/cxl/core/region.c | 217 ++------------------------------
> drivers/cxl/cxl.h | 42 +++++--
> tools/testing/cxl/Kbuild | 1 +
> 8 files changed, 283 insertions(+), 222 deletions(-)
> create mode 100644 drivers/cxl/core/pmem_region.c
>
> diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
> index 876469e23f7a..f0cbb096bfe7 100644
> --- a/drivers/cxl/Kconfig
> +++ b/drivers/cxl/Kconfig
> @@ -128,6 +128,18 @@ config CXL_REGION
>
> If unsure say 'y'
>
> +config CXL_PMEM_REGION
> + bool "CXL: Pmem Region Support"
> + default CXL_BUS
> + depends on CXL_REGION
> + select LIBNVDIMM if CXL_BUS = y
This is in the block covered by if CXL_BUS so I think you can simplify this check.
> + help
> + Enable the CXL core to enumerate and provision CXL pmem regions.
> + A CXL pmem region need to update region label into LSA. For LSA
> + updation/deletion libnvdimm is required.
> +
> + If unsure say 'y'
> +
> config CXL_REGION_INVALIDATION_TEST
> bool "CXL: Region Cache Management Bypass (TEST)"
> depends on CXL_REGION
> diff --git a/drivers/cxl/core/pmem_region.c b/drivers/cxl/core/pmem_region.c
> new file mode 100644
> index 000000000000..a29526c27d40
> --- /dev/null
> +++ b/drivers/cxl/core/pmem_region.c
> @@ -0,0 +1,222 @@
> @@ -3273,92 +3155,6 @@ static struct cxl_dax_region *cxl_dax_region_alloc(struct cxl_region *cxlr)
> return cxlr_dax;
> }
> static void cxlr_dax_unregister(void *_cxlr_dax)
> {
> struct cxl_dax_region *cxlr_dax = _cxlr_dax;
> @@ -3646,7 +3442,10 @@ static int cxl_region_probe(struct device *dev)
>
> switch (cxlr->mode) {
> case CXL_DECODER_PMEM:
> - return devm_cxl_add_pmem_region(cxlr);
> + if (IS_ENABLED(CONFIG_CXL_PMEM_REGION))
> + return devm_cxl_add_pmem_region(cxlr);
> + else
> + return -EINVAL;
if (!IS_ENABLED(CONFIG_CXL_PMEM_REGION))
return -EINVAL;
return devm_cxl_add_pmem_region()
Where ever possible keep the error conditions as the out of line ones.
That generally improves code readability and is common practice in the kernel.
> case CXL_DECODER_RAM:
> /*
> * The region can not be manged by CXL if any portion of
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 20/20] cxl/pmem_region: Add cxl region label updation and deletion device attributes
2025-06-17 12:39 ` [RFC PATCH 20/20] cxl/pmem_region: Add cxl region label updation and deletion device attributes Neeraj Kumar
@ 2025-06-23 9:56 ` Jonathan Cameron
2025-06-26 10:48 ` Neeraj Kumar
0 siblings, 1 reply; 66+ messages in thread
From: Jonathan Cameron @ 2025-06-23 9:56 UTC (permalink / raw)
To: Neeraj Kumar
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
On Tue, 17 Jun 2025 18:09:44 +0530
Neeraj Kumar <s.neeraj@samsung.com> wrote:
> Using these attributes region label is added/deleted into LSA. These
> attributes are called from userspace (ndctl) after region creation.
These need documentation. Documentation/ABI/testing/sysfs-bus-cxl
is probably the right place.
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
> ---
> drivers/cxl/core/pmem_region.c | 103 +++++++++++++++++++++++++++++++++
> drivers/cxl/cxl.h | 1 +
> 2 files changed, 104 insertions(+)
>
> diff --git a/drivers/cxl/core/pmem_region.c b/drivers/cxl/core/pmem_region.c
> index a29526c27d40..f582d796c21b 100644
> --- a/drivers/cxl/core/pmem_region.c
> +++ b/drivers/cxl/core/pmem_region.c
> @@ -45,8 +45,111 @@ static void cxl_pmem_region_release(struct device *dev)
> kfree(cxlr_pmem);
> }
>
> +static ssize_t region_label_update_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t len)
> +{
> + struct cxl_pmem_region *cxlr_pmem = to_cxl_pmem_region(dev);
> + struct cxl_region *cxlr = cxlr_pmem->cxlr;
> + struct cxl_region_params *p = &cxlr->params;
> + ssize_t rc;
> + bool update;
> +
> + rc = kstrtobool(buf, &update);
> + if (rc)
> + return rc;
> +
> + rc = down_write_killable(&cxl_region_rwsem);
Another use case for ACQUIRE()
> + if (rc)
> + return rc;
> +
> + /* Region not yet committed */
> + if (update && p->state != CXL_CONFIG_COMMIT) {
> + dev_dbg(dev, "region not committed, can't update into LSA\n");
> + rc = -ENXIO;
> + goto out;
> + }
> +
> + if (cxlr && cxlr->cxlr_pmem && cxlr->cxlr_pmem->nd_region) {
> + rc = nd_region_label_update(cxlr->cxlr_pmem->nd_region);
> +
> + if (!rc)
> + p->region_label_state = 1;
> + }
> +
> +out:
> + up_write(&cxl_region_rwsem);
> +
> + if (rc)
> + return rc;
> +
> + return len;
> +}
> +
> +static struct attribute *cxl_pmem_region_attrs[] = {
> + &dev_attr_region_label_update.attr,
> + &dev_attr_region_label_delete.attr,
> + NULL,
No need for trailing commas on terminating entries as we don't want it to be easy
to put something after them.
> +};
> +
> +struct attribute_group cxl_pmem_region_group = {
> + .attrs = cxl_pmem_region_attrs,
> +};
> +
> static const struct attribute_group *cxl_pmem_region_attribute_groups[] = {
> &cxl_base_attribute_group,
> + &cxl_pmem_region_group,
> NULL,
Hmm. Drop this trailing comma perhaps whilst here.
> };
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 02/20] nvdimm/label: Prep patch to accommodate cxl lsa 2.1 support
2025-06-17 12:39 ` [RFC PATCH 02/20] nvdimm/label: Prep patch to accommodate cxl lsa 2.1 support Neeraj Kumar
@ 2025-06-23 10:53 ` Jonathan Cameron
2025-06-26 9:51 ` Neeraj Kumar
2025-07-02 17:55 ` Ira Weiny
1 sibling, 1 reply; 66+ messages in thread
From: Jonathan Cameron @ 2025-06-23 10:53 UTC (permalink / raw)
To: Neeraj Kumar
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
On Tue, 17 Jun 2025 18:09:26 +0530
Neeraj Kumar <s.neeraj@samsung.com> wrote:
> In order to accommodate cxl lsa 2.1 format region label, renamed
> nd_namespace_label to nd_lsa_label.
I would add some more information on why. I've no idea from this
description whether the issue is a naming clash or a need for a broader
name or something entirely different.
Most readers aren't going to be particular familiar with the lsa spec
version changes, so help them out with a little more detail.
The comment you have with the union is probably the right info
to duplicate here.
>
> No functional change introduced.
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
This is quite a lot of churn which, just looking at this patch, could
be avoided by just setting local variables to point at a particular
member of the union rather than the containing struct.
You already do this in a few places like nd_label_reserve_dpa().
Perhaps it will be come clearer why that doesn't make sense as
I ready later patches.
> diff --git a/drivers/nvdimm/label.h b/drivers/nvdimm/label.h
> index 0650fb4b9821..4883b3a1320f 100644
> --- a/drivers/nvdimm/label.h
> +++ b/drivers/nvdimm/label.h
> @@ -183,6 +183,16 @@ struct nd_namespace_label {
> };
> };
>
> +/*
> + * LSA 2.1 format introduces region label, which can also reside
> + * into LSA along with only namespace label as per v1.1 and v1.2
> + */
> +struct nd_lsa_label {
> + union {
> + struct nd_namespace_label ns_label;
> + };
> +};
> diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
> index 55cfbf1e0a95..f180f0068c15 100644
> --- a/drivers/nvdimm/namespace_devs.c
> +++ b/drivers/nvdimm/namespace_devs.c
> @@ -1595,7 +1596,8 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, const uuid_t *uuid,
> return false;
> }
> found_uuid = true;
> - if (!nsl_validate_nlabel(nd_region, ndd, nd_label))
> + if (!nsl_validate_nlabel(nd_region,
> + ndd, &nd_label->ns_label))
Strange wrap. I'd move ndd up a line.
> continue;
> if (position != pos)
> continue;
> @@ -1615,7 +1617,7 @@ static int select_pmem_id(struct nd_region *nd_region, const uuid_t *pmem_id)
> for (i = 0; i < nd_region->ndr_mappings; i++) {
> struct nd_mapping *nd_mapping = &nd_region->mapping[i];
> struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
> - struct nd_namespace_label *nd_label = NULL;
> + struct nd_lsa_label *nd_label = NULL;
> u64 hw_start, hw_end, pmem_start, pmem_end;
> struct nd_label_ent *label_ent;
>
> @@ -1739,14 +1741,14 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region,
> * that position at labels[0], and NULL at labels[1]. In the process,
> * check that the namespace aligns with interleave-set.
> */
> - nsl_get_uuid(ndd, nd_label, &uuid);
> + nsl_get_uuid(ndd, &nd_label->ns_label, &uuid);
> rc = select_pmem_id(nd_region, &uuid);
> if (rc)
> goto err;
>
> /* Calculate total size and populate namespace properties from label0 */
> for (i = 0; i < nd_region->ndr_mappings; i++) {
> - struct nd_namespace_label *label0;
> + struct nd_lsa_label *label0;
If you are only ever going to use one part of the union in a given
bit of code, why not use a struct of that type so you only need to change
the point where it is assigned rather that lots of places.
So keep this as struct nd_namespace_label *label0;
If that makes sense, check for other places where doing that will reduce the churn
and complexity of the code.
> struct nvdimm_drvdata *ndd;
>
> nd_mapping = &nd_region->mapping[i];
> @@ -1760,17 +1762,17 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region,
> }
>
> ndd = to_ndd(nd_mapping);
> - size += nsl_get_rawsize(ndd, label0);
> - if (nsl_get_position(ndd, label0) != 0)
> + size += nsl_get_rawsize(ndd, &label0->ns_label);
> + if (nsl_get_position(ndd, &label0->ns_label) != 0)
> continue;
> WARN_ON(nspm->alt_name || nspm->uuid);
> - nspm->alt_name = kmemdup(nsl_ref_name(ndd, label0),
> + nspm->alt_name = kmemdup(nsl_ref_name(ndd, &label0->ns_label),
> NSLABEL_NAME_LEN, GFP_KERNEL);
> - nsl_get_uuid(ndd, label0, &uuid);
> + nsl_get_uuid(ndd, &label0->ns_label, &uuid);
> nspm->uuid = kmemdup(&uuid, sizeof(uuid_t), GFP_KERNEL);
> - nspm->lbasize = nsl_get_lbasize(ndd, label0);
> + nspm->lbasize = nsl_get_lbasize(ndd, &label0->ns_label);
> nspm->nsio.common.claim_class =
> - nsl_get_claim_class(ndd, label0);
> + nsl_get_claim_class(ndd, &label0->ns_label);
> }
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 01/20] nvdimm/label: Introduce NDD_CXL_LABEL flag to set cxl label format
2025-06-20 16:40 ` Jonathan Cameron
@ 2025-06-26 9:48 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-26 9:48 UTC (permalink / raw)
To: Jonathan Cameron
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 4301 bytes --]
On 20/06/25 05:40PM, Jonathan Cameron wrote:
>On Tue, 17 Jun 2025 18:09:25 +0530
>Neeraj Kumar <s.neeraj@samsung.com> wrote:
>
>> NDD_CXL_LABEL is introduced to set cxl LSA 2.1 label format
>> Accordingly updated label index version
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>A few local comments. I'll need to read on to figure out how this
>fits in generally.
>
>> ---
>> drivers/nvdimm/dimm.c | 1 +
>> drivers/nvdimm/dimm_devs.c | 10 ++++++++++
>> drivers/nvdimm/label.c | 16 ++++++++++++----
>> drivers/nvdimm/nd.h | 1 +
>> include/linux/libnvdimm.h | 3 +++
>> 5 files changed, 27 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c
>> index 91d9163ee303..8753b5cd91cc 100644
>> --- a/drivers/nvdimm/dimm.c
>> +++ b/drivers/nvdimm/dimm.c
>> @@ -62,6 +62,7 @@ static int nvdimm_probe(struct device *dev)
>> if (rc < 0)
>> dev_dbg(dev, "failed to unlock dimm: %d\n", rc);
>>
>> + ndd->cxl = nvdimm_check_cxl_label_format(ndd->dev);
>>
>> /*
>> * EACCES failures reading the namespace label-area-properties
>> diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
>> index 21498d461fde..e8f545f889fd 100644
>> --- a/drivers/nvdimm/dimm_devs.c
>> +++ b/drivers/nvdimm/dimm_devs.c
>> @@ -18,6 +18,16 @@
>>
>> static DEFINE_IDA(dimm_ida);
>>
>> +bool nvdimm_check_cxl_label_format(struct device *dev)
>> +{
>> + struct nvdimm *nvdimm = to_nvdimm(dev);
>> +
>> + if (test_bit(NDD_CXL_LABEL, &nvdimm->flags))
>> + return true;
>> +
>> + return false;
>
> return test_bit(NDD_CXL_LABEL, &nvdimm->flags);
>
>Unless this is going to get more complex in later patches, in which case
>may be fine to ignore this comment.
>
Okay. I will fix in V1 patch.
>> +}
>> +
>> /*
>> * Retrieve bus and dimm handle and return if this bus supports
>> * get_config_data commands
>> diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
>> index 082253a3a956..48b5ba90216d 100644
>> --- a/drivers/nvdimm/label.c
>> +++ b/drivers/nvdimm/label.c
>> @@ -687,11 +687,19 @@ static int nd_label_write_index(struct nvdimm_drvdata *ndd, int index, u32 seq,
>> - (unsigned long) to_namespace_index(ndd, 0);
>> nsindex->labeloff = __cpu_to_le64(offset);
>> nsindex->nslot = __cpu_to_le32(nslot);
>> - nsindex->major = __cpu_to_le16(1);
>> - if (sizeof_namespace_label(ndd) < 256)
>> +
>> + /* Support CXL LSA 2.1 label format */
>
>Might be good to sprinkle some extra details in the references.
>E.g. CXL r3.2 Table 9-9 Label Index Block Layout
>
Sure, I will update it in V1
>> + if (ndd->cxl) {
>> + nsindex->major = __cpu_to_le16(2);
>> nsindex->minor = __cpu_to_le16(1);
>> - else
>> - nsindex->minor = __cpu_to_le16(2);
>> + } else {
>> + nsindex->major = __cpu_to_le16(1);
>
>Same for these. Case of making reviewers jobs easier by
>giving them breadcrumb trails to follow.
>
Sure, I will update it in V1
>> + if (sizeof_namespace_label(ndd) < 256)
>> + nsindex->minor = __cpu_to_le16(1);
>> + else
>> + nsindex->minor = __cpu_to_le16(2);
>> + }
>> +
>> nsindex->checksum = __cpu_to_le64(0);
>> if (flags & ND_NSINDEX_INIT) {
>> unsigned long *free = (unsigned long *) nsindex->free;
>> diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
>> index 5ca06e9a2d29..304f0e9904f1 100644
>> --- a/drivers/nvdimm/nd.h
>> +++ b/drivers/nvdimm/nd.h
>> @@ -522,6 +522,7 @@ void nvdimm_set_labeling(struct device *dev);
>> void nvdimm_set_locked(struct device *dev);
>> void nvdimm_clear_locked(struct device *dev);
>> int nvdimm_security_setup_events(struct device *dev);
>> +bool nvdimm_check_cxl_label_format(struct device *dev);
>> #if IS_ENABLED(CONFIG_NVDIMM_KEYS)
>> int nvdimm_security_unlock(struct device *dev);
>> #else
>> diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
>> index e772aae71843..0a55900842c8 100644
>> --- a/include/linux/libnvdimm.h
>> +++ b/include/linux/libnvdimm.h
>> @@ -44,6 +44,9 @@ enum {
>> /* dimm provider wants synchronous registration by __nvdimm_create() */
>> NDD_REGISTER_SYNC = 8,
>>
>> + /* dimm supports region labels (LSA Format 2.1) */
>> + NDD_CXL_LABEL = 9,
>> +
>> /* need to set a limit somewhere, but yes, this is likely overkill */
>> ND_IOCTL_MAX_BUFLEN = SZ_4M,
>> ND_CMD_MAX_ELEM = 5,
>
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 02/20] nvdimm/label: Prep patch to accommodate cxl lsa 2.1 support
2025-06-23 10:53 ` Jonathan Cameron
@ 2025-06-26 9:51 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-26 9:51 UTC (permalink / raw)
To: Jonathan Cameron
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 4921 bytes --]
On 23/06/25 11:53AM, Jonathan Cameron wrote:
>On Tue, 17 Jun 2025 18:09:26 +0530
>Neeraj Kumar <s.neeraj@samsung.com> wrote:
>
>> In order to accommodate cxl lsa 2.1 format region label, renamed
>> nd_namespace_label to nd_lsa_label.
>
>I would add some more information on why. I've no idea from this
>description whether the issue is a naming clash or a need for a broader
>name or something entirely different.
>
>Most readers aren't going to be particular familiar with the lsa spec
>version changes, so help them out with a little more detail.
>
>The comment you have with the union is probably the right info
>to duplicate here.
>
Thanks Jonathan, I will elaborate commit message with more information.
>>
>> No functional change introduced.
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>
>This is quite a lot of churn which, just looking at this patch, could
>be avoided by just setting local variables to point at a particular
>member of the union rather than the containing struct.
>You already do this in a few places like nd_label_reserve_dpa().
>
>Perhaps it will be come clearer why that doesn't make sense as
>I ready later patches.
>
Sure, I will try to minimize wherever its possible.
>> diff --git a/drivers/nvdimm/label.h b/drivers/nvdimm/label.h
>> index 0650fb4b9821..4883b3a1320f 100644
>> --- a/drivers/nvdimm/label.h
>> +++ b/drivers/nvdimm/label.h
>> @@ -183,6 +183,16 @@ struct nd_namespace_label {
>> };
>> };
>>
>> +/*
>> + * LSA 2.1 format introduces region label, which can also reside
>> + * into LSA along with only namespace label as per v1.1 and v1.2
>> + */
>> +struct nd_lsa_label {
>> + union {
>> + struct nd_namespace_label ns_label;
>> + };
>> +};
>
>> diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
>> index 55cfbf1e0a95..f180f0068c15 100644
>> --- a/drivers/nvdimm/namespace_devs.c
>> +++ b/drivers/nvdimm/namespace_devs.c
>
>> @@ -1595,7 +1596,8 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, const uuid_t *uuid,
>> return false;
>> }
>> found_uuid = true;
>> - if (!nsl_validate_nlabel(nd_region, ndd, nd_label))
>> + if (!nsl_validate_nlabel(nd_region,
>> + ndd, &nd_label->ns_label))
>
>Strange wrap. I'd move ndd up a line.
>
>
Sure, I will fix it in V1
>> continue;
>> if (position != pos)
>> continue;
>> @@ -1615,7 +1617,7 @@ static int select_pmem_id(struct nd_region *nd_region, const uuid_t *pmem_id)
>> for (i = 0; i < nd_region->ndr_mappings; i++) {
>> struct nd_mapping *nd_mapping = &nd_region->mapping[i];
>> struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
>> - struct nd_namespace_label *nd_label = NULL;
>> + struct nd_lsa_label *nd_label = NULL;
>> u64 hw_start, hw_end, pmem_start, pmem_end;
>> struct nd_label_ent *label_ent;
>>
>
>
>> @@ -1739,14 +1741,14 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region,
>> * that position at labels[0], and NULL at labels[1]. In the process,
>> * check that the namespace aligns with interleave-set.
>> */
>> - nsl_get_uuid(ndd, nd_label, &uuid);
>> + nsl_get_uuid(ndd, &nd_label->ns_label, &uuid);
>> rc = select_pmem_id(nd_region, &uuid);
>> if (rc)
>> goto err;
>>
>> /* Calculate total size and populate namespace properties from label0 */
>> for (i = 0; i < nd_region->ndr_mappings; i++) {
>> - struct nd_namespace_label *label0;
>> + struct nd_lsa_label *label0;
>
>If you are only ever going to use one part of the union in a given
>bit of code, why not use a struct of that type so you only need to change
>the point where it is assigned rather that lots of places.
>
>So keep this as struct nd_namespace_label *label0;
>
>If that makes sense, check for other places where doing that will reduce the churn
>and complexity of the code.
>
Sure, Let me revisit these. Thanks
>
>
>> struct nvdimm_drvdata *ndd;
>>
>> nd_mapping = &nd_region->mapping[i];
>> @@ -1760,17 +1762,17 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region,
>> }
>>
>> ndd = to_ndd(nd_mapping);
>> - size += nsl_get_rawsize(ndd, label0);
>> - if (nsl_get_position(ndd, label0) != 0)
>> + size += nsl_get_rawsize(ndd, &label0->ns_label);
>> + if (nsl_get_position(ndd, &label0->ns_label) != 0)
>> continue;
>> WARN_ON(nspm->alt_name || nspm->uuid);
>> - nspm->alt_name = kmemdup(nsl_ref_name(ndd, label0),
>> + nspm->alt_name = kmemdup(nsl_ref_name(ndd, &label0->ns_label),
>> NSLABEL_NAME_LEN, GFP_KERNEL);
>> - nsl_get_uuid(ndd, label0, &uuid);
>> + nsl_get_uuid(ndd, &label0->ns_label, &uuid);
>> nspm->uuid = kmemdup(&uuid, sizeof(uuid_t), GFP_KERNEL);
>> - nspm->lbasize = nsl_get_lbasize(ndd, label0);
>> + nspm->lbasize = nsl_get_lbasize(ndd, &label0->ns_label);
>> nspm->nsio.common.claim_class =
>> - nsl_get_claim_class(ndd, label0);
>> + nsl_get_claim_class(ndd, &label0->ns_label);
>> }
>
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 05/20] nvdimm/region_label: Add region label updation routine
2025-06-23 9:05 ` Jonathan Cameron
@ 2025-06-26 9:54 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-26 9:54 UTC (permalink / raw)
To: Jonathan Cameron
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 4692 bytes --]
On 23/06/25 10:05AM, Jonathan Cameron wrote:
>On Tue, 17 Jun 2025 18:09:29 +0530
>Neeraj Kumar <s.neeraj@samsung.com> wrote:
>
>Add region label update routine
>
>
>> Added __pmem_region_label_update region label update routine to update
>> region label
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>A few trivial comments inline.
>
>Jonathan
>
>> ---
>> drivers/nvdimm/label.c | 142 ++++++++++++++++++++++++++++++++
>> drivers/nvdimm/label.h | 2 +
>> drivers/nvdimm/namespace_devs.c | 12 +++
>> drivers/nvdimm/nd.h | 20 +++++
>> include/linux/libnvdimm.h | 8 ++
>> 5 files changed, 184 insertions(+)
>>
>> diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
>> index d5cfaa99f976..7f33d14ce0ef 100644
>> --- a/drivers/nvdimm/label.c
>> +++ b/drivers/nvdimm/label.c
>> @@ -381,6 +381,16 @@ static void nsl_calculate_checksum(struct nvdimm_drvdata *ndd,
>> nsl_set_checksum(ndd, nd_label, sum);
>> }
>>
>> +static void rgl_calculate_checksum(struct nvdimm_drvdata *ndd,
>> + struct cxl_region_label *rg_label)
>> +{
>> + u64 sum;
>> +
>> + rgl_set_checksum(rg_label, 0);
>> + sum = nd_fletcher64(rg_label, sizeof_namespace_label(ndd), 1);
>> + rgl_set_checksum(rg_label, sum);
>> +}
>> +
>> static bool slot_valid(struct nvdimm_drvdata *ndd,
>> struct nd_lsa_label *nd_label, u32 slot)
>> {
>> @@ -1117,6 +1127,138 @@ int nd_pmem_namespace_label_update(struct nd_region *nd_region,
>> return 0;
>> }
>>
>> +static int __pmem_region_label_update(struct nd_region *nd_region,
>> + struct nd_mapping *nd_mapping, int pos, unsigned long flags)
>> +{
>> + struct nd_interleave_set *nd_set = nd_region->nd_set;
>> + struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
>> + struct nd_lsa_label *nd_label;
>> + struct cxl_region_label *rg_label;
>> + struct nd_namespace_index *nsindex;
>> + struct nd_label_ent *label_ent;
>> + unsigned long *free;
>> + u32 nslot, slot;
>> + size_t offset;
>> + int rc;
>> + uuid_t tmp;
>> +
>> + if (!preamble_next(ndd, &nsindex, &free, &nslot))
>> + return -ENXIO;
>> +
>> + /* allocate and write the label to the staging (next) index */
>> + slot = nd_label_alloc_slot(ndd);
>> + if (slot == UINT_MAX)
>> + return -ENXIO;
>> + dev_dbg(ndd->dev, "allocated: %d\n", slot);
>> +
>> + nd_label = to_label(ndd, slot);
>> +
>> + memset(nd_label, 0, sizeof_namespace_label(ndd));
>> + rg_label = &nd_label->rg_label;
>> +
>> + /* Set Region Label Format identification UUID */
>> + uuid_parse(CXL_REGION_UUID, &tmp);
>> + export_uuid(nd_label->rg_label.type, &tmp);
>> +
>> + /* Set Current Region Label UUID */
>> + export_uuid(nd_label->rg_label.uuid, &nd_set->uuid);
>> +
>> + rg_label->flags = __cpu_to_le32(flags);
>> + rg_label->nlabel = __cpu_to_le16(nd_region->ndr_mappings);
>> + rg_label->position = __cpu_to_le16(pos);
>> + rg_label->dpa = __cpu_to_le64(nd_mapping->start);
>> + rg_label->rawsize = __cpu_to_le64(nd_mapping->size);
>> + rg_label->hpa = __cpu_to_le64(nd_set->res->start);
>> + rg_label->slot = __cpu_to_le32(slot);
>> + rg_label->ig = __cpu_to_le32(nd_set->interleave_granularity);
>> + rg_label->align = __cpu_to_le16(0);
>> +
>> + /* Update fletcher64 Checksum */
>> + rgl_calculate_checksum(ndd, rg_label);
>> +
>> + /* update label */
>> + offset = nd_label_offset(ndd, nd_label);
>> + rc = nvdimm_set_config_data(ndd, offset, nd_label,
>> + sizeof_namespace_label(ndd));
>> + if (rc < 0) {
>> + nd_label_free_slot(ndd, slot);
>> + return rc;
>> + }
>> +
>> + /* Garbage collect the previous label */
>> + mutex_lock(&nd_mapping->lock);
>
>Perhaps use
>
> guard(mutex)(&nd_mapping->lock);
>
>so you can directly return in the error path below and simplify the flow
>a tiny bit.
>
Sure, Let me look at the gaurd(mutex). I will update it in V1
>> + list_for_each_entry(label_ent, &nd_mapping->labels, list) {
>> + if (!label_ent->label)
>> + continue;
>> + if (rgl_uuid_equal(&label_ent->label->rg_label, &nd_set->uuid))
>> + reap_victim(nd_mapping, label_ent);
>> + }
>> +
>> + /* update index */
>> + rc = nd_label_write_index(ndd, ndd->ns_next,
>> + nd_inc_seq(__le32_to_cpu(nsindex->seq)), 0);
>> +
>With guard this can be
> if (rc)
> return rec;
>
> list_for_each...
>
Sure, I will update it in V1
>> + if (rc == 0) {
>> + list_for_each_entry(label_ent, &nd_mapping->labels, list)
>> + if (!label_ent->label) {
>> + label_ent->label = nd_label;
>> + nd_label = NULL;
>> + break;
>> + }
>> + dev_WARN_ONCE(&nd_region->dev, nd_label,
>> + "failed to track label: %d\n",
>> + to_slot(ndd, nd_label));
>> + if (nd_label)
>> + rc = -ENXIO;
>> + }
>> + mutex_unlock(&nd_mapping->lock);
>> +
>> + return rc;
>> +}
>
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 06/20] nvdimm/region_label: Add region label deletion routine
2025-06-23 9:09 ` Jonathan Cameron
@ 2025-06-26 9:55 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-26 9:55 UTC (permalink / raw)
To: Jonathan Cameron
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 3778 bytes --]
On 23/06/25 10:09AM, Jonathan Cameron wrote:
>On Tue, 17 Jun 2025 18:09:30 +0530
>Neeraj Kumar <s.neeraj@samsung.com> wrote:
>
>> Added cxl v2.1 format region label deletion routine. This function is
>> used to delete region label from LSA
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>> ---
>> drivers/nvdimm/label.c | 75 ++++++++++++++++++++++++++++++---
>> drivers/nvdimm/label.h | 6 +++
>> drivers/nvdimm/namespace_devs.c | 12 ++++++
>> drivers/nvdimm/nd.h | 9 ++++
>> include/linux/libnvdimm.h | 1 +
>> 5 files changed, 98 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
>> index 7f33d14ce0ef..9381c50086fc 100644
>> --- a/drivers/nvdimm/label.c
>> +++ b/drivers/nvdimm/label.c
>> @@ -1034,7 +1034,8 @@ static int init_labels(struct nd_mapping *nd_mapping, int num_labels)
>> return max(num_labels, old_num_labels);
>> }
>>
>> -static int del_labels(struct nd_mapping *nd_mapping, uuid_t *uuid)
>> +static int del_labels(struct nd_mapping *nd_mapping, uuid_t *uuid,
>> + enum label_type ltype)
>> {
>> struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
>> struct nd_label_ent *label_ent, *e;
>> @@ -1058,8 +1059,18 @@ static int del_labels(struct nd_mapping *nd_mapping, uuid_t *uuid)
>> if (!nd_label)
>> continue;
>> active++;
>> - if (!nsl_uuid_equal(ndd, &nd_label->ns_label, uuid))
>> - continue;
>> +
>> + if (ltype == NS_LABEL_TYPE) {
>
>Perhaps a switch is more appropriate here.
>
Sure will update it in V1
>> + if (!nsl_uuid_equal(ndd, &nd_label->ns_label, uuid))
>> + continue;
>> + } else if (ltype == RG_LABEL_TYPE) {
>> + if (!nsl_uuid_equal(ndd, &nd_label->ns_label, uuid))
>> + continue;
>> + } else {
>> + dev_err(ndd->dev, "Invalid label type\n");
>> + return 0;
>> + }
>> +
>> active--;
>> slot = to_slot(ndd, nd_label);
>> nd_label_free_slot(ndd, slot);
>
>> @@ -1259,6 +1271,59 @@ int nd_pmem_region_label_update(struct nd_region *nd_region)
>> return 0;
>> }
>>
>> +int nd_pmem_region_label_delete(struct nd_region *nd_region)
>> +{
>> + int i, rc;
>> + struct nd_interleave_set *nd_set = nd_region->nd_set;
>> + struct nd_label_ent *label_ent;
>> + bool is_non_rgl = false;
>> + int ns_region_cnt = 0;
>> +
>> + for (i = 0; i < nd_region->ndr_mappings; i++) {
>> + struct nd_mapping *nd_mapping = &nd_region->mapping[i];
>> + struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
>> +
>> + /* Find non cxl format supported ndr_mappings */
>> + if (!ndd->cxl)
>> + is_non_rgl = true;
>> +
>> + /* Find if any NS label using this region */
>> + mutex_lock(&nd_mapping->lock);
>> + list_for_each_entry(label_ent, &nd_mapping->labels, list) {
>> + if (!label_ent->label)
>> + continue;
>> +
>> + /* Check if any available NS labels has same
>
>Looks like wrong style for multiline comments in this file.
>
> /*
> * Check ...
>
Thanks, Will update it accordingly in V1
>> + * region_uuid in LSA
>> + */
>> + if (nsl_region_uuid_equal(&label_ent->label->ns_label,
>> + &nd_set->uuid))
>> + ns_region_cnt++;
>> + }
>> + mutex_unlock(&nd_mapping->lock);
>> + }
>> +
>> + if (is_non_rgl) {
>> + dev_dbg(&nd_region->dev, "Region label deletion unsupported\n");
>> + return -EINVAL;
>
>Why not bail out where you originally detect that above?
>
Thanks, Will fix it in V1
>> + }
>> +
>> + if (ns_region_cnt) {
>> + dev_dbg(&nd_region->dev, "Region/Namespace label in use\n");
>> + return -EBUSY;
>> + }
>> +
>> + for (i = 0; i < nd_region->ndr_mappings; i++) {
>> + struct nd_mapping *nd_mapping = &nd_region->mapping[i];
>> +
>> + rc = del_labels(nd_mapping, &nd_set->uuid, RG_LABEL_TYPE);
>> + if (rc)
>> + return rc;
>> + }
>> +
>> + return 0;
>> +}
>
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 07/20] nvdimm/namespace_label: Update namespace init_labels and its region_uuid
2025-06-23 9:11 ` Jonathan Cameron
@ 2025-06-26 9:58 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-26 9:58 UTC (permalink / raw)
To: Jonathan Cameron
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 1846 bytes --]
On 23/06/25 10:11AM, Jonathan Cameron wrote:
>On Tue, 17 Jun 2025 18:09:31 +0530
>Neeraj Kumar <s.neeraj@samsung.com> wrote:
>
>> nd_mapping->labels maintains the list of labels present into LSA.
>> init_labels function prepares this list while adding new label
>
>init_labels() prepares
>
Thanks, Will fix it up
>
>> into LSA and updates nd_mapping->labels accordingly. During cxl
>> region creation nd_mapping->labels list and LSA was updated with
>> one region label. Therefore during new namespace label creation
>> pre-include the previously created region label, so increase
>> num_labels count by 1.
>>
>> Also updated nsl_set_region_uuid with region uuid with which
>> namespace is associated with.
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>> ---
>> drivers/nvdimm/label.c | 5 +++--
>> 1 file changed, 3 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
>> index 9381c50086fc..108100c4bf44 100644
>> --- a/drivers/nvdimm/label.c
>> +++ b/drivers/nvdimm/label.c
>> @@ -947,7 +947,7 @@ static int __pmem_label_update(struct nd_region *nd_region,
>> nsl_set_slot(ndd, ns_label, slot);
>> nsl_set_alignment(ndd, ns_label, 0);
>> nsl_set_type_guid(ndd, ns_label, &nd_set->type_guid);
>> - nsl_set_region_uuid(ndd, ns_label, NULL);
>> + nsl_set_region_uuid(ndd, ns_label, &nd_set->uuid);
>> nsl_set_claim_class(ndd, ns_label, ndns->claim_class);
>> nsl_calculate_checksum(ndd, ns_label);
>> nd_dbg_dpa(nd_region, ndd, res, "\n");
>> @@ -1114,7 +1114,8 @@ int nd_pmem_namespace_label_update(struct nd_region *nd_region,
>> count++;
>> WARN_ON_ONCE(!count);
>>
>> - rc = init_labels(nd_mapping, count);
>> + /* Adding 1 to pre include the already added region label */
>> + rc = init_labels(nd_mapping, count + 1);
>> if (rc < 0)
>> return rc;
>>
>
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 08/20] nvdimm/label: Include region label in slot validation
2025-06-23 9:13 ` Jonathan Cameron
@ 2025-06-26 10:00 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-26 10:00 UTC (permalink / raw)
To: Jonathan Cameron
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 1967 bytes --]
On 23/06/25 10:13AM, Jonathan Cameron wrote:
>On Tue, 17 Jun 2025 18:09:32 +0530
>Neeraj Kumar <s.neeraj@samsung.com> wrote:
>
>> slot validation routine validates label slot by calculating label
>> checksum. It was only validating namespace label. This changeset also
>> validates region label if present.
>>
>> Also validate and calculate lsa v2.1 namespace label checksum
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>
>
>
>> diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
>> index 1e5a68013735..ca8256b31472 100644
>> --- a/drivers/nvdimm/nd.h
>> +++ b/drivers/nvdimm/nd.h
>> @@ -331,6 +331,22 @@ static inline bool nsl_region_uuid_equal(struct nd_namespace_label *ns_label,
>> return uuid_equal(&tmp, uuid);
>> }
>>
>> +static inline bool is_region_label(struct nvdimm_drvdata *ndd,
>> + struct nd_lsa_label *nd_label)
>> +{
>> + uuid_t ns_type, region_type;
>> +
>> + if (ndd->cxl) {
>> + uuid_parse(CXL_REGION_UUID, ®ion_type);
>> + import_uuid(&ns_type, nd_label->ns_label.cxl.type);
>> + if (uuid_equal(®ion_type, &ns_type))
>> + return true;
>> + else
>> + return false;
>
> return uuid_equal(®_type, &ns_type);
>
Sure, Will fix it in V1
>> + } else
>{}
>for all legs if one needs it.
>
>However, if you aren't going to add more code here later, just flip the condition
>and exit early.
>
> if (!ndd->cxl)
> return false;
>
> uuid_parse...
>
Thanks, Will fix it in V1
>> + return false;
>> +}
>> +
>> static inline bool rgl_uuid_equal(struct cxl_region_label *rg_label,
>> const uuid_t *uuid)
>> {
>> @@ -340,6 +356,11 @@ static inline bool rgl_uuid_equal(struct cxl_region_label *rg_label,
>> return uuid_equal(&tmp, uuid);
>> }
>>
>> +static inline u32 rgl_get_slot(struct cxl_region_label *rg_label)
>> +{
>> + return __le32_to_cpu(rg_label->slot);
>> +}
>> +
>> static inline u64 rgl_get_checksum(struct cxl_region_label *rg_label)
>> {
>> return __le64_to_cpu(rg_label->checksum);
>
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 12/20] nvdimm/namespace_label: Skip region label during namespace creation
2025-06-23 9:17 ` Jonathan Cameron
@ 2025-06-26 10:02 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-26 10:02 UTC (permalink / raw)
To: Jonathan Cameron
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 3469 bytes --]
On 23/06/25 10:17AM, Jonathan Cameron wrote:
>On Tue, 17 Jun 2025 18:09:36 +0530
>Neeraj Kumar <s.neeraj@samsung.com> wrote:
>
>> During namespace creation skip presence of region label if present.
>> Also preserve region label into labels list if present.
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>> ---
>> drivers/nvdimm/namespace_devs.c | 48 +++++++++++++++++++++++++++++----
>> 1 file changed, 43 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
>> index b081661b7aaa..ca8f8546170c 100644
>> --- a/drivers/nvdimm/namespace_devs.c
>> +++ b/drivers/nvdimm/namespace_devs.c
>> @@ -1976,6 +1976,10 @@ static struct device **scan_labels(struct nd_region *nd_region)
>> if (!nd_label)
>> continue;
>>
>> + /* skip region labels if present */
>> + if (is_region_label(ndd, nd_label))
>> + continue;
>> +
>> /* skip labels that describe extents outside of the region */
>> if (nsl_get_dpa(ndd, &nd_label->ns_label) < nd_mapping->start ||
>> nsl_get_dpa(ndd, &nd_label->ns_label) > map_end)
>> @@ -2014,9 +2018,29 @@ static struct device **scan_labels(struct nd_region *nd_region)
>>
>> if (count == 0) {
>> struct nd_namespace_pmem *nspm;
>> + for (i = 0; i < nd_region->ndr_mappings; i++) {
>> + struct nd_label_ent *le, *e;
>> + LIST_HEAD(list);
>>
>> - /* Publish a zero-sized namespace for userspace to configure. */
>> - nd_mapping_free_labels(nd_mapping);
>> + nd_mapping = &nd_region->mapping[i];
>> + if (list_empty(&nd_mapping->labels))
>> + continue;
>> +
>> + list_for_each_entry_safe(le, e, &nd_mapping->labels,
>> + list) {
>> + struct nd_lsa_label *nd_label = le->label;
>> +
>> + /* preserve region labels if present */
>> + if (is_region_label(ndd, nd_label))
>> + list_move_tail(&le->list, &list);
>> + }
>> +
>> + /* Publish a zero-sized namespace for userspace
>
>Comment syntax as before looks to be inconsistent with file.
>
Thanks, Will update it everywhere its inconsistent.
>> + * to configure.
>> + */
>> + nd_mapping_free_labels(nd_mapping);
>> + list_splice_init(&list, &nd_mapping->labels);
>> + }
>> nspm = kzalloc(sizeof(*nspm), GFP_KERNEL);
>> if (!nspm)
>> goto err;
>> @@ -2028,7 +2052,7 @@ static struct device **scan_labels(struct nd_region *nd_region)
>> } else if (is_memory(&nd_region->dev)) {
>> /* clean unselected labels */
>> for (i = 0; i < nd_region->ndr_mappings; i++) {
>> - struct list_head *l, *e;
>> + struct nd_label_ent *le, *e;
>> LIST_HEAD(list);
>> int j;
>>
>> @@ -2039,10 +2063,24 @@ static struct device **scan_labels(struct nd_region *nd_region)
>> }
>>
>> j = count;
>> - list_for_each_safe(l, e, &nd_mapping->labels) {
>> + list_for_each_entry_safe(le, e, &nd_mapping->labels,
>> + list) {
>> + struct nd_lsa_label *nd_label = le->label;
>> +
>> + /* preserve region labels */
>> + if (is_region_label(ndd, nd_label)) {
>> + list_move_tail(&le->list, &list);
>> + continue;
>> + }
>> +
>> + /* Once preserving selected ns label done
>Comment syntax.
Sure, Will fix it up
>> + * break out of loop
>> + */
>> if (!j--)
>> break;
>> - list_move_tail(l, &list);
>> +
>> + /* preserve selected ns label */
>> + list_move_tail(&le->list, &list);
>> }
>> nd_mapping_free_labels(nd_mapping);
>> list_splice_init(&list, &nd_mapping->labels);
>
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 13/20] cxl/mem: Refactor cxl pmem region auto-assembling
2025-06-23 9:20 ` Jonathan Cameron
@ 2025-06-26 10:03 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-26 10:03 UTC (permalink / raw)
To: Jonathan Cameron
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 2302 bytes --]
On 23/06/25 10:20AM, Jonathan Cameron wrote:
>On Tue, 17 Jun 2025 18:09:37 +0530
>Neeraj Kumar <s.neeraj@samsung.com> wrote:
>
>> In 84ec985944ef3, For cxl pmem region auto-assembly after endpoint port
>> probing, cxl_nvd presence was required. And for cxl region persistency,
>> region creation happens during nvdimm_probe which need the completion
>> of endpoint probe.
>>
>> It is therefore refactored cxl pmem region auto-assembly after endpoint
>> probing to cxl mem probing
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>For ordering requirements this needs more eyes. I've never cared that
>much about he persistency and auto assembly code so not something I have
>a good mental model of!
>
Sure, Will see how other maintainers responds to it. Thanks for your
feedback.
>
>> ---
>> drivers/cxl/core/port.c | 38 ++++++++++++++++++++++++++++++++++++++
>> drivers/cxl/cxl.h | 1 +
>> drivers/cxl/mem.c | 27 ++++++++++++++++++---------
>> drivers/cxl/port.c | 38 --------------------------------------
>> 4 files changed, 57 insertions(+), 47 deletions(-)
>
>> diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
>> index 2f03a4d5606e..aaea4eb178ef 100644
>> --- a/drivers/cxl/mem.c
>> +++ b/drivers/cxl/mem.c
>
>> @@ -180,6 +171,24 @@ static int cxl_mem_probe(struct device *dev)
>> return rc;
>> }
>>
>> + if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM)) {
>> + rc = devm_cxl_add_nvdimm(parent_port, cxlmd);
>> + if (rc) {
>> + if (rc == -ENODEV)
>> + dev_info(dev, "PMEM disabled by platform\n");
>> + return rc;
>> + }
>> + }
>> +
>> + /*
>> + * Now that all endpoint decoders are successfully enumerated, try to
>> + * assemble region autodiscovery from committed decoders.
>> + * Earlier it was part of cxl_endpoint_port_probe, So moved it here
>
>I would drop this history statement. Good to have in the patch description
>but no point in keeping it in the code. Just state what the requirements
>are now.
>
Okay, I will remove this and update commit message with the same
>> + * as cxl_nvd of the memdev needs to be available during the pmem
>> + * region auto-assembling
>> + */
>> + cxl_region_discovery(cxlmd->endpoint);
>> +
>> /*
>> * The kernel may be operating out of CXL memory on this device,
>
>
>
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 14/20] cxl/region: Add cxl pmem region creation routine for region persistency
2025-06-23 9:43 ` Jonathan Cameron
@ 2025-06-26 10:23 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-26 10:23 UTC (permalink / raw)
To: Jonathan Cameron
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 8221 bytes --]
On 23/06/25 10:43AM, Jonathan Cameron wrote:
>On Tue, 17 Jun 2025 18:09:38 +0530
>Neeraj Kumar <s.neeraj@samsung.com> wrote:
>
>> Added exported cxl_create_pmem_region routine to create cxl pmem region
>
>For function names always add () after and drop 'function/routine' etc.
>Ends up shorter and easier to read.
>
Sure, Will fix it accordingly
>> from LSA parsed cxl region information.
>> Inspirition for the function is taken from ndctl device attribute
>> (_store) call. It allocates cxlr and fills information parsed from LSA
>> and calls device_add(&cxlr->dev) to initiates further region creation
>> porbes
>Spell check.
>
Thanks, Will fix it up.
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>> ---
>> drivers/cxl/core/port.c | 6 ++
>> drivers/cxl/core/region.c | 208 ++++++++++++++++++++++++++++++++++++++
>> drivers/cxl/cxl.h | 11 ++
>> 3 files changed, 225 insertions(+)
>>
>
>> diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
>> index b98b1ccffd1c..8990e3c3474d 100644
>> --- a/drivers/cxl/core/region.c
>> +++ b/drivers/cxl/core/region.c
>> @@ -2522,6 +2522,214 @@ static ssize_t create_ram_region_show(struct device *dev,
>> return __create_region_show(to_cxl_root_decoder(dev), buf);
>> }
>>
>> +static ssize_t update_region_size(struct cxl_region *cxlr, u64 val)
>> +{
>> + int rc;
>> +
>> + rc = down_write_killable(&cxl_region_rwsem);
>ACQUIRE() as mentioned below.
>
Sure, Let me look at Dan's new ACQUIRE() series. I will update it in V1
>> + if (rc)
>> + return rc;
>> +
>> + if (val)
>> + rc = alloc_hpa(cxlr, val);
>> + else
>> + rc = free_hpa(cxlr);
>> + up_write(&cxl_region_rwsem);
>> +
>> + if (rc)
>> + return rc;
>
> return rc;
>
Thanks, I will update it.
>> +
>> + return 0;
>> +}
>> +
>> +static ssize_t update_region_dpa_size(struct cxl_region *cxlr,
>> + struct cxl_decoder *cxld,
>> + unsigned long long size)
>> +{
>> + int rc;
>> + struct cxl_endpoint_decoder *cxled =
>> + to_cxl_endpoint_decoder(&cxld->dev);
>> +
>> + if (!IS_ALIGNED(size, SZ_256M))
>> + return -EINVAL;
>> +
>> + rc = cxl_dpa_free(cxled);
>> + if (rc)
>> + return rc;
>> +
>> + if (size == 0)
>> + return 0;
>> +
>> + rc = cxl_dpa_alloc(cxled, size);
>return cxl_dpa_alloc()
>
>Unless something more is getting added here in later patches in which case
>you can ignore this comment.
>
Thanks, Will fix it accordingly
>> + if (rc)
>> + return rc;
>> +
>> + return 0;
>> +}
>> +
>> +static ssize_t update_region_dpa_mode(struct cxl_region *cxlr,
>> + struct cxl_decoder *cxld)
>> +{
>> + int rc;
>> + struct cxl_endpoint_decoder *cxled =
>> + to_cxl_endpoint_decoder(&cxld->dev);
>Maybe don't bother with local variable and just put this
>below as the parameter.
Sure, I will fix it.
>> +
>> + rc = cxl_dpa_set_mode(cxled, CXL_DECODER_PMEM);
>
>return cxl_dpa_set_mode()
>
>> + if (rc)
>> + return rc;
>> +
>> + return 0;
>> +}
>> +
>> +static size_t attach_region_target(struct cxl_region *cxlr,
>> + struct cxl_decoder *cxld, int pos)
>> +{
>> + int rc;
>> + struct cxl_endpoint_decoder *cxled =
>> + to_cxl_endpoint_decoder(&cxld->dev);
>> +
>> + rc = attach_target(cxlr, cxled, pos, TASK_INTERRUPTIBLE);
>> +
>No blank line here
Sure, I will fix it.
>> + if (rc < 0)
>Can it ever be > 0 ?
>If not, return attach_target() should be fine.
Yes we can directly return from here, will fix it in V1
>> + return rc;
>> +
>> + return 0;
>> +}
>> +
>> +static ssize_t commit_region(struct cxl_region *cxlr)
>> +{
>> + struct cxl_region_params *p = &cxlr->params;
>> + ssize_t rc;
>> +
>> + rc = down_write_killable(&cxl_region_rwsem);
>
>Maybe look at Dan's new ACQUIRE() series. The last patch in there
>is targeting code similar to this.
Sure, Let me look at Dan's new ACQUIRE() series. I will update it in V1
>
>> + if (rc)
>> + return rc;
>> +
>> + /* Already in the requested state? */
>> + if (p->state >= CXL_CONFIG_COMMIT)
>> + goto out;
>> +
>> + /* Not ready to commit? */
>> + if (p->state < CXL_CONFIG_ACTIVE) {
>> + rc = -ENXIO;
>> + goto out;
>> + }
>> +
>> + /*
>> + * Invalidate caches before region setup to drop any speculative
>> + * consumption of this address space
>> + */
>> + rc = cxl_region_invalidate_memregion(cxlr);
>> + if (rc)
>> + goto out;
>> +
>> + rc = cxl_region_decode_commit(cxlr);
>> + if (rc == 0)
>With AQUIRE() stuff you can just do
> if (rc)
> return rc;
>
>here
>
Thanks, Will update it accordingly.
>> + p->state = CXL_CONFIG_COMMIT;
>> +out:
>> + up_write(&cxl_region_rwsem);
>> + if (rc)
>> + return rc;
>> + return 0;
>> +}
>> +
>> +static struct cxl_region *
>> +devm_cxl_pmem_add_region(struct cxl_root_decoder *cxlrd,
>> + struct cxl_decoder *cxld,
>> + struct cxl_pmem_region_params *params, int id,
>> + enum cxl_decoder_mode mode, enum cxl_decoder_type type)
>> +{
>> + struct cxl_port *port;
>> + struct cxl_region *cxlr;
>> + struct cxl_region_params *p;
>> + struct device *dev;
>> + int rc;
>> +
>> + if (!cxlrd)
>> + return ERR_PTR(-EINVAL);
>
>For a check like this, add a comment on why it might be NULL.
>If it can't be, then drop the check.
>
Sure, I will fix it in V1
>> +
>> + port = to_cxl_port(cxlrd->cxlsd.cxld.dev.parent);
>
>Maybe add a comment on which port this actually is. These long indirections
>can make that hard to figure out!
>
Sure, I will fix it in V1
>> +
>> + cxlr = cxl_region_alloc(cxlrd, id);
>> + if (IS_ERR(cxlr))
>> + return cxlr;
>> + cxlr->mode = mode;
>> + cxlr->type = type;
>> +
>> + dev = &cxlr->dev;
>> + rc = dev_set_name(dev, "region%d", id);
>> + if (rc)
>> + goto err;
>> +
>> + p = &cxlr->params;
>> + p->uuid = params->uuid;
>> + p->interleave_ways = params->nlabel;
>> + p->interleave_granularity = params->ig;
>> +
>> + /* Update region size */
>> + if (update_region_size(cxlr, params->rawsize))
>> + goto err;
>> +
>> + /* Flush cxl wq */
>
>Much more useful to say 'why' you are flushing it. It's obvious
>from the code that you are.
>
Sure Will update the comment properly
>> + cxl_wq_flush();
>> +
>> + /* Clear DPA Size */
>
>I'd look at all these comments and where they are obvious, drop the comment
>and let the code speak for itself.
>
Sure, Will update accordingly
>> + if (update_region_dpa_size(cxlr, cxld, 0))
>> + goto err;
>> +
>> + /* Update DPA mode */
>> + if (update_region_dpa_mode(cxlr, cxld))
>> + goto err;
>> +
>> + /* Update DPA Size */
>> + if (update_region_dpa_size(cxlr, cxld, params->rawsize))
>> + goto err;
>> +
>> + /* Attach region targets */
>It's attaching just one by the look of it. I'd just drop the comment.
>
Sure, Will update accordingly
>> + if (attach_region_target(cxlr, cxld, params->position))
>> + goto err;
>> +
>> + /* Commit Region */
>> + if (commit_region(cxlr))
>> + goto err;
>> +
>> + rc = device_add(dev);
>> + if (rc)
>> + goto err;
>> +
>> + rc = devm_add_action_or_reset(port->uport_dev, unregister_region, cxlr);
>> + if (rc)
>> + return ERR_PTR(rc);
>> +
>> + dev_dbg(port->uport_dev, "%s: created %s\n",
>> + dev_name(&cxlrd->cxlsd.cxld.dev), dev_name(dev));
>> + return cxlr;
>> +
>> +err:
>> + put_device(dev);
>> + return ERR_PTR(rc);
>> +}
>> +
>> +struct cxl_region *cxl_create_pmem_region(struct cxl_root_decoder *cxlrd,
>> + struct cxl_decoder *cxld,
>> + struct cxl_pmem_region_params *params, 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);
>> + }
>I'm a little surprised not to see cleanup of the memregion via
>devm somewhere here.
Actually its cleanup is happening at cxl_region_release().
During cxl_region_alloc, cxlr is allocated whose dev->type is
cxl_region_type
const struct device_type cxl_region_type = {
.name = "cxl_region",
.release = cxl_region_release,
.groups = region_groups
};
>> +
>> + return devm_cxl_pmem_add_region(cxlrd, cxld, params, id,
>> + CXL_DECODER_PMEM, CXL_DECODER_HOSTONLYMEM);
>> +}
>> +EXPORT_SYMBOL_NS_GPL(cxl_create_pmem_region, "CXL");
>> +
>> static struct cxl_region *__create_region(struct cxl_root_decoder *cxlrd,
>> enum cxl_decoder_mode mode, int id)
>> {
>
>
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 15/20] cxl: Add a routine to find cxl root decoder on cxl bus
2025-06-23 9:44 ` Jonathan Cameron
@ 2025-06-26 10:38 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-26 10:38 UTC (permalink / raw)
To: Jonathan Cameron
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 2348 bytes --]
On 23/06/25 10:44AM, Jonathan Cameron wrote:
>On Tue, 17 Jun 2025 18:09:39 +0530
>Neeraj Kumar <s.neeraj@samsung.com> wrote:
>
>> Add cxl_find_root_decoder to find root decoder on cxl bus. It is used to
>> find root decoder during region creation
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>> ---
>> drivers/cxl/core/port.c | 26 ++++++++++++++++++++++++++
>> drivers/cxl/cxl.h | 1 +
>> 2 files changed, 27 insertions(+)
>>
>> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
>> index 2452f7c15b2d..94d9322b8e38 100644
>> --- a/drivers/cxl/core/port.c
>> +++ b/drivers/cxl/core/port.c
>> @@ -513,6 +513,32 @@ struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev)
>> }
>> EXPORT_SYMBOL_NS_GPL(to_cxl_switch_decoder, "CXL");
>>
>> +static int match_root_decoder(struct device *dev, void *data)
>> +{
>> + return is_root_decoder(dev);
>> +}
>> +
>> +/**
>> + * cxl_find_root_decoder() - find a cxl root decoder on cxl bus
>> + * @port: any descendant port in root-cxl-port topology
>> + */
>> +struct cxl_root_decoder *cxl_find_root_decoder(struct cxl_port *port)
>> +{
>> + struct cxl_root *cxl_root __free(put_cxl_root) = find_cxl_root(port);
>> + struct device *dev;
>> +
>> + if (!cxl_root)
>> + return NULL;
>> +
>> + dev = device_find_child(&cxl_root->port.dev, NULL, match_root_decoder);
>> +
>
>No blank line here. Generally when we have a call then an error check
>it is easier to see how they are related if we keep them in one block.
>
Thanks, Will fix it in V1
>> + if (!dev)
>> + return NULL;
>> +
>> + return to_cxl_root_decoder(dev);
>> +}
>> +EXPORT_SYMBOL_NS_GPL(cxl_find_root_decoder, "CXL");
>> +
>> static void cxl_ep_release(struct cxl_ep *ep)
>> {
>> put_device(ep->ep);
>> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
>> index 30c80e04cb27..2c6a782d0941 100644
>> --- a/drivers/cxl/cxl.h
>> +++ b/drivers/cxl/cxl.h
>> @@ -871,6 +871,7 @@ bool is_cxl_nvdimm_bridge(struct device *dev);
>> int devm_cxl_add_nvdimm(struct cxl_port *parent_port, struct cxl_memdev *cxlmd);
>> struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_port *port);
>> void cxl_region_discovery(struct cxl_port *port);
>> +struct cxl_root_decoder *cxl_find_root_decoder(struct cxl_port *port);
>>
>> #ifdef CONFIG_CXL_REGION
>> bool is_cxl_pmem_region(struct device *dev);
>
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 18/20] cxl/pmem: Add support of cxl lsa 2.1 support in cxl pmem
2025-06-23 9:48 ` Jonathan Cameron
@ 2025-06-26 10:41 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-26 10:41 UTC (permalink / raw)
To: Jonathan Cameron
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 3250 bytes --]
On 23/06/25 10:48AM, Jonathan Cameron wrote:
>On Tue, 17 Jun 2025 18:09:42 +0530
>Neeraj Kumar <s.neeraj@samsung.com> wrote:
>
>> Add support of cxl lsa 2.1 using NDD_CXL_LABEL flag. It also creates cxl
>> region based on region information parsed from LSA.
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>> ---
>> drivers/cxl/pmem.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 59 insertions(+)
>>
>> diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c
>> index ffcebb8d382f..2733d79b32d5 100644
>> --- a/drivers/cxl/pmem.c
>> +++ b/drivers/cxl/pmem.c
>> @@ -58,6 +58,63 @@ static const struct attribute_group *cxl_dimm_attribute_groups[] = {
>> NULL
>> };
>>
>> +static int match_ep_decoder(struct device *dev, void *data)
>> +{
>> + struct cxl_decoder *cxld = to_cxl_decoder(dev);
>> +
>> + if (!cxld->region)
>> + return 1;
>> + else
>> + return 0;
>> +}
>> +
>> +static struct cxl_decoder *cxl_find_free_decoder(struct cxl_port *port)
>> +{
>> + struct device *dev;
>> +
>> + dev = device_find_child(&port->dev, NULL, match_ep_decoder);
>> + if (!dev)
>> + return NULL;
>> +
>> + return to_cxl_decoder(dev);
>> +}
>> +
>> +static int create_pmem_region(struct nvdimm *nvdimm)
>> +{
>> + struct cxl_nvdimm *cxl_nvd;
>> + struct cxl_memdev *cxlmd;
>> + struct cxl_nvdimm_bridge *cxl_nvb;
>> + struct cxl_pmem_region_params *params;
>> + struct cxl_root_decoder *cxlrd;
>> + struct cxl_decoder *cxld;
>> + struct cxl_region *cxlr;
>> +
>> + if (!nvdimm)
>> + return -ENOTTY;
>
>As with other checks like this, it is useful to add a comment on when you can
>call this function with a null parameter.
>
Sure, Will fix it accordingly
>> +
>> + if (!nvdimm_has_cxl_region(nvdimm))
>> + return 0;
>> +
>> + cxl_nvd = nvdimm_provider_data(nvdimm);
>> + params = nvdimm_get_cxl_region_param(nvdimm);
>> + cxlmd = cxl_nvd->cxlmd;
>> + cxl_nvb = cxlmd->cxl_nvb;
>> + cxlrd = cxlmd->cxlrd;
>> +
>> + /* FIXME: Limitation: Region creation only when interleave way == 1 */
>> + if (params->nlabel == 1) {
>> + cxld = cxl_find_free_decoder(cxlmd->endpoint);
>> + cxlr = cxl_create_pmem_region(cxlrd, cxld, params,
>> + atomic_read(&cxlrd->region_id));
>> + if (IS_ERR(cxlr))
>> + dev_dbg(&cxlmd->dev, "Region Creation failed\n");
>> + } else {
>> + dev_dbg(&cxlmd->dev, "Region Creation is not supported with iw > 1\n");
>> + }
>
>Flip logic to check for unhandled case first and also return an error if this happens
>rather than silently carrying on. dev_info() is appropriate here.
>
Thanks, Will fix it in V1
>> +
>> + return 0;
>> +}
>> +
>> static int cxl_nvdimm_probe(struct device *dev)
>> {
>> struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev);
>> @@ -74,6 +131,7 @@ static int cxl_nvdimm_probe(struct device *dev)
>> return rc;
>>
>> set_bit(NDD_LABELING, &flags);
>> + set_bit(NDD_CXL_LABEL, &flags);
>> set_bit(NDD_REGISTER_SYNC, &flags);
>> set_bit(ND_CMD_GET_CONFIG_SIZE, &cmd_mask);
>> set_bit(ND_CMD_GET_CONFIG_DATA, &cmd_mask);
>> @@ -86,6 +144,7 @@ static int cxl_nvdimm_probe(struct device *dev)
>> return -ENOMEM;
>>
>> dev_set_drvdata(dev, nvdimm);
>> + create_pmem_region(nvdimm);
>> return devm_add_action_or_reset(dev, unregister_nvdimm, nvdimm);
>> }
>>
>
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 19/20] cxl/pmem_region: Prep patch to accommodate pmem_region attributes
2025-06-23 9:53 ` Jonathan Cameron
@ 2025-06-26 10:45 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-26 10:45 UTC (permalink / raw)
To: Jonathan Cameron
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 3356 bytes --]
On 23/06/25 10:53AM, Jonathan Cameron wrote:
>On Tue, 17 Jun 2025 18:09:43 +0530
>Neeraj Kumar <s.neeraj@samsung.com> wrote:
>
>> Created a separate file core/pmem_region.c along with CONFIG_PMEM_REGION
>> Moved pmem_region related code from core/region.c to core/pmem_region.c
>> For region label update, need to create device attribute, which calls
>> nvdimm exported function thus making pmem_region dependent on libnvdimm.
>> Because of this dependency of pmem region on libnvdimm, segregated pmem
>
>segregate
>
Thanks, Will fix the commit message.
>> region related code from core/region.c
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>> ---
>> drivers/cxl/Kconfig | 12 ++
>> drivers/cxl/core/Makefile | 1 +
>> drivers/cxl/core/core.h | 8 +-
>> drivers/cxl/core/pmem_region.c | 222 +++++++++++++++++++++++++++++++++
>> drivers/cxl/core/port.c | 2 +-
>> drivers/cxl/core/region.c | 217 ++------------------------------
>> drivers/cxl/cxl.h | 42 +++++--
>> tools/testing/cxl/Kbuild | 1 +
>> 8 files changed, 283 insertions(+), 222 deletions(-)
>> create mode 100644 drivers/cxl/core/pmem_region.c
>>
>> diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
>> index 876469e23f7a..f0cbb096bfe7 100644
>> --- a/drivers/cxl/Kconfig
>> +++ b/drivers/cxl/Kconfig
>> @@ -128,6 +128,18 @@ config CXL_REGION
>>
>> If unsure say 'y'
>>
>> +config CXL_PMEM_REGION
>> + bool "CXL: Pmem Region Support"
>> + default CXL_BUS
>> + depends on CXL_REGION
>> + select LIBNVDIMM if CXL_BUS = y
>
>This is in the block covered by if CXL_BUS so I think you can simplify this check.
>
yes, its part of CXL_BUS block. I will update it as "select LIBNVDIMM".
Actually for CONFIG_CXL_PMEM_REGION=y we have dependency on CONFIG_LIBNVDIMM.
>> + help
>> + Enable the CXL core to enumerate and provision CXL pmem regions.
>> + A CXL pmem region need to update region label into LSA. For LSA
>> + updation/deletion libnvdimm is required.
>> +
>> + If unsure say 'y'
>> +
>> config CXL_REGION_INVALIDATION_TEST
>> bool "CXL: Region Cache Management Bypass (TEST)"
>> depends on CXL_REGION
>
>> diff --git a/drivers/cxl/core/pmem_region.c b/drivers/cxl/core/pmem_region.c
>> new file mode 100644
>> index 000000000000..a29526c27d40
>> --- /dev/null
>> +++ b/drivers/cxl/core/pmem_region.c
>> @@ -0,0 +1,222 @@
>
>> @@ -3273,92 +3155,6 @@ static struct cxl_dax_region *cxl_dax_region_alloc(struct cxl_region *cxlr)
>> return cxlr_dax;
>> }
>
>> static void cxlr_dax_unregister(void *_cxlr_dax)
>> {
>> struct cxl_dax_region *cxlr_dax = _cxlr_dax;
>> @@ -3646,7 +3442,10 @@ static int cxl_region_probe(struct device *dev)
>>
>> switch (cxlr->mode) {
>> case CXL_DECODER_PMEM:
>> - return devm_cxl_add_pmem_region(cxlr);
>> + if (IS_ENABLED(CONFIG_CXL_PMEM_REGION))
>> + return devm_cxl_add_pmem_region(cxlr);
>> + else
>> + return -EINVAL;
> if (!IS_ENABLED(CONFIG_CXL_PMEM_REGION))
> return -EINVAL;
>
> return devm_cxl_add_pmem_region()
>
>Where ever possible keep the error conditions as the out of line ones.
>That generally improves code readability and is common practice in the kernel.
>
Thanks for suggestion Jonathan. Sure will fix it in V1
>> case CXL_DECODER_RAM:
>> /*
>> * The region can not be manged by CXL if any portion of
>
>
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 20/20] cxl/pmem_region: Add cxl region label updation and deletion device attributes
2025-06-23 9:56 ` Jonathan Cameron
@ 2025-06-26 10:48 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-26 10:48 UTC (permalink / raw)
To: Jonathan Cameron
Cc: dan.j.williams, dave, dave.jiang, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 2776 bytes --]
On 23/06/25 10:56AM, Jonathan Cameron wrote:
>On Tue, 17 Jun 2025 18:09:44 +0530
>Neeraj Kumar <s.neeraj@samsung.com> wrote:
>
>> Using these attributes region label is added/deleted into LSA. These
>> attributes are called from userspace (ndctl) after region creation.
>
>These need documentation. Documentation/ABI/testing/sysfs-bus-cxl
>is probably the right place.
>
Sure, Will update this in Documentation as well as update it in commit
message
>
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>> ---
>> drivers/cxl/core/pmem_region.c | 103 +++++++++++++++++++++++++++++++++
>> drivers/cxl/cxl.h | 1 +
>> 2 files changed, 104 insertions(+)
>>
>> diff --git a/drivers/cxl/core/pmem_region.c b/drivers/cxl/core/pmem_region.c
>> index a29526c27d40..f582d796c21b 100644
>> --- a/drivers/cxl/core/pmem_region.c
>> +++ b/drivers/cxl/core/pmem_region.c
>> @@ -45,8 +45,111 @@ static void cxl_pmem_region_release(struct device *dev)
>> kfree(cxlr_pmem);
>> }
>>
>> +static ssize_t region_label_update_store(struct device *dev,
>> + struct device_attribute *attr,
>> + const char *buf, size_t len)
>> +{
>> + struct cxl_pmem_region *cxlr_pmem = to_cxl_pmem_region(dev);
>> + struct cxl_region *cxlr = cxlr_pmem->cxlr;
>> + struct cxl_region_params *p = &cxlr->params;
>> + ssize_t rc;
>> + bool update;
>> +
>> + rc = kstrtobool(buf, &update);
>> + if (rc)
>> + return rc;
>> +
>> + rc = down_write_killable(&cxl_region_rwsem);
>
>Another use case for ACQUIRE()
>
Sure, I will look at Dan's new ACQUIRE() series. I will update it in V1
>> + if (rc)
>> + return rc;
>> +
>> + /* Region not yet committed */
>> + if (update && p->state != CXL_CONFIG_COMMIT) {
>> + dev_dbg(dev, "region not committed, can't update into LSA\n");
>> + rc = -ENXIO;
>> + goto out;
>> + }
>> +
>> + if (cxlr && cxlr->cxlr_pmem && cxlr->cxlr_pmem->nd_region) {
>> + rc = nd_region_label_update(cxlr->cxlr_pmem->nd_region);
>> +
>> + if (!rc)
>> + p->region_label_state = 1;
>> + }
>> +
>> +out:
>> + up_write(&cxl_region_rwsem);
>> +
>> + if (rc)
>> + return rc;
>> +
>> + return len;
>> +}
>
>> +
>> +static struct attribute *cxl_pmem_region_attrs[] = {
>> + &dev_attr_region_label_update.attr,
>> + &dev_attr_region_label_delete.attr,
>> + NULL,
>No need for trailing commas on terminating entries as we don't want it to be easy
>to put something after them.
>
Sure, Will fix it in V1
>> +};
>> +
>> +struct attribute_group cxl_pmem_region_group = {
>> + .attrs = cxl_pmem_region_attrs,
>> +};
>> +
>> static const struct attribute_group *cxl_pmem_region_attribute_groups[] = {
>> &cxl_base_attribute_group,
>> + &cxl_pmem_region_group,
>> NULL,
>Hmm. Drop this trailing comma perhaps whilst here.
>> };
>
Sure, I will update it in V1
>
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 15/20] cxl: Add a routine to find cxl root decoder on cxl bus
2025-06-17 12:39 ` [RFC PATCH 15/20] cxl: Add a routine to find cxl root decoder on cxl bus Neeraj Kumar
2025-06-23 9:44 ` Jonathan Cameron
@ 2025-06-26 19:19 ` Alison Schofield
2025-06-27 9:03 ` Neeraj Kumar
2025-07-10 16:23 ` Dave Jiang
2 siblings, 1 reply; 66+ messages in thread
From: Alison Schofield @ 2025-06-26 19:19 UTC (permalink / raw)
To: Neeraj Kumar
Cc: dan.j.williams, dave, jonathan.cameron, dave.jiang,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
On Tue, Jun 17, 2025 at 06:09:39PM +0530, Neeraj Kumar wrote:
> Add cxl_find_root_decoder to find root decoder on cxl bus. It is used to
> find root decoder during region creation
Does the existing to_cxl_root_decoder() provide what you need here?
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
> ---
> drivers/cxl/core/port.c | 26 ++++++++++++++++++++++++++
> drivers/cxl/cxl.h | 1 +
> 2 files changed, 27 insertions(+)
>
> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
> index 2452f7c15b2d..94d9322b8e38 100644
> --- a/drivers/cxl/core/port.c
> +++ b/drivers/cxl/core/port.c
> @@ -513,6 +513,32 @@ struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev)
> }
> EXPORT_SYMBOL_NS_GPL(to_cxl_switch_decoder, "CXL");
>
> +static int match_root_decoder(struct device *dev, void *data)
> +{
> + return is_root_decoder(dev);
> +}
> +
> +/**
> + * cxl_find_root_decoder() - find a cxl root decoder on cxl bus
> + * @port: any descendant port in root-cxl-port topology
> + */
> +struct cxl_root_decoder *cxl_find_root_decoder(struct cxl_port *port)
> +{
> + struct cxl_root *cxl_root __free(put_cxl_root) = find_cxl_root(port);
> + struct device *dev;
> +
> + if (!cxl_root)
> + return NULL;
> +
> + dev = device_find_child(&cxl_root->port.dev, NULL, match_root_decoder);
> +
> + if (!dev)
> + return NULL;
> +
> + return to_cxl_root_decoder(dev);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_find_root_decoder, "CXL");
> +
> static void cxl_ep_release(struct cxl_ep *ep)
> {
> put_device(ep->ep);
> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> index 30c80e04cb27..2c6a782d0941 100644
> --- a/drivers/cxl/cxl.h
> +++ b/drivers/cxl/cxl.h
> @@ -871,6 +871,7 @@ bool is_cxl_nvdimm_bridge(struct device *dev);
> int devm_cxl_add_nvdimm(struct cxl_port *parent_port, struct cxl_memdev *cxlmd);
> struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_port *port);
> void cxl_region_discovery(struct cxl_port *port);
> +struct cxl_root_decoder *cxl_find_root_decoder(struct cxl_port *port);
>
> #ifdef CONFIG_CXL_REGION
> bool is_cxl_pmem_region(struct device *dev);
> --
> 2.34.1
>
>
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 15/20] cxl: Add a routine to find cxl root decoder on cxl bus
2025-06-26 19:19 ` Alison Schofield
@ 2025-06-27 9:03 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-06-27 9:03 UTC (permalink / raw)
To: Alison Schofield
Cc: dan.j.williams, dave, jonathan.cameron, dave.jiang,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 2816 bytes --]
On 26/06/25 12:19PM, Alison Schofield wrote:
>On Tue, Jun 17, 2025 at 06:09:39PM +0530, Neeraj Kumar wrote:
>> Add cxl_find_root_decoder to find root decoder on cxl bus. It is used to
>> find root decoder during region creation
>
>Does the existing to_cxl_root_decoder() provide what you need here?
>
Hi Alison,
Actually, my need is to find decoder0.0 from port1, with which endpoint device is connected.
Here i am already using to_cxl_root_decoder() inside cxl_find_root_decoder().
In cxl_find_root_decoder(), First i am finding dev which is required by to_cxl_root_decoder()
struct cxl_root_decoder *cxl_find_root_decoder(struct cxl_port *port)
{
struct cxl_root *cxl_root __free(put_cxl_root) = find_cxl_root(port);
struct device *dev = device_find_child(&cxl_root->port.dev, NULL, match_root_decoder);
return to_cxl_root_decoder(dev);
}
Thanks,
Neeraj
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>> ---
>> drivers/cxl/core/port.c | 26 ++++++++++++++++++++++++++
>> drivers/cxl/cxl.h | 1 +
>> 2 files changed, 27 insertions(+)
>>
>> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
>> index 2452f7c15b2d..94d9322b8e38 100644
>> --- a/drivers/cxl/core/port.c
>> +++ b/drivers/cxl/core/port.c
>> @@ -513,6 +513,32 @@ struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev)
>> }
>> EXPORT_SYMBOL_NS_GPL(to_cxl_switch_decoder, "CXL");
>>
>> +static int match_root_decoder(struct device *dev, void *data)
>> +{
>> + return is_root_decoder(dev);
>> +}
>> +
>> +/**
>> + * cxl_find_root_decoder() - find a cxl root decoder on cxl bus
>> + * @port: any descendant port in root-cxl-port topology
>> + */
>> +struct cxl_root_decoder *cxl_find_root_decoder(struct cxl_port *port)
>> +{
>> + struct cxl_root *cxl_root __free(put_cxl_root) = find_cxl_root(port);
>> + struct device *dev;
>> +
>> + if (!cxl_root)
>> + return NULL;
>> +
>> + dev = device_find_child(&cxl_root->port.dev, NULL, match_root_decoder);
>> +
>> + if (!dev)
>> + return NULL;
>> +
>> + return to_cxl_root_decoder(dev);
>> +}
>> +EXPORT_SYMBOL_NS_GPL(cxl_find_root_decoder, "CXL");
>> +
>> static void cxl_ep_release(struct cxl_ep *ep)
>> {
>> put_device(ep->ep);
>> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
>> index 30c80e04cb27..2c6a782d0941 100644
>> --- a/drivers/cxl/cxl.h
>> +++ b/drivers/cxl/cxl.h
>> @@ -871,6 +871,7 @@ bool is_cxl_nvdimm_bridge(struct device *dev);
>> int devm_cxl_add_nvdimm(struct cxl_port *parent_port, struct cxl_memdev *cxlmd);
>> struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_port *port);
>> void cxl_region_discovery(struct cxl_port *port);
>> +struct cxl_root_decoder *cxl_find_root_decoder(struct cxl_port *port);
>>
>> #ifdef CONFIG_CXL_REGION
>> bool is_cxl_pmem_region(struct device *dev);
>> --
>> 2.34.1
>>
>>
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 02/20] nvdimm/label: Prep patch to accommodate cxl lsa 2.1 support
2025-06-17 12:39 ` [RFC PATCH 02/20] nvdimm/label: Prep patch to accommodate cxl lsa 2.1 support Neeraj Kumar
2025-06-23 10:53 ` Jonathan Cameron
@ 2025-07-02 17:55 ` Ira Weiny
2025-07-03 10:04 ` Neeraj Kumar
1 sibling, 1 reply; 66+ messages in thread
From: Ira Weiny @ 2025-07-02 17:55 UTC (permalink / raw)
To: Neeraj Kumar, dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
Neeraj Kumar wrote:
> In order to accommodate cxl lsa 2.1 format region label, renamed
> nd_namespace_label to nd_lsa_label.
This does not really make it clear why a name change is required.
Could you elaborate here?
Ira
>
> No functional change introduced.
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
> ---
> drivers/nvdimm/label.c | 79 ++++++++++++++++++---------------
> drivers/nvdimm/label.h | 12 ++++-
> drivers/nvdimm/namespace_devs.c | 74 +++++++++++++++---------------
> drivers/nvdimm/nd.h | 2 +-
> 4 files changed, 92 insertions(+), 75 deletions(-)
>
> diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
> index 48b5ba90216d..30bccad98939 100644
> --- a/drivers/nvdimm/label.c
> +++ b/drivers/nvdimm/label.c
> @@ -271,7 +271,7 @@ static void nd_label_copy(struct nvdimm_drvdata *ndd,
> memcpy(dst, src, sizeof_namespace_index(ndd));
> }
>
> -static struct nd_namespace_label *nd_label_base(struct nvdimm_drvdata *ndd)
> +static struct nd_lsa_label *nd_label_base(struct nvdimm_drvdata *ndd)
> {
> void *base = to_namespace_index(ndd, 0);
>
> @@ -279,7 +279,7 @@ static struct nd_namespace_label *nd_label_base(struct nvdimm_drvdata *ndd)
> }
>
> static int to_slot(struct nvdimm_drvdata *ndd,
> - struct nd_namespace_label *nd_label)
> + struct nd_lsa_label *nd_label)
> {
> unsigned long label, base;
>
> @@ -289,14 +289,14 @@ static int to_slot(struct nvdimm_drvdata *ndd,
> return (label - base) / sizeof_namespace_label(ndd);
> }
>
> -static struct nd_namespace_label *to_label(struct nvdimm_drvdata *ndd, int slot)
> +static struct nd_lsa_label *to_label(struct nvdimm_drvdata *ndd, int slot)
> {
> unsigned long label, base;
>
> base = (unsigned long) nd_label_base(ndd);
> label = base + sizeof_namespace_label(ndd) * slot;
>
> - return (struct nd_namespace_label *) label;
> + return (struct nd_lsa_label *) label;
> }
>
> #define for_each_clear_bit_le(bit, addr, size) \
> @@ -382,14 +382,14 @@ static void nsl_calculate_checksum(struct nvdimm_drvdata *ndd,
> }
>
> static bool slot_valid(struct nvdimm_drvdata *ndd,
> - struct nd_namespace_label *nd_label, u32 slot)
> + struct nd_lsa_label *nd_label, u32 slot)
> {
> bool valid;
>
> /* check that we are written where we expect to be written */
> - if (slot != nsl_get_slot(ndd, nd_label))
> + if (slot != nsl_get_slot(ndd, &nd_label->ns_label))
> return false;
> - valid = nsl_validate_checksum(ndd, nd_label);
> + valid = nsl_validate_checksum(ndd, &nd_label->ns_label);
> if (!valid)
> dev_dbg(ndd->dev, "fail checksum. slot: %d\n", slot);
> return valid;
> @@ -405,7 +405,8 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd)
> return 0; /* no label, nothing to reserve */
>
> for_each_clear_bit_le(slot, free, nslot) {
> - struct nd_namespace_label *nd_label;
> + struct nd_lsa_label *nd_label;
> + struct nd_namespace_label *ns_label;
> struct nd_region *nd_region = NULL;
> struct nd_label_id label_id;
> struct resource *res;
> @@ -413,16 +414,17 @@ int nd_label_reserve_dpa(struct nvdimm_drvdata *ndd)
> u32 flags;
>
> nd_label = to_label(ndd, slot);
> + ns_label = &nd_label->ns_label;
>
> if (!slot_valid(ndd, nd_label, slot))
> continue;
>
> - nsl_get_uuid(ndd, nd_label, &label_uuid);
> - flags = nsl_get_flags(ndd, nd_label);
> + nsl_get_uuid(ndd, ns_label, &label_uuid);
> + flags = nsl_get_flags(ndd, ns_label);
> nd_label_gen_id(&label_id, &label_uuid, flags);
> res = nvdimm_allocate_dpa(ndd, &label_id,
> - nsl_get_dpa(ndd, nd_label),
> - nsl_get_rawsize(ndd, nd_label));
> + nsl_get_dpa(ndd, ns_label),
> + nsl_get_rawsize(ndd, ns_label));
> nd_dbg_dpa(nd_region, ndd, res, "reserve\n");
> if (!res)
> return -EBUSY;
> @@ -564,14 +566,14 @@ int nd_label_active_count(struct nvdimm_drvdata *ndd)
> return 0;
>
> for_each_clear_bit_le(slot, free, nslot) {
> - struct nd_namespace_label *nd_label;
> + struct nd_lsa_label *nd_label;
>
> nd_label = to_label(ndd, slot);
>
> if (!slot_valid(ndd, nd_label, slot)) {
> - u32 label_slot = nsl_get_slot(ndd, nd_label);
> - u64 size = nsl_get_rawsize(ndd, nd_label);
> - u64 dpa = nsl_get_dpa(ndd, nd_label);
> + u32 label_slot = nsl_get_slot(ndd, &nd_label->ns_label);
> + u64 size = nsl_get_rawsize(ndd, &nd_label->ns_label);
> + u64 dpa = nsl_get_dpa(ndd, &nd_label->ns_label);
>
> dev_dbg(ndd->dev,
> "slot%d invalid slot: %d dpa: %llx size: %llx\n",
> @@ -583,7 +585,7 @@ int nd_label_active_count(struct nvdimm_drvdata *ndd)
> return count;
> }
>
> -struct nd_namespace_label *nd_label_active(struct nvdimm_drvdata *ndd, int n)
> +struct nd_lsa_label *nd_label_active(struct nvdimm_drvdata *ndd, int n)
> {
> struct nd_namespace_index *nsindex;
> unsigned long *free;
> @@ -593,7 +595,7 @@ struct nd_namespace_label *nd_label_active(struct nvdimm_drvdata *ndd, int n)
> return NULL;
>
> for_each_clear_bit_le(slot, free, nslot) {
> - struct nd_namespace_label *nd_label;
> + struct nd_lsa_label *nd_label;
>
> nd_label = to_label(ndd, slot);
> if (!slot_valid(ndd, nd_label, slot))
> @@ -731,7 +733,7 @@ static int nd_label_write_index(struct nvdimm_drvdata *ndd, int index, u32 seq,
> }
>
> static unsigned long nd_label_offset(struct nvdimm_drvdata *ndd,
> - struct nd_namespace_label *nd_label)
> + struct nd_lsa_label *nd_label)
> {
> return (unsigned long) nd_label
> - (unsigned long) to_namespace_index(ndd, 0);
> @@ -885,7 +887,8 @@ static int __pmem_label_update(struct nd_region *nd_region,
> struct nd_namespace_common *ndns = &nspm->nsio.common;
> struct nd_interleave_set *nd_set = nd_region->nd_set;
> struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
> - struct nd_namespace_label *nd_label;
> + struct nd_lsa_label *nd_label;
> + struct nd_namespace_label *ns_label;
> struct nd_namespace_index *nsindex;
> struct nd_label_ent *label_ent;
> struct nd_label_id label_id;
> @@ -918,20 +921,22 @@ static int __pmem_label_update(struct nd_region *nd_region,
>
> nd_label = to_label(ndd, slot);
> memset(nd_label, 0, sizeof_namespace_label(ndd));
> - nsl_set_uuid(ndd, nd_label, nspm->uuid);
> - nsl_set_name(ndd, nd_label, nspm->alt_name);
> - nsl_set_flags(ndd, nd_label, flags);
> - nsl_set_nlabel(ndd, nd_label, nd_region->ndr_mappings);
> - nsl_set_nrange(ndd, nd_label, 1);
> - nsl_set_position(ndd, nd_label, pos);
> - nsl_set_isetcookie(ndd, nd_label, cookie);
> - nsl_set_rawsize(ndd, nd_label, resource_size(res));
> - nsl_set_lbasize(ndd, nd_label, nspm->lbasize);
> - nsl_set_dpa(ndd, nd_label, res->start);
> - nsl_set_slot(ndd, nd_label, slot);
> - nsl_set_type_guid(ndd, nd_label, &nd_set->type_guid);
> - nsl_set_claim_class(ndd, nd_label, ndns->claim_class);
> - nsl_calculate_checksum(ndd, nd_label);
> +
> + ns_label = &nd_label->ns_label;
> + nsl_set_uuid(ndd, ns_label, nspm->uuid);
> + nsl_set_name(ndd, ns_label, nspm->alt_name);
> + nsl_set_flags(ndd, ns_label, flags);
> + nsl_set_nlabel(ndd, ns_label, nd_region->ndr_mappings);
> + nsl_set_nrange(ndd, ns_label, 1);
> + nsl_set_position(ndd, ns_label, pos);
> + nsl_set_isetcookie(ndd, ns_label, cookie);
> + nsl_set_rawsize(ndd, ns_label, resource_size(res));
> + nsl_set_lbasize(ndd, ns_label, nspm->lbasize);
> + nsl_set_dpa(ndd, ns_label, res->start);
> + nsl_set_slot(ndd, ns_label, slot);
> + nsl_set_type_guid(ndd, ns_label, &nd_set->type_guid);
> + nsl_set_claim_class(ndd, ns_label, ndns->claim_class);
> + nsl_calculate_checksum(ndd, ns_label);
> nd_dbg_dpa(nd_region, ndd, res, "\n");
>
> /* update label */
> @@ -947,7 +952,7 @@ static int __pmem_label_update(struct nd_region *nd_region,
> if (!label_ent->label)
> continue;
> if (test_and_clear_bit(ND_LABEL_REAP, &label_ent->flags) ||
> - nsl_uuid_equal(ndd, label_ent->label, nspm->uuid))
> + nsl_uuid_equal(ndd, &label_ent->label->ns_label, nspm->uuid))
> reap_victim(nd_mapping, label_ent);
> }
>
> @@ -1035,12 +1040,12 @@ static int del_labels(struct nd_mapping *nd_mapping, uuid_t *uuid)
>
> mutex_lock(&nd_mapping->lock);
> list_for_each_entry_safe(label_ent, e, &nd_mapping->labels, list) {
> - struct nd_namespace_label *nd_label = label_ent->label;
> + struct nd_lsa_label *nd_label = label_ent->label;
>
> if (!nd_label)
> continue;
> active++;
> - if (!nsl_uuid_equal(ndd, nd_label, uuid))
> + if (!nsl_uuid_equal(ndd, &nd_label->ns_label, uuid))
> continue;
> active--;
> slot = to_slot(ndd, nd_label);
> diff --git a/drivers/nvdimm/label.h b/drivers/nvdimm/label.h
> index 0650fb4b9821..4883b3a1320f 100644
> --- a/drivers/nvdimm/label.h
> +++ b/drivers/nvdimm/label.h
> @@ -183,6 +183,16 @@ struct nd_namespace_label {
> };
> };
>
> +/*
> + * LSA 2.1 format introduces region label, which can also reside
> + * into LSA along with only namespace label as per v1.1 and v1.2
> + */
> +struct nd_lsa_label {
> + union {
> + struct nd_namespace_label ns_label;
> + };
> +};
> +
> #define NVDIMM_BTT_GUID "8aed63a2-29a2-4c66-8b12-f05d15d3922a"
> #define NVDIMM_BTT2_GUID "18633bfc-1735-4217-8ac9-17239282d3f8"
> #define NVDIMM_PFN_GUID "266400ba-fb9f-4677-bcb0-968f11d0d225"
> @@ -215,7 +225,7 @@ struct nvdimm_drvdata;
> int nd_label_data_init(struct nvdimm_drvdata *ndd);
> size_t sizeof_namespace_index(struct nvdimm_drvdata *ndd);
> int nd_label_active_count(struct nvdimm_drvdata *ndd);
> -struct nd_namespace_label *nd_label_active(struct nvdimm_drvdata *ndd, int n);
> +struct nd_lsa_label *nd_label_active(struct nvdimm_drvdata *ndd, int n);
> u32 nd_label_alloc_slot(struct nvdimm_drvdata *ndd);
> bool nd_label_free_slot(struct nvdimm_drvdata *ndd, u32 slot);
> u32 nd_label_nfree(struct nvdimm_drvdata *ndd);
> diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
> index 55cfbf1e0a95..f180f0068c15 100644
> --- a/drivers/nvdimm/namespace_devs.c
> +++ b/drivers/nvdimm/namespace_devs.c
> @@ -1009,15 +1009,15 @@ static int namespace_update_uuid(struct nd_region *nd_region,
>
> mutex_lock(&nd_mapping->lock);
> list_for_each_entry(label_ent, &nd_mapping->labels, list) {
> - struct nd_namespace_label *nd_label = label_ent->label;
> + struct nd_lsa_label *nd_label = label_ent->label;
> struct nd_label_id label_id;
> uuid_t uuid;
>
> if (!nd_label)
> continue;
> - nsl_get_uuid(ndd, nd_label, &uuid);
> + nsl_get_uuid(ndd, &nd_label->ns_label, &uuid);
> nd_label_gen_id(&label_id, &uuid,
> - nsl_get_flags(ndd, nd_label));
> + nsl_get_flags(ndd, &nd_label->ns_label));
> if (strcmp(old_label_id.id, label_id.id) == 0)
> set_bit(ND_LABEL_REAP, &label_ent->flags);
> }
> @@ -1562,7 +1562,7 @@ static struct device **create_namespace_io(struct nd_region *nd_region)
> static bool has_uuid_at_pos(struct nd_region *nd_region, const uuid_t *uuid,
> u64 cookie, u16 pos)
> {
> - struct nd_namespace_label *found = NULL;
> + struct nd_lsa_label *found = NULL;
> int i;
>
> for (i = 0; i < nd_region->ndr_mappings; i++) {
> @@ -1573,20 +1573,21 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, const uuid_t *uuid,
> bool found_uuid = false;
>
> list_for_each_entry(label_ent, &nd_mapping->labels, list) {
> - struct nd_namespace_label *nd_label = label_ent->label;
> + struct nd_lsa_label *nd_label = label_ent->label;
> u16 position;
>
> if (!nd_label)
> continue;
> - position = nsl_get_position(ndd, nd_label);
> + position = nsl_get_position(ndd, &nd_label->ns_label);
>
> - if (!nsl_validate_isetcookie(ndd, nd_label, cookie))
> + if (!nsl_validate_isetcookie(ndd, &nd_label->ns_label,
> + cookie))
> continue;
>
> - if (!nsl_uuid_equal(ndd, nd_label, uuid))
> + if (!nsl_uuid_equal(ndd, &nd_label->ns_label, uuid))
> continue;
>
> - if (!nsl_validate_type_guid(ndd, nd_label,
> + if (!nsl_validate_type_guid(ndd, &nd_label->ns_label,
> &nd_set->type_guid))
> continue;
>
> @@ -1595,7 +1596,8 @@ static bool has_uuid_at_pos(struct nd_region *nd_region, const uuid_t *uuid,
> return false;
> }
> found_uuid = true;
> - if (!nsl_validate_nlabel(nd_region, ndd, nd_label))
> + if (!nsl_validate_nlabel(nd_region,
> + ndd, &nd_label->ns_label))
> continue;
> if (position != pos)
> continue;
> @@ -1615,7 +1617,7 @@ static int select_pmem_id(struct nd_region *nd_region, const uuid_t *pmem_id)
> for (i = 0; i < nd_region->ndr_mappings; i++) {
> struct nd_mapping *nd_mapping = &nd_region->mapping[i];
> struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
> - struct nd_namespace_label *nd_label = NULL;
> + struct nd_lsa_label *nd_label = NULL;
> u64 hw_start, hw_end, pmem_start, pmem_end;
> struct nd_label_ent *label_ent;
>
> @@ -1624,7 +1626,7 @@ static int select_pmem_id(struct nd_region *nd_region, const uuid_t *pmem_id)
> nd_label = label_ent->label;
> if (!nd_label)
> continue;
> - if (nsl_uuid_equal(ndd, nd_label, pmem_id))
> + if (nsl_uuid_equal(ndd, &nd_label->ns_label, pmem_id))
> break;
> nd_label = NULL;
> }
> @@ -1640,15 +1642,15 @@ static int select_pmem_id(struct nd_region *nd_region, const uuid_t *pmem_id)
> */
> hw_start = nd_mapping->start;
> hw_end = hw_start + nd_mapping->size;
> - pmem_start = nsl_get_dpa(ndd, nd_label);
> - pmem_end = pmem_start + nsl_get_rawsize(ndd, nd_label);
> + pmem_start = nsl_get_dpa(ndd, &nd_label->ns_label);
> + pmem_end = pmem_start + nsl_get_rawsize(ndd, &nd_label->ns_label);
> if (pmem_start >= hw_start && pmem_start < hw_end
> && pmem_end <= hw_end && pmem_end > hw_start)
> /* pass */;
> else {
> dev_dbg(&nd_region->dev, "%s invalid label for %pUb\n",
> dev_name(ndd->dev),
> - nsl_uuid_raw(ndd, nd_label));
> + nsl_uuid_raw(ndd, &nd_label->ns_label));
> return -EINVAL;
> }
>
> @@ -1668,7 +1670,7 @@ static int select_pmem_id(struct nd_region *nd_region, const uuid_t *pmem_id)
> */
> static struct device *create_namespace_pmem(struct nd_region *nd_region,
> struct nd_mapping *nd_mapping,
> - struct nd_namespace_label *nd_label)
> + struct nd_lsa_label *nd_label)
> {
> struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
> struct nd_namespace_index *nsindex =
> @@ -1689,14 +1691,14 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region,
> return ERR_PTR(-ENXIO);
> }
>
> - if (!nsl_validate_isetcookie(ndd, nd_label, cookie)) {
> + if (!nsl_validate_isetcookie(ndd, &nd_label->ns_label, cookie)) {
> dev_dbg(&nd_region->dev, "invalid cookie in label: %pUb\n",
> - nsl_uuid_raw(ndd, nd_label));
> - if (!nsl_validate_isetcookie(ndd, nd_label, altcookie))
> + nsl_uuid_raw(ndd, &nd_label->ns_label));
> + if (!nsl_validate_isetcookie(ndd, &nd_label->ns_label, altcookie))
> return ERR_PTR(-EAGAIN);
>
> dev_dbg(&nd_region->dev, "valid altcookie in label: %pUb\n",
> - nsl_uuid_raw(ndd, nd_label));
> + nsl_uuid_raw(ndd, &nd_label->ns_label));
> }
>
> nspm = kzalloc(sizeof(*nspm), GFP_KERNEL);
> @@ -1712,7 +1714,7 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region,
> res->flags = IORESOURCE_MEM;
>
> for (i = 0; i < nd_region->ndr_mappings; i++) {
> - nsl_get_uuid(ndd, nd_label, &uuid);
> + nsl_get_uuid(ndd, &nd_label->ns_label, &uuid);
> if (has_uuid_at_pos(nd_region, &uuid, cookie, i))
> continue;
> if (has_uuid_at_pos(nd_region, &uuid, altcookie, i))
> @@ -1729,7 +1731,7 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region,
> * find a dimm with two instances of the same uuid.
> */
> dev_err(&nd_region->dev, "%s missing label for %pUb\n",
> - nvdimm_name(nvdimm), nsl_uuid_raw(ndd, nd_label));
> + nvdimm_name(nvdimm), nsl_uuid_raw(ndd, &nd_label->ns_label));
> rc = -EINVAL;
> goto err;
> }
> @@ -1739,14 +1741,14 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region,
> * that position at labels[0], and NULL at labels[1]. In the process,
> * check that the namespace aligns with interleave-set.
> */
> - nsl_get_uuid(ndd, nd_label, &uuid);
> + nsl_get_uuid(ndd, &nd_label->ns_label, &uuid);
> rc = select_pmem_id(nd_region, &uuid);
> if (rc)
> goto err;
>
> /* Calculate total size and populate namespace properties from label0 */
> for (i = 0; i < nd_region->ndr_mappings; i++) {
> - struct nd_namespace_label *label0;
> + struct nd_lsa_label *label0;
> struct nvdimm_drvdata *ndd;
>
> nd_mapping = &nd_region->mapping[i];
> @@ -1760,17 +1762,17 @@ static struct device *create_namespace_pmem(struct nd_region *nd_region,
> }
>
> ndd = to_ndd(nd_mapping);
> - size += nsl_get_rawsize(ndd, label0);
> - if (nsl_get_position(ndd, label0) != 0)
> + size += nsl_get_rawsize(ndd, &label0->ns_label);
> + if (nsl_get_position(ndd, &label0->ns_label) != 0)
> continue;
> WARN_ON(nspm->alt_name || nspm->uuid);
> - nspm->alt_name = kmemdup(nsl_ref_name(ndd, label0),
> + nspm->alt_name = kmemdup(nsl_ref_name(ndd, &label0->ns_label),
> NSLABEL_NAME_LEN, GFP_KERNEL);
> - nsl_get_uuid(ndd, label0, &uuid);
> + nsl_get_uuid(ndd, &label0->ns_label, &uuid);
> nspm->uuid = kmemdup(&uuid, sizeof(uuid_t), GFP_KERNEL);
> - nspm->lbasize = nsl_get_lbasize(ndd, label0);
> + nspm->lbasize = nsl_get_lbasize(ndd, &label0->ns_label);
> nspm->nsio.common.claim_class =
> - nsl_get_claim_class(ndd, label0);
> + nsl_get_claim_class(ndd, &label0->ns_label);
> }
>
> if (!nspm->alt_name || !nspm->uuid) {
> @@ -1887,7 +1889,7 @@ void nd_region_create_btt_seed(struct nd_region *nd_region)
> }
>
> static int add_namespace_resource(struct nd_region *nd_region,
> - struct nd_namespace_label *nd_label, struct device **devs,
> + struct nd_lsa_label *nd_label, struct device **devs,
> int count)
> {
> struct nd_mapping *nd_mapping = &nd_region->mapping[0];
> @@ -1902,7 +1904,7 @@ static int add_namespace_resource(struct nd_region *nd_region,
> continue;
> }
>
> - if (!nsl_uuid_equal(ndd, nd_label, uuid))
> + if (!nsl_uuid_equal(ndd, &nd_label->ns_label, uuid))
> continue;
> dev_err(&nd_region->dev,
> "error: conflicting extents for uuid: %pUb\n", uuid);
> @@ -1943,15 +1945,15 @@ static struct device **scan_labels(struct nd_region *nd_region)
>
> /* "safe" because create_namespace_pmem() might list_move() label_ent */
> list_for_each_entry_safe(label_ent, e, &nd_mapping->labels, list) {
> - struct nd_namespace_label *nd_label = label_ent->label;
> + struct nd_lsa_label *nd_label = label_ent->label;
> struct device **__devs;
>
> if (!nd_label)
> continue;
>
> /* skip labels that describe extents outside of the region */
> - if (nsl_get_dpa(ndd, nd_label) < nd_mapping->start ||
> - nsl_get_dpa(ndd, nd_label) > map_end)
> + if (nsl_get_dpa(ndd, &nd_label->ns_label) < nd_mapping->start ||
> + nsl_get_dpa(ndd, &nd_label->ns_label) > map_end)
> continue;
>
> i = add_namespace_resource(nd_region, nd_label, devs, count);
> @@ -2122,7 +2124,7 @@ static int init_active_labels(struct nd_region *nd_region)
> if (!count)
> continue;
> for (j = 0; j < count; j++) {
> - struct nd_namespace_label *label;
> + struct nd_lsa_label *label;
>
> label_ent = kzalloc(sizeof(*label_ent), GFP_KERNEL);
> if (!label_ent)
> diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
> index 304f0e9904f1..2ead96ac598b 100644
> --- a/drivers/nvdimm/nd.h
> +++ b/drivers/nvdimm/nd.h
> @@ -376,7 +376,7 @@ enum nd_label_flags {
> struct nd_label_ent {
> struct list_head list;
> unsigned long flags;
> - struct nd_namespace_label *label;
> + struct nd_lsa_label *label;
> };
>
> enum nd_mapping_lock_class {
> --
> 2.34.1
>
>
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 01/20] nvdimm/label: Introduce NDD_CXL_LABEL flag to set cxl label format
2025-06-17 12:39 ` [RFC PATCH 01/20] nvdimm/label: Introduce NDD_CXL_LABEL flag to set cxl label format Neeraj Kumar
2025-06-20 16:40 ` Jonathan Cameron
@ 2025-07-02 18:02 ` Ira Weiny
2025-07-03 9:58 ` Neeraj Kumar
2025-07-09 22:57 ` Dave Jiang
2 siblings, 1 reply; 66+ messages in thread
From: Ira Weiny @ 2025-07-02 18:02 UTC (permalink / raw)
To: Neeraj Kumar, dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
Neeraj Kumar wrote:
> NDD_CXL_LABEL is introduced to set cxl LSA 2.1 label format
> Accordingly updated label index version
I'm not following why CXL specific code needs to be in nvdimm?
I did not get a cover letter in this thread and looking at lore I don't
see one either:
https://lore.kernel.org/all/158453976.61750165203630.JavaMail.epsvc@epcpadp1new/
So perhaps I am completely out of the loop here? Could you point me at a
cover letter?
Ira
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
> ---
> drivers/nvdimm/dimm.c | 1 +
> drivers/nvdimm/dimm_devs.c | 10 ++++++++++
> drivers/nvdimm/label.c | 16 ++++++++++++----
> drivers/nvdimm/nd.h | 1 +
> include/linux/libnvdimm.h | 3 +++
> 5 files changed, 27 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c
> index 91d9163ee303..8753b5cd91cc 100644
> --- a/drivers/nvdimm/dimm.c
> +++ b/drivers/nvdimm/dimm.c
> @@ -62,6 +62,7 @@ static int nvdimm_probe(struct device *dev)
> if (rc < 0)
> dev_dbg(dev, "failed to unlock dimm: %d\n", rc);
>
> + ndd->cxl = nvdimm_check_cxl_label_format(ndd->dev);
>
> /*
> * EACCES failures reading the namespace label-area-properties
> diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
> index 21498d461fde..e8f545f889fd 100644
> --- a/drivers/nvdimm/dimm_devs.c
> +++ b/drivers/nvdimm/dimm_devs.c
> @@ -18,6 +18,16 @@
>
> static DEFINE_IDA(dimm_ida);
>
> +bool nvdimm_check_cxl_label_format(struct device *dev)
> +{
> + struct nvdimm *nvdimm = to_nvdimm(dev);
> +
> + if (test_bit(NDD_CXL_LABEL, &nvdimm->flags))
> + return true;
> +
> + return false;
> +}
> +
> /*
> * Retrieve bus and dimm handle and return if this bus supports
> * get_config_data commands
> diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
> index 082253a3a956..48b5ba90216d 100644
> --- a/drivers/nvdimm/label.c
> +++ b/drivers/nvdimm/label.c
> @@ -687,11 +687,19 @@ static int nd_label_write_index(struct nvdimm_drvdata *ndd, int index, u32 seq,
> - (unsigned long) to_namespace_index(ndd, 0);
> nsindex->labeloff = __cpu_to_le64(offset);
> nsindex->nslot = __cpu_to_le32(nslot);
> - nsindex->major = __cpu_to_le16(1);
> - if (sizeof_namespace_label(ndd) < 256)
> +
> + /* Support CXL LSA 2.1 label format */
> + if (ndd->cxl) {
> + nsindex->major = __cpu_to_le16(2);
> nsindex->minor = __cpu_to_le16(1);
> - else
> - nsindex->minor = __cpu_to_le16(2);
> + } else {
> + nsindex->major = __cpu_to_le16(1);
> + if (sizeof_namespace_label(ndd) < 256)
> + nsindex->minor = __cpu_to_le16(1);
> + else
> + nsindex->minor = __cpu_to_le16(2);
> + }
> +
> nsindex->checksum = __cpu_to_le64(0);
> if (flags & ND_NSINDEX_INIT) {
> unsigned long *free = (unsigned long *) nsindex->free;
> diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
> index 5ca06e9a2d29..304f0e9904f1 100644
> --- a/drivers/nvdimm/nd.h
> +++ b/drivers/nvdimm/nd.h
> @@ -522,6 +522,7 @@ void nvdimm_set_labeling(struct device *dev);
> void nvdimm_set_locked(struct device *dev);
> void nvdimm_clear_locked(struct device *dev);
> int nvdimm_security_setup_events(struct device *dev);
> +bool nvdimm_check_cxl_label_format(struct device *dev);
> #if IS_ENABLED(CONFIG_NVDIMM_KEYS)
> int nvdimm_security_unlock(struct device *dev);
> #else
> diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
> index e772aae71843..0a55900842c8 100644
> --- a/include/linux/libnvdimm.h
> +++ b/include/linux/libnvdimm.h
> @@ -44,6 +44,9 @@ enum {
> /* dimm provider wants synchronous registration by __nvdimm_create() */
> NDD_REGISTER_SYNC = 8,
>
> + /* dimm supports region labels (LSA Format 2.1) */
> + NDD_CXL_LABEL = 9,
> +
> /* need to set a limit somewhere, but yes, this is likely overkill */
> ND_IOCTL_MAX_BUFLEN = SZ_4M,
> ND_CMD_MAX_ELEM = 5,
> --
> 2.34.1
>
>
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 01/20] nvdimm/label: Introduce NDD_CXL_LABEL flag to set cxl label format
2025-07-02 18:02 ` Ira Weiny
@ 2025-07-03 9:58 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-07-03 9:58 UTC (permalink / raw)
To: Ira Weiny
Cc: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, a.manzanares, nifan.cxl,
anisa.su, vishak.g, krish.reddy, arun.george, alok.rathore,
neeraj.kernel, linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 1370 bytes --]
On 02/07/25 01:02PM, Ira Weiny wrote:
>Neeraj Kumar wrote:
>> NDD_CXL_LABEL is introduced to set cxl LSA 2.1 label format
>> Accordingly updated label index version
>
>I'm not following why CXL specific code needs to be in nvdimm?
Hi Ira,
Prior to LSA 2.1 version, LSA contain only namespace labels. LSA 2.1 was
introduced in CXL 2.0 Spec, which introduced region label along with
namespace label.
NDD_LABELING is the flag used to inform nvdimm driver about namespace
labels. As region label was introduced in cxl spec. so, I have used
NDD_CXL_LABEL flag to inform nvdimmm driver about it.
I have taken this naming reference from "drivers/nvdimm/label.h"
where region label is defined as "struct cxl_region_label"
Please let me know if i should use some other name in place of this
>
>I did not get a cover letter in this thread and looking at lore I don't
>see one either:
>
>https://lore.kernel.org/all/158453976.61750165203630.JavaMail.epsvc@epcpadp1new/
>
>So perhaps I am completely out of the loop here? Could you point me at a
>cover letter?
Yes, there seems some issue due to which my patch thread got broken into two.
1. Cover letter:
https://lore.kernel.org/linux-cxl/1931444790.41750165203442.JavaMail.epsvc@epcpadp1new/
2. Rest of the thread:
https://lore.kernel.org/linux-cxl/158453976.61750165203630.JavaMail.epsvc@epcpadp1new/
Regards,
Neeraj
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 02/20] nvdimm/label: Prep patch to accommodate cxl lsa 2.1 support
2025-07-02 17:55 ` Ira Weiny
@ 2025-07-03 10:04 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-07-03 10:04 UTC (permalink / raw)
To: Ira Weiny
Cc: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, a.manzanares, nifan.cxl,
anisa.su, vishak.g, krish.reddy, arun.george, alok.rathore,
neeraj.kernel, linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 737 bytes --]
On 02/07/25 12:55PM, Ira Weiny wrote:
>Neeraj Kumar wrote:
>> In order to accommodate cxl lsa 2.1 format region label, renamed
>> nd_namespace_label to nd_lsa_label.
>
>This does not really make it clear why a name change is required.
>
>Could you elaborate here?
Hi Ira,
LSA 2.1 format introduces region label, which can also reside into LSA
along with only namespace label as per v1.1 and v1.2
As both namespace and region labels are of same size, i.e, 256 bytes.
Therefore I have introduced nd_lsa_label as following
struct nd_lsa_label {
union {
struct nd_namespace_label ns_label;
struct cxl_region_label rg_label;
};
};
Sure, I will update commit message with above information in next
patch-set.
Thanks,
Neeraj
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 01/20] nvdimm/label: Introduce NDD_CXL_LABEL flag to set cxl label format
2025-06-17 12:39 ` [RFC PATCH 01/20] nvdimm/label: Introduce NDD_CXL_LABEL flag to set cxl label format Neeraj Kumar
2025-06-20 16:40 ` Jonathan Cameron
2025-07-02 18:02 ` Ira Weiny
@ 2025-07-09 22:57 ` Dave Jiang
2025-07-18 12:13 ` Neeraj Kumar
2 siblings, 1 reply; 66+ messages in thread
From: Dave Jiang @ 2025-07-09 22:57 UTC (permalink / raw)
To: Neeraj Kumar, dan.j.williams, dave, jonathan.cameron,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, neeraj.kernel, linux-kernel, linux-cxl,
nvdimm, gost.dev, cpgs
On 6/17/25 5:39 AM, Neeraj Kumar wrote:
> NDD_CXL_LABEL is introduced to set cxl LSA 2.1 label format
> Accordingly updated label index version
Maybe add the spec reference that defines label 2.1 format
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
> ---
> drivers/nvdimm/dimm.c | 1 +
> drivers/nvdimm/dimm_devs.c | 10 ++++++++++
> drivers/nvdimm/label.c | 16 ++++++++++++----
> drivers/nvdimm/nd.h | 1 +
> include/linux/libnvdimm.h | 3 +++
> 5 files changed, 27 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c
> index 91d9163ee303..8753b5cd91cc 100644
> --- a/drivers/nvdimm/dimm.c
> +++ b/drivers/nvdimm/dimm.c
> @@ -62,6 +62,7 @@ static int nvdimm_probe(struct device *dev)
> if (rc < 0)
> dev_dbg(dev, "failed to unlock dimm: %d\n", rc);
>
> + ndd->cxl = nvdimm_check_cxl_label_format(ndd->dev);
>
> /*
> * EACCES failures reading the namespace label-area-properties
> diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
> index 21498d461fde..e8f545f889fd 100644
> --- a/drivers/nvdimm/dimm_devs.c
> +++ b/drivers/nvdimm/dimm_devs.c
> @@ -18,6 +18,16 @@
>
> static DEFINE_IDA(dimm_ida);
>
> +bool nvdimm_check_cxl_label_format(struct device *dev)
> +{
> + struct nvdimm *nvdimm = to_nvdimm(dev);
> +
> + if (test_bit(NDD_CXL_LABEL, &nvdimm->flags))
> + return true;
> +
> + return false;
> +}
I think we may want to move the checking of the flag to where the patch also set the flag in order to provide a more coherent review experience. Given that I haven't read the rest of the patchset and don't know how NDD_CXL_LABEL is set, I really can't comment on whether there's a better way to detect LSA 2.1 labels. Is there a generic way to determine label versions without the implication of this is CXL device?
> +
> /*
> * Retrieve bus and dimm handle and return if this bus supports
> * get_config_data commands
> diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
> index 082253a3a956..48b5ba90216d 100644
> --- a/drivers/nvdimm/label.c
> +++ b/drivers/nvdimm/label.c
> @@ -687,11 +687,19 @@ static int nd_label_write_index(struct nvdimm_drvdata *ndd, int index, u32 seq,
> - (unsigned long) to_namespace_index(ndd, 0);
> nsindex->labeloff = __cpu_to_le64(offset);
> nsindex->nslot = __cpu_to_le32(nslot);
> - nsindex->major = __cpu_to_le16(1);
> - if (sizeof_namespace_label(ndd) < 256)
> +
> + /* Support CXL LSA 2.1 label format */
> + if (ndd->cxl) {
> + nsindex->major = __cpu_to_le16(2);
> nsindex->minor = __cpu_to_le16(1);
> - else
> - nsindex->minor = __cpu_to_le16(2);
> + } else {
> + nsindex->major = __cpu_to_le16(1);
> + if (sizeof_namespace_label(ndd) < 256)
> + nsindex->minor = __cpu_to_le16(1);
> + else
> + nsindex->minor = __cpu_to_le16(2);
> + }
Would like to see a more coherent way of detecting label versioning. What happens when there are newer versions introduced later on? This currently feels very disjointed.
> +
> nsindex->checksum = __cpu_to_le64(0);
> if (flags & ND_NSINDEX_INIT) {
> unsigned long *free = (unsigned long *) nsindex->free;
> diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
> index 5ca06e9a2d29..304f0e9904f1 100644
> --- a/drivers/nvdimm/nd.h
> +++ b/drivers/nvdimm/nd.h
> @@ -522,6 +522,7 @@ void nvdimm_set_labeling(struct device *dev);
> void nvdimm_set_locked(struct device *dev);
> void nvdimm_clear_locked(struct device *dev);
> int nvdimm_security_setup_events(struct device *dev);
> +bool nvdimm_check_cxl_label_format(struct device *dev);
> #if IS_ENABLED(CONFIG_NVDIMM_KEYS)
> int nvdimm_security_unlock(struct device *dev);
> #else
> diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
> index e772aae71843..0a55900842c8 100644
> --- a/include/linux/libnvdimm.h
> +++ b/include/linux/libnvdimm.h
> @@ -44,6 +44,9 @@ enum {
> /* dimm provider wants synchronous registration by __nvdimm_create() */
> NDD_REGISTER_SYNC = 8,
>
> + /* dimm supports region labels (LSA Format 2.1) */
> + NDD_CXL_LABEL = 9,
While 2.1 is defined by the CXL spec, is there anything declared by the CXL spec that makes 2.1 exclusive to CXL? Maybe the focus should be to support LSA 2.1 and avoid dragging naming CXL into the conversation at this point. It can be made more generic right? I'm concerned about dragging CXL into nvdimm when it isn't necessary. Maybe introduce a label cap field where when an nvdimm device is registered, the caller can pass in that it's capable of supporting up to a certain version of labeling? Just throwing ideas out to see if it's feasible.
> +
> /* need to set a limit somewhere, but yes, this is likely overkill */
> ND_IOCTL_MAX_BUFLEN = SZ_4M,
> ND_CMD_MAX_ELEM = 5,
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 13/20] cxl/mem: Refactor cxl pmem region auto-assembling
2025-06-17 12:39 ` [RFC PATCH 13/20] cxl/mem: Refactor cxl pmem region auto-assembling Neeraj Kumar
2025-06-23 9:20 ` Jonathan Cameron
@ 2025-07-10 0:38 ` Dave Jiang
2025-07-18 12:30 ` Neeraj Kumar
1 sibling, 1 reply; 66+ messages in thread
From: Dave Jiang @ 2025-07-10 0:38 UTC (permalink / raw)
To: Neeraj Kumar, dan.j.williams, dave, jonathan.cameron,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, neeraj.kernel, linux-kernel, linux-cxl,
nvdimm, gost.dev, cpgs
On 6/17/25 5:39 AM, Neeraj Kumar wrote:
> In 84ec985944ef3, For cxl pmem region auto-assembly after endpoint port
> probing, cxl_nvd presence was required. And for cxl region persistency,
> region creation happens during nvdimm_probe which need the completion
> of endpoint probe.
>
> It is therefore refactored cxl pmem region auto-assembly after endpoint
> probing to cxl mem probing
The region auto-assembly is moved after the endpoint device is added. However, it's not guaranteed that the endpoint probe has completed and completed successfully. You are just getting lucky timing wise that endpoint probe is completed when the new region discovery is starting. Return of devm_cxl_add_nvdimm() only adds the nvdimm device and triggers the async probe of nvdimm driver. You have to take the endpoint port lock and check if the driver is attached to be certain that endpoint probe is done and successful. Therefore moving the region discovery location probably does not do what you think it does. Maybe take a deeper look at the region discovery code and see how it does retry if things are not present and approach it from that angle?
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
> ---
> drivers/cxl/core/port.c | 38 ++++++++++++++++++++++++++++++++++++++
> drivers/cxl/cxl.h | 1 +
> drivers/cxl/mem.c | 27 ++++++++++++++++++---------
> drivers/cxl/port.c | 38 --------------------------------------
> 4 files changed, 57 insertions(+), 47 deletions(-)
>
> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
> index 78a5c2c25982..bca668193c49 100644
> --- a/drivers/cxl/core/port.c
> +++ b/drivers/cxl/core/port.c
> @@ -1038,6 +1038,44 @@ void put_cxl_root(struct cxl_root *cxl_root)
> }
> EXPORT_SYMBOL_NS_GPL(put_cxl_root, "CXL");
>
> +static int discover_region(struct device *dev, void *root)
> +{
> + struct cxl_endpoint_decoder *cxled;
> + int rc;
> +
> + if (!is_endpoint_decoder(dev))
> + return 0;
> +
> + cxled = to_cxl_endpoint_decoder(dev);
> + if ((cxled->cxld.flags & CXL_DECODER_F_ENABLE) == 0)
> + return 0;
> +
> + if (cxled->state != CXL_DECODER_STATE_AUTO)
> + return 0;
> +
> + /*
> + * Region enumeration is opportunistic, if this add-event fails,
> + * continue to the next endpoint decoder.
> + */
> + rc = cxl_add_to_region(root, cxled);
> + if (rc)
> + dev_dbg(dev, "failed to add to region: %#llx-%#llx\n",
> + cxled->cxld.hpa_range.start, cxled->cxld.hpa_range.end);
> +
> + return 0;
> +}
> +
> +void cxl_region_discovery(struct cxl_port *port)
> +{
> + struct cxl_port *root;
> + struct cxl_root *cxl_root __free(put_cxl_root) = find_cxl_root(port);
> +
> + root = &cxl_root->port;
> +
> + device_for_each_child(&port->dev, root, discover_region);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_region_discovery, "CXL");
> +
I have concerns about adding region related code in core/port.c while the rest of the region code is walled behind CONFIG_CXL_REGION. I think this change needs to go to core/region.c.
DJ
> static struct cxl_dport *find_dport(struct cxl_port *port, int id)
> {
> struct cxl_dport *dport;
> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> index dcf2a127efc7..9423ea3509ad 100644
> --- a/drivers/cxl/cxl.h
> +++ b/drivers/cxl/cxl.h
> @@ -869,6 +869,7 @@ bool is_cxl_nvdimm(struct device *dev);
> bool is_cxl_nvdimm_bridge(struct device *dev);
> int devm_cxl_add_nvdimm(struct cxl_port *parent_port, struct cxl_memdev *cxlmd);
> struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_port *port);
> +void cxl_region_discovery(struct cxl_port *port);
>
> #ifdef CONFIG_CXL_REGION
> bool is_cxl_pmem_region(struct device *dev);
> diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
> index 2f03a4d5606e..aaea4eb178ef 100644
> --- a/drivers/cxl/mem.c
> +++ b/drivers/cxl/mem.c
> @@ -152,15 +152,6 @@ static int cxl_mem_probe(struct device *dev)
> return -ENXIO;
> }
>
> - if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM)) {
> - rc = devm_cxl_add_nvdimm(parent_port, cxlmd);
> - if (rc) {
> - if (rc == -ENODEV)
> - dev_info(dev, "PMEM disabled by platform\n");
> - return rc;
> - }
> - }
> -
> if (dport->rch)
> endpoint_parent = parent_port->uport_dev;
> else
> @@ -180,6 +171,24 @@ static int cxl_mem_probe(struct device *dev)
> return rc;
> }
>
> + if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM)) {
> + rc = devm_cxl_add_nvdimm(parent_port, cxlmd);
> + if (rc) {
> + if (rc == -ENODEV)
> + dev_info(dev, "PMEM disabled by platform\n");
> + return rc;
> + }
> + }
> +
> + /*
> + * Now that all endpoint decoders are successfully enumerated, try to
> + * assemble region autodiscovery from committed decoders.
> + * Earlier it was part of cxl_endpoint_port_probe, So moved it here
> + * as cxl_nvd of the memdev needs to be available during the pmem
> + * region auto-assembling
> + */
> + cxl_region_discovery(cxlmd->endpoint);
> +
> /*
> * The kernel may be operating out of CXL memory on this device,
> * there is no spec defined way to determine whether this device
> diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
> index d2bfd1ff5492..361544760a4c 100644
> --- a/drivers/cxl/port.c
> +++ b/drivers/cxl/port.c
> @@ -30,33 +30,6 @@ static void schedule_detach(void *cxlmd)
> schedule_cxl_memdev_detach(cxlmd);
> }
>
> -static int discover_region(struct device *dev, void *root)
> -{
> - struct cxl_endpoint_decoder *cxled;
> - int rc;
> -
> - if (!is_endpoint_decoder(dev))
> - return 0;
> -
> - cxled = to_cxl_endpoint_decoder(dev);
> - if ((cxled->cxld.flags & CXL_DECODER_F_ENABLE) == 0)
> - return 0;
> -
> - if (cxled->state != CXL_DECODER_STATE_AUTO)
> - return 0;
> -
> - /*
> - * Region enumeration is opportunistic, if this add-event fails,
> - * continue to the next endpoint decoder.
> - */
> - rc = cxl_add_to_region(root, cxled);
> - if (rc)
> - dev_dbg(dev, "failed to add to region: %#llx-%#llx\n",
> - cxled->cxld.hpa_range.start, cxled->cxld.hpa_range.end);
> -
> - return 0;
> -}
> -
> static int cxl_switch_port_probe(struct cxl_port *port)
> {
> struct cxl_hdm *cxlhdm;
> @@ -95,7 +68,6 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
> struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
> struct cxl_dev_state *cxlds = cxlmd->cxlds;
> struct cxl_hdm *cxlhdm;
> - struct cxl_port *root;
> int rc;
>
> rc = cxl_dvsec_rr_decode(cxlds, &info);
> @@ -125,20 +97,10 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
> rc = devm_cxl_enumerate_decoders(cxlhdm, &info);
> if (rc)
> return rc;
> -
> /*
> * This can't fail in practice as CXL root exit unregisters all
> * descendant ports and that in turn synchronizes with cxl_port_probe()
> */
> - struct cxl_root *cxl_root __free(put_cxl_root) = find_cxl_root(port);
> -
> - root = &cxl_root->port;
> -
> - /*
> - * Now that all endpoint decoders are successfully enumerated, try to
> - * assemble regions from committed decoders
> - */
> - device_for_each_child(&port->dev, root, discover_region);
>
> return 0;
> }
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 14/20] cxl/region: Add cxl pmem region creation routine for region persistency
2025-06-17 12:39 ` [RFC PATCH 14/20] cxl/region: Add cxl pmem region creation routine for region persistency Neeraj Kumar
2025-06-23 9:43 ` Jonathan Cameron
@ 2025-07-10 15:59 ` Dave Jiang
2025-07-18 12:45 ` Neeraj Kumar
1 sibling, 1 reply; 66+ messages in thread
From: Dave Jiang @ 2025-07-10 15:59 UTC (permalink / raw)
To: Neeraj Kumar, dan.j.williams, dave, jonathan.cameron,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, neeraj.kernel, linux-kernel, linux-cxl,
nvdimm, gost.dev, cpgs
On 6/17/25 5:39 AM, Neeraj Kumar wrote:
> Added exported cxl_create_pmem_region routine to create cxl pmem region
> from LSA parsed cxl region information.
> Inspirition for the function is taken from ndctl device attribute
> (_store) call. It allocates cxlr and fills information parsed from LSA
> and calls device_add(&cxlr->dev) to initiates further region creation
> porbes
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
> ---
> drivers/cxl/core/port.c | 6 ++
> drivers/cxl/core/region.c | 208 ++++++++++++++++++++++++++++++++++++++
> drivers/cxl/cxl.h | 11 ++
> 3 files changed, 225 insertions(+)
>
> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
> index bca668193c49..2452f7c15b2d 100644
> --- a/drivers/cxl/core/port.c
> +++ b/drivers/cxl/core/port.c
> @@ -2150,6 +2150,12 @@ void cxl_bus_drain(void)
> }
> EXPORT_SYMBOL_NS_GPL(cxl_bus_drain, "CXL");
>
> +void cxl_wq_flush(void)
> +{
> + flush_workqueue(cxl_bus_wq);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_wq_flush, "CXL");
> +
> bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd)
> {
> return queue_work(cxl_bus_wq, &cxlmd->detach_work);
> diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
> index b98b1ccffd1c..8990e3c3474d 100644
> --- a/drivers/cxl/core/region.c
> +++ b/drivers/cxl/core/region.c
> @@ -2522,6 +2522,214 @@ static ssize_t create_ram_region_show(struct device *dev,
> return __create_region_show(to_cxl_root_decoder(dev), buf);
> }
>
> +static ssize_t update_region_size(struct cxl_region *cxlr, u64 val)
Maybe call it resize_or_free_region_hpa()?
Also rename 'val' to 'size'
> +{
> + int rc;
> +
> + rc = down_write_killable(&cxl_region_rwsem);
> + if (rc)
> + return rc;
> +
> + if (val)
> + rc = alloc_hpa(cxlr, val);
> + else
> + rc = free_hpa(cxlr);
> + up_write(&cxl_region_rwsem);
> +
> + if (rc)
> + return rc;
> +
> + return 0;
> +}
Share common code with core/region.c:size_store(). Please use helper function and not duplicate code.
> +
> +static ssize_t update_region_dpa_size(struct cxl_region *cxlr,
resize_or_free_dpa()
> + struct cxl_decoder *cxld,
> + unsigned long long size)
u64 size
> +{
> + int rc;
> + struct cxl_endpoint_decoder *cxled =
> + to_cxl_endpoint_decoder(&cxld->dev);
> +
> + if (!IS_ALIGNED(size, SZ_256M))
> + return -EINVAL;
> +
> + rc = cxl_dpa_free(cxled);
> + if (rc)
> + return rc;
> +
> + if (size == 0)
> + return 0;
> +
> + rc = cxl_dpa_alloc(cxled, size);
> + if (rc)
> + return rc;
> +
> + return 0;
> +}
Share common code with core/port.c:dpa_size_store(). Please use helper function and not duplicate code.
> +
> +static ssize_t update_region_dpa_mode(struct cxl_region *cxlr,
> + struct cxl_decoder *cxld)
> +{
> + int rc;
> + struct cxl_endpoint_decoder *cxled =
> + to_cxl_endpoint_decoder(&cxld->dev);
> +
> + rc = cxl_dpa_set_mode(cxled, CXL_DECODER_PMEM);
Don't think CXL_DECODER_PMEM exists any longer. It's CXL_PARTMODE_PMEM. Just beware there have been some changes while you are rebasing to the latest upstream code.
> + if (rc)
> + return rc;
> +
> + return 0;
> +}
> +
> +static size_t attach_region_target(struct cxl_region *cxlr,
> + struct cxl_decoder *cxld, int pos)
> +{
> + int rc;
> + struct cxl_endpoint_decoder *cxled =
> + to_cxl_endpoint_decoder(&cxld->dev);
> +
> + rc = attach_target(cxlr, cxled, pos, TASK_INTERRUPTIBLE);
> +
> + if (rc < 0)
> + return rc;
> +
> + return 0;
> +}
> +
> +static ssize_t commit_region(struct cxl_region *cxlr)
> +{
> + struct cxl_region_params *p = &cxlr->params;
> + ssize_t rc;
> +
> + rc = down_write_killable(&cxl_region_rwsem);
> + if (rc)
> + return rc;
> +
> + /* Already in the requested state? */
> + if (p->state >= CXL_CONFIG_COMMIT)
> + goto out;
> +
> + /* Not ready to commit? */
> + if (p->state < CXL_CONFIG_ACTIVE) {
> + rc = -ENXIO;
> + goto out;
> + }
> +
> + /*
> + * Invalidate caches before region setup to drop any speculative
> + * consumption of this address space
> + */
> + rc = cxl_region_invalidate_memregion(cxlr);
> + if (rc)
> + goto out;
> +
> + rc = cxl_region_decode_commit(cxlr);
> + if (rc == 0)
> + p->state = CXL_CONFIG_COMMIT;
> +out:
> + up_write(&cxl_region_rwsem);
> + if (rc)
> + return rc;
> + return 0;
> +}
Sharing common code with core/region.c:commit_store()?
> +
> +static struct cxl_region *
> +devm_cxl_pmem_add_region(struct cxl_root_decoder *cxlrd,
> + struct cxl_decoder *cxld,
> + struct cxl_pmem_region_params *params, int id,
> + enum cxl_decoder_mode mode, enum cxl_decoder_type type)
> +{
> + struct cxl_port *port;
> + struct cxl_region *cxlr;
> + struct cxl_region_params *p;
> + struct device *dev;
> + int rc;
> +
> + if (!cxlrd)
> + return ERR_PTR(-EINVAL);
> +
> + port = to_cxl_port(cxlrd->cxlsd.cxld.dev.parent);
> +
> + cxlr = cxl_region_alloc(cxlrd, id);
> + if (IS_ERR(cxlr))
> + return cxlr;
> + cxlr->mode = mode;
> + cxlr->type = type;
> +
> + dev = &cxlr->dev;
> + rc = dev_set_name(dev, "region%d", id);
> + if (rc)
> + goto err;
> +> + p = &cxlr->params;
> + p->uuid = params->uuid;
> + p->interleave_ways = params->nlabel;
> + p->interleave_granularity = params->ig;
> +
> + /* Update region size */
Not sure what value this comment adds
> + if (update_region_size(cxlr, params->rawsize))
> + goto err;
> +
> + /* Flush cxl wq */
Can you explain here why a flush is needed?
> + cxl_wq_flush();
> +
> + /* Clear DPA Size */
comment provides no value
> + if (update_region_dpa_size(cxlr, cxld, 0))
> + goto err;
> +
> + /* Update DPA mode */
same as above
> + if (update_region_dpa_mode(cxlr, cxld))
> + goto err;
> +
> + /* Update DPA Size */
same as above
> + if (update_region_dpa_size(cxlr, cxld, params->rawsize))
> + goto err;
> +
> + /* Attach region targets */
same as above
> + if (attach_region_target(cxlr, cxld, params->position))
> + goto err;
> +
> + /* Commit Region */
same as above
> + if (commit_region(cxlr))
> + goto err;
Can you please provide some verbose explanation as to what all these extra steps are doing for pmem versus devm_cxl_add_region() for dram?
> +
> + rc = device_add(dev);
> + if (rc)
> + goto err;
> +
> + rc = devm_add_action_or_reset(port->uport_dev, unregister_region, cxlr);
> + if (rc)
> + return ERR_PTR(rc);
> +
> + dev_dbg(port->uport_dev, "%s: created %s\n",
> + dev_name(&cxlrd->cxlsd.cxld.dev), dev_name(dev));
> + return cxlr;
> +
> +err:
> + put_device(dev);
> + return ERR_PTR(rc);
> +}
> +
> +struct cxl_region *cxl_create_pmem_region(struct cxl_root_decoder *cxlrd,
> + struct cxl_decoder *cxld,
> + struct cxl_pmem_region_params *params, 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_pmem_add_region(cxlrd, cxld, params, id,
> + CXL_DECODER_PMEM, CXL_DECODER_HOSTONLYMEM);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_create_pmem_region, "CXL");
Can __create_region() be modified to determine whether to create dram region or pmem?
DJ
> +
> static struct cxl_region *__create_region(struct cxl_root_decoder *cxlrd,
> enum cxl_decoder_mode mode, int id)
> {
> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> index 9423ea3509ad..30c80e04cb27 100644
> --- a/drivers/cxl/cxl.h
> +++ b/drivers/cxl/cxl.h
> @@ -759,6 +759,7 @@ DEFINE_FREE(put_cxl_port, struct cxl_port *, if (!IS_ERR_OR_NULL(_T)) put_device
> int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd);
> void cxl_bus_rescan(void);
> void cxl_bus_drain(void);
> +void cxl_wq_flush(void);
> struct cxl_port *cxl_pci_find_port(struct pci_dev *pdev,
> struct cxl_dport **dport);
> struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd,
> @@ -877,6 +878,9 @@ struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev);
> int cxl_add_to_region(struct cxl_port *root,
> struct cxl_endpoint_decoder *cxled);
> struct cxl_dax_region *to_cxl_dax_region(struct device *dev);
> +struct cxl_region *cxl_create_pmem_region(struct cxl_root_decoder *cxlrd,
> + struct cxl_decoder *cxld,
> + struct cxl_pmem_region_params *params, int id);
> #else
> static inline bool is_cxl_pmem_region(struct device *dev)
> {
> @@ -895,6 +899,13 @@ static inline struct cxl_dax_region *to_cxl_dax_region(struct device *dev)
> {
> return NULL;
> }
> +static inline struct cxl_region *cxl_create_pmem_region(
> + struct cxl_root_decoder *cxlrd,
> + struct cxl_decoder *cxld,
> + struct cxl_pmem_region_params *params, int id)
> +{
> + return NULL;
> +}
> #endif
>
> void cxl_endpoint_parse_cdat(struct cxl_port *port);
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 15/20] cxl: Add a routine to find cxl root decoder on cxl bus
2025-06-17 12:39 ` [RFC PATCH 15/20] cxl: Add a routine to find cxl root decoder on cxl bus Neeraj Kumar
2025-06-23 9:44 ` Jonathan Cameron
2025-06-26 19:19 ` Alison Schofield
@ 2025-07-10 16:23 ` Dave Jiang
2025-07-18 12:48 ` Neeraj Kumar
2 siblings, 1 reply; 66+ messages in thread
From: Dave Jiang @ 2025-07-10 16:23 UTC (permalink / raw)
To: Neeraj Kumar, dan.j.williams, dave, jonathan.cameron,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, neeraj.kernel, linux-kernel, linux-cxl,
nvdimm, gost.dev, cpgs
On 6/17/25 5:39 AM, Neeraj Kumar wrote:
> Add cxl_find_root_decoder to find root decoder on cxl bus. It is used to
> find root decoder during region creation
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
> ---
> drivers/cxl/core/port.c | 26 ++++++++++++++++++++++++++
> drivers/cxl/cxl.h | 1 +
> 2 files changed, 27 insertions(+)
>
> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
> index 2452f7c15b2d..94d9322b8e38 100644
> --- a/drivers/cxl/core/port.c
> +++ b/drivers/cxl/core/port.c
> @@ -513,6 +513,32 @@ struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev)
> }
> EXPORT_SYMBOL_NS_GPL(to_cxl_switch_decoder, "CXL");
>
> +static int match_root_decoder(struct device *dev, void *data)
> +{
> + return is_root_decoder(dev);
> +}
> +
> +/**
> + * cxl_find_root_decoder() - find a cxl root decoder on cxl bus
> + * @port: any descendant port in root-cxl-port topology
s/root-cxl-port/CXL port/
Please add a comment noting that the caller of this function must call put_device() when done as a device ref is taken via device_find_child().
> + */
> +struct cxl_root_decoder *cxl_find_root_decoder(struct cxl_port *port)
cxl_port_find_root_decoder(). There is a cxl_find_root_decoder() already in core/region.c and could cause potential symbol clash.
DJ
> +{
> + struct cxl_root *cxl_root __free(put_cxl_root) = find_cxl_root(port);
> + struct device *dev;
> +
> + if (!cxl_root)
> + return NULL;
> +
> + dev = device_find_child(&cxl_root->port.dev, NULL, match_root_decoder);
> +
> + if (!dev)
> + return NULL;
> +
> + return to_cxl_root_decoder(dev);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_find_root_decoder, "CXL");
> +
> static void cxl_ep_release(struct cxl_ep *ep)
> {
> put_device(ep->ep);
> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> index 30c80e04cb27..2c6a782d0941 100644
> --- a/drivers/cxl/cxl.h
> +++ b/drivers/cxl/cxl.h
> @@ -871,6 +871,7 @@ bool is_cxl_nvdimm_bridge(struct device *dev);
> int devm_cxl_add_nvdimm(struct cxl_port *parent_port, struct cxl_memdev *cxlmd);
> struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_port *port);
> void cxl_region_discovery(struct cxl_port *port);
> +struct cxl_root_decoder *cxl_find_root_decoder(struct cxl_port *port);
>
> #ifdef CONFIG_CXL_REGION
> bool is_cxl_pmem_region(struct device *dev);
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 18/20] cxl/pmem: Add support of cxl lsa 2.1 support in cxl pmem
2025-06-17 12:39 ` [RFC PATCH 18/20] cxl/pmem: Add support of cxl lsa 2.1 support in cxl pmem Neeraj Kumar
2025-06-23 9:48 ` Jonathan Cameron
@ 2025-07-10 17:18 ` Dave Jiang
2025-07-18 12:51 ` Neeraj Kumar
1 sibling, 1 reply; 66+ messages in thread
From: Dave Jiang @ 2025-07-10 17:18 UTC (permalink / raw)
To: Neeraj Kumar, dan.j.williams, dave, jonathan.cameron,
alison.schofield, vishal.l.verma, ira.weiny
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, neeraj.kernel, linux-kernel, linux-cxl,
nvdimm, gost.dev, cpgs
On 6/17/25 5:39 AM, Neeraj Kumar wrote:
> Add support of cxl lsa 2.1 using NDD_CXL_LABEL flag. It also creates cxl
> region based on region information parsed from LSA.
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
> ---
> drivers/cxl/pmem.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 59 insertions(+)
>
> diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c
> index ffcebb8d382f..2733d79b32d5 100644
> --- a/drivers/cxl/pmem.c
> +++ b/drivers/cxl/pmem.c
> @@ -58,6 +58,63 @@ static const struct attribute_group *cxl_dimm_attribute_groups[] = {
> NULL
> };
>
> +static int match_ep_decoder(struct device *dev, void *data)
> +{
> + struct cxl_decoder *cxld = to_cxl_decoder(dev);
> +
> + if (!cxld->region)
> + return 1;
> + else
> + return 0;
> +}
return !cxld->region;
> +
> +static struct cxl_decoder *cxl_find_free_decoder(struct cxl_port *port)
> +{
> + struct device *dev;
> +
> + dev = device_find_child(&port->dev, NULL, match_ep_decoder);
> + if (!dev)
> + return NULL;
> +
> + return to_cxl_decoder(dev);
> +}
> +
> +static int create_pmem_region(struct nvdimm *nvdimm)
> +{
> + struct cxl_nvdimm *cxl_nvd;
> + struct cxl_memdev *cxlmd;
> + struct cxl_nvdimm_bridge *cxl_nvb;
> + struct cxl_pmem_region_params *params;
> + struct cxl_root_decoder *cxlrd;
> + struct cxl_decoder *cxld;
> + struct cxl_region *cxlr;
> +
probably need a lockdep_assert_held(&cxl_region_rwsem).
> + if (!nvdimm)
> + return -ENOTTY;
-ENODEV?
> +
> + if (!nvdimm_has_cxl_region(nvdimm))
> + return 0;
> +
> + cxl_nvd = nvdimm_provider_data(nvdimm);
> + params = nvdimm_get_cxl_region_param(nvdimm);
> + cxlmd = cxl_nvd->cxlmd;
> + cxl_nvb = cxlmd->cxl_nvb;
> + cxlrd = cxlmd->cxlrd;
> +
> + /* FIXME: Limitation: Region creation only when interleave way == 1 */
> + if (params->nlabel == 1) {
> + cxld = cxl_find_free_decoder(cxlmd->endpoint);
> + cxlr = cxl_create_pmem_region(cxlrd, cxld, params,
> + atomic_read(&cxlrd->region_id));
> + if (IS_ERR(cxlr))
> + dev_dbg(&cxlmd->dev, "Region Creation failed\n");
return PTR_ERR(cxlr); ?
> + } else {
> + dev_dbg(&cxlmd->dev, "Region Creation is not supported with iw > 1\n");
> + }
> +
> + return 0;
> +}
> +
> static int cxl_nvdimm_probe(struct device *dev)
> {
> struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev);
> @@ -74,6 +131,7 @@ static int cxl_nvdimm_probe(struct device *dev)
> return rc;
>
> set_bit(NDD_LABELING, &flags);
> + set_bit(NDD_CXL_LABEL, &flags);
Ok here's the NDD_CXL_LABEL set. I think the driver should be probing the label index block and retrieve the label version and determine how to support from there instead of hard coding a flag.
> set_bit(NDD_REGISTER_SYNC, &flags);
> set_bit(ND_CMD_GET_CONFIG_SIZE, &cmd_mask);
> set_bit(ND_CMD_GET_CONFIG_DATA, &cmd_mask);
> @@ -86,6 +144,7 @@ static int cxl_nvdimm_probe(struct device *dev)
> return -ENOMEM;
>
> dev_set_drvdata(dev, nvdimm);
> + create_pmem_region(nvdimm);
> return devm_add_action_or_reset(dev, unregister_nvdimm, nvdimm);
> }
>
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 05/20] nvdimm/region_label: Add region label updation routine
2025-06-17 12:39 ` [RFC PATCH 05/20] nvdimm/region_label: Add region label updation routine Neeraj Kumar
2025-06-23 9:05 ` Jonathan Cameron
@ 2025-07-17 22:53 ` Fabio M. De Francesco
2025-07-18 13:00 ` Neeraj Kumar
1 sibling, 1 reply; 66+ messages in thread
From: Fabio M. De Francesco @ 2025-07-17 22:53 UTC (permalink / raw)
To: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny, Neeraj Kumar
Cc: a.manzanares, nifan.cxl, anisa.su, vishak.g, krish.reddy,
arun.george, alok.rathore, s.neeraj, neeraj.kernel, linux-kernel,
linux-cxl, nvdimm, gost.dev, cpgs
On Tuesday, June 17, 2025 2:39:29 PM Central European Summer Time Neeraj Kumar wrote:
> Added __pmem_region_label_update region label update routine to update
> region label
>
> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
> ---
> drivers/nvdimm/label.c | 142 ++++++++++++++++++++++++++++++++
> drivers/nvdimm/label.h | 2 +
> drivers/nvdimm/namespace_devs.c | 12 +++
> drivers/nvdimm/nd.h | 20 +++++
> include/linux/libnvdimm.h | 8 ++
> 5 files changed, 184 insertions(+)
>
> diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
> index d5cfaa99f976..7f33d14ce0ef 100644
> --- a/drivers/nvdimm/label.c
> +++ b/drivers/nvdimm/label.c
> @@ -381,6 +381,16 @@ static void nsl_calculate_checksum(struct nvdimm_drvdata *ndd,
> nsl_set_checksum(ndd, nd_label, sum);
> }
>
> +static void rgl_calculate_checksum(struct nvdimm_drvdata *ndd,
> + struct cxl_region_label *rg_label)
> +{
> + u64 sum;
> +
> + rgl_set_checksum(rg_label, 0);
> + sum = nd_fletcher64(rg_label, sizeof_namespace_label(ndd), 1);
> + rgl_set_checksum(rg_label, sum);
> +}
> +
> static bool slot_valid(struct nvdimm_drvdata *ndd,
> struct nd_lsa_label *nd_label, u32 slot)
> {
> @@ -1117,6 +1127,138 @@ int nd_pmem_namespace_label_update(struct nd_region *nd_region,
> return 0;
> }
>
> +static int __pmem_region_label_update(struct nd_region *nd_region,
> + struct nd_mapping *nd_mapping, int pos, unsigned long flags)
Hi Neeraj,
I've noticed that __pmem_region_label_update() shares many similarities
with the existing __pmem_label_update().
> +{
> + struct nd_interleave_set *nd_set = nd_region->nd_set;
> + struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
> + struct nd_lsa_label *nd_label;
> + struct cxl_region_label *rg_label;
> + struct nd_namespace_index *nsindex;
> + struct nd_label_ent *label_ent;
> + unsigned long *free;
> + u32 nslot, slot;
> + size_t offset;
> + int rc;
> + uuid_t tmp;
> +
> + if (!preamble_next(ndd, &nsindex, &free, &nslot))
> + return -ENXIO;
> +
> + /* allocate and write the label to the staging (next) index */
> + slot = nd_label_alloc_slot(ndd);
> + if (slot == UINT_MAX)
> + return -ENXIO;
> + dev_dbg(ndd->dev, "allocated: %d\n", slot);
> +
> + nd_label = to_label(ndd, slot);
> +
> + memset(nd_label, 0, sizeof_namespace_label(ndd));
> + rg_label = &nd_label->rg_label;
> +
> + /* Set Region Label Format identification UUID */
> + uuid_parse(CXL_REGION_UUID, &tmp);
> + export_uuid(nd_label->rg_label.type, &tmp);
> +
> + /* Set Current Region Label UUID */
> + export_uuid(nd_label->rg_label.uuid, &nd_set->uuid);
> +
> + rg_label->flags = __cpu_to_le32(flags);
> + rg_label->nlabel = __cpu_to_le16(nd_region->ndr_mappings);
> + rg_label->position = __cpu_to_le16(pos);
> + rg_label->dpa = __cpu_to_le64(nd_mapping->start);
> + rg_label->rawsize = __cpu_to_le64(nd_mapping->size);
> + rg_label->hpa = __cpu_to_le64(nd_set->res->start);
> + rg_label->slot = __cpu_to_le32(slot);
> + rg_label->ig = __cpu_to_le32(nd_set->interleave_granularity);
> + rg_label->align = __cpu_to_le16(0);
> +
> + /* Update fletcher64 Checksum */
> + rgl_calculate_checksum(ndd, rg_label);
> +
> + /* update label */
> + offset = nd_label_offset(ndd, nd_label);
> + rc = nvdimm_set_config_data(ndd, offset, nd_label,
> + sizeof_namespace_label(ndd));
> + if (rc < 0) {
> + nd_label_free_slot(ndd, slot);
> + return rc;
> + }
> +
> + /* Garbage collect the previous label */
> + mutex_lock(&nd_mapping->lock);
> + list_for_each_entry(label_ent, &nd_mapping->labels, list) {
> + if (!label_ent->label)
> + continue;
> + if (rgl_uuid_equal(&label_ent->label->rg_label, &nd_set->uuid))
> + reap_victim(nd_mapping, label_ent);
> + }
> +
> + /* update index */
> + rc = nd_label_write_index(ndd, ndd->ns_next,
> + nd_inc_seq(__le32_to_cpu(nsindex->seq)), 0);
> +
> + if (rc == 0) {
> + list_for_each_entry(label_ent, &nd_mapping->labels, list)
> + if (!label_ent->label) {
> + label_ent->label = nd_label;
> + nd_label = NULL;
> + break;
> + }
> + dev_WARN_ONCE(&nd_region->dev, nd_label,
> + "failed to track label: %d\n",
> + to_slot(ndd, nd_label));
> + if (nd_label)
> + rc = -ENXIO;
> + }
> + mutex_unlock(&nd_mapping->lock);
> +
> + return rc;
> +}
> +
> +int nd_pmem_region_label_update(struct nd_region *nd_region)
Same here. nd_pmem_region_label_update() is almost identical to the
existing nd_pmem_namespace_label_update.
Although I'm not familiar with drivers/nvdimm, it seems preferable to
reuse and adapt the existing functions to reduce redundancy and simplify
future maintenance, unless there are specific reasons for not doing so
that I'm unaware of.
Thanks,
Fabio
> +{
> + int i, rc;
> +
> + for (i = 0; i < nd_region->ndr_mappings; i++) {
> + struct nd_mapping *nd_mapping = &nd_region->mapping[i];
> + struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
> +
> + /* No need to update region label for non cxl format */
> + if (!ndd->cxl)
> + continue;
> +
> + /* Init labels to include region label */
> + rc = init_labels(nd_mapping, 1);
> +
> + if (rc < 0)
> + return rc;
> +
> + rc = __pmem_region_label_update(nd_region, nd_mapping, i,
> + NSLABEL_FLAG_UPDATING);
> +
> + if (rc)
> + return rc;
> + }
> +
> + /* Clear the UPDATING flag per UEFI 2.7 expectations */
> + for (i = 0; i < nd_region->ndr_mappings; i++) {
> + struct nd_mapping *nd_mapping = &nd_region->mapping[i];
> + struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
> +
> + /* No need to update region label for non cxl format */
> + if (!ndd->cxl)
> + continue;
> +
> + rc = __pmem_region_label_update(nd_region, nd_mapping, i, 0);
> +
> + if (rc)
> + return rc;
> + }
> +
> + return 0;
> +}
> +
> int __init nd_label_init(void)
> {
> WARN_ON(guid_parse(NVDIMM_BTT_GUID, &nvdimm_btt_guid));
> diff --git a/drivers/nvdimm/label.h b/drivers/nvdimm/label.h
> index 4883b3a1320f..0f428695017d 100644
> --- a/drivers/nvdimm/label.h
> +++ b/drivers/nvdimm/label.h
> @@ -190,6 +190,7 @@ struct nd_namespace_label {
> struct nd_lsa_label {
> union {
> struct nd_namespace_label ns_label;
> + struct cxl_region_label rg_label;
> };
> };
>
> @@ -233,4 +234,5 @@ struct nd_region;
> struct nd_namespace_pmem;
> int nd_pmem_namespace_label_update(struct nd_region *nd_region,
> struct nd_namespace_pmem *nspm, resource_size_t size);
> +int nd_pmem_region_label_update(struct nd_region *nd_region);
> #endif /* __LABEL_H__ */
> diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
> index 23b9def71012..6cccb4d2fc7b 100644
> --- a/drivers/nvdimm/namespace_devs.c
> +++ b/drivers/nvdimm/namespace_devs.c
> @@ -232,6 +232,18 @@ static ssize_t __alt_name_store(struct device *dev, const char *buf,
> return rc;
> }
>
> +int nd_region_label_update(struct nd_region *nd_region)
> +{
> + int rc;
> +
> + nvdimm_bus_lock(&nd_region->dev);
> + rc = nd_pmem_region_label_update(nd_region);
> + nvdimm_bus_unlock(&nd_region->dev);
> +
> + return rc;
> +}
> +EXPORT_SYMBOL_GPL(nd_region_label_update);
> +
> static int nd_namespace_label_update(struct nd_region *nd_region,
> struct device *dev)
> {
> diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
> index 07d665f18bf6..2fdc92b29e8a 100644
> --- a/drivers/nvdimm/nd.h
> +++ b/drivers/nvdimm/nd.h
> @@ -322,6 +322,26 @@ static inline void nsl_set_region_uuid(struct nvdimm_drvdata *ndd,
> export_uuid(ns_label->cxl.region_uuid, uuid);
> }
>
> +static inline bool rgl_uuid_equal(struct cxl_region_label *rg_label,
> + const uuid_t *uuid)
> +{
> + uuid_t tmp;
> +
> + import_uuid(&tmp, rg_label->uuid);
> + return uuid_equal(&tmp, uuid);
> +}
> +
> +static inline u64 rgl_get_checksum(struct cxl_region_label *rg_label)
> +{
> + return __le64_to_cpu(rg_label->checksum);
> +}
> +
> +static inline void rgl_set_checksum(struct cxl_region_label *rg_label,
> + u64 checksum)
> +{
> + rg_label->checksum = __cpu_to_le64(checksum);
> +}
> +
> bool nsl_validate_type_guid(struct nvdimm_drvdata *ndd,
> struct nd_namespace_label *nd_label, guid_t *guid);
> enum nvdimm_claim_class nsl_get_claim_class(struct nvdimm_drvdata *ndd,
> diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
> index 0a55900842c8..b06bd45373f4 100644
> --- a/include/linux/libnvdimm.h
> +++ b/include/linux/libnvdimm.h
> @@ -115,6 +115,13 @@ struct nd_interleave_set {
> u64 altcookie;
>
> guid_t type_guid;
> +
> + /* v2.1 region label info */
> + uuid_t uuid;
> + int interleave_ways;
> + int interleave_granularity;
> + struct resource *res;
> + int nr_targets;
> };
>
> struct nd_mapping_desc {
> @@ -302,6 +309,7 @@ int nvdimm_has_flush(struct nd_region *nd_region);
> int nvdimm_has_cache(struct nd_region *nd_region);
> int nvdimm_in_overwrite(struct nvdimm *nvdimm);
> bool is_nvdimm_sync(struct nd_region *nd_region);
> +int nd_region_label_update(struct nd_region *nd_region);
>
> static inline int nvdimm_ctl(struct nvdimm *nvdimm, unsigned int cmd, void *buf,
> unsigned int buf_len, int *cmd_rc)
> --
> 2.34.1
>
>
>
>
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 01/20] nvdimm/label: Introduce NDD_CXL_LABEL flag to set cxl label format
2025-07-09 22:57 ` Dave Jiang
@ 2025-07-18 12:13 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-07-18 12:13 UTC (permalink / raw)
To: Dave Jiang
Cc: dan.j.williams, dave, jonathan.cameron, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 5533 bytes --]
On 09/07/25 03:57PM, Dave Jiang wrote:
>
>
>On 6/17/25 5:39 AM, Neeraj Kumar wrote:
>> NDD_CXL_LABEL is introduced to set cxl LSA 2.1 label format
>> Accordingly updated label index version
>
>Maybe add the spec reference that defines label 2.1 format
Sure Dave, I will update commit message accordingly.
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>> ---
>> drivers/nvdimm/dimm.c | 1 +
>> drivers/nvdimm/dimm_devs.c | 10 ++++++++++
>> drivers/nvdimm/label.c | 16 ++++++++++++----
>> drivers/nvdimm/nd.h | 1 +
>> include/linux/libnvdimm.h | 3 +++
>> 5 files changed, 27 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c
>> index 91d9163ee303..8753b5cd91cc 100644
>> --- a/drivers/nvdimm/dimm.c
>> +++ b/drivers/nvdimm/dimm.c
>> @@ -62,6 +62,7 @@ static int nvdimm_probe(struct device *dev)
>> if (rc < 0)
>> dev_dbg(dev, "failed to unlock dimm: %d\n", rc);
>>
>> + ndd->cxl = nvdimm_check_cxl_label_format(ndd->dev);
>>
>> /*
>> * EACCES failures reading the namespace label-area-properties
>> diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
>> index 21498d461fde..e8f545f889fd 100644
>> --- a/drivers/nvdimm/dimm_devs.c
>> +++ b/drivers/nvdimm/dimm_devs.c
>> @@ -18,6 +18,16 @@
>>
>> static DEFINE_IDA(dimm_ida);
>>
>> +bool nvdimm_check_cxl_label_format(struct device *dev)
>> +{
>> + struct nvdimm *nvdimm = to_nvdimm(dev);
>> +
>> + if (test_bit(NDD_CXL_LABEL, &nvdimm->flags))
>> + return true;
>> +
>> + return false;
>> +}
>
>I think we may want to move the checking of the flag to where the patch also set the flag in order to provide a more coherent review experience. Given that I haven't read the rest of the patchset and don't know how NDD_CXL_LABEL is set, I really can't comment on whether there's a better way to detect LSA 2.1 labels. Is there a generic way to determine label versions without the implication of this is CXL device?
>
Its been set in cxl driver in later patch, May be I will update the
commit message with this information.
>> +
>> /*
>> * Retrieve bus and dimm handle and return if this bus supports
>> * get_config_data commands
>> diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
>> index 082253a3a956..48b5ba90216d 100644
>> --- a/drivers/nvdimm/label.c
>> +++ b/drivers/nvdimm/label.c
>> @@ -687,11 +687,19 @@ static int nd_label_write_index(struct nvdimm_drvdata *ndd, int index, u32 seq,
>> - (unsigned long) to_namespace_index(ndd, 0);
>> nsindex->labeloff = __cpu_to_le64(offset);
>> nsindex->nslot = __cpu_to_le32(nslot);
>> - nsindex->major = __cpu_to_le16(1);
>> - if (sizeof_namespace_label(ndd) < 256)
>> +
>> + /* Support CXL LSA 2.1 label format */
>> + if (ndd->cxl) {
>> + nsindex->major = __cpu_to_le16(2);
>> nsindex->minor = __cpu_to_le16(1);
>> - else
>> - nsindex->minor = __cpu_to_le16(2);
>> + } else {
>> + nsindex->major = __cpu_to_le16(1);
>> + if (sizeof_namespace_label(ndd) < 256)
>> + nsindex->minor = __cpu_to_le16(1);
>> + else
>> + nsindex->minor = __cpu_to_le16(2);
>> + }
>
>Would like to see a more coherent way of detecting label versioning. What happens when there are newer versions introduced later on? This currently feels very disjointed.
>
Thanks Dave for your suggestion. This current patch-set is extension of
commit 5af96835e4daf. We may have to do some more change to address this
coherent way of detecting label versioning. May be we can take this later.
>> +
>> nsindex->checksum = __cpu_to_le64(0);
>> if (flags & ND_NSINDEX_INIT) {
>> unsigned long *free = (unsigned long *) nsindex->free;
>> diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
>> index 5ca06e9a2d29..304f0e9904f1 100644
>> --- a/drivers/nvdimm/nd.h
>> +++ b/drivers/nvdimm/nd.h
>> @@ -522,6 +522,7 @@ void nvdimm_set_labeling(struct device *dev);
>> void nvdimm_set_locked(struct device *dev);
>> void nvdimm_clear_locked(struct device *dev);
>> int nvdimm_security_setup_events(struct device *dev);
>> +bool nvdimm_check_cxl_label_format(struct device *dev);
>> #if IS_ENABLED(CONFIG_NVDIMM_KEYS)
>> int nvdimm_security_unlock(struct device *dev);
>> #else
>> diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
>> index e772aae71843..0a55900842c8 100644
>> --- a/include/linux/libnvdimm.h
>> +++ b/include/linux/libnvdimm.h
>> @@ -44,6 +44,9 @@ enum {
>> /* dimm provider wants synchronous registration by __nvdimm_create() */
>> NDD_REGISTER_SYNC = 8,
>>
>> + /* dimm supports region labels (LSA Format 2.1) */
>> + NDD_CXL_LABEL = 9,
>
>While 2.1 is defined by the CXL spec, is there anything declared by the CXL spec that makes 2.1 exclusive to CXL? Maybe the focus should be to support LSA 2.1 and avoid dragging naming CXL into the conversation at this point. It can be made more generic right? I'm concerned about dragging CXL into nvdimm when it isn't necessary. Maybe introduce a label cap field where when an nvdimm device is registered, the caller can pass in that it's capable of supporting up to a certain version of labeling? Just throwing ideas out to see if it's feasible.
>
Hi Dave,
I have taken this naming reference from "drivers/nvdimm/label.h"
where namespace label is defined as "struct nvdimm_efi_label" (LSA 1.1
is defined in nvdimm namespace spec and LSA 1.2 is defined in efi spec)
where (from commit 540ccaa2e4dd6) region label is defined as "struct
cxl_region_label"
Please let me know if I should use some other name in place of this
Regards,
Neeraj
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 13/20] cxl/mem: Refactor cxl pmem region auto-assembling
2025-07-10 0:38 ` Dave Jiang
@ 2025-07-18 12:30 ` Neeraj Kumar
2025-07-21 18:11 ` Dave Jiang
0 siblings, 1 reply; 66+ messages in thread
From: Neeraj Kumar @ 2025-07-18 12:30 UTC (permalink / raw)
To: Dave Jiang
Cc: dan.j.williams, dave, jonathan.cameron, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 5401 bytes --]
On 09/07/25 05:38PM, Dave Jiang wrote:
>
>
>On 6/17/25 5:39 AM, Neeraj Kumar wrote:
>> In 84ec985944ef3, For cxl pmem region auto-assembly after endpoint port
>> probing, cxl_nvd presence was required. And for cxl region persistency,
>> region creation happens during nvdimm_probe which need the completion
>> of endpoint probe.
>>
>> It is therefore refactored cxl pmem region auto-assembly after endpoint
>> probing to cxl mem probing
>
>The region auto-assembly is moved after the endpoint device is added. However, it's not guaranteed that the endpoint probe has completed and completed successfully. You are just getting lucky timing wise that endpoint probe is completed when the new region discovery is starting.
Hi Dave,
For region auto-assembly two things are required
1. endpoint(s) decoder should be enumerated successfully
2. As per fix in 84ec985944ef3, The cxl_nvd of the memdev needs to be available during the pmem region probe
Prior to current patch, region auto-assembly was happening from cxl_endpoint_port_probe() after endpoint decoder enumeration.
In 84ec985944ef3, sequence of devm_cxl_add_nvdimm() was moved before devm_cxl_add_endpoint() so as to meet region auto assembly dependency on cxl_nvd of the memdev.
Here, In this patch I have moved region auto-assembly after
1. devm_cxl_add_endpoint(): This function makes sure cxl_endpoint_port_probe() has completed successfully, as per below check in devm_cxl_add_endpoint()
if (!endpoint->dev.driver) {
dev_err(&cxlmd->dev, "%s failed probe\n", dev_name(&endpoint->dev));
return -ENXIO;
}
And successfull completion of cxl_endpoint_port_probe(), it must have enumerated endpoint(s) decoder successfully
2. devm_cxl_add_nvdimm(): As you rightly said, this allocates "cxl_nvd" nvdimm device and triggers the async probe of nvdimm driver
Actually in this patch, from async probe function (cxl_nvdimm_probe()), I am creating "struct nvdimm" using __nvdimm_create()
This __nvdimm_create() ultimately scans LSA. If LSA finds region label into it then it saves region information into struct nvdimm
and then using create_pmem_region(nvdimm), I am re-creating cxl region for region persistency.
As for cxl region persistency (based on LSA 2.1 scanning - this patch)
following sequence should be required
1. devm_cxl_add_endpoint(): endpoint probe completion - which is getting done by devm_cxl_add_endpoint()
2. devm_cxl_add_nvdimm(): Here after nvdimm device creation, cxl region is being created
It is therefore re-sequencing of region-auto assembly is required to move from cxl_endpoint_port_probe() to after
devm_cxl_add_endpoint() and devm_cxl_add_nvdimm()
>Return of devm_cxl_add_nvdimm() only adds the nvdimm device and triggers the async probe of nvdimm driver. You have to take the endpoint port lock
I think we may not require endpoint port lock as auto-assembly and region persistency code sequence is always after successful completion of endpoint probe.
>and check if the driver is attached to be certain that endpoint probe is done and successful. Therefore moving the region discovery location probably does not do what you think it does.
>Maybe take a deeper look at the region discovery code and see how it does retry if things are not present and approach it from that angle?
>
Please let me know if my understanding is correct or am I missing something?
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>> ---
>> drivers/cxl/core/port.c | 38 ++++++++++++++++++++++++++++++++++++++
>> drivers/cxl/cxl.h | 1 +
>> drivers/cxl/mem.c | 27 ++++++++++++++++++---------
>> drivers/cxl/port.c | 38 --------------------------------------
>> 4 files changed, 57 insertions(+), 47 deletions(-)
>>
>> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
>> index 78a5c2c25982..bca668193c49 100644
>> --- a/drivers/cxl/core/port.c
>> +++ b/drivers/cxl/core/port.c
>> @@ -1038,6 +1038,44 @@ void put_cxl_root(struct cxl_root *cxl_root)
>> }
>> EXPORT_SYMBOL_NS_GPL(put_cxl_root, "CXL");
>>
>> +static int discover_region(struct device *dev, void *root)
>> +{
>> + struct cxl_endpoint_decoder *cxled;
>> + int rc;
>> +
>> + if (!is_endpoint_decoder(dev))
>> + return 0;
>> +
>> + cxled = to_cxl_endpoint_decoder(dev);
>> + if ((cxled->cxld.flags & CXL_DECODER_F_ENABLE) == 0)
>> + return 0;
>> +
>> + if (cxled->state != CXL_DECODER_STATE_AUTO)
>> + return 0;
>> +
>> + /*
>> + * Region enumeration is opportunistic, if this add-event fails,
>> + * continue to the next endpoint decoder.
>> + */
>> + rc = cxl_add_to_region(root, cxled);
>> + if (rc)
>> + dev_dbg(dev, "failed to add to region: %#llx-%#llx\n",
>> + cxled->cxld.hpa_range.start, cxled->cxld.hpa_range.end);
>> +
>> + return 0;
>> +}
>> +
>> +void cxl_region_discovery(struct cxl_port *port)
>> +{
>> + struct cxl_port *root;
>> + struct cxl_root *cxl_root __free(put_cxl_root) = find_cxl_root(port);
>> +
>> + root = &cxl_root->port;
>> +
>> + device_for_each_child(&port->dev, root, discover_region);
>> +}
>> +EXPORT_SYMBOL_NS_GPL(cxl_region_discovery, "CXL");
>> +
>
>I have concerns about adding region related code in core/port.c while the rest of the region code is walled behind CONFIG_CXL_REGION. I think this change needs to go to core/region.c.
>
>DJ
>
Sure Dave, I will move it into core/region.c in next patch-set.
Regards,
Neeraj
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 14/20] cxl/region: Add cxl pmem region creation routine for region persistency
2025-07-10 15:59 ` Dave Jiang
@ 2025-07-18 12:45 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-07-18 12:45 UTC (permalink / raw)
To: Dave Jiang
Cc: dan.j.williams, dave, jonathan.cameron, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 8153 bytes --]
On 10/07/25 08:59AM, Dave Jiang wrote:
>
>
>On 6/17/25 5:39 AM, Neeraj Kumar wrote:
>> Added exported cxl_create_pmem_region routine to create cxl pmem region
>> from LSA parsed cxl region information.
>> Inspirition for the function is taken from ndctl device attribute
>> (_store) call. It allocates cxlr and fills information parsed from LSA
>> and calls device_add(&cxlr->dev) to initiates further region creation
>> porbes
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>> ---
>> drivers/cxl/core/port.c | 6 ++
>> drivers/cxl/core/region.c | 208 ++++++++++++++++++++++++++++++++++++++
>> drivers/cxl/cxl.h | 11 ++
>> 3 files changed, 225 insertions(+)
>>
>> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
>> index bca668193c49..2452f7c15b2d 100644
>> --- a/drivers/cxl/core/port.c
>> +++ b/drivers/cxl/core/port.c
>> @@ -2150,6 +2150,12 @@ void cxl_bus_drain(void)
>> }
>> EXPORT_SYMBOL_NS_GPL(cxl_bus_drain, "CXL");
>>
>> +void cxl_wq_flush(void)
>> +{
>> + flush_workqueue(cxl_bus_wq);
>> +}
>> +EXPORT_SYMBOL_NS_GPL(cxl_wq_flush, "CXL");
>> +
>> bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd)
>> {
>> return queue_work(cxl_bus_wq, &cxlmd->detach_work);
>> diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
>> index b98b1ccffd1c..8990e3c3474d 100644
>> --- a/drivers/cxl/core/region.c
>> +++ b/drivers/cxl/core/region.c
>> @@ -2522,6 +2522,214 @@ static ssize_t create_ram_region_show(struct device *dev,
>> return __create_region_show(to_cxl_root_decoder(dev), buf);
>> }
>>
>> +static ssize_t update_region_size(struct cxl_region *cxlr, u64 val)
>
>Maybe call it resize_or_free_region_hpa()?
>
>Also rename 'val' to 'size'
>
Sure Dave, I will fix it next patch-set.
>> +{
>> + int rc;
>> +
>> + rc = down_write_killable(&cxl_region_rwsem);
>> + if (rc)
>> + return rc;
>> +
>> + if (val)
>> + rc = alloc_hpa(cxlr, val);
>> + else
>> + rc = free_hpa(cxlr);
>> + up_write(&cxl_region_rwsem);
>> +
>> + if (rc)
>> + return rc;
>> +
>> + return 0;
>> +}
>
>Share common code with core/region.c:size_store(). Please use helper function and not duplicate code.
>
Sure, I will try to minimize duplicate code as much as possible in next patch-set.
>> +
>> +static ssize_t update_region_dpa_size(struct cxl_region *cxlr,
>
>resize_or_free_dpa()
>
Sure, I will fix it in next patch-set
>> + struct cxl_decoder *cxld,
>> + unsigned long long size)
>
>u64 size
>
Sure, I will fix it in next patch-set
>> +{
>> + int rc;
>> + struct cxl_endpoint_decoder *cxled =
>> + to_cxl_endpoint_decoder(&cxld->dev);
>> +
>> + if (!IS_ALIGNED(size, SZ_256M))
>> + return -EINVAL;
>> +
>> + rc = cxl_dpa_free(cxled);
>> + if (rc)
>> + return rc;
>> +
>> + if (size == 0)
>> + return 0;
>> +
>> + rc = cxl_dpa_alloc(cxled, size);
>> + if (rc)
>> + return rc;
>> +
>> + return 0;
>> +}
>
>Share common code with core/port.c:dpa_size_store(). Please use helper function and not duplicate code.
>
Sure, I will try minimizing duplicate code as much as possible.
>> +
>> +static ssize_t update_region_dpa_mode(struct cxl_region *cxlr,
>> + struct cxl_decoder *cxld)
>> +{
>> + int rc;
>> + struct cxl_endpoint_decoder *cxled =
>> + to_cxl_endpoint_decoder(&cxld->dev);
>> +
>> + rc = cxl_dpa_set_mode(cxled, CXL_DECODER_PMEM);
>
>Don't think CXL_DECODER_PMEM exists any longer. It's CXL_PARTMODE_PMEM. Just beware there have been some changes while you are rebasing to the latest upstream code.
>
Thanks, I will rebase and fix it with latest change
>> + if (rc)
>> + return rc;
>> +
>> + return 0;
>> +}
>> +
>> +static size_t attach_region_target(struct cxl_region *cxlr,
>> + struct cxl_decoder *cxld, int pos)
>> +{
>> + int rc;
>> + struct cxl_endpoint_decoder *cxled =
>> + to_cxl_endpoint_decoder(&cxld->dev);
>> +
>> + rc = attach_target(cxlr, cxled, pos, TASK_INTERRUPTIBLE);
>> +
>> + if (rc < 0)
>> + return rc;
>> +
>> + return 0;
>> +}
>> +
>> +static ssize_t commit_region(struct cxl_region *cxlr)
>> +{
>> + struct cxl_region_params *p = &cxlr->params;
>> + ssize_t rc;
>> +
>> + rc = down_write_killable(&cxl_region_rwsem);
>> + if (rc)
>> + return rc;
>> +
>> + /* Already in the requested state? */
>> + if (p->state >= CXL_CONFIG_COMMIT)
>> + goto out;
>> +
>> + /* Not ready to commit? */
>> + if (p->state < CXL_CONFIG_ACTIVE) {
>> + rc = -ENXIO;
>> + goto out;
>> + }
>> +
>> + /*
>> + * Invalidate caches before region setup to drop any speculative
>> + * consumption of this address space
>> + */
>> + rc = cxl_region_invalidate_memregion(cxlr);
>> + if (rc)
>> + goto out;
>> +
>> + rc = cxl_region_decode_commit(cxlr);
>> + if (rc == 0)
>> + p->state = CXL_CONFIG_COMMIT;
>> +out:
>> + up_write(&cxl_region_rwsem);
>> + if (rc)
>> + return rc;
>> + return 0;
>> +}
>
>Sharing common code with core/region.c:commit_store()?
>
Sure, I will handle it in next patch-set
>> +
>> +static struct cxl_region *
>> +devm_cxl_pmem_add_region(struct cxl_root_decoder *cxlrd,
>> + struct cxl_decoder *cxld,
>> + struct cxl_pmem_region_params *params, int id,
>> + enum cxl_decoder_mode mode, enum cxl_decoder_type type)
>> +{
>> + struct cxl_port *port;
>> + struct cxl_region *cxlr;
>> + struct cxl_region_params *p;
>> + struct device *dev;
>> + int rc;
>> +
>> + if (!cxlrd)
>> + return ERR_PTR(-EINVAL);
>> +
>> + port = to_cxl_port(cxlrd->cxlsd.cxld.dev.parent);
>> +
>> + cxlr = cxl_region_alloc(cxlrd, id);
>> + if (IS_ERR(cxlr))
>> + return cxlr;
>> + cxlr->mode = mode;
>> + cxlr->type = type;
>> +
>> + dev = &cxlr->dev;
>> + rc = dev_set_name(dev, "region%d", id);
>> + if (rc)
>> + goto err;
>> +> + p = &cxlr->params;
>> + p->uuid = params->uuid;
>> + p->interleave_ways = params->nlabel;
>> + p->interleave_granularity = params->ig;
>> +
>> + /* Update region size */
>Not sure what value this comment adds
Sure, I will remove these comments
>> + if (update_region_size(cxlr, params->rawsize))
>> + goto err;
>> +
>> + /* Flush cxl wq */
>Can you explain here why a flush is needed?
These steps of region creation is taken from how ndctl creates region
using *_store(). I will re-look if its required here.
>> + cxl_wq_flush();
>> +
>> + /* Clear DPA Size */
>comment provides no value
>> + if (update_region_dpa_size(cxlr, cxld, 0))
>> + goto err;
>> +
>> + /* Update DPA mode */
>same as above
>> + if (update_region_dpa_mode(cxlr, cxld))
>> + goto err;
>> +
>> + /* Update DPA Size */
>same as above
>> + if (update_region_dpa_size(cxlr, cxld, params->rawsize))
>> + goto err;
>> +
>> + /* Attach region targets */
>same as above
>> + if (attach_region_target(cxlr, cxld, params->position))
>> + goto err;
>> +
>> + /* Commit Region */
>same as above
Sure, I will remove unwanted comments
>> + if (commit_region(cxlr))
>> + goto err;
>
>Can you please provide some verbose explanation as to what all these extra steps are doing for pmem versus devm_cxl_add_region() for dram?
>
These steps of region creation is taken from how ndctl creates region.
Sure I will update the comments accordingly.
>> +
>> + rc = device_add(dev);
>> + if (rc)
>> + goto err;
>> +
>> + rc = devm_add_action_or_reset(port->uport_dev, unregister_region, cxlr);
>> + if (rc)
>> + return ERR_PTR(rc);
>> +
>> + dev_dbg(port->uport_dev, "%s: created %s\n",
>> + dev_name(&cxlrd->cxlsd.cxld.dev), dev_name(dev));
>> + return cxlr;
>> +
>> +err:
>> + put_device(dev);
>> + return ERR_PTR(rc);
>> +}
>> +
>> +struct cxl_region *cxl_create_pmem_region(struct cxl_root_decoder *cxlrd,
>> + struct cxl_decoder *cxld,
>> + struct cxl_pmem_region_params *params, 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_pmem_add_region(cxlrd, cxld, params, id,
>> + CXL_DECODER_PMEM, CXL_DECODER_HOSTONLYMEM);
>> +}
>> +EXPORT_SYMBOL_NS_GPL(cxl_create_pmem_region, "CXL");
>
>Can __create_region() be modified to determine whether to create dram region or pmem?
>
>DJ
Sure, I will refactor it accordingly
Regards,
Neeraj
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 15/20] cxl: Add a routine to find cxl root decoder on cxl bus
2025-07-10 16:23 ` Dave Jiang
@ 2025-07-18 12:48 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-07-18 12:48 UTC (permalink / raw)
To: Dave Jiang
Cc: dan.j.williams, dave, jonathan.cameron, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 1541 bytes --]
On 10/07/25 09:23AM, Dave Jiang wrote:
>
>
>On 6/17/25 5:39 AM, Neeraj Kumar wrote:
>> Add cxl_find_root_decoder to find root decoder on cxl bus. It is used to
>> find root decoder during region creation
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>> ---
>> drivers/cxl/core/port.c | 26 ++++++++++++++++++++++++++
>> drivers/cxl/cxl.h | 1 +
>> 2 files changed, 27 insertions(+)
>>
>> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
>> index 2452f7c15b2d..94d9322b8e38 100644
>> --- a/drivers/cxl/core/port.c
>> +++ b/drivers/cxl/core/port.c
>> @@ -513,6 +513,32 @@ struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev)
>> }
>> EXPORT_SYMBOL_NS_GPL(to_cxl_switch_decoder, "CXL");
>>
>> +static int match_root_decoder(struct device *dev, void *data)
>> +{
>> + return is_root_decoder(dev);
>> +}
>> +
>> +/**
>> + * cxl_find_root_decoder() - find a cxl root decoder on cxl bus
>> + * @port: any descendant port in root-cxl-port topology
>
>s/root-cxl-port/CXL port/
>
>Please add a comment noting that the caller of this function must call put_device() when done as a device ref is taken via device_find_child().
>
Thanks Dave for pointing this, Sure I will update it accordingly.
>> + */
>> +struct cxl_root_decoder *cxl_find_root_decoder(struct cxl_port *port)
>
>cxl_port_find_root_decoder(). There is a cxl_find_root_decoder() already in core/region.c and could cause potential symbol clash.
>
>DJ
>
Sure Dave, I will rename it while rebasing for next patch-set
Regards,
Neeraj
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 18/20] cxl/pmem: Add support of cxl lsa 2.1 support in cxl pmem
2025-07-10 17:18 ` Dave Jiang
@ 2025-07-18 12:51 ` Neeraj Kumar
2025-07-21 17:44 ` Dave Jiang
0 siblings, 1 reply; 66+ messages in thread
From: Neeraj Kumar @ 2025-07-18 12:51 UTC (permalink / raw)
To: Dave Jiang
Cc: dan.j.williams, dave, jonathan.cameron, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 3228 bytes --]
On 10/07/25 10:18AM, Dave Jiang wrote:
>
>
>On 6/17/25 5:39 AM, Neeraj Kumar wrote:
>> Add support of cxl lsa 2.1 using NDD_CXL_LABEL flag. It also creates cxl
>> region based on region information parsed from LSA.
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>> ---
>> drivers/cxl/pmem.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 59 insertions(+)
>>
>> diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c
>> index ffcebb8d382f..2733d79b32d5 100644
>> --- a/drivers/cxl/pmem.c
>> +++ b/drivers/cxl/pmem.c
>> @@ -58,6 +58,63 @@ static const struct attribute_group *cxl_dimm_attribute_groups[] = {
>> NULL
>> };
>>
>> +static int match_ep_decoder(struct device *dev, void *data)
>> +{
>> + struct cxl_decoder *cxld = to_cxl_decoder(dev);
>> +
>> + if (!cxld->region)
>> + return 1;
>> + else
>> + return 0;
>> +}
>
>return !cxld->region;
>
Thanks, I will fix it in next patch-set
>
>> +
>> +static struct cxl_decoder *cxl_find_free_decoder(struct cxl_port *port)
>> +{
>> + struct device *dev;
>> +
>> + dev = device_find_child(&port->dev, NULL, match_ep_decoder);
>> + if (!dev)
>> + return NULL;
>> +
>> + return to_cxl_decoder(dev);
>> +}
>> +
>> +static int create_pmem_region(struct nvdimm *nvdimm)
>> +{
>> + struct cxl_nvdimm *cxl_nvd;
>> + struct cxl_memdev *cxlmd;
>> + struct cxl_nvdimm_bridge *cxl_nvb;
>> + struct cxl_pmem_region_params *params;
>> + struct cxl_root_decoder *cxlrd;
>> + struct cxl_decoder *cxld;
>> + struct cxl_region *cxlr;
>> +
>
>probably need a lockdep_assert_held(&cxl_region_rwsem).
>
Thanks Dave, Sure i will fix it with V2
>> + if (!nvdimm)
>> + return -ENOTTY;
>
>-ENODEV?
Sure I will fix it with V2
>
>> +
>> + if (!nvdimm_has_cxl_region(nvdimm))
>> + return 0;
>> +
>> + cxl_nvd = nvdimm_provider_data(nvdimm);
>> + params = nvdimm_get_cxl_region_param(nvdimm);
>> + cxlmd = cxl_nvd->cxlmd;
>> + cxl_nvb = cxlmd->cxl_nvb;
>> + cxlrd = cxlmd->cxlrd;
>> +
>> + /* FIXME: Limitation: Region creation only when interleave way == 1 */
>> + if (params->nlabel == 1) {
>> + cxld = cxl_find_free_decoder(cxlmd->endpoint);
>> + cxlr = cxl_create_pmem_region(cxlrd, cxld, params,
>> + atomic_read(&cxlrd->region_id));
>> + if (IS_ERR(cxlr))
>> + dev_dbg(&cxlmd->dev, "Region Creation failed\n");
>
>return PTR_ERR(cxlr); ?
>
Thanks, I will fix it in next patch-set
>> + } else {
>> + dev_dbg(&cxlmd->dev, "Region Creation is not supported with iw > 1\n");
>> + }
>> +
>> + return 0;
>> +}
>> +
>> static int cxl_nvdimm_probe(struct device *dev)
>> {
>> struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev);
>> @@ -74,6 +131,7 @@ static int cxl_nvdimm_probe(struct device *dev)
>> return rc;
>>
>> set_bit(NDD_LABELING, &flags);
>> + set_bit(NDD_CXL_LABEL, &flags);
>
>Ok here's the NDD_CXL_LABEL set. I think the driver should be probing the label index block and retrieve the label version and determine how to support from there instead of hard coding a flag.
Hi Dave,
We actually write label index information into LSA during namespace/region label updation.
During that time we update its major/minor.
So during first time updation of LSA we must need some way to inform nvdimm about LSA versioning.
Regards,
Neeraj
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 05/20] nvdimm/region_label: Add region label updation routine
2025-07-17 22:53 ` Fabio M. De Francesco
@ 2025-07-18 13:00 ` Neeraj Kumar
0 siblings, 0 replies; 66+ messages in thread
From: Neeraj Kumar @ 2025-07-18 13:00 UTC (permalink / raw)
To: Fabio M. De Francesco
Cc: dan.j.williams, dave, jonathan.cameron, dave.jiang,
alison.schofield, vishal.l.verma, ira.weiny, a.manzanares,
nifan.cxl, anisa.su, vishak.g, krish.reddy, arun.george,
alok.rathore, neeraj.kernel, linux-kernel, linux-cxl, nvdimm,
gost.dev, cpgs
[-- Attachment #1: Type: text/plain, Size: 5241 bytes --]
On 18/07/25 12:53AM, Fabio M. De Francesco wrote:
>On Tuesday, June 17, 2025 2:39:29 PM Central European Summer Time Neeraj Kumar wrote:
>> Added __pmem_region_label_update region label update routine to update
>> region label
>>
>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>> ---
>> drivers/nvdimm/label.c | 142 ++++++++++++++++++++++++++++++++
>> drivers/nvdimm/label.h | 2 +
>> drivers/nvdimm/namespace_devs.c | 12 +++
>> drivers/nvdimm/nd.h | 20 +++++
>> include/linux/libnvdimm.h | 8 ++
>> 5 files changed, 184 insertions(+)
>>
>> diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
>> index d5cfaa99f976..7f33d14ce0ef 100644
>> --- a/drivers/nvdimm/label.c
>> +++ b/drivers/nvdimm/label.c
>> @@ -381,6 +381,16 @@ static void nsl_calculate_checksum(struct nvdimm_drvdata *ndd,
>> nsl_set_checksum(ndd, nd_label, sum);
>> }
>>
>> +static void rgl_calculate_checksum(struct nvdimm_drvdata *ndd,
>> + struct cxl_region_label *rg_label)
>> +{
>> + u64 sum;
>> +
>> + rgl_set_checksum(rg_label, 0);
>> + sum = nd_fletcher64(rg_label, sizeof_namespace_label(ndd), 1);
>> + rgl_set_checksum(rg_label, sum);
>> +}
>> +
>> static bool slot_valid(struct nvdimm_drvdata *ndd,
>> struct nd_lsa_label *nd_label, u32 slot)
>> {
>> @@ -1117,6 +1127,138 @@ int nd_pmem_namespace_label_update(struct nd_region *nd_region,
>> return 0;
>> }
>>
>> +static int __pmem_region_label_update(struct nd_region *nd_region,
>> + struct nd_mapping *nd_mapping, int pos, unsigned long flags)
>
>Hi Neeraj,
>
>I've noticed that __pmem_region_label_update() shares many similarities
>with the existing __pmem_label_update().
Hi Fabio,
Yes these functions looks similar, as one is updating namespace label
and other (__pmem_region_label_update) is updating region label. But
they don't use much duplicated code.
May be I will try refactoring to avoid any duplicate code.
>
>> +{
>> + struct nd_interleave_set *nd_set = nd_region->nd_set;
>> + struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
>> + struct nd_lsa_label *nd_label;
>> + struct cxl_region_label *rg_label;
>> + struct nd_namespace_index *nsindex;
>> + struct nd_label_ent *label_ent;
>> + unsigned long *free;
>> + u32 nslot, slot;
>> + size_t offset;
>> + int rc;
>> + uuid_t tmp;
>> +
>> + if (!preamble_next(ndd, &nsindex, &free, &nslot))
>> + return -ENXIO;
>> +
>> + /* allocate and write the label to the staging (next) index */
>> + slot = nd_label_alloc_slot(ndd);
>> + if (slot == UINT_MAX)
>> + return -ENXIO;
>> + dev_dbg(ndd->dev, "allocated: %d\n", slot);
>> +
>> + nd_label = to_label(ndd, slot);
>> +
>> + memset(nd_label, 0, sizeof_namespace_label(ndd));
>> + rg_label = &nd_label->rg_label;
>> +
>> + /* Set Region Label Format identification UUID */
>> + uuid_parse(CXL_REGION_UUID, &tmp);
>> + export_uuid(nd_label->rg_label.type, &tmp);
>> +
>> + /* Set Current Region Label UUID */
>> + export_uuid(nd_label->rg_label.uuid, &nd_set->uuid);
>> +
>> + rg_label->flags = __cpu_to_le32(flags);
>> + rg_label->nlabel = __cpu_to_le16(nd_region->ndr_mappings);
>> + rg_label->position = __cpu_to_le16(pos);
>> + rg_label->dpa = __cpu_to_le64(nd_mapping->start);
>> + rg_label->rawsize = __cpu_to_le64(nd_mapping->size);
>> + rg_label->hpa = __cpu_to_le64(nd_set->res->start);
>> + rg_label->slot = __cpu_to_le32(slot);
>> + rg_label->ig = __cpu_to_le32(nd_set->interleave_granularity);
>> + rg_label->align = __cpu_to_le16(0);
>> +
>> + /* Update fletcher64 Checksum */
>> + rgl_calculate_checksum(ndd, rg_label);
>> +
>> + /* update label */
>> + offset = nd_label_offset(ndd, nd_label);
>> + rc = nvdimm_set_config_data(ndd, offset, nd_label,
>> + sizeof_namespace_label(ndd));
>> + if (rc < 0) {
>> + nd_label_free_slot(ndd, slot);
>> + return rc;
>> + }
>> +
>> + /* Garbage collect the previous label */
>> + mutex_lock(&nd_mapping->lock);
>> + list_for_each_entry(label_ent, &nd_mapping->labels, list) {
>> + if (!label_ent->label)
>> + continue;
>> + if (rgl_uuid_equal(&label_ent->label->rg_label, &nd_set->uuid))
>> + reap_victim(nd_mapping, label_ent);
>> + }
>> +
>> + /* update index */
>> + rc = nd_label_write_index(ndd, ndd->ns_next,
>> + nd_inc_seq(__le32_to_cpu(nsindex->seq)), 0);
>> +
>> + if (rc == 0) {
>> + list_for_each_entry(label_ent, &nd_mapping->labels, list)
>> + if (!label_ent->label) {
>> + label_ent->label = nd_label;
>> + nd_label = NULL;
>> + break;
>> + }
>> + dev_WARN_ONCE(&nd_region->dev, nd_label,
>> + "failed to track label: %d\n",
>> + to_slot(ndd, nd_label));
>> + if (nd_label)
>> + rc = -ENXIO;
>> + }
>> + mutex_unlock(&nd_mapping->lock);
>> +
>> + return rc;
>> +}
>> +
>> +int nd_pmem_region_label_update(struct nd_region *nd_region)
>
>Same here. nd_pmem_region_label_update() is almost identical to the
>existing nd_pmem_namespace_label_update.
Sure, I will try refactoring these in next patch-set.
>
>Although I'm not familiar with drivers/nvdimm, it seems preferable to
>reuse and adapt the existing functions to reduce redundancy and simplify
>future maintenance, unless there are specific reasons for not doing so
>that I'm unaware of.
>
>Thanks,
>
>Fabio
Thanks Fabio for your feedback.
Regards,
Neeraj
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 18/20] cxl/pmem: Add support of cxl lsa 2.1 support in cxl pmem
2025-07-18 12:51 ` Neeraj Kumar
@ 2025-07-21 17:44 ` Dave Jiang
0 siblings, 0 replies; 66+ messages in thread
From: Dave Jiang @ 2025-07-21 17:44 UTC (permalink / raw)
To: Neeraj Kumar
Cc: dan.j.williams, dave, jonathan.cameron, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
On 7/18/25 5:51 AM, Neeraj Kumar wrote:
> On 10/07/25 10:18AM, Dave Jiang wrote:
>>
>>
>> On 6/17/25 5:39 AM, Neeraj Kumar wrote:
>>> Add support of cxl lsa 2.1 using NDD_CXL_LABEL flag. It also creates cxl
>>> region based on region information parsed from LSA.
>>>
>>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>>> ---
>>> drivers/cxl/pmem.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++
>>> 1 file changed, 59 insertions(+)
>>>
>>> diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c
>>> index ffcebb8d382f..2733d79b32d5 100644
>>> --- a/drivers/cxl/pmem.c
>>> +++ b/drivers/cxl/pmem.c
>>> @@ -58,6 +58,63 @@ static const struct attribute_group *cxl_dimm_attribute_groups[] = {
>>> NULL
>>> };
>>>
>>> +static int match_ep_decoder(struct device *dev, void *data)
>>> +{
>>> + struct cxl_decoder *cxld = to_cxl_decoder(dev);
>>> +
>>> + if (!cxld->region)
>>> + return 1;
>>> + else
>>> + return 0;
>>> +}
>>
>> return !cxld->region;
>>
>
> Thanks, I will fix it in next patch-set
>
>>
>>> +
>>> +static struct cxl_decoder *cxl_find_free_decoder(struct cxl_port *port)
>>> +{
>>> + struct device *dev;
>>> +
>>> + dev = device_find_child(&port->dev, NULL, match_ep_decoder);
>>> + if (!dev)
>>> + return NULL;
>>> +
>>> + return to_cxl_decoder(dev);
>>> +}
>>> +
>>> +static int create_pmem_region(struct nvdimm *nvdimm)
>>> +{
>>> + struct cxl_nvdimm *cxl_nvd;
>>> + struct cxl_memdev *cxlmd;
>>> + struct cxl_nvdimm_bridge *cxl_nvb;
>>> + struct cxl_pmem_region_params *params;
>>> + struct cxl_root_decoder *cxlrd;
>>> + struct cxl_decoder *cxld;
>>> + struct cxl_region *cxlr;
>>> +
>>
>> probably need a lockdep_assert_held(&cxl_region_rwsem).
>>
>
> Thanks Dave, Sure i will fix it with V2
>
>>> + if (!nvdimm)
>>> + return -ENOTTY;
>>
>> -ENODEV?
>
> Sure I will fix it with V2
>
>>
>>> +
>>> + if (!nvdimm_has_cxl_region(nvdimm))
>>> + return 0;
>>> +
>>> + cxl_nvd = nvdimm_provider_data(nvdimm);
>>> + params = nvdimm_get_cxl_region_param(nvdimm);
>>> + cxlmd = cxl_nvd->cxlmd;
>>> + cxl_nvb = cxlmd->cxl_nvb;
>>> + cxlrd = cxlmd->cxlrd;
>>> +
>>> + /* FIXME: Limitation: Region creation only when interleave way == 1 */
>>> + if (params->nlabel == 1) {
>>> + cxld = cxl_find_free_decoder(cxlmd->endpoint);
>>> + cxlr = cxl_create_pmem_region(cxlrd, cxld, params,
>>> + atomic_read(&cxlrd->region_id));
>>> + if (IS_ERR(cxlr))
>>> + dev_dbg(&cxlmd->dev, "Region Creation failed\n");
>>
>> return PTR_ERR(cxlr); ?
>>
>
> Thanks, I will fix it in next patch-set
>
>>> + } else {
>>> + dev_dbg(&cxlmd->dev, "Region Creation is not supported with iw > 1\n");
>>> + }
>>> +
>>> + return 0;
>>> +}
>>> +
>>> static int cxl_nvdimm_probe(struct device *dev)
>>> {
>>> struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev);
>>> @@ -74,6 +131,7 @@ static int cxl_nvdimm_probe(struct device *dev)
>>> return rc;
>>>
>>> set_bit(NDD_LABELING, &flags);
>>> + set_bit(NDD_CXL_LABEL, &flags);
>>
>> Ok here's the NDD_CXL_LABEL set. I think the driver should be probing the label index block and retrieve the label version and determine how to support from there instead of hard coding a flag.
>
> Hi Dave,
>
> We actually write label index information into LSA during namespace/region label updation.
> During that time we update its major/minor.
>
> So during first time updation of LSA we must need some way to inform nvdimm about LSA versioning.
Gotcha. I'm not sure I like adding just a single version (flag bit) to the flags for __nvdimm_create(). Maybe we need some refactoring on the nvdimm side to allow passing in an enum for LSA versioning looking to the future. Thoughts? Also I wonder on the CXL side we need to add some checking of LSA size when retrieved from Identify Memory Device payload in order to make sure the LSA we want is supported properly by the device.
>
>
> Regards,
> Neeraj
>
^ permalink raw reply [flat|nested] 66+ messages in thread
* Re: [RFC PATCH 13/20] cxl/mem: Refactor cxl pmem region auto-assembling
2025-07-18 12:30 ` Neeraj Kumar
@ 2025-07-21 18:11 ` Dave Jiang
0 siblings, 0 replies; 66+ messages in thread
From: Dave Jiang @ 2025-07-21 18:11 UTC (permalink / raw)
To: Neeraj Kumar
Cc: dan.j.williams, dave, jonathan.cameron, alison.schofield,
vishal.l.verma, ira.weiny, a.manzanares, nifan.cxl, anisa.su,
vishak.g, krish.reddy, arun.george, alok.rathore, neeraj.kernel,
linux-kernel, linux-cxl, nvdimm, gost.dev, cpgs
On 7/18/25 5:30 AM, Neeraj Kumar wrote:
> On 09/07/25 05:38PM, Dave Jiang wrote:
>>
>>
>> On 6/17/25 5:39 AM, Neeraj Kumar wrote:
>>> In 84ec985944ef3, For cxl pmem region auto-assembly after endpoint port
>>> probing, cxl_nvd presence was required. And for cxl region persistency,
>>> region creation happens during nvdimm_probe which need the completion
>>> of endpoint probe.
>>>
>>> It is therefore refactored cxl pmem region auto-assembly after endpoint
>>> probing to cxl mem probing
>>
>> The region auto-assembly is moved after the endpoint device is added. However, it's not guaranteed that the endpoint probe has completed and completed successfully. You are just getting lucky timing wise that endpoint probe is completed when the new region discovery is starting.
>
> Hi Dave,
>
> For region auto-assembly two things are required
> 1. endpoint(s) decoder should be enumerated successfully
> 2. As per fix in 84ec985944ef3, The cxl_nvd of the memdev needs to be available during the pmem region probe
>
> Prior to current patch, region auto-assembly was happening from cxl_endpoint_port_probe() after endpoint decoder enumeration.
> In 84ec985944ef3, sequence of devm_cxl_add_nvdimm() was moved before devm_cxl_add_endpoint() so as to meet region auto assembly dependency on cxl_nvd of the memdev.
>
> Here, In this patch I have moved region auto-assembly after
> 1. devm_cxl_add_endpoint(): This function makes sure cxl_endpoint_port_probe() has completed successfully, as per below check in devm_cxl_add_endpoint()
> if (!endpoint->dev.driver) {
> dev_err(&cxlmd->dev, "%s failed probe\n", dev_name(&endpoint->dev));
> return -ENXIO;
> }
> And successfull completion of cxl_endpoint_port_probe(), it must have enumerated endpoint(s) decoder successfully
> 2. devm_cxl_add_nvdimm(): As you rightly said, this allocates "cxl_nvd" nvdimm device and triggers the async probe of nvdimm driver
>
> Actually in this patch, from async probe function (cxl_nvdimm_probe()), I am creating "struct nvdimm" using __nvdimm_create()
> This __nvdimm_create() ultimately scans LSA. If LSA finds region label into it then it saves region information into struct nvdimm
> and then using create_pmem_region(nvdimm), I am re-creating cxl region for region persistency.
>
> As for cxl region persistency (based on LSA 2.1 scanning - this patch)
> following sequence should be required
> 1. devm_cxl_add_endpoint(): endpoint probe completion - which is getting done by devm_cxl_add_endpoint()
> 2. devm_cxl_add_nvdimm(): Here after nvdimm device creation, cxl region is being created
>
> It is therefore re-sequencing of region-auto assembly is required to move from cxl_endpoint_port_probe() to after
> devm_cxl_add_endpoint() and devm_cxl_add_nvdimm()
>
>> Return of devm_cxl_add_nvdimm() only adds the nvdimm device and triggers the async probe of nvdimm driver. You have to take the endpoint port lock
>
> I think we may not require endpoint port lock as auto-assembly and region persistency code sequence is always after successful completion of endpoint probe.
>
>> and check if the driver is attached to be certain that endpoint probe is done and successful. Therefore moving the region discovery location probably does not do what you think it does.
>> Maybe take a deeper look at the region discovery code and see how it does retry if things are not present and approach it from that angle?
>>
>
> Please let me know if my understanding is correct or am I missing something?
No I think your assumptions are fine. I incorrectly assumed that the cxl_port driver is probed async. But in reality, only the cxl_pci driver is probed async. So devm_cxl_add_endpoint() will ensure that the port driver is attached and the rest should work as what you have setup for nvdimm. Sorry about the noise.
DJ
>
>>>
>>> Signed-off-by: Neeraj Kumar <s.neeraj@samsung.com>
>>> ---
>>> drivers/cxl/core/port.c | 38 ++++++++++++++++++++++++++++++++++++++
>>> drivers/cxl/cxl.h | 1 +
>>> drivers/cxl/mem.c | 27 ++++++++++++++++++---------
>>> drivers/cxl/port.c | 38 --------------------------------------
>>> 4 files changed, 57 insertions(+), 47 deletions(-)
>>>
>>> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
>>> index 78a5c2c25982..bca668193c49 100644
>>> --- a/drivers/cxl/core/port.c
>>> +++ b/drivers/cxl/core/port.c
>>> @@ -1038,6 +1038,44 @@ void put_cxl_root(struct cxl_root *cxl_root)
>>> }
>>> EXPORT_SYMBOL_NS_GPL(put_cxl_root, "CXL");
>>>
>>> +static int discover_region(struct device *dev, void *root)
>>> +{
>>> + struct cxl_endpoint_decoder *cxled;
>>> + int rc;
>>> +
>>> + if (!is_endpoint_decoder(dev))
>>> + return 0;
>>> +
>>> + cxled = to_cxl_endpoint_decoder(dev);
>>> + if ((cxled->cxld.flags & CXL_DECODER_F_ENABLE) == 0)
>>> + return 0;
>>> +
>>> + if (cxled->state != CXL_DECODER_STATE_AUTO)
>>> + return 0;
>>> +
>>> + /*
>>> + * Region enumeration is opportunistic, if this add-event fails,
>>> + * continue to the next endpoint decoder.
>>> + */
>>> + rc = cxl_add_to_region(root, cxled);
>>> + if (rc)
>>> + dev_dbg(dev, "failed to add to region: %#llx-%#llx\n",
>>> + cxled->cxld.hpa_range.start, cxled->cxld.hpa_range.end);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +void cxl_region_discovery(struct cxl_port *port)
>>> +{
>>> + struct cxl_port *root;
>>> + struct cxl_root *cxl_root __free(put_cxl_root) = find_cxl_root(port);
>>> +
>>> + root = &cxl_root->port;
>>> +
>>> + device_for_each_child(&port->dev, root, discover_region);
>>> +}
>>> +EXPORT_SYMBOL_NS_GPL(cxl_region_discovery, "CXL");
>>> +
>>
>> I have concerns about adding region related code in core/port.c while the rest of the region code is walled behind CONFIG_CXL_REGION. I think this change needs to go to core/region.c.
>>
>> DJ
>>
>
> Sure Dave, I will move it into core/region.c in next patch-set.
>
> Regards,
> Neeraj
>
^ permalink raw reply [flat|nested] 66+ messages in thread
end of thread, other threads:[~2025-07-21 18:12 UTC | newest]
Thread overview: 66+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20250617123944.78345-1-s.neeraj@samsung.com>
[not found] ` <CGME20250617124008epcas5p2e702f786645d44ceb1cdd980a914ce8e@epcas5p2.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 01/20] nvdimm/label: Introduce NDD_CXL_LABEL flag to set cxl label format Neeraj Kumar
2025-06-20 16:40 ` Jonathan Cameron
2025-06-26 9:48 ` Neeraj Kumar
2025-07-02 18:02 ` Ira Weiny
2025-07-03 9:58 ` Neeraj Kumar
2025-07-09 22:57 ` Dave Jiang
2025-07-18 12:13 ` Neeraj Kumar
[not found] ` <CGME20250617124011epcas5p2264e30ec58977907f80d311083265641@epcas5p2.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 02/20] nvdimm/label: Prep patch to accommodate cxl lsa 2.1 support Neeraj Kumar
2025-06-23 10:53 ` Jonathan Cameron
2025-06-26 9:51 ` Neeraj Kumar
2025-07-02 17:55 ` Ira Weiny
2025-07-03 10:04 ` Neeraj Kumar
[not found] ` <CGME20250617124013epcas5p3c241c626448fcf7851a100fdf2816160@epcas5p3.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 03/20] nvdimm/namespace_label: Add namespace label changes as per CXL LSA v2.1 Neeraj Kumar
[not found] ` <CGME20250617124016epcas5p20b04482f41a58c7f83484aa2b8b0c33c@epcas5p2.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 04/20] nvdimm/label: CXL labels skip the need for 'interleave-set cookie' Neeraj Kumar
[not found] ` <CGME20250617124019epcas5p39815cc0f2b175aee40c194625166695c@epcas5p3.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 05/20] nvdimm/region_label: Add region label updation routine Neeraj Kumar
2025-06-23 9:05 ` Jonathan Cameron
2025-06-26 9:54 ` Neeraj Kumar
2025-07-17 22:53 ` Fabio M. De Francesco
2025-07-18 13:00 ` Neeraj Kumar
[not found] ` <CGME20250617124022epcas5p2441d6c5dfaeceb744b5fc00add7ceae0@epcas5p2.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 06/20] nvdimm/region_label: Add region label deletion routine Neeraj Kumar
2025-06-23 9:09 ` Jonathan Cameron
2025-06-26 9:55 ` Neeraj Kumar
[not found] ` <CGME20250617124025epcas5p1ce6656fed9ef1175812f80574048cd7a@epcas5p1.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 07/20] nvdimm/namespace_label: Update namespace init_labels and its region_uuid Neeraj Kumar
2025-06-23 9:11 ` Jonathan Cameron
2025-06-26 9:58 ` Neeraj Kumar
[not found] ` <CGME20250617124028epcas5p2bb45182c91359a16efc5b1561927abce@epcas5p2.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 08/20] nvdimm/label: Include region label in slot validation Neeraj Kumar
2025-06-23 9:13 ` Jonathan Cameron
2025-06-26 10:00 ` Neeraj Kumar
[not found] ` <CGME20250617124031epcas5p3542c2fc6d946f3cdcbc06dbfc65743e2@epcas5p3.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 09/20] nvdimm/namespace_label: Skip region label during ns label DPA reservation Neeraj Kumar
[not found] ` <CGME20250617124034epcas5p2f53c3cc21c51b7c176ad580d5d954c64@epcas5p2.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 10/20] nvdimm/region_label: Preserve cxl region information from region label Neeraj Kumar
[not found] ` <CGME20250617124037epcas5p2efa5e8ac19df70cdeb7330404eed385f@epcas5p2.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 11/20] nvdimm/region_label: Export routine to fetch region information Neeraj Kumar
[not found] ` <CGME20250617124040epcas5p3be044cbdc5b33b0b8465d84870a5b280@epcas5p3.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 12/20] nvdimm/namespace_label: Skip region label during namespace creation Neeraj Kumar
2025-06-23 9:17 ` Jonathan Cameron
2025-06-26 10:02 ` Neeraj Kumar
[not found] ` <CGME20250617124043epcas5p21e5b77aa3a6acfa7e01847ffd58350ed@epcas5p2.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 13/20] cxl/mem: Refactor cxl pmem region auto-assembling Neeraj Kumar
2025-06-23 9:20 ` Jonathan Cameron
2025-06-26 10:03 ` Neeraj Kumar
2025-07-10 0:38 ` Dave Jiang
2025-07-18 12:30 ` Neeraj Kumar
2025-07-21 18:11 ` Dave Jiang
[not found] ` <CGME20250617124046epcas5p16a45d2afe3b41ca08994a5cca09bfb68@epcas5p1.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 14/20] cxl/region: Add cxl pmem region creation routine for region persistency Neeraj Kumar
2025-06-23 9:43 ` Jonathan Cameron
2025-06-26 10:23 ` Neeraj Kumar
2025-07-10 15:59 ` Dave Jiang
2025-07-18 12:45 ` Neeraj Kumar
[not found] ` <CGME20250617124049epcas5p1de7eeee3b5ddd12ea221ca3ebf22f6e8@epcas5p1.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 15/20] cxl: Add a routine to find cxl root decoder on cxl bus Neeraj Kumar
2025-06-23 9:44 ` Jonathan Cameron
2025-06-26 10:38 ` Neeraj Kumar
2025-06-26 19:19 ` Alison Schofield
2025-06-27 9:03 ` Neeraj Kumar
2025-07-10 16:23 ` Dave Jiang
2025-07-18 12:48 ` Neeraj Kumar
[not found] ` <CGME20250617124052epcas5p24aace8321ed09af8bdd1e8c30c20cd84@epcas5p2.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 16/20] cxl/mem: Preserve cxl root decoder during mem probe Neeraj Kumar
[not found] ` <CGME20250617124055epcas5p4978a3c139128bf5873c60ca0a10f5199@epcas5p4.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 17/20] cxl/pmem: Preserve region information into nd_set Neeraj Kumar
[not found] ` <CGME20250617124058epcas5p2324bd3b1bf95d47f553d90fdc727e50d@epcas5p2.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 18/20] cxl/pmem: Add support of cxl lsa 2.1 support in cxl pmem Neeraj Kumar
2025-06-23 9:48 ` Jonathan Cameron
2025-06-26 10:41 ` Neeraj Kumar
2025-07-10 17:18 ` Dave Jiang
2025-07-18 12:51 ` Neeraj Kumar
2025-07-21 17:44 ` Dave Jiang
[not found] ` <CGME20250617124101epcas5p4d54f34ebc5161b7cb816e352d144d9a1@epcas5p4.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 19/20] cxl/pmem_region: Prep patch to accommodate pmem_region attributes Neeraj Kumar
2025-06-23 9:53 ` Jonathan Cameron
2025-06-26 10:45 ` Neeraj Kumar
[not found] ` <CGME20250617124104epcas5p41105ad63af456b5cdb041e174a99925e@epcas5p4.samsung.com>
2025-06-17 12:39 ` [RFC PATCH 20/20] cxl/pmem_region: Add cxl region label updation and deletion device attributes Neeraj Kumar
2025-06-23 9:56 ` Jonathan Cameron
2025-06-26 10:48 ` Neeraj Kumar
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).