]> Git Repo - linux.git/commitdiff
dmaengine: idxd: check device state before issue command
authorDave Jiang <[email protected]>
Mon, 1 Feb 2021 15:26:14 +0000 (08:26 -0700)
committerVinod Koul <[email protected]>
Wed, 3 Feb 2021 11:27:12 +0000 (16:57 +0530)
Add device state check before executing command. Without the check the
command can be issued while device is in halt state and causes the driver to
block while waiting for the completion of the command.

Reported-by: Sanjay Kumar <[email protected]>
Signed-off-by: Dave Jiang <[email protected]>
Tested-by: Sanjay Kumar <[email protected]>
Fixes: 0d5c10b4c84d ("dmaengine: idxd: add work queue drain support")
Link: https://lore.kernel.org/r/161219313921.2976211.12222625226450097465.stgit@djiang5-desk3.ch.intel.com
Signed-off-by: Vinod Koul <[email protected]>
drivers/dma/idxd/device.c
drivers/dma/idxd/idxd.h
drivers/dma/idxd/init.c

index 95f94a3ed6beb44f466fb511f3a78332a5903687..84a6ea60ecf0bddd6107312fc69bff2a19e2c28a 100644 (file)
@@ -398,17 +398,31 @@ static inline bool idxd_is_enabled(struct idxd_device *idxd)
        return false;
 }
 
+static inline bool idxd_device_is_halted(struct idxd_device *idxd)
+{
+       union gensts_reg gensts;
+
+       gensts.bits = ioread32(idxd->reg_base + IDXD_GENSTATS_OFFSET);
+
+       return (gensts.state == IDXD_DEVICE_STATE_HALT);
+}
+
 /*
  * 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)
+int idxd_device_init_reset(struct idxd_device *idxd)
 {
        struct device *dev = &idxd->pdev->dev;
        union idxd_command_reg cmd;
        unsigned long flags;
 
+       if (idxd_device_is_halted(idxd)) {
+               dev_warn(&idxd->pdev->dev, "Device is HALTED!\n");
+               return -ENXIO;
+       }
+
        memset(&cmd, 0, sizeof(cmd));
        cmd.cmd = IDXD_CMD_RESET_DEVICE;
        dev_dbg(dev, "%s: sending reset for init.\n", __func__);
@@ -419,6 +433,7 @@ void idxd_device_init_reset(struct idxd_device *idxd)
               IDXD_CMDSTS_ACTIVE)
                cpu_relax();
        spin_unlock_irqrestore(&idxd->dev_lock, flags);
+       return 0;
 }
 
 static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand,
@@ -428,6 +443,12 @@ static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand,
        DECLARE_COMPLETION_ONSTACK(done);
        unsigned long flags;
 
+       if (idxd_device_is_halted(idxd)) {
+               dev_warn(&idxd->pdev->dev, "Device is HALTED!\n");
+               *status = IDXD_CMDSTS_HW_ERR;
+               return;
+       }
+
        memset(&cmd, 0, sizeof(cmd));
        cmd.cmd = cmd_code;
        cmd.operand = operand;
index 5a50e91c71bf01fcfee884d8244be1fb6681dcc3..81a0e65fd316d7af96b316af82e4d8f029dfdf57 100644 (file)
@@ -326,7 +326,7 @@ void idxd_mask_msix_vector(struct idxd_device *idxd, int vec_id);
 void idxd_unmask_msix_vector(struct idxd_device *idxd, int vec_id);
 
 /* device control */
-void idxd_device_init_reset(struct idxd_device *idxd);
+int idxd_device_init_reset(struct idxd_device *idxd);
 int idxd_device_enable(struct idxd_device *idxd);
 int idxd_device_disable(struct idxd_device *idxd);
 void idxd_device_reset(struct idxd_device *idxd);
index 2c051e07c34c2410458e2590ead84dbdc9f72201..fa04acd5582a0a13b09e37933166eba68b35662b 100644 (file)
@@ -335,7 +335,10 @@ static int idxd_probe(struct idxd_device *idxd)
        int rc;
 
        dev_dbg(dev, "%s entered and resetting device\n", __func__);
-       idxd_device_init_reset(idxd);
+       rc = idxd_device_init_reset(idxd);
+       if (rc < 0)
+               return rc;
+
        dev_dbg(dev, "IDXD reset complete\n");
 
        if (IS_ENABLED(CONFIG_INTEL_IDXD_SVM)) {
This page took 0.067683 seconds and 4 git commands to generate.