Skip to content

Commit 7930d85

Browse files
davejiangvinodkoul
authored andcommitted
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 <[email protected]> Signed-off-by: Dave Jiang <[email protected]> Link: https://lore.kernel.org/r/163820629464.2702134.7577370098568297574.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul <[email protected]>
1 parent 92452a7 commit 7930d85

File tree

7 files changed

+75
-8
lines changed

7 files changed

+75
-8
lines changed

Documentation/ABI/stable/sysfs-driver-dma-idxd

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,13 @@ Contact: [email protected]
220220
Description: Show the current number of entries in this WQ if WQ Occupancy
221221
Support bit WQ capabilities is 1.
222222

223+
What: /sys/bus/dsa/devices/wq<m>.<n>/enqcmds_retries
224+
Date Oct 29, 2021
225+
KernelVersion: 5.17.0
226+
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+
223230
What: /sys/bus/dsa/devices/engine<m>.<n>/group_id
224231
Date: Oct 25, 2019
225232
KernelVersion: 5.6.0

drivers/dma/idxd/device.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,7 @@ static void idxd_wq_disable_cleanup(struct idxd_wq *wq)
387387
wq->threshold = 0;
388388
wq->priority = 0;
389389
wq->ats_dis = 0;
390+
wq->enqcmds_retries = IDXD_ENQCMDS_RETRIES;
390391
clear_bit(WQ_FLAG_DEDICATED, &wq->flags);
391392
clear_bit(WQ_FLAG_BLOCK_ON_FAULT, &wq->flags);
392393
memset(wq->name, 0, WQ_NAME_SIZE);

drivers/dma/idxd/idxd.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ enum idxd_type {
5252
#define IDXD_NAME_SIZE 128
5353
#define IDXD_PMU_EVENT_MAX 64
5454

55+
#define IDXD_ENQCMDS_RETRIES 32
56+
#define IDXD_ENQCMDS_MAX_RETRIES 64
57+
5558
struct idxd_device_driver {
5659
const char *name;
5760
enum idxd_dev_type *type;
@@ -173,6 +176,7 @@ struct idxd_dma_chan {
173176
struct idxd_wq {
174177
void __iomem *portal;
175178
u32 portal_offset;
179+
unsigned int enqcmds_retries;
176180
struct percpu_ref wq_active;
177181
struct completion wq_dead;
178182
struct completion wq_resurrect;
@@ -584,6 +588,7 @@ int idxd_wq_init_percpu_ref(struct idxd_wq *wq);
584588
int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc);
585589
struct idxd_desc *idxd_alloc_desc(struct idxd_wq *wq, enum idxd_op_type optype);
586590
void idxd_free_desc(struct idxd_wq *wq, struct idxd_desc *desc);
591+
int idxd_enqcmds(struct idxd_wq *wq, void __iomem *portal, const void *desc);
587592

588593
/* dmaengine */
589594
int idxd_register_dma_device(struct idxd_device *idxd);

drivers/dma/idxd/init.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
248248
init_completion(&wq->wq_resurrect);
249249
wq->max_xfer_bytes = WQ_DEFAULT_MAX_XFER;
250250
wq->max_batch_size = WQ_DEFAULT_MAX_BATCH;
251+
wq->enqcmds_retries = IDXD_ENQCMDS_RETRIES;
251252
wq->wqcfg = kzalloc_node(idxd->wqcfg_size, GFP_KERNEL, dev_to_node(dev));
252253
if (!wq->wqcfg) {
253254
put_device(conf_dev);

drivers/dma/idxd/irq.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ static void idxd_int_handle_revoke_drain(struct idxd_irq_entry *ie)
9898
if (wq_dedicated(wq)) {
9999
iosubmit_cmds512(portal, &desc, 1);
100100
} else {
101-
rc = enqcmds(portal, &desc);
101+
rc = idxd_enqcmds(wq, portal, &desc);
102102
/* This should not fail unless hardware failed. */
103103
if (rc < 0)
104104
dev_warn(dev, "Failed to submit drain desc on wq %d\n", wq->id);

drivers/dma/idxd/submit.c

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,29 @@ static void llist_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie,
123123
idxd_dma_complete_txd(found, IDXD_COMPLETE_ABORT, false);
124124
}
125125

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+
126149
int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc)
127150
{
128151
struct idxd_device *idxd = wq->idxd;
@@ -166,13 +189,7 @@ int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc)
166189
if (wq_dedicated(wq)) {
167190
iosubmit_cmds512(portal, desc->hw, 1);
168191
} else {
169-
/*
170-
* It's not likely that we would receive queue full rejection
171-
* since the descriptor allocation gates at wq size. If we
172-
* receive a -EAGAIN, that means something went wrong such as the
173-
* device is not accepting descriptor at all.
174-
*/
175-
rc = enqcmds(portal, desc->hw);
192+
rc = idxd_enqcmds(wq, portal, desc->hw);
176193
if (rc < 0) {
177194
percpu_ref_put(&wq->wq_active);
178195
/* abort operation frees the descriptor */

drivers/dma/idxd/sysfs.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,41 @@ static ssize_t wq_occupancy_show(struct device *dev, struct device_attribute *at
945945
static struct device_attribute dev_attr_wq_occupancy =
946946
__ATTR(occupancy, 0444, wq_occupancy_show, NULL);
947947

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+
948983
static struct attribute *idxd_wq_attributes[] = {
949984
&dev_attr_wq_clients.attr,
950985
&dev_attr_wq_state.attr,
@@ -961,6 +996,7 @@ static struct attribute *idxd_wq_attributes[] = {
961996
&dev_attr_wq_max_batch_size.attr,
962997
&dev_attr_wq_ats_disable.attr,
963998
&dev_attr_wq_occupancy.attr,
999+
&dev_attr_wq_enqcmds_retries.attr,
9641000
NULL,
9651001
};
9661002

0 commit comments

Comments
 (0)