From c1207dc20cfb10830a48d20d77f7a913d7a96029 Mon Sep 17 00:00:00 2001 From: jhb Date: Thu, 27 Jun 2013 20:21:54 +0000 Subject: 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 --- sys/kern/subr_bus.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'sys/kern/subr_bus.c') diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c index 1d45f28..f196c8b 100644 --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -3316,6 +3316,48 @@ resource_list_release(struct resource_list *rl, device_t bus, device_t child, } /** + * @brief Release all active resources of a given type + * + * Release all active resources of a specified type. This is intended + * to be used to cleanup resources leaked by a driver after detach or + * a failed attach. + * + * @param rl the resource list which was allocated from + * @param bus the parent device of @p child + * @param child the device whose active resources are being released + * @param type the type of resources to release + * + * @retval 0 success + * @retval EBUSY at least one resource was active + */ +int +resource_list_release_active(struct resource_list *rl, device_t bus, + device_t child, int type) +{ + struct resource_list_entry *rle; + int error, retval; + + retval = 0; + STAILQ_FOREACH(rle, rl, link) { + if (rle->type != type) + continue; + if (rle->res == NULL) + continue; + if ((rle->flags & (RLE_RESERVED | RLE_ALLOCATED)) == + RLE_RESERVED) + continue; + retval = EBUSY; + error = resource_list_release(rl, bus, child, type, + rman_get_rid(rle->res), rle->res); + if (error != 0) + device_printf(bus, + "Failed to release active resource: %d\n", error); + } + return (retval); +} + + +/** * @brief Fully release a reserved resource * * Fully releases a resource reserved via resource_list_reserve(). -- cgit v1.1