Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

dmaengine: idxd: add knob for enqcmds retries

Add a sysfs knob to allow tuning of retries for the kernel ENQCMDS
descriptor submission. While on host, it is not as likely that ENQCMDS
return busy during normal operations due to the driver controlling the
number of descriptors allocated for submission. However, when the driver is
operating as a guest driver, the chance of retry goes up significantly due
to sharing a wq with multiple VMs. A default value is provided with the
system admin being able to tune the value on a per WQ basis.

Suggested-by: Sanjay Kumar <sanjay.k.kumar@intel.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Link: https://lore.kernel.org/r/163820629464.2702134.7577370098568297574.stgit@djiang5-desk3.ch.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Dave Jiang and committed by
Vinod Koul
7930d855 92452a72

+75 -8
+7
Documentation/ABI/stable/sysfs-driver-dma-idxd
··· 220 220 Description: Show the current number of entries in this WQ if WQ Occupancy 221 221 Support bit WQ capabilities is 1. 222 222 223 + What: /sys/bus/dsa/devices/wq<m>.<n>/enqcmds_retries 224 + Date Oct 29, 2021 225 + KernelVersion: 5.17.0 226 + Contact: dmaengine@vger.kernel.org 227 + Description: Indicate the number of retires for an enqcmds submission on a shared wq. 228 + A max value to set attribute is capped at 64. 229 + 223 230 What: /sys/bus/dsa/devices/engine<m>.<n>/group_id 224 231 Date: Oct 25, 2019 225 232 KernelVersion: 5.6.0
+1
drivers/dma/idxd/device.c
··· 387 387 wq->threshold = 0; 388 388 wq->priority = 0; 389 389 wq->ats_dis = 0; 390 + wq->enqcmds_retries = IDXD_ENQCMDS_RETRIES; 390 391 clear_bit(WQ_FLAG_DEDICATED, &wq->flags); 391 392 clear_bit(WQ_FLAG_BLOCK_ON_FAULT, &wq->flags); 392 393 memset(wq->name, 0, WQ_NAME_SIZE);
+5
drivers/dma/idxd/idxd.h
··· 52 52 #define IDXD_NAME_SIZE 128 53 53 #define IDXD_PMU_EVENT_MAX 64 54 54 55 + #define IDXD_ENQCMDS_RETRIES 32 56 + #define IDXD_ENQCMDS_MAX_RETRIES 64 57 + 55 58 struct idxd_device_driver { 56 59 const char *name; 57 60 enum idxd_dev_type *type; ··· 176 173 struct idxd_wq { 177 174 void __iomem *portal; 178 175 u32 portal_offset; 176 + unsigned int enqcmds_retries; 179 177 struct percpu_ref wq_active; 180 178 struct completion wq_dead; 181 179 struct completion wq_resurrect; ··· 588 584 int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc); 589 585 struct idxd_desc *idxd_alloc_desc(struct idxd_wq *wq, enum idxd_op_type optype); 590 586 void idxd_free_desc(struct idxd_wq *wq, struct idxd_desc *desc); 587 + int idxd_enqcmds(struct idxd_wq *wq, void __iomem *portal, const void *desc); 591 588 592 589 /* dmaengine */ 593 590 int idxd_register_dma_device(struct idxd_device *idxd);
+1
drivers/dma/idxd/init.c
··· 248 248 init_completion(&wq->wq_resurrect); 249 249 wq->max_xfer_bytes = WQ_DEFAULT_MAX_XFER; 250 250 wq->max_batch_size = WQ_DEFAULT_MAX_BATCH; 251 + wq->enqcmds_retries = IDXD_ENQCMDS_RETRIES; 251 252 wq->wqcfg = kzalloc_node(idxd->wqcfg_size, GFP_KERNEL, dev_to_node(dev)); 252 253 if (!wq->wqcfg) { 253 254 put_device(conf_dev);
+1 -1
drivers/dma/idxd/irq.c
··· 98 98 if (wq_dedicated(wq)) { 99 99 iosubmit_cmds512(portal, &desc, 1); 100 100 } else { 101 - rc = enqcmds(portal, &desc); 101 + rc = idxd_enqcmds(wq, portal, &desc); 102 102 /* This should not fail unless hardware failed. */ 103 103 if (rc < 0) 104 104 dev_warn(dev, "Failed to submit drain desc on wq %d\n", wq->id);
+24 -7
drivers/dma/idxd/submit.c
··· 123 123 idxd_dma_complete_txd(found, IDXD_COMPLETE_ABORT, false); 124 124 } 125 125 126 + /* 127 + * ENQCMDS typically fail when the WQ is inactive or busy. On host submission, the driver 128 + * has better control of number of descriptors being submitted to a shared wq by limiting 129 + * the number of driver allocated descriptors to the wq size. However, when the swq is 130 + * exported to a guest kernel, it may be shared with multiple guest kernels. This means 131 + * the likelihood of getting busy returned on the swq when submitting goes significantly up. 132 + * Having a tunable retry mechanism allows the driver to keep trying for a bit before giving 133 + * up. The sysfs knob can be tuned by the system administrator. 134 + */ 135 + int idxd_enqcmds(struct idxd_wq *wq, void __iomem *portal, const void *desc) 136 + { 137 + int rc, retries = 0; 138 + 139 + do { 140 + rc = enqcmds(portal, desc); 141 + if (rc == 0) 142 + break; 143 + cpu_relax(); 144 + } while (retries++ < wq->enqcmds_retries); 145 + 146 + return rc; 147 + } 148 + 126 149 int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc) 127 150 { 128 151 struct idxd_device *idxd = wq->idxd; ··· 189 166 if (wq_dedicated(wq)) { 190 167 iosubmit_cmds512(portal, desc->hw, 1); 191 168 } else { 192 - /* 193 - * It's not likely that we would receive queue full rejection 194 - * since the descriptor allocation gates at wq size. If we 195 - * receive a -EAGAIN, that means something went wrong such as the 196 - * device is not accepting descriptor at all. 197 - */ 198 - rc = enqcmds(portal, desc->hw); 169 + rc = idxd_enqcmds(wq, portal, desc->hw); 199 170 if (rc < 0) { 200 171 percpu_ref_put(&wq->wq_active); 201 172 /* abort operation frees the descriptor */
+36
drivers/dma/idxd/sysfs.c
··· 945 945 static struct device_attribute dev_attr_wq_occupancy = 946 946 __ATTR(occupancy, 0444, wq_occupancy_show, NULL); 947 947 948 + static ssize_t wq_enqcmds_retries_show(struct device *dev, 949 + struct device_attribute *attr, char *buf) 950 + { 951 + struct idxd_wq *wq = confdev_to_wq(dev); 952 + 953 + if (wq_dedicated(wq)) 954 + return -EOPNOTSUPP; 955 + 956 + return sysfs_emit(buf, "%u\n", wq->enqcmds_retries); 957 + } 958 + 959 + static ssize_t wq_enqcmds_retries_store(struct device *dev, struct device_attribute *attr, 960 + const char *buf, size_t count) 961 + { 962 + struct idxd_wq *wq = confdev_to_wq(dev); 963 + int rc; 964 + unsigned int retries; 965 + 966 + if (wq_dedicated(wq)) 967 + return -EOPNOTSUPP; 968 + 969 + rc = kstrtouint(buf, 10, &retries); 970 + if (rc < 0) 971 + return rc; 972 + 973 + if (retries > IDXD_ENQCMDS_MAX_RETRIES) 974 + retries = IDXD_ENQCMDS_MAX_RETRIES; 975 + 976 + wq->enqcmds_retries = retries; 977 + return count; 978 + } 979 + 980 + static struct device_attribute dev_attr_wq_enqcmds_retries = 981 + __ATTR(enqcmds_retries, 0644, wq_enqcmds_retries_show, wq_enqcmds_retries_store); 982 + 948 983 static struct attribute *idxd_wq_attributes[] = { 949 984 &dev_attr_wq_clients.attr, 950 985 &dev_attr_wq_state.attr, ··· 996 961 &dev_attr_wq_max_batch_size.attr, 997 962 &dev_attr_wq_ats_disable.attr, 998 963 &dev_attr_wq_occupancy.attr, 964 + &dev_attr_wq_enqcmds_retries.attr, 999 965 NULL, 1000 966 }; 1001 967