| From 63e84f907a4df1f3f46f6450b181835ccd986e50 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 24 Feb 2022 19:51:26 +0800 |
| Subject: scsi: hisi_sas: Free irq vectors in order for v3 HW |
| |
| From: Qi Liu <liuqi115@huawei.com> |
| |
| [ Upstream commit 554fb72ee34f4732c7f694f56c3c6e67790352a0 ] |
| |
| If the driver probe fails to request the channel IRQ or fatal IRQ, the |
| driver will free the IRQ vectors before freeing the IRQs in free_irq(), |
| and this will cause a kernel BUG like this: |
| |
| ------------[ cut here ]------------ |
| kernel BUG at drivers/pci/msi.c:369! |
| Internal error: Oops - BUG: 0 [#1] PREEMPT SMP |
| Call trace: |
| free_msi_irqs+0x118/0x13c |
| pci_disable_msi+0xfc/0x120 |
| pci_free_irq_vectors+0x24/0x3c |
| hisi_sas_v3_probe+0x360/0x9d0 [hisi_sas_v3_hw] |
| local_pci_probe+0x44/0xb0 |
| work_for_cpu_fn+0x20/0x34 |
| process_one_work+0x1d0/0x340 |
| worker_thread+0x2e0/0x460 |
| kthread+0x180/0x190 |
| ret_from_fork+0x10/0x20 |
| ---[ end trace b88990335b610c11 ]--- |
| |
| So we use devm_add_action() to control the order in which we free the |
| vectors. |
| |
| Link: https://lore.kernel.org/r/1645703489-87194-4-git-send-email-john.garry@huawei.com |
| Signed-off-by: Qi Liu <liuqi115@huawei.com> |
| Signed-off-by: John Garry <john.garry@huawei.com> |
| Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 16 +++++++++++----- |
| 1 file changed, 11 insertions(+), 5 deletions(-) |
| |
| diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c |
| index b3bdbea3c955..8392463d57de 100644 |
| --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c |
| +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c |
| @@ -2390,17 +2390,25 @@ static irqreturn_t cq_interrupt_v3_hw(int irq_no, void *p) |
| return IRQ_WAKE_THREAD; |
| } |
| |
| +static void hisi_sas_v3_free_vectors(void *data) |
| +{ |
| + struct pci_dev *pdev = data; |
| + |
| + pci_free_irq_vectors(pdev); |
| +} |
| + |
| static int interrupt_preinit_v3_hw(struct hisi_hba *hisi_hba) |
| { |
| int vectors; |
| int max_msi = HISI_SAS_MSI_COUNT_V3_HW, min_msi; |
| struct Scsi_Host *shost = hisi_hba->shost; |
| + struct pci_dev *pdev = hisi_hba->pci_dev; |
| struct irq_affinity desc = { |
| .pre_vectors = BASE_VECTORS_V3_HW, |
| }; |
| |
| min_msi = MIN_AFFINE_VECTORS_V3_HW; |
| - vectors = pci_alloc_irq_vectors_affinity(hisi_hba->pci_dev, |
| + vectors = pci_alloc_irq_vectors_affinity(pdev, |
| min_msi, max_msi, |
| PCI_IRQ_MSI | |
| PCI_IRQ_AFFINITY, |
| @@ -2412,6 +2420,7 @@ static int interrupt_preinit_v3_hw(struct hisi_hba *hisi_hba) |
| hisi_hba->cq_nvecs = vectors - BASE_VECTORS_V3_HW; |
| shost->nr_hw_queues = hisi_hba->cq_nvecs; |
| |
| + devm_add_action(&pdev->dev, hisi_sas_v3_free_vectors, pdev); |
| return 0; |
| } |
| |
| @@ -4763,7 +4772,7 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
| |
| rc = scsi_add_host(shost, dev); |
| if (rc) |
| - goto err_out_free_irq_vectors; |
| + goto err_out_debugfs; |
| |
| rc = sas_register_ha(sha); |
| if (rc) |
| @@ -4792,8 +4801,6 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
| sas_unregister_ha(sha); |
| err_out_register_ha: |
| scsi_remove_host(shost); |
| -err_out_free_irq_vectors: |
| - pci_free_irq_vectors(pdev); |
| err_out_debugfs: |
| debugfs_exit_v3_hw(hisi_hba); |
| err_out_ha: |
| @@ -4817,7 +4824,6 @@ hisi_sas_v3_destroy_irqs(struct pci_dev *pdev, struct hisi_hba *hisi_hba) |
| |
| devm_free_irq(&pdev->dev, pci_irq_vector(pdev, nr), cq); |
| } |
| - pci_free_irq_vectors(pdev); |
| } |
| |
| static void hisi_sas_v3_remove(struct pci_dev *pdev) |
| -- |
| 2.35.1 |
| |