acpi: use new work system for uacpi

This commit is contained in:
Matheus
2026-09-09 13:01:24 -03:00
parent 32efe13071
commit abd1e45852
2 changed files with 67 additions and 79 deletions
+1 -1
View File
@@ -42,7 +42,7 @@ void acpi_init(void) {
uacpi_install_fixed_event_handler(UACPI_FIXED_EVENT_POWER_BUTTON, handle_pwrbtn, UACPI_NULL); 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) { int acpi_poweroff(void) {
uacpi_status ret = uacpi_prepare_for_sleep_state(UACPI_SLEEP_STATE_S5); uacpi_status ret = uacpi_prepare_for_sleep_state(UACPI_SLEEP_STATE_S5);
+65 -77
View File
@@ -2,11 +2,13 @@
#include <uacpi/status.h> #include <uacpi/status.h>
#include <uacpi/types.h> #include <uacpi/types.h>
#include <kernel/interrupt.h> #include <kernel/interrupt.h>
#include <kernel/init.h>
#include <kernel/scheduler.h> #include <kernel/scheduler.h>
#include <kernel/alloc.h> #include <kernel/alloc.h>
#include <kernel/page.h> #include <kernel/page.h>
#include <kernel/pci.h> #include <kernel/pci.h>
#include <kernel/timekeeper.h> #include <kernel/timekeeper.h>
#include <kernel/work.h>
#include <arch/cpu.h> #include <arch/cpu.h>
#include <arch/mmu.h> #include <arch/mmu.h>
#include <arch/context.h> #include <arch/context.h>
@@ -348,71 +350,51 @@ uacpi_status uacpi_kernel_uninstall_interrupt_handler(uacpi_interrupt_handler ha
return UACPI_STATUS_UNIMPLEMENTED; return UACPI_STATUS_UNIMPLEMENTED;
} }
#define ACPI_WORK_POOL_SIZE 16
struct acpi_workctx;
struct acpi_work { struct acpi_work {
work_t work;
list_node_t pool_node;
uacpi_work_handler handler; uacpi_work_handler handler;
uacpi_handle ctx; uacpi_handle ctx;
struct acpi_work *next; struct acpi_workctx *workctx;
}; };
struct acpi_workctx { struct acpi_workctx {
semaphore_t sem; work_queue_t *queue;
spinlock_t queuelock; spinlock_t pool_lock;
thread_t *thread; list_t free_list;
struct acpi_work *head; struct acpi_work pool[ACPI_WORK_POOL_SIZE];
bool target_bsp;
}; };
static struct acpi_workctx gpework; static struct acpi_workctx gpework;
static struct acpi_workctx notifywork; static struct acpi_workctx notifywork;
static void acpi_initwork(struct acpi_workctx *ctx, void (*proc)(void)) { static void acpi_dowork(void *context, size_t pending) {
SEMAPHORE_INIT(&ctx->sem, 0); (void)pending;
SPINLOCK_INIT(ctx->queuelock);
ctx->thread = sched_newthread(proc, PAGE_SIZE * 4, 0, NULL, NULL); struct acpi_work *work = context;
__assert(ctx->thread); struct acpi_workctx *workctx = work->workctx;
sched_queue(ctx->thread); uacpi_work_handler handler = work->handler;
} uacpi_handle handler_ctx = work->ctx;
static void acpi_dowork(struct acpi_workctx *ctx) { // no need to untarget later, a workctx that takes this path
for (;;) { // will always run on the bsp
semaphore_wait(&ctx->sem, true); if (workctx->target_bsp)
struct acpi_work *work = NULL;
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); sched_reschedule_on_cpu(get_bsp(), true);
acpi_dowork(&gpework); handler(handler_ctx);
sched_target_cpu(NULL); 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);
static void acpi_donotifywork() {
acpi_dowork(&notifywork);
} }
uacpi_status uacpi_kernel_initialize(uacpi_init_level lvl) { uacpi_status uacpi_kernel_initialize(uacpi_init_level lvl) {
if (lvl != UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED) (void)lvl;
return UACPI_STATUS_OK;
acpi_initwork(&gpework, acpi_dogpework);
acpi_initwork(&notifywork, acpi_donotifywork);
return UACPI_STATUS_OK; return UACPI_STATUS_OK;
} }
@@ -420,16 +402,8 @@ void uacpi_kernel_deinitialize() { }
uacpi_status uacpi_kernel_schedule_work( uacpi_status uacpi_kernel_schedule_work(
uacpi_work_type type, uacpi_work_handler handler, uacpi_handle ctx) { uacpi_work_type type, uacpi_work_handler handler, uacpi_handle ctx) {
struct acpi_work *work;
struct acpi_workctx *workctx; 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) { switch (type) {
case UACPI_WORK_GPE_EXECUTION: case UACPI_WORK_GPE_EXECUTION:
workctx = &gpework; workctx = &gpework;
@@ -439,36 +413,50 @@ uacpi_status uacpi_kernel_schedule_work(
break; break;
} }
bool irqstate = spinlock_acquire_irq_clear(&workctx->queuelock); long old_ipl = spinlock_acquire_raise_ipl(&workctx->pool_lock, IPL_ACPI);
work->next = workctx->head; list_node_t *node = list_pop_front(&workctx->free_list);
workctx->head = work; if (node == NULL) {
spinlock_release_irq_restore(&workctx->queuelock, irqstate); spinlock_release_lower_ipl(&workctx->pool_lock, old_ipl);
return UACPI_STATUS_OUT_OF_MEMORY;
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);
} }
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) { uacpi_status uacpi_kernel_wait_for_work_completion(void) {
work_await(&gpework); work_drain(gpework.queue);
work_await(&notifywork); work_drain(notifywork.queue);
return UACPI_STATUS_OK; 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(&notifywork, "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_status uacpi_kernel_handle_firmware_request(
uacpi_firmware_request *req) { uacpi_firmware_request *req) {
switch (req->type) { switch (req->type) {