From abd1e458529af582e45d31584305e6eef1e58451 Mon Sep 17 00:00:00 2001 From: Matheus Date: Wed, 9 Sep 2026 13:01:24 -0300 Subject: [PATCH] acpi: use new work system for uacpi --- kernel-src/io/acpi/acpi.c | 2 +- kernel-src/io/acpi/glue.c | 144 +++++++++++++++++--------------------- 2 files changed, 67 insertions(+), 79 deletions(-) diff --git a/kernel-src/io/acpi/acpi.c b/kernel-src/io/acpi/acpi.c index db193524..2df85c2f 100644 --- a/kernel-src/io/acpi/acpi.c +++ b/kernel-src/io/acpi/acpi.c @@ -42,7 +42,7 @@ void acpi_init(void) { uacpi_install_fixed_event_handler(UACPI_FIXED_EVENT_POWER_BUTTON, handle_pwrbtn, UACPI_NULL); } -INIT_ROUTINE_DEFINE(acpi, INIT_ROUTINE_FLAGS_NONE, acpi_init, pci, devfs, scheduler); +INIT_ROUTINE_DEFINE(acpi, INIT_ROUTINE_FLAGS_NONE, acpi_init, pci, devfs, scheduler, acpi_work); int acpi_poweroff(void) { uacpi_status ret = uacpi_prepare_for_sleep_state(UACPI_SLEEP_STATE_S5); diff --git a/kernel-src/io/acpi/glue.c b/kernel-src/io/acpi/glue.c index 5497898a..186e44f4 100644 --- a/kernel-src/io/acpi/glue.c +++ b/kernel-src/io/acpi/glue.c @@ -2,11 +2,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -348,71 +350,51 @@ uacpi_status uacpi_kernel_uninstall_interrupt_handler(uacpi_interrupt_handler ha return UACPI_STATUS_UNIMPLEMENTED; } +#define ACPI_WORK_POOL_SIZE 16 + +struct acpi_workctx; + struct acpi_work { + work_t work; + list_node_t pool_node; uacpi_work_handler handler; uacpi_handle ctx; - struct acpi_work *next; + struct acpi_workctx *workctx; }; struct acpi_workctx { - semaphore_t sem; - spinlock_t queuelock; - thread_t *thread; - struct acpi_work *head; + work_queue_t *queue; + spinlock_t pool_lock; + list_t free_list; + struct acpi_work pool[ACPI_WORK_POOL_SIZE]; + bool target_bsp; }; static struct acpi_workctx gpework; static struct acpi_workctx notifywork; -static void acpi_initwork(struct acpi_workctx *ctx, void (*proc)(void)) { - SEMAPHORE_INIT(&ctx->sem, 0); - SPINLOCK_INIT(ctx->queuelock); +static void acpi_dowork(void *context, size_t pending) { + (void)pending; - ctx->thread = sched_newthread(proc, PAGE_SIZE * 4, 0, NULL, NULL); - __assert(ctx->thread); - sched_queue(ctx->thread); -} + struct acpi_work *work = context; + struct acpi_workctx *workctx = work->workctx; + uacpi_work_handler handler = work->handler; + uacpi_handle handler_ctx = work->ctx; -static void acpi_dowork(struct acpi_workctx *ctx) { - for (;;) { - semaphore_wait(&ctx->sem, true); + // no need to untarget later, a workctx that takes this path + // will always run on the bsp + if (workctx->target_bsp) + sched_reschedule_on_cpu(get_bsp(), true); - struct acpi_work *work = NULL; + handler(handler_ctx); - bool irqstate = spinlock_acquire_irq_clear(&ctx->queuelock); - if (ctx->head) { - work = ctx->head; - ctx->head = work->next; - } - spinlock_release_irq_restore(&ctx->queuelock, irqstate); - - if (work == NULL) - continue; - - work->handler(work->ctx); - free(work); - } -} - -static void acpi_dogpework() { - sched_reschedule_on_cpu(get_bsp(), true); - - acpi_dowork(&gpework); - - sched_target_cpu(NULL); -} - -static void acpi_donotifywork() { - acpi_dowork(¬ifywork); + long old_ipl = spinlock_acquire_raise_ipl(&workctx->pool_lock, IPL_ACPI); + list_push_back(&workctx->free_list, &work->pool_node); + spinlock_release_lower_ipl(&workctx->pool_lock, old_ipl); } uacpi_status uacpi_kernel_initialize(uacpi_init_level lvl) { - if (lvl != UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED) - return UACPI_STATUS_OK; - - acpi_initwork(&gpework, acpi_dogpework); - acpi_initwork(¬ifywork, acpi_donotifywork); - + (void)lvl; return UACPI_STATUS_OK; } @@ -420,16 +402,8 @@ void uacpi_kernel_deinitialize() { } uacpi_status uacpi_kernel_schedule_work( uacpi_work_type type, uacpi_work_handler handler, uacpi_handle ctx) { - struct acpi_work *work; struct acpi_workctx *workctx; - work = alloc(sizeof(*work)); - if (work == NULL) - return UACPI_STATUS_OUT_OF_MEMORY; - - work->ctx = ctx; - work->handler = handler; - switch (type) { case UACPI_WORK_GPE_EXECUTION: workctx = &gpework; @@ -439,36 +413,50 @@ uacpi_status uacpi_kernel_schedule_work( break; } - bool irqstate = spinlock_acquire_irq_clear(&workctx->queuelock); - work->next = workctx->head; - workctx->head = work; - spinlock_release_irq_restore(&workctx->queuelock, irqstate); - - semaphore_signal(&workctx->sem); - return UACPI_STATUS_OK; -} - -static void work_await(struct acpi_workctx *ctx) { - for (;;) { - bool empty; - - bool irqstate = spinlock_acquire_irq_clear(&ctx->queuelock); - empty = ctx->head == NULL; - spinlock_release_irq_restore(&ctx->queuelock, irqstate); - - if (empty) - return; - - sched_sleep_us(100 * 1000); + long old_ipl = spinlock_acquire_raise_ipl(&workctx->pool_lock, IPL_ACPI); + list_node_t *node = list_pop_front(&workctx->free_list); + if (node == NULL) { + spinlock_release_lower_ipl(&workctx->pool_lock, old_ipl); + return UACPI_STATUS_OUT_OF_MEMORY; } + + struct acpi_work *work = container_of(node, struct acpi_work, pool_node); + work->handler = handler; + work->ctx = ctx; + spinlock_release_lower_ipl(&workctx->pool_lock, old_ipl); + + work_enqueue(workctx->queue, &work->work); + return UACPI_STATUS_OK; } uacpi_status uacpi_kernel_wait_for_work_completion(void) { - work_await(&gpework); - work_await(¬ifywork); + work_drain(gpework.queue); + work_drain(notifywork.queue); return UACPI_STATUS_OK; } +static void acpi_initwork(struct acpi_workctx *workctx, const char *name, bool target_bsp) { + SPINLOCK_INIT(workctx->pool_lock); + list_init(&workctx->free_list); + workctx->target_bsp = target_bsp; + workctx->queue = work_queue_create(name, 1, IPL_ACPI); + __assert(workctx->queue); + + for (size_t i = 0; i < ACPI_WORK_POOL_SIZE; ++i) { + struct acpi_work *work = &workctx->pool[i]; + WORK_INIT(&work->work, acpi_dowork, work); + work->workctx = workctx; + list_push_back(&workctx->free_list, &work->pool_node); + } +} + +static void acpi_work_init(void) { + acpi_initwork(&gpework, "acpi-gpe", true); + acpi_initwork(¬ifywork, "acpi-notify", false); +} + +INIT_ROUTINE_DEFINE(acpi_work, INIT_ROUTINE_FLAGS_NONE, acpi_work_init, work_queue); + uacpi_status uacpi_kernel_handle_firmware_request( uacpi_firmware_request *req) { switch (req->type) {