summaryrefslogtreecommitdiff
path: root/drivers/dma/idxd/device.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dma/idxd/device.c')
-rw-r--r--drivers/dma/idxd/device.c33
1 files changed, 24 insertions, 9 deletions
diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c
index c41ef195eeb9..c2cdf41b6e57 100644
--- a/drivers/dma/idxd/device.c
+++ b/drivers/dma/idxd/device.c
@@ -16,6 +16,7 @@ static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand,
u32 *status);
static void idxd_device_wqs_clear_state(struct idxd_device *idxd);
static void idxd_wq_disable_cleanup(struct idxd_wq *wq);
+static int idxd_wq_config_write(struct idxd_wq *wq);
/* Interrupt control bits */
void idxd_unmask_error_interrupts(struct idxd_device *idxd)
@@ -161,7 +162,7 @@ int idxd_wq_alloc_resources(struct idxd_wq *wq)
free_hw_descs(wq);
return rc;
}
-EXPORT_SYMBOL_NS_GPL(idxd_wq_alloc_resources, IDXD);
+EXPORT_SYMBOL_NS_GPL(idxd_wq_alloc_resources, "IDXD");
void idxd_wq_free_resources(struct idxd_wq *wq)
{
@@ -175,7 +176,7 @@ void idxd_wq_free_resources(struct idxd_wq *wq)
dma_free_coherent(dev, wq->compls_size, wq->compls, wq->compls_addr);
sbitmap_queue_free(&wq->sbq);
}
-EXPORT_SYMBOL_NS_GPL(idxd_wq_free_resources, IDXD);
+EXPORT_SYMBOL_NS_GPL(idxd_wq_free_resources, "IDXD");
int idxd_wq_enable(struct idxd_wq *wq)
{
@@ -215,14 +216,28 @@ int idxd_wq_disable(struct idxd_wq *wq, bool reset_config)
return 0;
}
+ /*
+ * Disable WQ does not drain address translations, if WQ attributes are
+ * changed before translations are drained, pending translations can
+ * be issued using updated WQ attibutes, resulting in invalid
+ * translations being cached in the device translation cache.
+ *
+ * To make sure pending translations are drained before WQ
+ * attributes are changed, we use a WQ Drain followed by WQ Reset and
+ * then restore the WQ configuration.
+ */
+ idxd_wq_drain(wq);
+
operand = BIT(wq->id % 16) | ((wq->id / 16) << 16);
- idxd_cmd_exec(idxd, IDXD_CMD_DISABLE_WQ, operand, &status);
+ idxd_cmd_exec(idxd, IDXD_CMD_RESET_WQ, operand, &status);
if (status != IDXD_CMDSTS_SUCCESS) {
- dev_dbg(dev, "WQ disable failed: %#x\n", status);
+ dev_dbg(dev, "WQ reset failed: %#x\n", status);
return -ENXIO;
}
+ idxd_wq_config_write(wq);
+
if (reset_config)
idxd_wq_disable_cleanup(wq);
clear_bit(wq->id, idxd->wq_enable_map);
@@ -407,7 +422,7 @@ int idxd_wq_init_percpu_ref(struct idxd_wq *wq)
reinit_completion(&wq->wq_resurrect);
return 0;
}
-EXPORT_SYMBOL_NS_GPL(idxd_wq_init_percpu_ref, IDXD);
+EXPORT_SYMBOL_NS_GPL(idxd_wq_init_percpu_ref, "IDXD");
void __idxd_wq_quiesce(struct idxd_wq *wq)
{
@@ -417,7 +432,7 @@ void __idxd_wq_quiesce(struct idxd_wq *wq)
complete_all(&wq->wq_resurrect);
wait_for_completion(&wq->wq_dead);
}
-EXPORT_SYMBOL_NS_GPL(__idxd_wq_quiesce, IDXD);
+EXPORT_SYMBOL_NS_GPL(__idxd_wq_quiesce, "IDXD");
void idxd_wq_quiesce(struct idxd_wq *wq)
{
@@ -425,7 +440,7 @@ void idxd_wq_quiesce(struct idxd_wq *wq)
__idxd_wq_quiesce(wq);
mutex_unlock(&wq->wq_lock);
}
-EXPORT_SYMBOL_NS_GPL(idxd_wq_quiesce, IDXD);
+EXPORT_SYMBOL_NS_GPL(idxd_wq_quiesce, "IDXD");
/* Device control bits */
static inline bool idxd_is_enabled(struct idxd_device *idxd)
@@ -1494,7 +1509,7 @@ err_map_portal:
err:
return rc;
}
-EXPORT_SYMBOL_NS_GPL(idxd_drv_enable_wq, IDXD);
+EXPORT_SYMBOL_NS_GPL(idxd_drv_enable_wq, "IDXD");
void idxd_drv_disable_wq(struct idxd_wq *wq)
{
@@ -1516,7 +1531,7 @@ void idxd_drv_disable_wq(struct idxd_wq *wq)
wq->type = IDXD_WQT_NONE;
wq->client_count = 0;
}
-EXPORT_SYMBOL_NS_GPL(idxd_drv_disable_wq, IDXD);
+EXPORT_SYMBOL_NS_GPL(idxd_drv_disable_wq, "IDXD");
int idxd_device_drv_probe(struct idxd_dev *idxd_dev)
{