From: Navneet Singh <navneet.si...@intel.com>

To properly configure CXL regions on Dynamic Capacity Devices (DCD),
user space will need to know the details of the DC partitions available.

Expose dynamic capacity capabilities through sysfs.

Signed-off-by: Navneet Singh <navneet.si...@intel.com>
Reviewed-by: Jonathan Cameron <jonathan.came...@huawei.com>
Co-developed-by: Ira Weiny <ira.we...@intel.com>
Signed-off-by: Ira Weiny <ira.we...@intel.com>
---
Changes:
[Fan: Use proper str_false_true() call]
[Jonathan: minor cleanups]
[Bagas: Clean up documentation language]
---
 Documentation/ABI/testing/sysfs-bus-cxl |  45 ++++++++++++
 drivers/cxl/core/memdev.c               | 124 ++++++++++++++++++++++++++++++++
 2 files changed, 169 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-cxl 
b/Documentation/ABI/testing/sysfs-bus-cxl
index 
3f5627a1210a16aca7c18d17131a56491048a0c2..ff3ae83477f0876c0ee2d3955d27a11fa9d16d83
 100644
--- a/Documentation/ABI/testing/sysfs-bus-cxl
+++ b/Documentation/ABI/testing/sysfs-bus-cxl
@@ -54,6 +54,51 @@ Description:
                identically named field in the Identify Memory Device Output
                Payload in the CXL-2.0 specification.
 
+What:          /sys/bus/cxl/devices/memX/dcY/size
+Date:          December, 2024
+KernelVersion: v6.13
+Contact:       linux-...@vger.kernel.org
+Description:
+               (RO) Dynamic Capacity (DC) region information.  Devices only
+               export dcY if DCD partition Y is supported.
+               dcY/size is the size of each of those partitions.
+
+What:          /sys/bus/cxl/devices/memX/dcY/read_only
+Date:          December, 2024
+KernelVersion: v6.13
+Contact:       linux-...@vger.kernel.org
+Description:
+               (RO) Dynamic Capacity (DC) region information.  Devices only
+               export dcY if DCD partition Y is supported.
+               dcY/read_only indicates true if the region is exported
+               read_only from the device.
+
+What:          /sys/bus/cxl/devices/memX/dcY/shareable
+Date:          December, 2024
+KernelVersion: v6.13
+Contact:       linux-...@vger.kernel.org
+Description:
+               (RO) Dynamic Capacity (DC) region information.  Devices only
+               export dcY if DCD partition Y is supported.
+               dcY/shareable indicates true if the region is exported
+               shareable from the device.
+
+What:          /sys/bus/cxl/devices/memX/dcY/qos_class
+Date:          December, 2024
+KernelVersion: v6.13
+Contact:       linux-...@vger.kernel.org
+Description:
+               (RO) Dynamic Capacity (DC) region information.  Devices only
+               export dcY if DCD partition Y is supported.  For CXL host
+               platforms that support "QoS Telemmetry" this attribute conveys
+               a comma delimited list of platform specific cookies that
+               identifies a QoS performance class for the persistent partition
+               of the CXL mem device. These class-ids can be compared against
+               a similar "qos_class" published for a root decoder. While it is
+               not required that the endpoints map their local memory-class to
+               a matching platform class, mismatches are not recommended as
+               there are platform specific performance related side-effects
+               that may result. First class-id is displayed.
 
 What:          /sys/bus/cxl/devices/memX/pmem/qos_class
 Date:          May, 2023
diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
index 
84fefb76dafabc22e6e1a12397381b3f18eea7c5..857a9dd88b20291116d20b9c0bbe9e7961f4491f
 100644
--- a/drivers/cxl/core/memdev.c
+++ b/drivers/cxl/core/memdev.c
@@ -2,6 +2,7 @@
 /* Copyright(c) 2020 Intel Corporation. */
 
 #include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/string_choices.h>
 #include <linux/firmware.h>
 #include <linux/device.h>
 #include <linux/slab.h>
@@ -449,6 +450,121 @@ static struct attribute *cxl_memdev_security_attributes[] 
= {
        NULL,
 };
 
