diff --git a/sys/dev/acpica/acpi_cpu.c b/sys/dev/acpica/acpi_cpu.c index 1111111..2222222 100644 --- a/sys/dev/acpica/acpi_cpu.c +++ b/sys/dev/acpica/acpi_cpu.c @@ -48,6 +48,7 @@ static int acpi_cpu_probe(device_t dev); static int acpi_cpu_attach(device_t dev); static struct resource_list * acpi_cpu_get_rlist(device_t, device_t); +static int acpi_cpu_detach(device_t dev); static struct resource * acpi_cpu_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int, int); @@ -64,7 +65,7 @@ static device_method_t acpi_cpu_methods[] = { /* Device interface */ DEVMETHOD(device_probe, acpi_cpu_probe), DEVMETHOD(device_attach, acpi_cpu_attach), - DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_detach, acpi_cpu_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), @@ -235,14 +236,19 @@ acpi_cpu_attach(device_t dev) child = BUS_ADD_CHILD(dev, dev, 0, "cpu_cst", -1); if (child == NULL) - return ENXIO; + goto fail; acpi_set_handle(child, handle); acpi_set_magic(child, cpu_id); sc->cpu_cst = child; child = BUS_ADD_CHILD(dev, dev, 0, "cpu_pst", -1); if (child == NULL) - return ENXIO; + goto fail_cst; acpi_set_handle(child, handle); acpi_set_magic(child, cpu_id); sc->cpu_pst = child; @@ -254,6 +260,33 @@ acpi_cpu_attach(device_t dev) AcpiInstallNotifyHandler(handle, ACPI_DEVICE_NOTIFY, acpi_cpu_notify, sc); return 0; + +fail_cst: + device_delete_child(dev, sc->cpu_cst); +fail: + sysctl_ctx_free(&sc->pcpu_sysctl_ctx); + if (sc->glob_sysctl_tree != NULL) /* only cpu_id == 0 created it */ + sysctl_ctx_free(&sc->glob_sysctl_ctx); + sensordev_deinstall(&sc->cpu_sensdev); + return ENXIO; +} + +static int +acpi_cpu_detach(device_t dev) +{ + struct acpi_cpu_softc *sc = device_get_softc(dev); + int error; + + /* Stop ACPI notifies first: they call into the children through + * sc->cpu_cst_notify / sc->cpu_pst_notify, which the children set at + * attach and never clear. */ + AcpiRemoveNotifyHandler(acpi_get_handle(dev), ACPI_DEVICE_NOTIFY, + acpi_cpu_notify); + + /* Detach children (cpu_cst / cpu_pst); they added sysctl handlers to + * our contexts, so free the contexts only after they are gone. */ + error = bus_generic_detach(dev); + if (error) + return (error); + + sysctl_ctx_free(&sc->pcpu_sysctl_ctx); + if (sc->glob_sysctl_tree != NULL) + sysctl_ctx_free(&sc->glob_sysctl_ctx); + sensordev_deinstall(&sc->cpu_sensdev); + + return (0); } /*