dmaengine: idxd: add configuration for concurrent work descriptor processing
authorDave Jiang <dave.jiang@intel.com>
Sat, 17 Sep 2022 16:12:21 +0000 (09:12 -0700)
committerVinod Koul <vkoul@kernel.org>
Thu, 29 Sep 2022 17:16:08 +0000 (22:46 +0530)
Add sysfs knob to allow control of the number of work descriptors that can
be concurrently processed by an engine in the group as a fraction of the
Maximum Work Descriptors in Progress value specified in ENGCAP register.
This control knob is part of toggle for QoS control.

Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Co-developed-by: Fenghua Yu <fenghua.yu@intel.com>
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
Link: https://lore.kernel.org/r/20220917161222.2835172-5-fenghua.yu@intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Documentation/ABI/stable/sysfs-driver-dma-idxd
drivers/dma/idxd/device.c
drivers/dma/idxd/idxd.h
drivers/dma/idxd/registers.h
drivers/dma/idxd/sysfs.c

index 3f9f93b..02a721a 100644 (file)
@@ -266,3 +266,15 @@ Contact:   dmaengine@vger.kernel.org
 Description:   Indicates the number of Read Buffers reserved for the use of
                engines in the group. See DSA spec v1.2 9.2.18 GRPCFG Read Buffers
                Reserved.
+
+What:          /sys/bus/dsa/devices/group<m>.<n>/desc_progress_limit
+Date:          Sept 14, 2022
+KernelVersion: 6.0.0
+Contact:       dmaengine@vger.kernel.org
+Description:   Allows control of the number of work descriptors that can be
+               concurrently processed by an engine in the group as a fraction
+               of the Maximum Work Descriptors in Progress value specified in
+               the ENGCAP register. The acceptable values are 0 (default),
+               1 (1/2 of max value), 2 (1/4 of the max value), and 3 (1/8 of
+               the max value). It's visible only on platforms that support
+               the capability.
index df1c108..05a982e 100644 (file)
@@ -709,6 +709,7 @@ static void idxd_groups_clear_state(struct idxd_device *idxd)
                        group->tc_a = -1;
                        group->tc_b = -1;
                }
+               group->desc_progress_limit = 0;
        }
 }
 
@@ -765,10 +766,10 @@ static void idxd_group_config_write(struct idxd_group *group)
 
        /* setup GRPFLAGS */
        grpcfg_offset = GRPFLGCFG_OFFSET(idxd, group->id);
-       iowrite32(group->grpcfg.flags.bits, idxd->reg_base + grpcfg_offset);
-       dev_dbg(dev, "GRPFLAGS flags[%d: %#x]: %#x\n",
+       iowrite64(group->grpcfg.flags.bits, idxd->reg_base + grpcfg_offset);
+       dev_dbg(dev, "GRPFLAGS flags[%d: %#x]: %#llx\n",
                group->id, grpcfg_offset,
-               ioread32(idxd->reg_base + grpcfg_offset));
+               ioread64(idxd->reg_base + grpcfg_offset));
 }
 
 static int idxd_groups_config_write(struct idxd_device *idxd)
@@ -929,6 +930,8 @@ static void idxd_group_flags_setup(struct idxd_device *idxd)
                        group->grpcfg.flags.rdbufs_allowed = group->rdbufs_allowed;
                else
                        group->grpcfg.flags.rdbufs_allowed = idxd->max_rdbufs;
+
+               group->grpcfg.flags.desc_progress_limit = group->desc_progress_limit;
        }
 }
 
@@ -1111,8 +1114,8 @@ static void idxd_group_load_config(struct idxd_group *group)
        }
 
        grpcfg_offset = GRPFLGCFG_OFFSET(idxd, group->id);
-       group->grpcfg.flags.bits = ioread32(idxd->reg_base + grpcfg_offset);
-       dev_dbg(dev, "GRPFLAGS flags[%d: %#x]: %#x\n",
+       group->grpcfg.flags.bits = ioread64(idxd->reg_base + grpcfg_offset);
+       dev_dbg(dev, "GRPFLAGS flags[%d: %#x]: %#llx\n",
                group->id, grpcfg_offset, group->grpcfg.flags.bits);
 }
 
