scsi: hisi_sas: Free irq vectors in order for v3 HW
[ 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>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
f49ffaa85d
commit
224903cc60
@@ -2372,17 +2372,25 @@ static irqreturn_t cq_interrupt_v3_hw(int irq_no, void *p)
|
|||||||
return IRQ_WAKE_THREAD;
|
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)
|
static int interrupt_preinit_v3_hw(struct hisi_hba *hisi_hba)
|
||||||
{
|
{
|
||||||
int vectors;
|
int vectors;
|
||||||
int max_msi = HISI_SAS_MSI_COUNT_V3_HW, min_msi;
|
int max_msi = HISI_SAS_MSI_COUNT_V3_HW, min_msi;
|
||||||
struct Scsi_Host *shost = hisi_hba->shost;
|
struct Scsi_Host *shost = hisi_hba->shost;
|
||||||
|
struct pci_dev *pdev = hisi_hba->pci_dev;
|
||||||
struct irq_affinity desc = {
|
struct irq_affinity desc = {
|
||||||
.pre_vectors = BASE_VECTORS_V3_HW,
|
.pre_vectors = BASE_VECTORS_V3_HW,
|
||||||
};
|
};
|
||||||
|
|
||||||
min_msi = MIN_AFFINE_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,
|
min_msi, max_msi,
|
||||||
PCI_IRQ_MSI |
|
PCI_IRQ_MSI |
|
||||||
PCI_IRQ_AFFINITY,
|
PCI_IRQ_AFFINITY,
|
||||||
@@ -2394,6 +2402,7 @@ static int interrupt_preinit_v3_hw(struct hisi_hba *hisi_hba)
|
|||||||
hisi_hba->cq_nvecs = vectors - BASE_VECTORS_V3_HW;
|
hisi_hba->cq_nvecs = vectors - BASE_VECTORS_V3_HW;
|
||||||
shost->nr_hw_queues = hisi_hba->cq_nvecs;
|
shost->nr_hw_queues = hisi_hba->cq_nvecs;
|
||||||
|
|
||||||
|
devm_add_action(&pdev->dev, hisi_sas_v3_free_vectors, pdev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3313,7 +3322,7 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||||||
dev_err(dev, "%d hw queues\n", shost->nr_hw_queues);
|
dev_err(dev, "%d hw queues\n", shost->nr_hw_queues);
|
||||||
rc = scsi_add_host(shost, dev);
|
rc = scsi_add_host(shost, dev);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto err_out_free_irq_vectors;
|
goto err_out_debugfs;
|
||||||
|
|
||||||
rc = sas_register_ha(sha);
|
rc = sas_register_ha(sha);
|
||||||
if (rc)
|
if (rc)
|
||||||
@@ -3340,8 +3349,6 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||||||
|
|
||||||
err_out_register_ha:
|
err_out_register_ha:
|
||||||
scsi_remove_host(shost);
|
scsi_remove_host(shost);
|
||||||
err_out_free_irq_vectors:
|
|
||||||
pci_free_irq_vectors(pdev);
|
|
||||||
err_out_debugfs:
|
err_out_debugfs:
|
||||||
hisi_sas_debugfs_exit(hisi_hba);
|
hisi_sas_debugfs_exit(hisi_hba);
|
||||||
err_out_ha:
|
err_out_ha:
|
||||||
@@ -3369,7 +3376,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);
|
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)
|
static void hisi_sas_v3_remove(struct pci_dev *pdev)
|
||||||
|
Reference in New Issue
Block a user