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

dmaengine: idxd: check device state before issue command

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 <sanjay.k.kumar@intel.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Tested-by: Sanjay Kumar <sanjay.k.kumar@intel.com>
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 <vkoul@kernel.org>

authored by

Dave Jiang and committed by
Vinod Koul
89e3becd fed1b6a0

+27 -3
+22 -1
drivers/dma/idxd/device.c
··· 398 398 return false; 399 399 } 400 400 401 + static inline bool idxd_device_is_halted(struct idxd_device *idxd) 402 + { 403 + union gensts_reg gensts; 404 + 405 + gensts.bits = ioread32(idxd->reg_base + IDXD_GENSTATS_OFFSET); 406 + 407 + return (gensts.state == IDXD_DEVICE_STATE_HALT); 408 + } 409 + 401 410 /* 402 411 * This is function is only used for reset during probe and will 403 412 * poll for completion. Once the device is setup with interrupts, 404 413 * all commands will be done via interrupt completion. 405 414 */ 406 - void idxd_device_init_reset(struct idxd_device *idxd) 415 + int idxd_device_init_reset(struct idxd_device *idxd) 407 416 { 408 417 struct device *dev = &idxd->pdev->dev; 409 418 union idxd_command_reg cmd; 410 419 unsigned long flags; 420 + 421 + if (idxd_device_is_halted(idxd)) { 422 + dev_warn(&idxd->pdev->dev, "Device is HALTED!\n"); 423 + return -ENXIO; 424 + } 411 425 412 426 memset(&cmd, 0, sizeof(cmd)); 413 427 cmd.cmd = IDXD_CMD_RESET_DEVICE; ··· 433 419 IDXD_CMDSTS_ACTIVE) 434 420 cpu_relax(); 435 421 spin_unlock_irqrestore(&idxd->dev_lock, flags); 422 + return 0; 436 423 } 437 424 438 425 static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand, ··· 442 427 union idxd_command_reg cmd; 443 428 DECLARE_COMPLETION_ONSTACK(done); 444 429 unsigned long flags; 430 + 431 + if (idxd_device_is_halted(idxd)) { 432 + dev_warn(&idxd->pdev->dev, "Device is HALTED!\n"); 433 + *status = IDXD_CMDSTS_HW_ERR; 434 + return; 435 + } 445 436 446 437 memset(&cmd, 0, sizeof(cmd)); 447 438 cmd.cmd = cmd_code;
+1 -1
drivers/dma/idxd/idxd.h
··· 326 326 void idxd_unmask_msix_vector(struct idxd_device *idxd, int vec_id); 327 327 328 328 /* device control */ 329 - void idxd_device_init_reset(struct idxd_device *idxd); 329 + int idxd_device_init_reset(struct idxd_device *idxd); 330 330 int idxd_device_enable(struct idxd_device *idxd); 331 331 int idxd_device_disable(struct idxd_device *idxd); 332 332 void idxd_device_reset(struct idxd_device *idxd);
+4 -1
drivers/dma/idxd/init.c
··· 335 335 int rc; 336 336 337 337 dev_dbg(dev, "%s entered and resetting device\n", __func__); 338 - idxd_device_init_reset(idxd); 338 + rc = idxd_device_init_reset(idxd); 339 + if (rc < 0) 340 + return rc; 341 + 339 342 dev_dbg(dev, "IDXD reset complete\n"); 340 343 341 344 if (IS_ENABLED(CONFIG_INTEL_IDXD_SVM)) {