Commit 7227aac4 authored by Bryan O'Sullivan's avatar Bryan O'Sullivan Committed by Roland Dreier

IB/ipath: Clean up module exit code

Signed-off-by: default avatarBryan O'Sullivan <bryan.osullivan@qlogic.com>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent 957670a5
...@@ -517,33 +517,146 @@ bail: ...@@ -517,33 +517,146 @@ bail:
return ret; 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); ipath_shutdown_device(dd);
if (!pdev)
return;
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) { if (dd->ipath_pioavailregs_dma) {
ipath_unregister_ib_device(dd->verbs_dev); dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
dd->verbs_dev = NULL; (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_diag_remove(dd);
ipath_user_remove(dd); ipath_user_remove(dd);
ipathfs_remove_device(dd); ipathfs_remove_device(dd);
ipath_device_remove_group(&pdev->dev, dd); ipath_device_remove_group(&pdev->dev, dd);
ipath_cdbg(VERBOSE, "Releasing pci memory regions, dd %p, " ipath_cdbg(VERBOSE, "Releasing pci memory regions, dd %p, "
"unit %u\n", dd, (u32) dd->ipath_unit); "unit %u\n", dd, (u32) dd->ipath_unit);
if (dd->ipath_kregbase) {
ipath_cdbg(VERBOSE, "Unmapping kregbase %p\n", cleanup_device(dd);
dd->ipath_kregbase);
/*
* 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); iounmap((volatile void __iomem *) dd->ipath_kregbase);
dd->ipath_kregbase = NULL;
}
pci_release_regions(pdev); pci_release_regions(pdev);
ipath_cdbg(VERBOSE, "calling pci_disable_device\n"); ipath_cdbg(VERBOSE, "calling pci_disable_device\n");
pci_disable_device(pdev); pci_disable_device(pdev);
...@@ -1917,158 +2030,12 @@ bail: ...@@ -1917,158 +2030,12 @@ bail:
return ret; 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) static void __exit infinipath_cleanup(void)
{ {
struct ipath_devdata *dd, *tmp;
unsigned long flags;
ipath_diagpkt_remove();
ipath_exit_ipathfs(); ipath_exit_ipathfs();
ipath_driver_remove_group(&ipath_driver.driver); 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"); ipath_cdbg(VERBOSE, "Unregistering pci driver\n");
pci_unregister_driver(&ipath_driver); pci_unregister_driver(&ipath_driver);
......
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