index ba6e94f..7ee870e 100644 (file)
@@ -96,6 +96,7 @@ struct idxd_group {
        u8 rdbufs_reserved;
        int tc_a;
        int tc_b;
+       int desc_progress_limit;
 };
 
 struct idxd_pmu {
index 7b95be8..2cc2543 100644 (file)
@@ -68,7 +68,8 @@ union group_cap_reg {
                u64 total_rdbufs:8;     /* formerly total_tokens */
                u64 rdbuf_ctrl:1;       /* formerly token_en */
                u64 rdbuf_limit:1;      /* formerly token_limit */
-               u64 rsvd:46;
+               u64 progress_limit:1;   /* descriptor and batch descriptor */
+               u64 rsvd:45;
        };
        u64 bits;
 } __packed;
@@ -288,16 +289,18 @@ union msix_perm {
 
 union group_flags {
        struct {
-               u32 tc_a:3;
-               u32 tc_b:3;
-               u32 rsvd:1;
-               u32 use_rdbuf_limit:1;
-               u32 rdbufs_reserved:8;
-               u32 rsvd2:4;
-               u32 rdbufs_allowed:8;
-               u32 rsvd3:4;
+               u64 tc_a:3;
+               u64 tc_b:3;
+               u64 rsvd:1;
+               u64 use_rdbuf_limit:1;
+               u64 rdbufs_reserved:8;
+               u64 rsvd2:4;
+               u64 rdbufs_allowed:8;
+               u64 rsvd3:4;
+               u64 desc_progress_limit:2;
+               u64 rsvd4:30;
        };
-       u32 bits;
+       u64 bits;
 } __packed;
 
 struct grpcfg {
index 6dbdd74..3624bde 100644 (file)
@@ -443,6 +443,37 @@ static struct device_attribute dev_attr_group_traffic_class_b =
                __ATTR(traffic_class_b, 0644, group_traffic_class_b_show,
                       group_traffic_class_b_store);
 
+static ssize_t group_desc_progress_limit_show(struct device *dev,
+                                             struct device_attribute *attr,
+                                             char *buf)
+{
+       struct idxd_group *group = confdev_to_group(dev);
+
+       return sysfs_emit(buf, "%d\n", group->desc_progress_limit);
+}
+
+static ssize_t group_desc_progress_limit_store(struct device *dev,
+                                              struct device_attribute *attr,
+                                              const char *buf, size_t count)
+{
+       struct idxd_group *group = confdev_to_group(dev);
+       int val, rc;
+
+       rc = kstrtoint(buf, 10, &val);
+       if (rc < 0)
+               return -EINVAL;
+
+       if (val & ~GENMASK(1, 0))
+               return -EINVAL;
+
+       group->desc_progress_limit = val;
+       return count;
+}
+
+static struct device_attribute dev_attr_group_desc_progress_limit =
+               __ATTR(desc_progress_limit, 0644, group_desc_progress_limit_show,
+                      group_desc_progress_limit_store);
+
 static struct attribute *idxd_group_attributes[] = {
        &dev_attr_group_work_queues.attr,
        &dev_attr_group_engines.attr,
@@ -454,11 +485,33 @@ static struct attribute *idxd_group_attributes[] = {
        &dev_attr_group_read_buffers_reserved.attr,
        &dev_attr_group_traffic_class_a.attr,
        &dev_attr_group_traffic_class_b.attr,
+       &dev_attr_group_desc_progress_limit.attr,
        NULL,
 };
 
+static bool idxd_group_attr_progress_limit_invisible(struct attribute *attr,
+                                                    struct idxd_device *idxd)
+{
+       return attr == &dev_attr_group_desc_progress_limit.attr &&
+              !idxd->hw.group_cap.progress_limit;
+}
+
+static umode_t idxd_group_attr_visible(struct kobject *kobj,
+                                      struct attribute *attr, int n)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct idxd_group *group = confdev_to_group(dev);
+       struct idxd_device *idxd = group->idxd;
+
+       if (idxd_group_attr_progress_limit_invisible(attr, idxd))
+               return 0;
+
+       return attr->mode;
+}
+
 static const struct attribute_group idxd_group_attribute_group = {
        .attrs = idxd_group_attributes,
+       .is_visible = idxd_group_attr_visible,
 };
 
 static const struct attribute_group *idxd_group_attribute_groups[] = {