Skip to content

Commit

Permalink
dmaengine: idxd: fix sequence for pci driver remove() and shutdown()
Browse files Browse the repository at this point in the history
->shutdown() call should only be responsible for quiescing the device.
Currently it is doing PCI device tear down. This causes issue when things
like MMIO mapping is removed while idxd_unregister_devices() will trigger
removal of idxd device sub-driver and still initiates MMIO writes to the
device. Another issue is with the unregistering of idxd 'struct device',
the memory context gets freed. So the teardown calls are accessing freed
memory and can cause kernel oops. Move all the teardown bits that doesn't
belong in shutdown to ->remove() call. Move unregistering of the idxd
conf_dev 'struct device' to after doing all the teardown to free all
the memory that's no longer needed.

Fixes: 47c16ac ("dmaengine: idxd: fix idxd conf_dev 'struct device' lifetime")
Signed-off-by: Dave Jiang <[email protected]>
Link: https://lore.kernel.org/r/162629983901.395844.17964803190905549615.stgit@djiang5-desk3.ch.intel.com
Signed-off-by: Vinod Koul <[email protected]>
  • Loading branch information
davejiang authored and vinodkoul committed Jul 20, 2021
1 parent 8ba89a3 commit 7eb25da
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 11 deletions.
26 changes: 17 additions & 9 deletions drivers/dma/idxd/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -760,32 +760,40 @@ static void idxd_shutdown(struct pci_dev *pdev)
for (i = 0; i < msixcnt; i++) {
irq_entry = &idxd->irq_entries[i];
synchronize_irq(irq_entry->vector);
free_irq(irq_entry->vector, irq_entry);
if (i == 0)
continue;
idxd_flush_pending_llist(irq_entry);
idxd_flush_work_list(irq_entry);
}

idxd_msix_perm_clear(idxd);
idxd_release_int_handles(idxd);
pci_free_irq_vectors(pdev);
pci_iounmap(pdev, idxd->reg_base);
pci_disable_device(pdev);
destroy_workqueue(idxd->wq);
flush_workqueue(idxd->wq);
}

static void idxd_remove(struct pci_dev *pdev)
{
struct idxd_device *idxd = pci_get_drvdata(pdev);
struct idxd_irq_entry *irq_entry;
int msixcnt = pci_msix_vec_count(pdev);
int i;

dev_dbg(&pdev->dev, "%s called\n", __func__);
idxd_shutdown(pdev);
if (device_pasid_enabled(idxd))
idxd_disable_system_pasid(idxd);
idxd_unregister_devices(idxd);
perfmon_pmu_remove(idxd);

for (i = 0; i < msixcnt; i++) {
irq_entry = &idxd->irq_entries[i];
free_irq(irq_entry->vector, irq_entry);
}
idxd_msix_perm_clear(idxd);
idxd_release_int_handles(idxd);
pci_free_irq_vectors(pdev);
pci_iounmap(pdev, idxd->reg_base);
iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_SVA);
pci_disable_device(pdev);
destroy_workqueue(idxd->wq);
perfmon_pmu_remove(idxd);
device_unregister(&idxd->conf_dev);
}

static struct pci_driver idxd_pci_driver = {
Expand Down
2 changes: 0 additions & 2 deletions drivers/dma/idxd/sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1744,8 +1744,6 @@ void idxd_unregister_devices(struct idxd_device *idxd)

device_unregister(&group->conf_dev);
}

device_unregister(&idxd->conf_dev);
}

int idxd_register_bus_type(void)
Expand Down

0 comments on commit 7eb25da

Please sign in to comment.