|
@@ -517,33 +517,146 @@ bail:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static void __devexit ipath_remove_one(struct pci_dev *pdev)
|
|
|
+static void __devexit cleanup_device(struct ipath_devdata *dd)
|
|
|
{
|
|
|
- struct ipath_devdata *dd;
|
|
|
+ int port;
|
|
|
|
|
|
- ipath_cdbg(VERBOSE, "removing, pdev=%p\n", pdev);
|
|
|
- if (!pdev)
|
|
|
- return;
|
|
|
+ ipath_shutdown_device(dd);
|
|
|
|
|
|
- dd = pci_get_drvdata(pdev);
|
|
|
+ if (*dd->ipath_statusp & IPATH_STATUS_CHIP_PRESENT) {
|
|
|
+ /* can't do anything more with chip; needs re-init */
|
|
|
+ *dd->ipath_statusp &= ~IPATH_STATUS_CHIP_PRESENT;
|
|
|
+ if (dd->ipath_kregbase) {
|
|
|
+ /*
|
|
|
+ * if we haven't already cleaned up before these are
|
|
|
+ * to ensure any register reads/writes "fail" until
|
|
|
+ * re-init
|
|
|
+ */
|
|
|
+ dd->ipath_kregbase = NULL;
|
|
|
+ dd->ipath_uregbase = 0;
|
|
|
+ dd->ipath_sregbase = 0;
|
|
|
+ dd->ipath_cregbase = 0;
|
|
|
+ dd->ipath_kregsize = 0;
|
|
|
+ }
|
|
|
+ ipath_disable_wc(dd);
|
|
|
+ }
|
|
|
|
|
|
- if (dd->verbs_dev) {
|
|
|
- ipath_unregister_ib_device(dd->verbs_dev);
|
|
|
- dd->verbs_dev = NULL;
|
|
|
+ if (dd->ipath_pioavailregs_dma) {
|
|
|
+ dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
|
|
|
+ (void *) dd->ipath_pioavailregs_dma,
|
|
|
+ dd->ipath_pioavailregs_phys);
|
|
|
+ dd->ipath_pioavailregs_dma = NULL;
|
|
|
+ }
|
|
|
+ if (dd->ipath_dummy_hdrq) {
|
|
|
+ dma_free_coherent(&dd->pcidev->dev,
|
|
|
+ dd->ipath_pd[0]->port_rcvhdrq_size,
|
|
|
+ dd->ipath_dummy_hdrq, dd->ipath_dummy_hdrq_phys);
|
|
|
+ dd->ipath_dummy_hdrq = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dd->ipath_pageshadow) {
|
|
|
+ struct page **tmpp = dd->ipath_pageshadow;
|
|
|
+ dma_addr_t *tmpd = dd->ipath_physshadow;
|
|
|
+ int i, cnt = 0;
|
|
|
+
|
|
|
+ ipath_cdbg(VERBOSE, "Unlocking any expTID pages still "
|
|
|
+ "locked\n");
|
|
|
+ for (port = 0; port < dd->ipath_cfgports; port++) {
|
|
|
+ int port_tidbase = port * dd->ipath_rcvtidcnt;
|
|
|
+ int maxtid = port_tidbase + dd->ipath_rcvtidcnt;
|
|
|
+ for (i = port_tidbase; i < maxtid; i++) {
|
|
|
+ if (!tmpp[i])
|
|
|
+ continue;
|
|
|
+ pci_unmap_page(dd->pcidev, tmpd[i],
|
|
|
+ PAGE_SIZE, PCI_DMA_FROMDEVICE);
|
|
|
+ ipath_release_user_pages(&tmpp[i], 1);
|
|
|
+ tmpp[i] = NULL;
|
|
|
+ cnt++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (cnt) {
|
|
|
+ ipath_stats.sps_pageunlocks += cnt;
|
|
|
+ ipath_cdbg(VERBOSE, "There were still %u expTID "
|
|
|
+ "entries locked\n", cnt);
|
|
|
+ }
|
|
|
+ if (ipath_stats.sps_pagelocks ||
|
|
|
+ ipath_stats.sps_pageunlocks)
|
|
|
+ ipath_cdbg(VERBOSE, "%llu pages locked, %llu "
|
|
|
+ "unlocked via ipath_m{un}lock\n",
|
|
|
+ (unsigned long long)
|
|
|
+ ipath_stats.sps_pagelocks,
|
|
|
+ (unsigned long long)
|
|
|
+ ipath_stats.sps_pageunlocks);
|
|
|
+
|
|
|
+ ipath_cdbg(VERBOSE, "Free shadow page tid array at %p\n",
|
|
|
+ dd->ipath_pageshadow);
|
|
|
+ vfree(dd->ipath_pageshadow);
|
|
|
+ dd->ipath_pageshadow = NULL;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * free any resources still in use (usually just kernel ports)
|
|
|
+ * at unload; we do for portcnt, not cfgports, because cfgports
|
|
|
+ * could have changed while we were loaded.
|
|
|
+ */
|
|
|
+ for (port = 0; port < dd->ipath_portcnt; port++) {
|
|
|
+ struct ipath_portdata *pd = dd->ipath_pd[port];
|
|
|
+ dd->ipath_pd[port] = NULL;
|
|
|
+ ipath_free_pddata(dd, pd);
|
|
|
+ }
|
|
|
+ kfree(dd->ipath_pd);
|
|
|
+ /*
|
|
|
+ * debuggability, in case some cleanup path tries to use it
|
|
|
+ * after this
|
|
|
+ */
|
|
|
+ dd->ipath_pd = NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static void __devexit ipath_remove_one(struct pci_dev *pdev)
|
|
|
+{
|
|
|
+ struct ipath_devdata *dd = pci_get_drvdata(pdev);
|
|
|
+
|
|
|
+ ipath_cdbg(VERBOSE, "removing, pdev=%p, dd=%p\n", pdev, dd);
|
|
|
+
|
|
|
+ if (dd->verbs_dev)
|
|
|
+ ipath_unregister_ib_device(dd->verbs_dev);
|
|
|
+
|
|
|
ipath_diag_remove(dd);
|
|
|
ipath_user_remove(dd);
|
|
|
ipathfs_remove_device(dd);
|
|
|
ipath_device_remove_group(&pdev->dev, dd);
|
|
|
+
|
|
|
ipath_cdbg(VERBOSE, "Releasing pci memory regions, dd %p, "
|
|
|
"unit %u\n", dd, (u32) dd->ipath_unit);
|
|
|
- if (dd->ipath_kregbase) {
|
|
|
- ipath_cdbg(VERBOSE, "Unmapping kregbase %p\n",
|
|
|
- dd->ipath_kregbase);
|
|
|
- iounmap((volatile void __iomem *) dd->ipath_kregbase);
|
|
|
- dd->ipath_kregbase = NULL;
|
|
|
- }
|
|
|
+
|
|
|
+ cleanup_device(dd);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * turn off rcv, send, and interrupts for all ports, all drivers
|
|
|
+ * should also hard reset the chip here?
|
|
|
+ * free up port 0 (kernel) rcvhdr, egr bufs, and eventually tid bufs
|
|
|
+ * for all versions of the driver, if they were allocated
|
|
|
+ */
|
|
|
+ if (pdev->irq) {
|
|
|
+ ipath_cdbg(VERBOSE,
|
|
|
+ "unit %u free_irq of irq %x\n",
|
|
|
+ dd->ipath_unit, pdev->irq);
|
|
|
+ free_irq(pdev->irq, dd);
|
|
|
+ } else
|
|
|
+ ipath_dbg("irq is 0, not doing free_irq "
|
|
|
+ "for unit %u\n", dd->ipath_unit);
|
|
|
+ /*
|
|
|
+ * we check for NULL here, because it's outside
|
|
|
+ * the kregbase check, and we need to call it
|
|
|
+ * after the free_irq. Thus it's possible that
|
|
|
+ * the function pointers were never initialized.
|
|
|
+ */
|
|
|
+ if (dd->ipath_f_cleanup)
|
|
|
+ /* clean up chip-specific stuff */
|
|
|
+ dd->ipath_f_cleanup(dd);
|
|
|
+
|
|
|
+ ipath_cdbg(VERBOSE, "Unmapping kregbase %p\n", dd->ipath_kregbase);
|
|
|
+ iounmap((volatile void __iomem *) dd->ipath_kregbase);
|
|
|
pci_release_regions(pdev);
|
|
|
ipath_cdbg(VERBOSE, "calling pci_disable_device\n");
|
|
|
pci_disable_device(pdev);
|
|
@@ -1917,158 +2030,12 @@ bail:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static void cleanup_device(struct ipath_devdata *dd)
|
|
|
-{
|
|
|
- int port;
|
|
|
-
|
|
|
- ipath_shutdown_device(dd);
|
|
|
-
|
|
|
- if (*dd->ipath_statusp & IPATH_STATUS_CHIP_PRESENT) {
|
|
|
- /* can't do anything more with chip; needs re-init */
|
|
|
- *dd->ipath_statusp &= ~IPATH_STATUS_CHIP_PRESENT;
|
|
|
- if (dd->ipath_kregbase) {
|
|
|
- /*
|
|
|
- * if we haven't already cleaned up before these are
|
|
|
- * to ensure any register reads/writes "fail" until
|
|
|
- * re-init
|
|
|
- */
|
|
|
- dd->ipath_kregbase = NULL;
|
|
|
- dd->ipath_uregbase = 0;
|
|
|
- dd->ipath_sregbase = 0;
|
|
|
- dd->ipath_cregbase = 0;
|
|
|
- dd->ipath_kregsize = 0;
|
|
|
- }
|
|
|
- ipath_disable_wc(dd);
|
|
|
- }
|
|
|
-
|
|
|
- if (dd->ipath_pioavailregs_dma) {
|
|
|
- dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
|
|
|
- (void *) dd->ipath_pioavailregs_dma,
|
|
|
- dd->ipath_pioavailregs_phys);
|
|
|
- dd->ipath_pioavailregs_dma = NULL;
|
|
|
- }
|
|
|
- if (dd->ipath_dummy_hdrq) {
|
|
|
- dma_free_coherent(&dd->pcidev->dev,
|
|
|
- dd->ipath_pd[0]->port_rcvhdrq_size,
|
|
|
- dd->ipath_dummy_hdrq, dd->ipath_dummy_hdrq_phys);
|
|
|
- dd->ipath_dummy_hdrq = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (dd->ipath_pageshadow) {
|
|
|
- struct page **tmpp = dd->ipath_pageshadow;
|
|
|
- dma_addr_t *tmpd = dd->ipath_physshadow;
|
|
|
- int i, cnt = 0;
|
|
|
-
|
|
|
- ipath_cdbg(VERBOSE, "Unlocking any expTID pages still "
|
|
|
- "locked\n");
|
|
|
- for (port = 0; port < dd->ipath_cfgports; port++) {
|
|
|
- int port_tidbase = port * dd->ipath_rcvtidcnt;
|
|
|
- int maxtid = port_tidbase + dd->ipath_rcvtidcnt;
|
|
|
- for (i = port_tidbase; i < maxtid; i++) {
|
|
|
- if (!tmpp[i])
|
|
|
- continue;
|
|
|
- pci_unmap_page(dd->pcidev, tmpd[i],
|
|
|
- PAGE_SIZE, PCI_DMA_FROMDEVICE);
|
|
|
- ipath_release_user_pages(&tmpp[i], 1);
|
|
|
- tmpp[i] = NULL;
|
|
|
- cnt++;
|
|
|
- }
|
|
|
- }
|
|
|
- if (cnt) {
|
|
|
- ipath_stats.sps_pageunlocks += cnt;
|
|
|
- ipath_cdbg(VERBOSE, "There were still %u expTID "
|
|
|
- "entries locked\n", cnt);
|
|
|
- }
|
|
|
- if (ipath_stats.sps_pagelocks ||
|
|
|
- ipath_stats.sps_pageunlocks)
|
|
|
- ipath_cdbg(VERBOSE, "%llu pages locked, %llu "
|
|
|
- "unlocked via ipath_m{un}lock\n",
|
|
|
- (unsigned long long)
|
|
|
- ipath_stats.sps_pagelocks,
|
|
|
- (unsigned long long)
|
|
|
- ipath_stats.sps_pageunlocks);
|
|
|
-
|
|
|
- ipath_cdbg(VERBOSE, "Free shadow page tid array at %p\n",
|
|
|
- dd->ipath_pageshadow);
|
|
|
- vfree(dd->ipath_pageshadow);
|
|
|
- dd->ipath_pageshadow = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * free any resources still in use (usually just kernel ports)
|
|
|
- * at unload; we do for portcnt, not cfgports, because cfgports
|
|
|
- * could have changed while we were loaded.
|
|
|
- */
|
|
|
- for (port = 0; port < dd->ipath_portcnt; port++) {
|
|
|
- struct ipath_portdata *pd = dd->ipath_pd[port];
|
|
|
- dd->ipath_pd[port] = NULL;
|
|
|
- ipath_free_pddata(dd, pd);
|
|
|
- }
|
|
|
- kfree(dd->ipath_pd);
|
|
|
- /*
|
|
|
- * debuggability, in case some cleanup path tries to use it
|
|
|
- * after this
|
|
|
- */
|
|
|
- dd->ipath_pd = NULL;
|
|
|
-}
|
|
|
-
|
|
|
static void __exit infinipath_cleanup(void)
|
|
|
{
|
|
|
- struct ipath_devdata *dd, *tmp;
|
|
|
- unsigned long flags;
|
|
|
-
|
|
|
- ipath_diagpkt_remove();
|
|
|
-
|
|
|
ipath_exit_ipathfs();
|
|
|
|
|
|
ipath_driver_remove_group(&ipath_driver.driver);
|
|
|
|
|
|
- spin_lock_irqsave(&ipath_devs_lock, flags);
|
|
|
-
|
|
|
- /*
|
|
|
- * turn off rcv, send, and interrupts for all ports, all drivers
|
|
|
- * should also hard reset the chip here?
|
|
|
- * free up port 0 (kernel) rcvhdr, egr bufs, and eventually tid bufs
|
|
|
- * for all versions of the driver, if they were allocated
|
|
|
- */
|
|
|
- list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) {
|
|
|
- spin_unlock_irqrestore(&ipath_devs_lock, flags);
|
|
|
-
|
|
|
- if (dd->verbs_dev) {
|
|
|
- ipath_unregister_ib_device(dd->verbs_dev);
|
|
|
- dd->verbs_dev = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (dd->ipath_kregbase)
|
|
|
- cleanup_device(dd);
|
|
|
-
|
|
|
- if (dd->pcidev) {
|
|
|
- if (dd->pcidev->irq) {
|
|
|
- ipath_cdbg(VERBOSE,
|
|
|
- "unit %u free_irq of irq %x\n",
|
|
|
- dd->ipath_unit, dd->pcidev->irq);
|
|
|
- free_irq(dd->pcidev->irq, dd);
|
|
|
- } else
|
|
|
- ipath_dbg("irq is 0, not doing free_irq "
|
|
|
- "for unit %u\n", dd->ipath_unit);
|
|
|
-
|
|
|
- /*
|
|
|
- * we check for NULL here, because it's outside
|
|
|
- * the kregbase check, and we need to call it
|
|
|
- * after the free_irq. Thus it's possible that
|
|
|
- * the function pointers were never initialized.
|
|
|
- */
|
|
|
- if (dd->ipath_f_cleanup)
|
|
|
- /* clean up chip-specific stuff */
|
|
|
- dd->ipath_f_cleanup(dd);
|
|
|
-
|
|
|
- dd->pcidev = NULL;
|
|
|
- }
|
|
|
- spin_lock_irqsave(&ipath_devs_lock, flags);
|
|
|
- }
|
|
|
-
|
|
|
- spin_unlock_irqrestore(&ipath_devs_lock, flags);
|
|
|
-
|
|
|
ipath_cdbg(VERBOSE, "Unregistering pci driver\n");
|
|
|
pci_unregister_driver(&ipath_driver);
|
|
|
|