From b8ecf7075b96b281ff837cf3612316733a6f7dbf Mon Sep 17 00:00:00 2001 From: Pawel Wieczorkiewicz Date: Fri, 6 Aug 2021 13:21:56 +0200 Subject: [PATCH] acpica: add interrupt handling functionality to OSL Signed-off-by: Pawel Wieczorkiewicz --- arch/x86/entry.S | 5 +++- drivers/acpi/acpica/osl.c | 63 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/arch/x86/entry.S b/arch/x86/entry.S index 6b508885..63a93f3f 100644 --- a/arch/x86/entry.S +++ b/arch/x86/entry.S @@ -93,6 +93,9 @@ END_FUNC(handle_exception) interrupt_handler timer timer_interrupt_handler interrupt_handler uart uart_interrupt_handler interrupt_handler keyboard keyboard_interrupt_handler +#ifdef KTF_ACPICA +interrupt_handler acpi acpi_interrupt_handler +#endif ENTRY(usermode_call_asm) /* FIXME: Add 32-bit support */ @@ -142,4 +145,4 @@ ENTRY(rmode_exception) .Lhalt_loop: hlt jmp .Lhalt_loop -END_FUNC(rmode_exception) \ No newline at end of file +END_FUNC(rmode_exception) diff --git a/drivers/acpi/acpica/osl.c b/drivers/acpi/acpica/osl.c index 19f74261..2ea008b3 100644 --- a/drivers/acpi/acpica/osl.c +++ b/drivers/acpi/acpica/osl.c @@ -25,8 +25,10 @@ #ifdef KTF_ACPICA #include #include +#include #include #include +#include #include #include #include @@ -365,4 +367,65 @@ UINT64 AcpiOsGetTimer(void) { return get_timer_ticks(); } /* FIXME: Use microseconds granularity */ void AcpiOsStall(UINT32 Microseconds) { msleep(1); } + +/* ACPI interrupt handling functions */ + +extern void asm_interrupt_handler_acpi(void); +static bool acpi_irq_installed = false; +static uint32_t acpi_irq_num; +static ACPI_OSD_HANDLER acpi_irq_handler = NULL; +static void *acpi_irq_context = NULL; +static bool acpi_irq_handled = false; + +void acpi_interrupt_handler(void) { + uint32_t ret = acpi_irq_handler(acpi_irq_context); + + if (ret == ACPI_INTERRUPT_HANDLED) + acpi_irq_handled = true; + else if (ret == ACPI_INTERRUPT_NOT_HANDLED) + acpi_irq_handled = false; +} + +ACPI_STATUS AcpiOsInstallInterruptHandler(UINT32 InterruptLevel, ACPI_OSD_HANDLER Handler, + void *Context) { + percpu_t *percpu = get_percpu_page(get_bsp_cpu_id()); + + if (acpi_irq_installed) + return AE_ALREADY_EXISTS; + + if (!Handler || InterruptLevel > ARRAY_SIZE(idt)) + return AE_BAD_PARAMETER; + + acpi_irq_num = InterruptLevel; + acpi_irq_handler = Handler; + acpi_irq_context = Context; + + set_intr_gate(&percpu->idt[acpi_irq_num], __KERN_CS, _ul(asm_interrupt_handler_acpi), + GATE_DPL0, GATE_PRESENT, 1); + barrier(); + + acpi_irq_installed = true; + return AE_OK; +} + +ACPI_STATUS AcpiOsRemoveInterruptHandler(UINT32 InterruptLevel, + ACPI_OSD_HANDLER Handler) { + percpu_t *percpu = get_percpu_page(get_bsp_cpu_id()); + + if (!acpi_irq_installed) + return AE_NOT_EXIST; + + if (!Handler || InterruptLevel > ARRAY_SIZE(idt) || InterruptLevel != acpi_irq_num) + return AE_BAD_PARAMETER; + + if (Handler != _ptr(get_intr_handler(&percpu->idt[acpi_irq_num]))) + return AE_BAD_PARAMETER; + + set_intr_gate(&percpu->idt[acpi_irq_num], __KERN_CS, _ul(NULL), GATE_DPL0, + GATE_NOT_PRESENT, 0); + barrier(); + + acpi_irq_installed = false; + return AE_OK; +} #endif /* KTF_ACPICA */