mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
acpi: use new work system for uacpi
This commit is contained in:
@@ -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);
|
||||
|
||||
+66
-78
@@ -2,11 +2,13 @@
|
||||
#include <uacpi/status.h>
|
||||
#include <uacpi/types.h>
|
||||
#include <kernel/interrupt.h>
|
||||
#include <kernel/init.h>
|
||||
#include <kernel/scheduler.h>
|
||||
#include <kernel/alloc.h>
|
||||
#include <kernel/page.h>
|
||||
#include <kernel/pci.h>
|
||||
#include <kernel/timekeeper.h>
|
||||
#include <kernel/work.h>
|
||||
#include <arch/cpu.h>
|
||||
#include <arch/mmu.h>
|
||||
#include <arch/context.h>
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user