Skip to content

Commit ddf742d

Browse files
davejiangvinodkoul
authored andcommitted
dmaengine: idxd: Add missing cleanup for early error out in probe call
The probe call stack is missing some cleanup when things fail in the middle. Add the appropriate cleanup routines to make sure we exit gracefully. Fixes: a39c7cd ("dmaengine: idxd: removal of pcim managed mmio mapping") Reported-by: Nikhil Rao <[email protected]> Signed-off-by: Dave Jiang <[email protected]> Link: https://lore.kernel.org/r/162197061707.392656.15760573520817310791.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul <[email protected]>
1 parent 9f007e7 commit ddf742d

File tree

1 file changed

+58
-3
lines changed

1 file changed

+58
-3
lines changed

drivers/dma/idxd/init.c

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,32 @@ static int idxd_setup_interrupts(struct idxd_device *idxd)
168168
return rc;
169169
}
170170

171+
static void idxd_cleanup_interrupts(struct idxd_device *idxd)
172+
{
173+
struct pci_dev *pdev = idxd->pdev;
174+
struct idxd_irq_entry *irq_entry;
175+
int i, msixcnt;
176+
177+
msixcnt = pci_msix_vec_count(pdev);
178+
if (msixcnt <= 0)
179+
return;
180+
181+
irq_entry = &idxd->irq_entries[0];
182+
free_irq(irq_entry->vector, irq_entry);
183+
184+
for (i = 1; i < msixcnt; i++) {
185+
186+
irq_entry = &idxd->irq_entries[i];
187+
if (idxd->hw.cmd_cap & BIT(IDXD_CMD_RELEASE_INT_HANDLE))
188+
idxd_device_release_int_handle(idxd, idxd->int_handles[i],
189+
IDXD_IRQ_MSIX);
190+
free_irq(irq_entry->vector, irq_entry);
191+
}
192+
193+
idxd_mask_error_interrupts(idxd);
194+
pci_free_irq_vectors(pdev);
195+
}
196+
171197
static int idxd_setup_wqs(struct idxd_device *idxd)
172198
{
173199
struct device *dev = &idxd->pdev->dev;
@@ -304,6 +330,19 @@ static int idxd_setup_groups(struct idxd_device *idxd)
304330
return rc;
305331
}
306332

333+
static void idxd_cleanup_internals(struct idxd_device *idxd)
334+
{
335+
int i;
336+
337+
for (i = 0; i < idxd->max_groups; i++)
338+
put_device(&idxd->groups[i]->conf_dev);
339+
for (i = 0; i < idxd->max_engines; i++)
340+
put_device(&idxd->engines[i]->conf_dev);
341+
for (i = 0; i < idxd->max_wqs; i++)
342+
put_device(&idxd->wqs[i]->conf_dev);
343+
destroy_workqueue(idxd->wq);
344+
}
345+
307346
static int idxd_setup_internals(struct idxd_device *idxd)
308347
{
309348
struct device *dev = &idxd->pdev->dev;
@@ -532,12 +571,12 @@ static int idxd_probe(struct idxd_device *idxd)
532571
dev_dbg(dev, "Loading RO device config\n");
533572
rc = idxd_device_load_config(idxd);
534573
if (rc < 0)
535-
goto err;
574+
goto err_config;
536575
}
537576

538577
rc = idxd_setup_interrupts(idxd);
539578
if (rc)
540-
goto err;
579+
goto err_config;
541580

542581
dev_dbg(dev, "IDXD interrupt setup complete.\n");
543582

@@ -550,13 +589,27 @@ static int idxd_probe(struct idxd_device *idxd)
550589
dev_dbg(dev, "IDXD device %d probed successfully\n", idxd->id);
551590
return 0;
552591

592+
err_config:
593+
idxd_cleanup_internals(idxd);
553594
err:
554595
if (device_pasid_enabled(idxd))
555596
idxd_disable_system_pasid(idxd);
556597
iommu_dev_disable_feature(dev, IOMMU_DEV_FEAT_SVA);
557598
return rc;
558599
}
559600

601+
static void idxd_cleanup(struct idxd_device *idxd)
602+
{
603+
struct device *dev = &idxd->pdev->dev;
604+
605+
perfmon_pmu_remove(idxd);
606+
idxd_cleanup_interrupts(idxd);
607+
idxd_cleanup_internals(idxd);
608+
if (device_pasid_enabled(idxd))
609+
idxd_disable_system_pasid(idxd);
610+
iommu_dev_disable_feature(dev, IOMMU_DEV_FEAT_SVA);
611+
}
612+
560613
static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
561614
{
562615
struct device *dev = &pdev->dev;
@@ -609,7 +662,7 @@ static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
609662
rc = idxd_register_devices(idxd);
610663
if (rc) {
611664
dev_err(dev, "IDXD sysfs setup failed\n");
612-
goto err;
665+
goto err_dev_register;
613666
}
614667

615668
idxd->state = IDXD_DEV_CONF_READY;
@@ -619,6 +672,8 @@ static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
619672

620673
return 0;
621674

675+
err_dev_register:
676+
idxd_cleanup(idxd);
622677
err:
623678
pci_iounmap(pdev, idxd->reg_base);
624679
err_iomap:

0 commit comments

Comments
 (0)