fix.diff for DF-4410 — quiesce pending acpi_asus_led_task work before destroying the LEDs/softc in detach (dying flag + outstanding counter + wait). Authored against the read-only sys/ tree; never applied there. fix_status: not_testable (no ATK0100/ASUS010 firmware and no /dev/led on the audit guest; see env.txt). --- a/sys/dev/acpica/acpi_asus/acpi_asus.c +++ b/sys/dev/acpica/acpi_asus/acpi_asus.c @@ -116,6 +116,11 @@ struct acpi_asus_softc { device_t dev; ACPI_HANDLE handle; ACPI_HANDLE lcdd_handle; + + struct lock led_lock; + int led_dying; /* no new tasks once set */ + int led_pending; /* outstanding acpi_asus_led_task */ struct acpi_asus_model *model; @@ -732,6 +737,8 @@ sc = device_get_softc(dev); acpi_sc = acpi_device_get_parent_softc(dev); + lockinit(&sc->led_lock, "asus led", 0, 0); + /* Build sysctl tree */ sysctl_ctx_init(&sc->sysctl_ctx); @@ -838,6 +845,18 @@ ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); sc = device_get_softc(dev); + + /* Stop new LED tasks and drain pending ones before freeing anything + * they touch (ledsc via led_destroy, softc via newbus). */ + lockmgr(&sc->led_lock, LK_EXCLUSIVE); + sc->led_dying = 1; + while (sc->led_pending > 0) + lksleep(&sc->led_pending, &sc->led_lock, 0, "asusled", hz); + lockmgr(&sc->led_lock, LK_RELEASE); + /* Turn the lights off */ if (sc->model->bled_set) led_destroy(sc->s_bled.cdev); @@ -871,6 +890,8 @@ /* Free sysctl tree */ sysctl_ctx_free(&sc->sysctl_ctx); + lockuninit(&sc->led_lock); + return (0); } static void acpi_asus_led_task(struct acpi_asus_led *led, int pending __unused) @@ -916,7 +937,13 @@ default: kprintf("acpi_asus_led: invalid LED type %d\n", (int)led->type); - return; + goto out; } acpi_SetInteger(sc->handle, method, state); +out: led->busy = 0; + lockmgr(&sc->led_lock, LK_EXCLUSIVE); + sc->led_pending--; + if (sc->led_pending == 0) + wakeup(&sc->led_pending); + lockmgr(&sc->led_lock, LK_RELEASE); } static void acpi_asus_led(struct acpi_asus_led *led, int state) @@ -926,9 +953,15 @@ sc = led->sc; + lockmgr(&sc->led_lock, LK_EXCLUSIVE); if (led->busy) - return; + goto out; led->busy = 1; led->state = state; + sc->led_pending++; - AcpiOsExecute(OSL_NOTIFY_HANDLER, (void *)acpi_asus_led_task, led); + if (AcpiOsExecute(OSL_NOTIFY_HANDLER, (void *)acpi_asus_led_task, + led) != AE_OK) { + led->busy = 0; + sc->led_pending--; + } +out: + lockmgr(&sc->led_lock, LK_RELEASE); }