From: Ira Weiny <[email protected]>

Extent information can be helpful to the user to coordinate memory
usage with the external orchestrator and FM.

Expose the details of each dc_extent by creating the following sysfs
entries.

        /sys/bus/cxl/devices/dax_regionX/extentX.Y
        /sys/bus/cxl/devices/dax_regionX/extentX.Y/offset
        /sys/bus/cxl/devices/dax_regionX/extentX.Y/length
        /sys/bus/cxl/devices/dax_regionX/extentX.Y/uuid

Each dc_extent surfaces as its own extentX.Y device under the parent
dax_region.  offset and length describe that dc_extent's HPA range,
not an aggregate bounding box across the containing tagged
allocation — so when a tagged allocation has multiple
DPA-discontiguous extents, each is reported with its own offset and
length.  uuid is the tag identifying the containing allocation; it
is shared across dc_extents that belong to the same tagged
allocation and is hidden for untagged extents.

Based on an original patch by Navneet Singh.

Reviewed-by: Jonathan Cameron <[email protected]>
Reviewed-by: Fan Ni <[email protected]>
Tested-by: Fan Ni <[email protected]>
Signed-off-by: Ira Weiny <[email protected]>
---
 Documentation/ABI/testing/sysfs-bus-cxl | 36 +++++++++++++++
 drivers/cxl/core/extent.c               | 58 +++++++++++++++++++++++++
 2 files changed, 94 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-cxl 
b/Documentation/ABI/testing/sysfs-bus-cxl
index 3080aef9ad67..38cf0a2894b9 100644
--- a/Documentation/ABI/testing/sysfs-bus-cxl
+++ b/Documentation/ABI/testing/sysfs-bus-cxl
@@ -661,3 +661,39 @@ Description:
                The count is persistent across power loss and wraps back to 0
                upon overflow. If this file is not present, the device does not
                have the necessary support for dirty tracking.
+
+
+What:          /sys/bus/cxl/devices/dax_regionX/extentX.Y/offset
+Date:          May, 2025
+KernelVersion: v6.16
+Contact:       [email protected]
+Description:
+               (RO) [For Dynamic Capacity regions only] Users can use the
+               extent information to create DAX devices on specific extents.
+               This is done by creating and destroying DAX devices in specific
+               sequences and looking at the mappings created.  Extent offset
+               within the region.
+
+
+What:          /sys/bus/cxl/devices/dax_regionX/extentX.Y/length
+Date:          May, 2025
+KernelVersion: v6.16
+Contact:       [email protected]
+Description:
+               (RO) [For Dynamic Capacity regions only] Users can use the
+               extent information to create DAX devices on specific extents.
+               This is done by creating and destroying DAX devices in specific
+               sequences and looking at the mappings created.  Extent length
+               within the region.
+
+
+What:          /sys/bus/cxl/devices/dax_regionX/extentX.Y/uuid
+Date:          May, 2025
+KernelVersion: v6.16
+Contact:       [email protected]
+Description:
+               (RO) [For Dynamic Capacity regions only] Users can use the
+               extent information to create DAX devices on specific extents.
+               This is done by creating and destroying DAX devices in specific
+               sequences and looking at the mappings created.  UUID of this
+               extent.
diff --git a/drivers/cxl/core/extent.c b/drivers/cxl/core/extent.c
index f66fa8c600c5..34babfe032d1 100644
--- a/drivers/cxl/core/extent.c
+++ b/drivers/cxl/core/extent.c
@@ -6,6 +6,63 @@
 
 #include "core.h"
 
+static ssize_t offset_show(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct dc_extent *dc_extent = to_dc_extent(dev);
+
+       return sysfs_emit(buf, "%#llx\n", dc_extent->hpa_range.start);
+}
+static DEVICE_ATTR_RO(offset);
+
+static ssize_t length_show(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct dc_extent *dc_extent = to_dc_extent(dev);
+       u64 length = range_len(&dc_extent->hpa_range);
+
+       return sysfs_emit(buf, "%#llx\n", length);
+}
+static DEVICE_ATTR_RO(length);
+
+static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct dc_extent *dc_extent = to_dc_extent(dev);
+
+       return sysfs_emit(buf, "%pUb\n", &dc_extent->group->uuid);
+}
+static DEVICE_ATTR_RO(uuid);
+
+static struct attribute *dc_extent_attrs[] = {
+       &dev_attr_offset.attr,
+       &dev_attr_length.attr,
+       &dev_attr_uuid.attr,
+       NULL
+};
+
+static uuid_t empty_uuid = { 0 };
+
+static umode_t dc_extent_visible(struct kobject *kobj,
+                                struct attribute *a, int n)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct dc_extent *dc_extent = to_dc_extent(dev);
+
+       if (a == &dev_attr_uuid.attr &&
+           uuid_equal(&dc_extent->group->uuid, &empty_uuid))
+               return 0;
+
+       return a->mode;
+}
+
+static const struct attribute_group dc_extent_attribute_group = {
+       .attrs = dc_extent_attrs,
+       .is_visible = dc_extent_visible,
+};
+
+__ATTRIBUTE_GROUPS(dc_extent_attribute);
+
 
 static void cxled_release_extent(struct cxl_endpoint_decoder *cxled,
                                 struct dc_extent *dc_extent)
@@ -93,6 +150,7 @@ static void dc_extent_release(struct device *dev)
 static const struct device_type dc_extent_type = {
        .name = "extent",
        .release = dc_extent_release,
+       .groups = dc_extent_attribute_groups,
 };
 
 bool is_dc_extent(struct device *dev)
-- 
2.43.0


Reply via email to