+static ssize_t show_size_dcN(struct cxl_memdev *cxlmd, char *buf, int pos)
+{
+       struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
+
+       return sysfs_emit(buf, "%#llx\n", mds->dc_region[pos].decode_len);
+}
+
+static ssize_t show_read_only_dcN(struct cxl_memdev *cxlmd, char *buf, int pos)
+{
+       struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
+
+       return sysfs_emit(buf, "%s\n",
+                         str_true_false(mds->dc_region[pos].read_only));
+}
+
+static ssize_t show_shareable_dcN(struct cxl_memdev *cxlmd, char *buf, int pos)
+{
+       struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
+
+       return sysfs_emit(buf, "%s\n",
+                         str_true_false(mds->dc_region[pos].shareable));
+}
+
+static ssize_t show_qos_class_dcN(struct cxl_memdev *cxlmd, char *buf, int pos)
+{
+       struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
+
+       return sysfs_emit(buf, "%d\n", mds->dc_perf[pos].qos_class);
+}
+
+#define CXL_MEMDEV_DC_ATTR_GROUP(n)                                            
\
+static ssize_t dc##n##_size_show(struct device *dev,                           
\
+                                struct device_attribute *attr,                 
\
+                                char *buf)                                     
\
+{                                                                              
\
+       return show_size_dcN(to_cxl_memdev(dev), buf, (n));                     
\
+}                                                                              
\
+struct device_attribute dc##n##_size = {                                       
\
+       .attr   = { .name = "size", .mode = 0444 },                             
\
+       .show   = dc##n##_size_show,                                            
\
+};                                                                             
\
+static ssize_t dc##n##_read_only_show(struct device *dev,                      
\
+                                     struct device_attribute *attr,            
\
+                                     char *buf)                                
\
+{                                                                              
\
+       return show_read_only_dcN(to_cxl_memdev(dev), buf, (n));                
\
+}                                                                              
\
+struct device_attribute dc##n##_read_only = {                                  
\
+       .attr   = { .name = "read_only", .mode = 0444 },                        
\
+       .show   = dc##n##_read_only_show,                                       
\
+};                                                                             
\
+static ssize_t dc##n##_shareable_show(struct device *dev,                      
\
+                                    struct device_attribute *attr,             
\
+                                    char *buf)                                 
\
+{                                                                              
\
+       return show_shareable_dcN(to_cxl_memdev(dev), buf, (n));                
\
+}                                                                              
\
+struct device_attribute dc##n##_shareable = {                                  
\
+       .attr   = { .name = "shareable", .mode = 0444 },                        
\
+       .show   = dc##n##_shareable_show,                                       
\
+};                                                                             
\
+static ssize_t dc##n##_qos_class_show(struct device *dev,                      
\
+                                     struct device_attribute *attr,            
\
+                                     char *buf)                                
\
+{                                                                              
\
+       return show_qos_class_dcN(to_cxl_memdev(dev), buf, (n));                
\
+}                                                                              
\
+struct device_attribute dc##n##_qos_class = {                                  
\
+       .attr   = { .name = "qos_class", .mode = 0444 },                        
\
+       .show   = dc##n##_qos_class_show,                                       
\
+};                                                                             
\
+static struct attribute *cxl_memdev_dc##n##_attributes[] = {                   
\
+       &dc##n##_size.attr,                                                     
\
+       &dc##n##_read_only.attr,                                                
\
+       &dc##n##_shareable.attr,                                                
\
+       &dc##n##_qos_class.attr,                                                
\
+       NULL                                                                    
\
+};                                                                             
\
+static umode_t cxl_memdev_dc##n##_attr_visible(struct kobject *kobj,           
\
+                                              struct attribute *a,             
\
+                                              int pos)                         
\
+{                                                                              
\
+       struct device *dev = kobj_to_dev(kobj);                                 
\
+       struct cxl_memdev *cxlmd = to_cxl_memdev(dev);                          
\
+       struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);       
\
+                                                                               
\
+       /* Not a memory device */                                               
\
+       if (!mds)                                                               
\
+               return 0;                                                       
\
+       return a->mode;                                                         
\
+}                                                                              
\
+static umode_t cxl_memdev_dc##n##_group_visible(struct kobject *kobj)          
\
+{                                                                              
\
+       struct device *dev = kobj_to_dev(kobj);                                 
\
+       struct cxl_memdev *cxlmd = to_cxl_memdev(dev);                          
\
+       struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);       
\
+                                                                               
\
+       /* Not a memory device or partition not supported */                    
\
+       return mds && n < mds->nr_dc_region;                                    
\
+}                                                                              
\
+DEFINE_SYSFS_GROUP_VISIBLE(cxl_memdev_dc##n);                                  
\
+static struct attribute_group cxl_memdev_dc##n##_group = {                     
\
+       .name = "dc"#n,                                                         
\
+       .attrs = cxl_memdev_dc##n##_attributes,                                 
\
+       .is_visible = SYSFS_GROUP_VISIBLE(cxl_memdev_dc##n),                    
\
+}
+CXL_MEMDEV_DC_ATTR_GROUP(0);
+CXL_MEMDEV_DC_ATTR_GROUP(1);
+CXL_MEMDEV_DC_ATTR_GROUP(2);
+CXL_MEMDEV_DC_ATTR_GROUP(3);
+CXL_MEMDEV_DC_ATTR_GROUP(4);
+CXL_MEMDEV_DC_ATTR_GROUP(5);
+CXL_MEMDEV_DC_ATTR_GROUP(6);
+CXL_MEMDEV_DC_ATTR_GROUP(7);
+
 static umode_t cxl_memdev_visible(struct kobject *kobj, struct attribute *a,
                                  int n)
 {
@@ -525,6 +641,14 @@ static struct attribute_group 
cxl_memdev_security_attribute_group = {
 };
 
 static const struct attribute_group *cxl_memdev_attribute_groups[] = {
+       &cxl_memdev_dc0_group,
+       &cxl_memdev_dc1_group,
+       &cxl_memdev_dc2_group,
+       &cxl_memdev_dc3_group,
+       &cxl_memdev_dc4_group,
+       &cxl_memdev_dc5_group,
+       &cxl_memdev_dc6_group,
+       &cxl_memdev_dc7_group,
        &cxl_memdev_attribute_group,
        &cxl_memdev_ram_attribute_group,
        &cxl_memdev_pmem_attribute_group,

-- 
2.47.0


Reply via email to