From c5bdc1ccbe257e2065145a447a51b79bd69ef682 Mon Sep 17 00:00:00 2001 From: Christian Helmuth Date: Fri, 1 Jul 2022 17:10:57 +0200 Subject: [PATCH] acpica: configure SCI IRQ mode Issue #4553 --- repos/libports/run/acpica.run | 38 +++++++++++-- repos/libports/src/app/acpica/ec.h | 2 +- repos/libports/src/app/acpica/os.cc | 76 ++++++++++++++++++++++++- repos/libports/src/app/acpica/report.cc | 13 +---- repos/libports/src/app/acpica/util.h | 20 +++++++ 5 files changed, 128 insertions(+), 21 deletions(-) diff --git a/repos/libports/run/acpica.run b/repos/libports/run/acpica.run index cf75822097..9cc8fdcbaf 100644 --- a/repos/libports/run/acpica.run +++ b/repos/libports/run/acpica.run @@ -72,8 +72,8 @@ set config { } append_if [expr !$use_acpica_as_acpi_drv] config { - - + + @@ -178,9 +178,9 @@ append config { - - - + + + @@ -225,4 +225,30 @@ build_boot_image $boot_modules append qemu_args "-nographic " -run_genode_until {\[init -\> acpi.*SCI IRQ:.*\n} 30 +if {![have_include "power_on/qemu"]} { + run_genode_until {\[init -\> acpi.*SCI IRQ:.*\n} 30 + exit 0 +} + +run_genode_until {.*PS2 uses IRQ, vector 0xc.*} 30 + +set spawn_id $qemu_spawn_id + +sleep 1 + +# send Ctrl-a+c to enter Qemu's monitor mode +send "\x01\x63" + +# wait for monitor to become ready +run_genode_until {(qemu)} 20 $spawn_id + + +for {set i 0} {$i < 3} {incr i} { + + sleep 1 + send "system_powerdown\n" + run_genode_until {.*key count: 0.*} 3 $spawn_id +} + +puts "\nTest succeeded\n" +exit 0 diff --git a/repos/libports/src/app/acpica/ec.h b/repos/libports/src/app/acpica/ec.h index dfb42406a4..173568cbac 100644 --- a/repos/libports/src/app/acpica/ec.h +++ b/repos/libports/src/app/acpica/ec.h @@ -81,7 +81,7 @@ class Ec : Acpica::Callback { State::access_t state = ec->ec_cmdsta->inb(ec->ec_port_cmdsta); if (!State::Sci_evt::get(state)) { - Genode::error("unknown status ", Genode::Hex(state)); + Genode::error("unknown status ", Genode::Hex(state)); return ACPI_REENABLE_GPE; /* gpe is acked and re-enabled */ } diff --git a/repos/libports/src/app/acpica/os.cc b/repos/libports/src/app/acpica/os.cc index 2737c79d35..142b703bab 100644 --- a/repos/libports/src/app/acpica/os.cc +++ b/repos/libports/src/app/acpica/os.cc @@ -116,6 +116,9 @@ struct Acpica::Main static struct Irq_handler { UINT32 irq; + Genode::Irq_session::Trigger trigger; + Genode::Irq_session::Polarity polarity; + ACPI_OSD_HANDLER handler; void *context; } irq_handler; @@ -152,9 +155,10 @@ struct Acpica::Main return; } - sci_conn.construct(env, irq_handler.irq); + sci_conn.construct(env, irq_handler.irq, irq_handler.trigger, irq_handler.polarity); - Genode::log("SCI IRQ: ", irq_handler.irq); + Genode::log("SCI IRQ: ", irq_handler.irq, + " (", irq_handler.trigger, "-", irq_handler.polarity, ")"); sci_conn->sigh(sci_irq); sci_conn->ack_irq(); @@ -276,6 +280,67 @@ void Acpica::Main::init_acpica(Wait_acpi_ready wait_acpi_ready, return; } + { + using Genode::Irq_session; + + /* + * ACPI Spec 2.1 General ACPI Terminology + * + * System Control Interrupt (SCI) A system interrupt used by hardware + * to notify the OS of ACPI events. The SCI is an active, low, + * shareable, level interrupt. + */ + irq_handler.irq = AcpiGbl_FADT.SciInterrupt; + irq_handler.trigger = Irq_session::TRIGGER_LEVEL; + irq_handler.polarity = Irq_session::POLARITY_LOW; + + /* apply potential override in MADT */ + ACPI_TABLE_MADT *madt = nullptr; + + ACPI_STATUS status = AcpiGetTable(ACPI_STRING(ACPI_SIG_MADT), 0, (ACPI_TABLE_HEADER **)&madt); + if (status == AE_OK) { + using Genode::String; + + for_each_element(madt, (ACPI_SUBTABLE_HEADER *) nullptr, + [&](ACPI_SUBTABLE_HEADER const * const s) { + + if (s->Type != ACPI_MADT_TYPE_INTERRUPT_OVERRIDE) + return; + + ACPI_MADT_INTERRUPT_OVERRIDE const * const irq = + reinterpret_cast(s); + + auto polarity_from_flags = [] (UINT16 flags) { + switch (flags & 0b11) { + case 0b01: return Irq_session::POLARITY_HIGH; + case 0b11: return Irq_session::POLARITY_LOW; + case 0b00: + default: + return Irq_session::POLARITY_UNCHANGED; + } + }; + + auto trigger_from_flags = [] (UINT16 flags) { + switch ((flags & 0b1100) >> 2) { + case 0b01: return Irq_session::TRIGGER_EDGE; + case 0b11: return Irq_session::TRIGGER_LEVEL; + case 0b00: + default: + return Irq_session::TRIGGER_UNCHANGED; + } + }; + + if (irq->SourceIrq == AcpiGbl_FADT.SciInterrupt) { + irq_handler.irq = irq->GlobalIrq; + irq_handler.trigger = trigger_from_flags(irq->IntiFlags); + irq_handler.polarity = polarity_from_flags(irq->IntiFlags); + + AcpiGbl_FADT.SciInterrupt = irq->GlobalIrq; + } + }, [](ACPI_SUBTABLE_HEADER const * const s) { return s->Length; }); + } + } + status = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION); if (status != AE_OK) { Genode::error("AcpiEnableSubsystem failed, status=", status); @@ -398,7 +463,12 @@ struct Acpica::Main::Irq_handler Acpica::Main::irq_handler; ACPI_STATUS AcpiOsInstallInterruptHandler(UINT32 irq, ACPI_OSD_HANDLER handler, void *context) { - Acpica::Main::irq_handler.irq = irq; + if (irq != Acpica::Main::irq_handler.irq) { + Genode::error("SCI interrupt is ", Acpica::Main::irq_handler.irq, + " but library requested ", irq); + return AE_BAD_PARAMETER; + } + Acpica::Main::irq_handler.handler = handler; Acpica::Main::irq_handler.context = context; return AE_OK; diff --git a/repos/libports/src/app/acpica/report.cc b/repos/libports/src/app/acpica/report.cc index b737d155e6..7c08622d75 100644 --- a/repos/libports/src/app/acpica/report.cc +++ b/repos/libports/src/app/acpica/report.cc @@ -16,21 +16,12 @@ #include "util.h" #include "bridge.h" +using namespace Acpica; + using Genode::Reporter; extern void AcpiGenodeFreeIOMem(ACPI_PHYSICAL_ADDRESS const phys, ACPI_SIZE const size); -template -void for_each_element(H const head, S *, F const &fn, FSIZE const &fn_size) -{ - for(S const * e = reinterpret_cast(head + 1); - e < reinterpret_cast(reinterpret_cast(head) + head->Header.Length); - e = reinterpret_cast(reinterpret_cast(e) + fn_size(e))) - { - fn(e); - } -} - static void add_madt(ACPI_TABLE_MADT const * const madt, Reporter::Xml_generator &xml) { diff --git a/repos/libports/src/app/acpica/util.h b/repos/libports/src/app/acpica/util.h index 578f82e1a6..40643e68c9 100644 --- a/repos/libports/src/app/acpica/util.h +++ b/repos/libports/src/app/acpica/util.h @@ -10,6 +10,9 @@ * under the terms of the GNU Affero General Public License version 3. */ +#ifndef _ACPICA__UTIL_H_ +#define _ACPICA__UTIL_H_ + extern "C" { #include "acpi.h" } @@ -20,6 +23,9 @@ namespace Acpica { template class Buffer; template class Callback; void generate_report(Genode::Env &, Bridge *); + + template + void for_each_element(H const head, S *, F const &fn, FSIZE const &fn_size); } template @@ -48,3 +54,17 @@ class Acpica::Callback : public Genode::List >::Element reinterpret_cast(this)->generate(xml); } }; + + +template +void Acpica::for_each_element(H const head, S *, F const &fn, FSIZE const &fn_size) +{ + for(S const * e = reinterpret_cast(head + 1); + e < reinterpret_cast(reinterpret_cast(head) + head->Header.Length); + e = reinterpret_cast(reinterpret_cast(e) + fn_size(e))) + { + fn(e); + } +} + +#endif /* _ACPICA__UTIL_H_ */