Commit 8a253888 authored by Xiang Chen's avatar Xiang Chen Committed by Martin K. Petersen

scsi: hisi_sas: add irq and tasklet cleanup in v2 hw

This patch adds support to clean-up allocated IRQs and kill tasklets
when probe fails and for driver removal.
Signed-off-by: default avatarXiang Chen <chenxiang66@hisilicon.com>
Signed-off-by: default avatarJohn Garry <john.garry@huawei.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent cef4e1ab
...@@ -3290,97 +3290,92 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba) ...@@ -3290,97 +3290,92 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
{ {
struct platform_device *pdev = hisi_hba->platform_dev; struct platform_device *pdev = hisi_hba->platform_dev;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
int i, irq, rc, irq_map[128]; int irq, rc, irq_map[128];
int i, phy_no, fatal_no, queue_no, k;
for (i = 0; i < 128; i++) for (i = 0; i < 128; i++)
irq_map[i] = platform_get_irq(pdev, i); irq_map[i] = platform_get_irq(pdev, i);
for (i = 0; i < HISI_SAS_PHY_INT_NR; i++) { for (i = 0; i < HISI_SAS_PHY_INT_NR; i++) {
int idx = i; irq = irq_map[i + 1]; /* Phy up/down is irq1 */
irq = irq_map[idx + 1]; /* Phy up/down is irq1 */
if (!irq) {
dev_err(dev, "irq init: fail map phy interrupt %d\n",
idx);
return -ENOENT;
}
rc = devm_request_irq(dev, irq, phy_interrupts[i], 0, rc = devm_request_irq(dev, irq, phy_interrupts[i], 0,
DRV_NAME " phy", hisi_hba); DRV_NAME " phy", hisi_hba);
if (rc) { if (rc) {
dev_err(dev, "irq init: could not request " dev_err(dev, "irq init: could not request "
"phy interrupt %d, rc=%d\n", "phy interrupt %d, rc=%d\n",
irq, rc); irq, rc);
return -ENOENT; rc = -ENOENT;
goto free_phy_int_irqs;
} }
} }
for (i = 0; i < hisi_hba->n_phy; i++) { for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
struct hisi_sas_phy *phy = &hisi_hba->phy[i]; struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
int idx = i + 72; /* First SATA interrupt is irq72 */
irq = irq_map[idx];
if (!irq) {
dev_err(dev, "irq init: fail map phy interrupt %d\n",
idx);
return -ENOENT;
}
irq = irq_map[phy_no + 72];
rc = devm_request_irq(dev, irq, sata_int_v2_hw, 0, rc = devm_request_irq(dev, irq, sata_int_v2_hw, 0,
DRV_NAME " sata", phy); DRV_NAME " sata", phy);
if (rc) { if (rc) {
dev_err(dev, "irq init: could not request " dev_err(dev, "irq init: could not request "
"sata interrupt %d, rc=%d\n", "sata interrupt %d, rc=%d\n",
irq, rc); irq, rc);
return -ENOENT; rc = -ENOENT;
goto free_sata_int_irqs;
} }
} }
for (i = 0; i < HISI_SAS_FATAL_INT_NR; i++) { for (fatal_no = 0; fatal_no < HISI_SAS_FATAL_INT_NR; fatal_no++) {
int idx = i; irq = irq_map[fatal_no + 81];
rc = devm_request_irq(dev, irq, fatal_interrupts[fatal_no], 0,
irq = irq_map[idx + 81];
if (!irq) {
dev_err(dev, "irq init: fail map fatal interrupt %d\n",
idx);
return -ENOENT;
}
rc = devm_request_irq(dev, irq, fatal_interrupts[i], 0,
DRV_NAME " fatal", hisi_hba); DRV_NAME " fatal", hisi_hba);
if (rc) { if (rc) {
dev_err(dev, dev_err(dev,
"irq init: could not request fatal interrupt %d, rc=%d\n", "irq init: could not request fatal interrupt %d, rc=%d\n",
irq, rc); irq, rc);
return -ENOENT; rc = -ENOENT;
goto free_fatal_int_irqs;
} }
} }
for (i = 0; i < hisi_hba->queue_count; i++) { for (queue_no = 0; queue_no < hisi_hba->queue_count; queue_no++) {
int idx = i + 96; /* First cq interrupt is irq96 */ struct hisi_sas_cq *cq = &hisi_hba->cq[queue_no];
struct hisi_sas_cq *cq = &hisi_hba->cq[i];
struct tasklet_struct *t = &cq->tasklet; struct tasklet_struct *t = &cq->tasklet;
irq = irq_map[idx]; irq = irq_map[queue_no + 96];
if (!irq) {
dev_err(dev,
"irq init: could not map cq interrupt %d\n",
idx);
return -ENOENT;
}
rc = devm_request_irq(dev, irq, cq_interrupt_v2_hw, 0, rc = devm_request_irq(dev, irq, cq_interrupt_v2_hw, 0,
DRV_NAME " cq", &hisi_hba->cq[i]); DRV_NAME " cq", cq);
if (rc) { if (rc) {
dev_err(dev, dev_err(dev,
"irq init: could not request cq interrupt %d, rc=%d\n", "irq init: could not request cq interrupt %d, rc=%d\n",
irq, rc); irq, rc);
return -ENOENT; rc = -ENOENT;
goto free_cq_int_irqs;
} }
tasklet_init(t, cq_tasklet_v2_hw, (unsigned long)cq); tasklet_init(t, cq_tasklet_v2_hw, (unsigned long)cq);
} }
return 0; return 0;
free_cq_int_irqs:
for (k = 0; k < queue_no; k++) {
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++)
free_irq(irq_map[k + 81], hisi_hba);
free_sata_int_irqs:
for (k = 0; k < phy_no; k++) {
struct hisi_sas_phy *phy = &hisi_hba->phy[k];
free_irq(irq_map[k + 72], phy);
}
free_phy_int_irqs:
for (k = 0; k < i; k++)
free_irq(irq_map[k + 1], hisi_hba);
return rc;
} }
static int hisi_sas_v2_init(struct hisi_hba *hisi_hba) static int hisi_sas_v2_init(struct hisi_hba *hisi_hba)
...@@ -3518,10 +3513,17 @@ static int hisi_sas_v2_remove(struct platform_device *pdev) ...@@ -3518,10 +3513,17 @@ static int hisi_sas_v2_remove(struct platform_device *pdev)
{ {
struct sas_ha_struct *sha = platform_get_drvdata(pdev); struct sas_ha_struct *sha = platform_get_drvdata(pdev);
struct hisi_hba *hisi_hba = sha->lldd_ha; struct hisi_hba *hisi_hba = sha->lldd_ha;
int i;
if (timer_pending(&hisi_hba->timer)) if (timer_pending(&hisi_hba->timer))
del_timer(&hisi_hba->timer); del_timer(&hisi_hba->timer);
for (i = 0; i < hisi_hba->queue_count; i++) {
struct hisi_sas_cq *cq = &hisi_hba->cq[i];
tasklet_kill(&cq->tasklet);
}
return hisi_sas_remove(pdev); return hisi_sas_remove(pdev);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment