diff options
author | jhb <jhb@FreeBSD.org> | 2013-06-27 20:21:54 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2013-06-27 20:21:54 +0000 |
commit | c1207dc20cfb10830a48d20d77f7a913d7a96029 (patch) | |
tree | 69d881f3333bd86e947935bed15eb731c8b66001 /sys/dev/pci | |
parent | 823196e2536bd8942ccac6fbac1ee337562c4623 (diff) | |
download | FreeBSD-src-c1207dc20cfb10830a48d20d77f7a913d7a96029.zip FreeBSD-src-c1207dc20cfb10830a48d20d77f7a913d7a96029.tar.gz |
Make detaching drivers from PCI devices more robust. While here, fix a
bug where a PCI device would be powered down if it failed to probe, but
not when its driver was detached (e.g. via kldunload).
- Add a new helper method resource_list_release_active() which forcefully
releases any active resources of a specified type from a resource list.
- Add a bus_child_detached method for the PCI bus driver which forces any
active resources to be released (and whines to the console if it finds
any) and then powers the device down.
- Call pci_child_detached() if we fail to probe a device when a driver
is kldloaded. This isn't perfect but can avoid leaking resources
from a probe() routine in the kldload case.
Reviewed by: imp, brooks
MFC after: 1 month
Diffstat (limited to 'sys/dev/pci')
-rw-r--r-- | sys/dev/pci/pci.c | 31 | ||||
-rw-r--r-- | sys/dev/pci/pci_private.h | 1 |
2 files changed, 31 insertions, 1 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index bea162b..091d02c 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -152,6 +152,7 @@ static device_method_t pci_methods[] = { DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), DEVMETHOD(bus_activate_resource, pci_activate_resource), DEVMETHOD(bus_deactivate_resource, pci_deactivate_resource), + DEVMETHOD(bus_child_detached, pci_child_detached), DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method), DEVMETHOD(bus_child_location_str, pci_child_location_str_method), DEVMETHOD(bus_remap_intr, pci_remap_intr_method), @@ -3489,7 +3490,7 @@ pci_driver_added(device_t dev, driver_t *driver) pci_printf(&dinfo->cfg, "reprobing on driver added\n"); pci_cfg_restore(child, dinfo); if (device_probe_and_attach(child) != 0) - pci_cfg_save(child, dinfo, 1); + pci_child_detached(dev, child); } free(devlist, M_TEMP); } @@ -3804,6 +3805,34 @@ pci_probe_nomatch(device_t dev, device_t child) pci_cfg_save(child, device_get_ivars(child), 1); } +void +pci_child_detached(device_t dev, device_t child) +{ + struct pci_devinfo *dinfo; + struct resource_list *rl; + + dinfo = device_get_ivars(child); + rl = &dinfo->resources; + + /* + * Have to deallocate IRQs before releasing any MSI messages and + * have to release MSI messages before deallocating any memory + * BARs. + */ + if (resource_list_release_active(rl, dev, child, SYS_RES_IRQ) != 0) + pci_printf(&dinfo->cfg, "Device leaked IRQ resources\n"); + if (dinfo->cfg.msi.msi_alloc != 0 || dinfo->cfg.msix.msix_alloc != 0) { + pci_printf(&dinfo->cfg, "Device leaked MSI vectors\n"); + (void)pci_release_msi(child); + } + if (resource_list_release_active(rl, dev, child, SYS_RES_MEMORY) != 0) + pci_printf(&dinfo->cfg, "Device leaked memory resources\n"); + if (resource_list_release_active(rl, dev, child, SYS_RES_IOPORT) != 0) + pci_printf(&dinfo->cfg, "Device leaked I/O resources\n"); + + pci_cfg_save(child, dinfo, 1); +} + /* * Parse the PCI device database, if loaded, and return a pointer to a * description of the device. diff --git a/sys/dev/pci/pci_private.h b/sys/dev/pci/pci_private.h index b4c0c9e..9eb0df0 100644 --- a/sys/dev/pci/pci_private.h +++ b/sys/dev/pci/pci_private.h @@ -106,6 +106,7 @@ struct pci_devinfo *pci_read_device(device_t pcib, int d, int b, int s, int f, size_t size); void pci_print_verbose(struct pci_devinfo *dinfo); int pci_freecfg(struct pci_devinfo *dinfo); +void pci_child_detached(device_t dev, device_t child); int pci_child_location_str_method(device_t cbdev, device_t child, char *buf, size_t buflen); int pci_child_pnpinfo_str_method(device_t cbdev, device_t child, |