Commit d6f5bcc2 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/switchtec'

- Do dma_mrpc cleanup during switchtec_pci_remove() to match its devm
  ioremapping in switchtec_pci_probe().  Previously the cleanup was done in
  stdev_release(), which used stale pointers if stdev->cdev happened to be
  open when the PCI device was removed (Daniel Stodden)

* pci/switchtec:
  PCI: switchtec: Fix stdev_release() crash after surprise hot remove
parents 5a4af2ca df254611
Loading
Loading
Loading
Loading
+17 −8
Original line number Diff line number Diff line
@@ -1308,13 +1308,6 @@ static void stdev_release(struct device *dev)
{
	struct switchtec_dev *stdev = to_stdev(dev);

	if (stdev->dma_mrpc) {
		iowrite32(0, &stdev->mmio_mrpc->dma_en);
		flush_wc_buf(stdev);
		writeq(0, &stdev->mmio_mrpc->dma_addr);
		dma_free_coherent(&stdev->pdev->dev, sizeof(*stdev->dma_mrpc),
				stdev->dma_mrpc, stdev->dma_mrpc_dma_addr);
	}
	kfree(stdev);
}

@@ -1358,7 +1351,7 @@ static struct switchtec_dev *stdev_create(struct pci_dev *pdev)
		return ERR_PTR(-ENOMEM);

	stdev->alive = true;
	stdev->pdev = pdev;
	stdev->pdev = pci_dev_get(pdev);
	INIT_LIST_HEAD(&stdev->mrpc_queue);
	mutex_init(&stdev->mrpc_mutex);
	stdev->mrpc_busy = 0;
@@ -1391,6 +1384,7 @@ static struct switchtec_dev *stdev_create(struct pci_dev *pdev)
	return stdev;

err_put:
	pci_dev_put(stdev->pdev);
	put_device(&stdev->dev);
	return ERR_PTR(rc);
}
@@ -1644,6 +1638,18 @@ static int switchtec_init_pci(struct switchtec_dev *stdev,
	return 0;
}

static void switchtec_exit_pci(struct switchtec_dev *stdev)
{
	if (stdev->dma_mrpc) {
		iowrite32(0, &stdev->mmio_mrpc->dma_en);
		flush_wc_buf(stdev);
		writeq(0, &stdev->mmio_mrpc->dma_addr);
		dma_free_coherent(&stdev->pdev->dev, sizeof(*stdev->dma_mrpc),
				  stdev->dma_mrpc, stdev->dma_mrpc_dma_addr);
		stdev->dma_mrpc = NULL;
	}
}

static int switchtec_pci_probe(struct pci_dev *pdev,
			       const struct pci_device_id *id)
{
@@ -1703,6 +1709,9 @@ static void switchtec_pci_remove(struct pci_dev *pdev)
	ida_free(&switchtec_minor_ida, MINOR(stdev->dev.devt));
	dev_info(&stdev->dev, "unregistered.\n");
	stdev_kill(stdev);
	switchtec_exit_pci(stdev);
	pci_dev_put(stdev->pdev);
	stdev->pdev = NULL;
	put_device(&stdev->dev);
}