Currently, dma_alloc_coherent is being called with a GFP_KERNEL flag which allows it to sleep with a spinlock held. The call tree is: wd719x_host_reset() holds wd->sh->host_lock -> wd719x_chip_init() -> dma_alloc_coherent() uses GFP_KERNEL This patch introduces a can_sleep parameter into the wd719x_chip_init() function. When we have spinlock and can't sleep, we pass in 0; in other cases, we pass in 1. Signed-off-by: Wen Yang <wen.yang99@xxxxxxxxxx> CC: "James E.J. Bottomley" <jejb@xxxxxxxxxxxxx> CC: "Martin K. Petersen" <martin.petersen@xxxxxxxxxx> CC: linux-scsi@xxxxxxxxxxxxxxx CC: linux-kernel@xxxxxxxxxxxxxxx --- drivers/scsi/wd719x.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/wd719x.c b/drivers/scsi/wd719x.c index 808ba8e952db..e1dac0115947 100644 --- a/drivers/scsi/wd719x.c +++ b/drivers/scsi/wd719x.c @@ -289,7 +289,7 @@ static int wd719x_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd) return 0; } -static int wd719x_chip_init(struct wd719x *wd) +static int wd719x_chip_init(struct wd719x *wd, int can_sleep) { int i, ret; u32 risc_init[3]; @@ -318,7 +318,8 @@ static int wd719x_chip_init(struct wd719x *wd) if (!wd->fw_virt) wd->fw_virt = dma_alloc_coherent(&wd->pdev->dev, wd->fw_size, - &wd->fw_phys, GFP_KERNEL); + &wd->fw_phys, can_sleep ? + GFP_KERNEL : GFP_ATOMIC); if (!wd->fw_virt) { ret = -ENOMEM; goto wd719x_init_end; @@ -510,7 +511,7 @@ static int wd719x_host_reset(struct scsi_cmnd *cmd) dev_info(&wd->pdev->dev, "host reset requested\n"); spin_lock_irqsave(wd->sh->host_lock, flags); /* Try to reinit the RISC */ - if (wd719x_chip_init(wd) == 0) + if (wd719x_chip_init(wd, 0) == 0) result = SUCCESS; else result = FAILED; @@ -834,7 +835,7 @@ static int wd719x_board_found(struct Scsi_Host *sh) /* read parameters from EEPROM */ wd719x_read_eeprom(wd); - ret = wd719x_chip_init(wd); + ret = wd719x_chip_init(wd, 1); if (ret) goto fail_free_irq; -- 2.19.1