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.c155
1 files changed, 70 insertions, 85 deletions
diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c
index 8f05b29e7891..1d8d64508a28 100644
--- a/drivers/dma/idxd/device.c
+++ b/drivers/dma/idxd/device.c
@@ -11,8 +11,8 @@
#include "idxd.h"
#include "registers.h"
-static int idxd_cmd_wait(struct idxd_device *idxd, u32 *status, int timeout);
-static int idxd_cmd_send(struct idxd_device *idxd, int cmd_code, u32 operand);
+static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand,
+ u32 *status);
/* Interrupt control bits */
int idxd_mask_msix_vector(struct idxd_device *idxd, int vec_id)
@@ -233,21 +233,13 @@ int idxd_wq_enable(struct idxd_wq *wq)
struct idxd_device *idxd = wq->idxd;
struct device *dev = &idxd->pdev->dev;
u32 status;
- int rc;
-
- lockdep_assert_held(&idxd->dev_lock);
if (wq->state == IDXD_WQ_ENABLED) {
dev_dbg(dev, "WQ %d already enabled\n", wq->id);
return -ENXIO;
}
- rc = idxd_cmd_send(idxd, IDXD_CMD_ENABLE_WQ, wq->id);
- if (rc < 0)
- return rc;
- rc = idxd_cmd_wait(idxd, &status, IDXD_REG_TIMEOUT);
- if (rc < 0)
- return rc;
+ idxd_cmd_exec(idxd, IDXD_CMD_ENABLE_WQ, wq->id, &status);
if (status != IDXD_CMDSTS_SUCCESS &&
status != IDXD_CMDSTS_ERR_WQ_ENABLED) {
@@ -265,9 +257,7 @@ int idxd_wq_disable(struct idxd_wq *wq)
struct idxd_device *idxd = wq->idxd;
struct device *dev = &idxd->pdev->dev;
u32 status, operand;
- int rc;
- lockdep_assert_held(&idxd->dev_lock);
dev_dbg(dev, "Disabling WQ %d\n", wq->id);
if (wq->state != IDXD_WQ_ENABLED) {
@@ -276,12 +266,7 @@ int idxd_wq_disable(struct idxd_wq *wq)
}
operand = BIT(wq->id % 16) | ((wq->id / 16) << 16);
- rc = idxd_cmd_send(idxd, IDXD_CMD_DISABLE_WQ, operand);
- if (rc < 0)
- return rc;
- rc = idxd_cmd_wait(idxd, &status, IDXD_REG_TIMEOUT);
- if (rc < 0)
- return rc;
+ idxd_cmd_exec(idxd, IDXD_CMD_DISABLE_WQ, operand, &status);
if (status != IDXD_CMDSTS_SUCCESS) {
dev_dbg(dev, "WQ disable failed: %#x\n", status);
@@ -293,6 +278,22 @@ int idxd_wq_disable(struct idxd_wq *wq)
return 0;
}
+void idxd_wq_drain(struct idxd_wq *wq)
+{
+ struct idxd_device *idxd = wq->idxd;
+ struct device *dev = &idxd->pdev->dev;
+ u32 operand;
+
+ if (wq->state != IDXD_WQ_ENABLED) {
+ dev_dbg(dev, "WQ %d in wrong state: %d\n", wq->id, wq->state);
+ return;
+ }
+
+ dev_dbg(dev, "Draining WQ %d\n", wq->id);
+ operand = BIT(wq->id % 16) | ((wq->id / 16) << 16);
+ idxd_cmd_exec(idxd, IDXD_CMD_DRAIN_WQ, operand, NULL);
+}
+
int idxd_wq_map_portal(struct idxd_wq *wq)
{
struct idxd_device *idxd = wq->idxd;
@@ -330,66 +331,79 @@ static inline bool idxd_is_enabled(struct idxd_device *idxd)
return false;
}
-static int idxd_cmd_wait(struct idxd_device *idxd, u32 *status, int timeout)
+/*
+ * This is function is only used for reset during probe and will
+ * poll for completion. Once the device is setup with interrupts,
+ * all commands will be done via interrupt completion.
+ */
+void idxd_device_init_reset(struct idxd_device *idxd)
{
- u32 sts, to = timeout;
-
- lockdep_assert_held(&idxd->dev_lock);
- sts = ioread32(idxd->reg_base + IDXD_CMDSTS_OFFSET);
- while (sts & IDXD_CMDSTS_ACTIVE && --to) {
- cpu_relax();
- sts = ioread32(idxd->reg_base + IDXD_CMDSTS_OFFSET);
- }
+ struct device *dev = &idxd->pdev->dev;
+ union idxd_command_reg cmd;
+ unsigned long flags;
- if (to == 0 && sts & IDXD_CMDSTS_ACTIVE) {
- dev_warn(&idxd->pdev->dev, "%s timed out!\n", __func__);
- *status = 0;
- return -EBUSY;
- }
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.cmd = IDXD_CMD_RESET_DEVICE;
+ dev_dbg(dev, "%s: sending reset for init.\n", __func__);
+ spin_lock_irqsave(&idxd->dev_lock, flags);
+ iowrite32(cmd.bits, idxd->reg_base + IDXD_CMD_OFFSET);
- *status = sts;
- return 0;
+ while (ioread32(idxd->reg_base + IDXD_CMDSTS_OFFSET) &
+ IDXD_CMDSTS_ACTIVE)
+ cpu_relax();
+ spin_unlock_irqrestore(&idxd->dev_lock, flags);
}
-static int idxd_cmd_send(struct idxd_device *idxd, int cmd_code, u32 operand)
+static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand,
+ u32 *status)
{
union idxd_command_reg cmd;
- int rc;
- u32 status;
-
- lockdep_assert_held(&idxd->dev_lock);
- rc = idxd_cmd_wait(idxd, &status, IDXD_REG_TIMEOUT);
- if (rc < 0)
- return rc;
+ DECLARE_COMPLETION_ONSTACK(done);
+ unsigned long flags;
memset(&cmd, 0, sizeof(cmd));
cmd.cmd = cmd_code;
cmd.operand = operand;
+ cmd.int_req = 1;
+
+ spin_lock_irqsave(&idxd->dev_lock, flags);
+ wait_event_lock_irq(idxd->cmd_waitq,
+ !test_bit(IDXD_FLAG_CMD_RUNNING, &idxd->flags),
+ idxd->dev_lock);
+
dev_dbg(&idxd->pdev->dev, "%s: sending cmd: %#x op: %#x\n",
__func__, cmd_code, operand);
+
+ __set_bit(IDXD_FLAG_CMD_RUNNING, &idxd->flags);
+ idxd->cmd_done = &done;
iowrite32(cmd.bits, idxd->reg_base + IDXD_CMD_OFFSET);
- return 0;
+ /*
+ * After command submitted, release lock and go to sleep until
+ * the command completes via interrupt.
+ */
+ spin_unlock_irqrestore(&idxd->dev_lock, flags);
+ wait_for_completion(&done);
+ spin_lock_irqsave(&idxd->dev_lock, flags);
+ if (status)
+ *status = ioread32(idxd->reg_base + IDXD_CMDSTS_OFFSET);
+ __clear_bit(IDXD_FLAG_CMD_RUNNING, &idxd->flags);
+ /* Wake up other pending commands */
+ wake_up(&idxd->cmd_waitq);
+ spin_unlock_irqrestore(&idxd->dev_lock, flags);
}
int idxd_device_enable(struct idxd_device *idxd)
{
struct device *dev = &idxd->pdev->dev;
- int rc;
u32 status;
- lockdep_assert_held(&idxd->dev_lock);
if (idxd_is_enabled(idxd)) {
dev_dbg(dev, "Device already enabled\n");
return -ENXIO;
}
- rc = idxd_cmd_send(idxd, IDXD_CMD_ENABLE_DEVICE, 0);
- if (rc < 0)
- return rc;
- rc = idxd_cmd_wait(idxd, &status, IDXD_REG_TIMEOUT);
- if (rc < 0)
- return rc;
+ idxd_cmd_exec(idxd, IDXD_CMD_ENABLE_DEVICE, 0, &status);
/* If the command is successful or if the device was enabled */
if (status != IDXD_CMDSTS_SUCCESS &&
@@ -405,58 +419,29 @@ int idxd_device_enable(struct idxd_device *idxd)
int idxd_device_disable(struct idxd_device *idxd)
{
struct device *dev = &idxd->pdev->dev;
- int rc;
u32 status;
- lockdep_assert_held(&idxd->dev_lock);
if (!idxd_is_enabled(idxd)) {
dev_dbg(dev, "Device is not enabled\n");
return 0;
}
- rc = idxd_cmd_send(idxd, IDXD_CMD_DISABLE_DEVICE, 0);
- if (rc < 0)
- return rc;
- rc = idxd_cmd_wait(idxd, &status, IDXD_REG_TIMEOUT);
- if (rc < 0)
- return rc;
+ idxd_cmd_exec(idxd, IDXD_CMD_DISABLE_DEVICE, 0, &status);
/* If the command is successful or if the device was disabled */
if (status != IDXD_CMDSTS_SUCCESS &&
!(status & IDXD_CMDSTS_ERR_DIS_DEV_EN)) {
dev_dbg(dev, "%s: err_code: %#x\n", __func__, status);
- rc = -ENXIO;
- return rc;
+ return -ENXIO;
}
idxd->state = IDXD_DEV_CONF_READY;
return 0;
}
-int __idxd_device_reset(struct idxd_device *idxd)
-{
- u32 status;
- int rc;
-
- rc = idxd_cmd_send(idxd, IDXD_CMD_RESET_DEVICE, 0);
- if (rc < 0)
- return rc;
- rc = idxd_cmd_wait(idxd, &status, IDXD_REG_TIMEOUT);
- if (rc < 0)
- return rc;
-
- return 0;
-}
-
-int idxd_device_reset(struct idxd_device *idxd)
+void idxd_device_reset(struct idxd_device *idxd)
{
- unsigned long flags;
- int rc;
-
- spin_lock_irqsave(&idxd->dev_lock, flags);
- rc = __idxd_device_reset(idxd);
- spin_unlock_irqrestore(&idxd->dev_lock, flags);
- return rc;
+ idxd_cmd_exec(idxd, IDXD_CMD_RESET_DEVICE, 0, NULL);
}
/* Device configuration bits */