--- sys/dev/acpica/Osd/OsdSchedule.c 2026-06-29 12:51:18.000000000 +0000 +++ /tmp/opencode/fix/OsdSchedule.c.new 2026-09-24 06:10:14.853914695 +0000 @@ -73,6 +73,14 @@ struct lwkt_port acpi_afree_rport; /* + * Number of OSD execution callbacks queued to or being run by the ACPI + * helper thread. AcpiOsWaitEventsComplete() blocks until this drops to + * zero so that a driver being unloaded (kldunload) can wait for deferred + * work that references its code to finish before its text is freed. + */ +static volatile int acpi_osd_npending; + +/* * Initialize the ACPI helper thread. */ int @@ -106,7 +114,10 @@ func = at->at_function; func(at->at_context); lwkt_replymsg(&at->at_msg, 0); + atomic_subtract_int(&acpi_osd_npending, 1); + wakeup(&acpi_osd_npending); } + /* NOT REACHED */ lwkt_reltoken(&acpi_token); } @@ -139,11 +150,28 @@ at->at_function = Function; at->at_context = Context; at->at_type = Type; + atomic_add_int(&acpi_osd_npending, 1); lwkt_sendmsg(&acpi_task_td->td_msgport, &at->at_msg); return_ACPI_STATUS (AE_OK); } /* + * Wait until every OSD execution callback queued via AcpiOsExecute() has + * run to completion. Drivers must call this before their code becomes + * unloadable (see acpi_dock_detach()), since callbacks queued by ACPICA + * (deferred notifies, GPE bottom halves, driver AcpiOsExecute() work such + * as acpi_dock's attach_later) otherwise keep raw pointers into driver + * text that kldunload frees. + */ +void +AcpiOsWaitEventsComplete(void) +{ + + while (acpi_osd_npending > 0) + tsleep(&acpi_osd_npending, 0, "acpievt", hz); +} + +/* * The message's reply port just frees the message. */ static void --- sys/dev/acpica/acpi_dock/acpi_dock.c 2026-06-29 12:51:18.000000000 +0000 +++ /tmp/opencode/fix/acpi_dock.c.new 2026-09-24 06:25:20.678077247 +0000 @@ -525,8 +525,21 @@ acpi_dock_detach(device_t dev) { struct acpi_dock_softc *sc; + ACPI_HANDLE h; sc = device_get_softc(dev); + h = acpi_get_handle(dev); + + /* + * Remove the notify handler and wait for all deferred ACPI work that + * may still reference this driver (queued notifications and the + * AcpiOsExecute(acpi_dock_attach_later) callbacks queued by + * acpi_dock_insert_children()) to drain before the module text is + * freed by kldunload. + */ + AcpiRemoveNotifyHandler(h, ACPI_ALL_NOTIFY, acpi_dock_notify_handler); + AcpiOsWaitEventsComplete(); + sysctl_ctx_free(&sc->sysctl_ctx); return (0); --- sys/contrib/dev/acpica/source/include/platform/acdragonfly.h 2026-06-29 12:51:18.000000000 +0000 +++ /tmp/opencode/fix/acdragonfly.h.new 2026-09-24 06:19:52.526359042 +0000 @@ -215,10 +215,6 @@ _AcpiOsUnmapMemory((LogicalAddress), (Size), __func__, __LINE__) #endif -/* XXX TBI */ -#define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsWaitEventsComplete -#define AcpiOsWaitEventsComplete() - #define USE_NATIVE_ALLOCATE_ZEROED #define ACPI_SPINLOCK struct acpi_spinlock *