From: Xingui Yang yangxingui@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
--------------------- This reverts commit 5c725a983c0dedd067e5e643633db6fb5ecbeb91.
this optimization patch depends on the kernel block MQ patch. If the block MQ patch is not integrated, there is a possibility that the spinlock deadlock occurs.
Signed-off-by: Xingui Yang yangxingui@huawei.com Reviewed-by: Kangfenglong kangfenglong@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/scsi/hisi_sas/hisi_sas_main.c | 50 ++++++++++++++------------ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 12 ++++--- 2 files changed, 35 insertions(+), 27 deletions(-)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index bde4307596234..39fe67239f929 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -172,11 +172,13 @@ static void hisi_sas_slot_index_clear(struct hisi_hba *hisi_hba, int slot_idx)
static void hisi_sas_slot_index_free(struct hisi_hba *hisi_hba, int slot_idx) { + unsigned long flags; + if (hisi_hba->hw->slot_index_alloc || (slot_idx >= hisi_hba->hw->max_command_entries - HISI_SAS_RESERVED_IPTT_CNT)) { - spin_lock(&hisi_hba->lock); + spin_lock_irqsave(&hisi_hba->lock, flags); hisi_sas_slot_index_clear(hisi_hba, slot_idx); - spin_unlock(&hisi_hba->lock); + spin_unlock_irqrestore(&hisi_hba->lock, flags); } }
@@ -192,12 +194,13 @@ static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba, { int index; void *bitmap = hisi_hba->slot_index_tags; + unsigned long flags;
if (scsi_cmnd) { return scsi_cmnd->request->tag; }
- spin_lock(&hisi_hba->lock); + spin_lock_irqsave(&hisi_hba->lock, flags); index = find_next_zero_bit(bitmap, hisi_hba->slot_index_count, hisi_hba->last_slot_index + 1); if (index >= hisi_hba->slot_index_count) { @@ -206,13 +209,13 @@ static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba, hisi_hba->hw->max_command_entries - HISI_SAS_RESERVED_IPTT_CNT); if (index >= hisi_hba->slot_index_count) { - spin_unlock(&hisi_hba->lock); + spin_unlock_irqrestore(&hisi_hba->lock, flags); return -SAS_QUEUE_FULL; } } hisi_sas_slot_index_set(hisi_hba, index); hisi_hba->last_slot_index = index; - spin_unlock(&hisi_hba->lock); + spin_unlock_irqrestore(&hisi_hba->lock, flags);
return index; } @@ -228,6 +231,7 @@ static void hisi_sas_slot_index_init(struct hisi_hba *hisi_hba) void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, struct hisi_sas_slot *slot) { + unsigned long flags; int device_id = slot->device_id; struct hisi_sas_device *sas_dev = &hisi_hba->devices[device_id];
@@ -256,9 +260,9 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, } }
- spin_lock(&sas_dev->lock); + spin_lock_irqsave(&sas_dev->lock, flags); list_del_init(&slot->entry); - spin_unlock(&sas_dev->lock); + spin_unlock_irqrestore(&sas_dev->lock, flags);
memset(slot, 0, offsetof(struct hisi_sas_slot, buf));
@@ -510,14 +514,14 @@ static int hisi_sas_task_prep(struct sas_task *task, slot_idx = rc; slot = &hisi_hba->slot_info[slot_idx];
- spin_lock(&dq->lock); + spin_lock_irqsave(&dq->lock, flags); wr_q_index = dq->wr_point; dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS; list_add_tail(&slot->delivery, &dq->list); - spin_unlock(&dq->lock); - spin_lock(&sas_dev->lock); + spin_unlock_irqrestore(&dq->lock, flags); + spin_lock_irqsave(&sas_dev->lock, flags); list_add_tail(&slot->entry, &sas_dev->list); - spin_unlock(&sas_dev->lock); + spin_unlock_irqrestore(&sas_dev->lock, flags);
dlvry_queue = dq->id; dlvry_queue_slot = wr_q_index; @@ -583,6 +587,7 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, { u32 rc; u32 pass = 0; + unsigned long flags; struct hisi_hba *hisi_hba; struct device *dev; struct domain_device *device = task->dev; @@ -616,9 +621,9 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, dev_err(dev, "task exec: failed[%d]!\n", rc);
if (likely(pass)) { - spin_lock(&dq->lock); + spin_lock_irqsave(&dq->lock, flags); hisi_hba->hw->start_delivery(dq); - spin_unlock(&dq->lock); + spin_unlock_irqrestore(&dq->lock, flags); }
return rc; @@ -669,11 +674,12 @@ static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device) { struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct hisi_sas_device *sas_dev = NULL; + unsigned long flags; int first = (hisi_hba->last_dev_id + 1) % HISI_SAS_MAX_DEVICES; int dev_id; int i;
- spin_lock(&hisi_hba->lock); + spin_lock_irqsave(&hisi_hba->lock, flags); for (i = first; i < first + HISI_SAS_MAX_DEVICES; i++) { dev_id = i % HISI_SAS_MAX_DEVICES; if (hisi_hba->devices[dev_id].dev_type == SAS_PHY_UNUSED) { @@ -694,7 +700,7 @@ static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device) } if (sas_dev) hisi_hba->last_dev_id = i; - spin_unlock(&hisi_hba->lock); + spin_unlock_irqrestore(&hisi_hba->lock, flags);
return sas_dev; } @@ -1964,7 +1970,7 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, struct asd_sas_port *sas_port = device->port; struct hisi_sas_cmd_hdr *cmd_hdr_base; int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx; - unsigned long flags; + unsigned long flags, flags_dq = 0; int wr_q_index;
if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) @@ -1983,14 +1989,14 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, slot_idx = rc; slot = &hisi_hba->slot_info[slot_idx];
- spin_lock(&dq->lock); + spin_lock_irqsave(&dq->lock, flags_dq); wr_q_index = dq->wr_point; dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS; list_add_tail(&slot->delivery, &dq->list); - spin_unlock(&dq->lock); - spin_lock(&sas_dev->lock); + spin_unlock_irqrestore(&dq->lock, flags_dq); + spin_lock_irqsave(&sas_dev->lock, flags); list_add_tail(&slot->entry, &sas_dev->list); - spin_unlock(&sas_dev->lock); + spin_unlock_irqrestore(&sas_dev->lock, flags);
dlvry_queue = dq->id; dlvry_queue_slot = wr_q_index; @@ -2019,9 +2025,9 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, spin_unlock_irqrestore(&task->task_state_lock, flags); WRITE_ONCE(slot->ready, 1); /* send abort command to the chip */ - spin_lock(&dq->lock); + spin_lock_irqsave(&dq->lock, flags); hisi_hba->hw->start_delivery(dq); - spin_unlock(&dq->lock); + spin_unlock_irqrestore(&dq->lock, flags);
return 0;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 730191e7f55b8..fa4233454dccb 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -778,6 +778,7 @@ slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_device *sas_dev = device->lldd_dev; int sata_idx = sas_dev->sata_idx; int start, end; + unsigned long flags;
if (!sata_dev) { /* @@ -801,12 +802,12 @@ slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, end = 64 * (sata_idx + 2); }
- spin_lock(&hisi_hba->lock); + spin_lock_irqsave(&hisi_hba->lock, flags); while (1) { start = find_next_zero_bit(bitmap, hisi_hba->slot_index_count, start); if (start >= end) { - spin_unlock(&hisi_hba->lock); + spin_unlock_irqrestore(&hisi_hba->lock, flags); return -SAS_QUEUE_FULL; } /* @@ -818,7 +819,7 @@ slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, }
set_bit(start, bitmap); - spin_unlock(&hisi_hba->lock); + spin_unlock_irqrestore(&hisi_hba->lock, flags); return start; }
@@ -847,8 +848,9 @@ hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device) struct hisi_sas_device *sas_dev = NULL; int i, sata_dev = dev_is_sata(device); int sata_idx = -1; + unsigned long flags;
- spin_lock(&hisi_hba->lock); + spin_lock_irqsave(&hisi_hba->lock, flags);
if (sata_dev) if (!sata_index_alloc_v2_hw(hisi_hba, &sata_idx)) @@ -879,7 +881,7 @@ hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device) }
out: - spin_unlock(&hisi_hba->lock); + spin_unlock_irqrestore(&hisi_hba->lock, flags);
return sas_dev; }
From: Xingui Yang yangxingui@huawei.com
driver inclusion category: bugfix bugzilla: NA CVE: NA
----------------------------------------- This reverts commit c1c0d1e96fce58f24c3178246bea164260abd445.
this optimization patch depends on the patch of the kernel MQ block. If the block MQ patch is not integrated at the upper layer, there is a possibility that the spinlock deadlock occurs.
Signed-off-by: Xingui Yang yangxingui@huawei.com Reviewed-by: Kangfenglong kangfenglong@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/scsi/hisi_sas/hisi_sas.h | 4 ++-- drivers/scsi/hisi_sas/hisi_sas_main.c | 22 +++++++++--------- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 28 ++++++++++++++-------- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 32 ++++++++++++++------------ 4 files changed, 48 insertions(+), 38 deletions(-)
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 8e9424e62a150..2a70af0191af0 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -189,9 +189,9 @@ struct hisi_sas_port {
struct hisi_sas_cq { struct hisi_hba *hisi_hba; + struct tasklet_struct tasklet; int rd_point; int id; - int irq_no; };
struct hisi_sas_dq { @@ -608,7 +608,7 @@ extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, extern void hisi_sas_init_mem(struct hisi_hba *hisi_hba); extern void hisi_sas_rst_work_handler(struct work_struct *work); extern void hisi_sas_sync_rst_work_handler(struct work_struct *work); -extern void hisi_sas_sync_irqs(struct hisi_hba *hisi_hba); +extern void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba); extern bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy, enum hisi_sas_phy_event event); extern void hisi_sas_release_tasks(struct hisi_hba *hisi_hba); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 39fe67239f929..32f55248c356d 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1248,10 +1248,10 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, struct hisi_sas_cq *cq = &hisi_hba->cq[slot->dlvry_queue]; /* - * sync irq to avoid free'ing task + * flush tasklet to avoid free'ing task * before using task in IO completion */ - synchronize_irq(cq->irq_no); + tasklet_kill(&cq->tasklet); slot->task = NULL; }
@@ -1655,11 +1655,11 @@ static int hisi_sas_abort_task(struct sas_task *task)
if (slot) { /* - * sync irq to avoid free'ing task + * flush tasklet to avoid free'ing task * before using task in IO completion */ cq = &hisi_hba->cq[slot->dlvry_queue]; - synchronize_irq(cq->irq_no); + tasklet_kill(&cq->tasklet); } spin_unlock_irqrestore(&task->task_state_lock, flags); rc = TMF_RESP_FUNC_COMPLETE; @@ -1722,10 +1722,10 @@ static int hisi_sas_abort_task(struct sas_task *task) if (((rc < 0) || (rc == TMF_RESP_FUNC_FAILED)) && task->lldd_task) { /* - * sync irq to avoid free'ing task + * flush tasklet to avoid free'ing task * before using task in IO completion */ - synchronize_irq(cq->irq_no); + tasklet_kill(&cq->tasklet); slot->task = NULL; } } @@ -2097,10 +2097,10 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, struct hisi_sas_cq *cq = &hisi_hba->cq[slot->dlvry_queue]; /* - * sync irq to avoid free'ing task + * flush tasklet to avoid free'ing task * before using task in IO completion */ - synchronize_irq(cq->irq_no); + tasklet_kill(&cq->tasklet); slot->task = NULL; } dev_err(dev, "internal task abort: timeout and not done.\n"); @@ -2258,17 +2258,17 @@ void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy) } EXPORT_SYMBOL_GPL(hisi_sas_phy_down);
-void hisi_sas_sync_irqs(struct hisi_hba *hisi_hba) +void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba) { int i;
for (i = 0; i < hisi_hba->nvecs; i++) { struct hisi_sas_cq *cq = &hisi_hba->cq[i];
- synchronize_irq(cq->irq_no); + tasklet_kill(&cq->tasklet); } } -EXPORT_SYMBOL_GPL(hisi_sas_sync_irqs); +EXPORT_SYMBOL_GPL(hisi_sas_kill_tasklets);
int hisi_sas_host_reset(struct Scsi_Host *shost, int reset_type) { diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index fa4233454dccb..61ff065e5d9b8 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -3148,9 +3148,9 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p) return IRQ_HANDLED; }
-static irqreturn_t cq_thread_v2_hw(int irq_no, void *p) +static void cq_tasklet_v2_hw(unsigned long val) { - struct hisi_sas_cq *cq = p; + struct hisi_sas_cq *cq = (struct hisi_sas_cq *)val; struct hisi_hba *hisi_hba = cq->hisi_hba; struct hisi_sas_slot *slot; struct hisi_sas_itct *itct; @@ -3212,8 +3212,6 @@ static irqreturn_t cq_thread_v2_hw(int irq_no, void *p) /* update rd_point */ cq->rd_point = rd_point; hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point); - - return IRQ_HANDLED; }
static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p) @@ -3224,7 +3222,9 @@ static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p)
hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
- return IRQ_WAKE_THREAD; + tasklet_schedule(&cq->tasklet); + + return IRQ_HANDLED; }
static irqreturn_t sata_int_v2_hw(int irq_no, void *p) @@ -3394,11 +3394,11 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
for (queue_no = 0; queue_no < hisi_hba->queue_count; queue_no++) { struct hisi_sas_cq *cq = &hisi_hba->cq[queue_no]; - cq->irq_no = irq_map[queue_no + 96]; - rc = devm_request_threaded_irq(dev, cq->irq_no, - cq_interrupt_v2_hw, - cq_thread_v2_hw, IRQF_ONESHOT, - DRV_NAME " cq", cq); + struct tasklet_struct *t = &cq->tasklet; + + irq = irq_map[queue_no + 96]; + rc = devm_request_irq(dev, irq, cq_interrupt_v2_hw, 0, + DRV_NAME " cq", cq); if (rc) { dev_err(dev, "irq init: could not request cq interrupt %d, rc=%d\n", @@ -3406,6 +3406,7 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba) rc = -ENOENT; goto free_cq_int_irqs; } + tasklet_init(t, cq_tasklet_v2_hw, (unsigned long)cq); }
hisi_hba->nvecs = hisi_hba->queue_count; @@ -3417,6 +3418,7 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba) struct hisi_sas_cq *cq = &hisi_hba->cq[k];
free_irq(irq_map[k + 96], cq); + tasklet_kill(&cq->tasklet); } free_fatal_int_irqs: for (k = 0; k < fatal_no; k++) @@ -3485,6 +3487,7 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
interrupt_disable_v2_hw(hisi_hba); hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0); + hisi_sas_kill_tasklets(hisi_hba);
hisi_sas_stop_phys(hisi_hba);
@@ -3657,6 +3660,11 @@ static int hisi_sas_v2_probe(struct platform_device *pdev)
static int hisi_sas_v2_remove(struct platform_device *pdev) { + struct sas_ha_struct *sha = platform_get_drvdata(pdev); + struct hisi_hba *hisi_hba = sha->lldd_ha; + + hisi_sas_kill_tasklets(hisi_hba); + return hisi_sas_remove(pdev); }
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 9d6e21be35841..babf6486af526 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -2530,9 +2530,9 @@ slot_complete_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) return sts; }
-static irqreturn_t cq_thread_v3_hw(int irq_no, void *p) +static void cq_tasklet_v3_hw(unsigned long val) { - struct hisi_sas_cq *cq = p; + struct hisi_sas_cq *cq = (struct hisi_sas_cq *)val; struct hisi_hba *hisi_hba = cq->hisi_hba; struct hisi_sas_slot *slot; struct hisi_sas_complete_v3_hdr *complete_queue; @@ -2569,8 +2569,6 @@ static irqreturn_t cq_thread_v3_hw(int irq_no, void *p) hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (NEXT_DQCQ_REG_OFF * queue), rd_point); - - return IRQ_HANDLED; }
static irqreturn_t cq_interrupt_v3_hw(int irq_no, void *p) @@ -2581,7 +2579,9 @@ static irqreturn_t cq_interrupt_v3_hw(int irq_no, void *p)
hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
- return IRQ_WAKE_THREAD; + tasklet_schedule(&cq->tasklet); + + return IRQ_HANDLED; }
static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) @@ -2650,19 +2650,17 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) goto free_chnl_interrupt; }
+ /* Init tasklets for cq only */ for (i = 0; i < hisi_hba->nvecs; i++) { struct hisi_sas_cq *cq = &hisi_hba->cq[i]; + struct tasklet_struct *t = &cq->tasklet; int nr = hisi_sas_intr_conv ? PCI_IRQ_CQ_BASE : PCI_IRQ_CQ_BASE + i; - unsigned long irqflags = hisi_sas_intr_conv ? IRQF_SHARED : - IRQF_ONESHOT; - - cq->irq_no = pci_irq_vector(pdev, nr); - rc = devm_request_threaded_irq(dev, cq->irq_no, - cq_interrupt_v3_hw, - cq_thread_v3_hw, - irqflags, - DRV_NAME " cq", cq); + unsigned long irqflags = hisi_sas_intr_conv ? IRQF_SHARED : 0; + + rc = devm_request_irq(dev, pci_irq_vector(pdev, nr), + cq_interrupt_v3_hw, irqflags, + DRV_NAME " cq", cq); if (rc) { dev_err(dev, "could not request cq%d interrupt, rc=%d\n", @@ -2670,6 +2668,8 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) rc = -ENOENT; goto free_cq_irqs; } + + tasklet_init(t, cq_tasklet_v3_hw, (uintptr_t)cq); }
return 0; @@ -2792,6 +2792,7 @@ static int disable_host_v3_hw(struct hisi_hba *hisi_hba)
interrupt_disable_v3_hw(hisi_hba); hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0); + hisi_sas_kill_tasklets(hisi_hba);
hisi_sas_stop_phys(hisi_hba);
@@ -3144,7 +3145,7 @@ static void debugfs_snapshot_prepare_v3_hw(struct hisi_hba *hisi_hba) if (wait_cmds_complete_timeout_v3_hw(hisi_hba, 100, 5000) == -ETIMEDOUT) dev_dbg(dev, "Wait commands complete timeout!\n");
- hisi_sas_sync_irqs(hisi_hba); + hisi_sas_kill_tasklets(hisi_hba); }
static void debugfs_snapshot_restore_v3_hw(struct hisi_hba *hisi_hba) @@ -3538,6 +3539,7 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev) sas_remove_host(sha->core.shost);
hisi_sas_v3_destroy_irqs(pdev, hisi_hba); + hisi_sas_kill_tasklets(hisi_hba); pci_release_regions(pdev); pci_disable_device(pdev); hisi_sas_free(hisi_hba);