Index: sys/dev/acpica/acpi_pcib_pci.c =================================================================== --- sys/dev/acpica/acpi_pcib_pci.c +++ sys/dev/acpica/acpi_pcib_pci.c @@ -66,6 +66,7 @@ static int acpi_pcib_pci_probe(device_t bus); static int acpi_pcib_pci_attach(device_t bus); +static int acpi_pcib_pci_detach(device_t bus); static int acpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result); static int acpi_pcib_pci_route_interrupt(device_t pcib, @@ -75,6 +76,7 @@ /* Device interface */ DEVMETHOD(device_probe, acpi_pcib_pci_probe), DEVMETHOD(device_attach, acpi_pcib_pci_attach), + DEVMETHOD(device_detach, acpi_pcib_pci_detach), /* Bus interface */ DEVMETHOD(bus_read_ivar, acpi_pcib_read_ivar), @@ -127,6 +129,21 @@ } static int +acpi_pcib_pci_detach(device_t dev) +{ + struct acpi_pcib_softc *sc; + int error; + + ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); + + sc = device_get_softc(dev); + error = pcib_detach(dev); + if (error == 0) + AcpiOsFree(sc->ap_prt.Pointer); + return (error); +} + +static int acpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { struct acpi_pcib_softc *sc = device_get_softc(dev); Index: sys/dev/pccbb/pccbb_pci.c =================================================================== --- sys/dev/pccbb/pccbb_pci.c +++ sys/dev/pccbb/pccbb_pci.c @@ -435,6 +435,22 @@ return (ENOMEM); } +static int +cbb_pci_detach(device_t brdev) +{ +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) + struct cbb_softc *sc = device_get_softc(brdev); +#endif + int error; + + error = cbb_detach(brdev); +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) + if (error == 0) + pcib_free_secbus(brdev, &sc->bus); +#endif + return (error); +} + static void cbb_chipinit(struct cbb_softc *sc) { @@ -917,7 +933,7 @@ /* Device interface */ DEVMETHOD(device_probe, cbb_pci_probe), DEVMETHOD(device_attach, cbb_pci_attach), - DEVMETHOD(device_detach, cbb_detach), + DEVMETHOD(device_detach, cbb_pci_detach), DEVMETHOD(device_shutdown, cbb_pci_shutdown), DEVMETHOD(device_suspend, cbb_pci_suspend), DEVMETHOD(device_resume, cbb_pci_resume), Index: sys/dev/pci/pci_pci.c =================================================================== --- sys/dev/pci/pci_pci.c +++ sys/dev/pci/pci_pci.c @@ -80,7 +80,7 @@ /* Device interface */ DEVMETHOD(device_probe, pcib_probe), DEVMETHOD(device_attach, pcib_attach), - DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_detach, pcib_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, pcib_suspend), DEVMETHOD(device_resume, pcib_resume), @@ -543,6 +543,42 @@ } } +static void +pcib_release_window(struct pcib_softc *sc, struct pcib_window *w, int type) +{ + device_t dev; + int error, i; + + if (!w->valid) + return; + + dev = sc->dev; + error = rman_fini(&w->rman); + if (error) { + device_printf(dev, "failed to release %s rman\n", w->name); + return; + } + free(__DECONST(char *, w->rman.rm_descr), M_DEVBUF); + + for (i = 0; i < w->count; i++) { + error = bus_free_resource(dev, type, w->res[i]); + if (error) + device_printf(dev, + "failed to release %s resource: %d\n", w->name, + error); + } + free(w->res, M_DEVBUF); +} + +static void +pcib_free_windows(struct pcib_softc *sc) +{ + + pcib_release_window(sc, &sc->pmem, SYS_RES_MEMORY); + pcib_release_window(sc, &sc->mem, SYS_RES_MEMORY); + pcib_release_window(sc, &sc->io, SYS_RES_IOPORT); +} + #ifdef PCI_RES_BUS /* * Allocate a suitable secondary bus for this bridge if needed and @@ -617,6 +653,24 @@ } } +void +pcib_free_secbus(device_t dev, struct pcib_secbus *bus) +{ + int error; + + error = rman_fini(&bus->rman); + if (error) { + device_printf(dev, "failed to release bus number rman\n"); + return; + } + free(__DECONST(char *, bus->rman.rm_descr), M_DEVBUF); + + error = bus_free_resource(dev, PCI_RES_BUS, bus->res); + if (error) + device_printf(dev, + "failed to release bus numbers resource: %d\n", error); +} + static struct resource * pcib_suballoc_bus(struct pcib_secbus *bus, device_t child, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) @@ -1263,6 +1317,22 @@ return (0); } +static int +pcib_release_pcie_irq(struct pcib_softc *sc) +{ + device_t dev; + int error; + + dev = sc->dev; + error = bus_teardown_intr(dev, sc->pcie_irq, sc->pcie_ihand); + if (error) + return (error); + error = bus_free_resource(dev, SYS_RES_IRQ, sc->pcie_irq); + if (error) + return (error); + return (pci_release_msi(dev)); +} + static void pcib_setup_hotplug(struct pcib_softc *sc) { @@ -1306,6 +1376,21 @@ pcib_pcie_hotplug_update(sc, val, mask, false); } + +static int +pcib_detach_hotplug(struct pcib_softc *sc) +{ + int error; + + error = pcib_release_pcie_irq(sc); + if (error) + return (error); + taskqueue_drain(taskqueue_thread, &sc->pcie_hp_task); + callout_drain(&sc->pcie_ab_timer); + callout_drain(&sc->pcie_cc_timer); + callout_drain(&sc->pcie_dll_timer); + return (0); +} #endif /* @@ -1592,6 +1677,39 @@ } int +pcib_detach(device_t dev) +{ +#if defined(PCI_HP) || defined(NEW_PCIB) + struct pcib_softc *sc; +#endif + int error; + +#if defined(PCI_HP) || defined(NEW_PCIB) + sc = device_get_softc(dev); +#endif + error = bus_generic_detach(dev); + if (error) + return (error); +#ifdef PCI_HP + if (sc->flags & PCIB_HOTPLUG) { + error = pcib_detach_hotplug(sc); + if (error) + return (error); + } +#endif + error = device_delete_children(dev); + if (error) + return (error); +#ifdef NEW_PCIB + pcib_free_windows(sc); +#ifdef PCI_RES_BUS + pcib_free_secbus(dev, &sc->bus); +#endif +#endif + return (0); +} + +int pcib_suspend(device_t dev) { Index: sys/dev/pci/pcib_private.h =================================================================== --- sys/dev/pci/pcib_private.h +++ sys/dev/pci/pcib_private.h @@ -160,6 +160,7 @@ struct resource *pcib_alloc_subbus(struct pcib_secbus *bus, device_t child, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags); +void pcib_free_secbus(device_t dev, struct pcib_secbus *bus); void pcib_setup_secbus(device_t dev, struct pcib_secbus *bus, int min_count); #endif @@ -171,6 +172,7 @@ const char *pcib_child_name(device_t child); #endif int pcib_child_present(device_t dev, device_t child); +int pcib_detach(device_t dev); int pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result); int pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value); struct resource *pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,