acpica: configure SCI IRQ mode

Issue #4553
This commit is contained in:
Christian Helmuth 2022-07-01 17:10:57 +02:00
parent 924e1d741d
commit c5bdc1ccbe
5 changed files with 128 additions and 21 deletions

View File

@ -72,8 +72,8 @@ set config {
</start>} </start>}
append_if [expr !$use_acpica_as_acpi_drv] config { append_if [expr !$use_acpica_as_acpi_drv] config {
<start name="acpica" caps="150"> <start name="acpica" caps="200">
<resource name="RAM" quantum="5M"/> <resource name="RAM" quantum="8M"/>
<config ld_verbose="yes" reset="no" poweroff="no" report="yes" acpi_ready="yes"> <config ld_verbose="yes" reset="no" poweroff="no" report="yes" acpi_ready="yes">
</config> </config>
<route> <route>
@ -178,9 +178,9 @@ append config {
<map acpi="ec" value="25" to_key="KEY_VENDOR"/> <map acpi="ec" value="25" to_key="KEY_VENDOR"/>
<map acpi="ec" value="20" to_key="KEY_BRIGHTNESSUP"/> <map acpi="ec" value="20" to_key="KEY_BRIGHTNESSUP"/>
<map acpi="ec" value="21" to_key="KEY_BRIGHTNESSDOWN"/> <map acpi="ec" value="21" to_key="KEY_BRIGHTNESSDOWN"/>
<map acpi="fixed" value="0" to_key="KEY_POWER" as="PRESS_RELEASE"/> <map acpi="fixed" value="0" to_key="KEY_POWER" as="PRESS_RELEASE"/>
<map acpi="lid" value="CLOSED" to_key="KEY_SLEEP" as="PRESS"/> <map acpi="lid" value="CLOSED" to_key="KEY_SLEEP" as="PRESS_RELEASE"/>
<map acpi="lid" value="OPEN" to_key="KEY_SLEEP" as="RELEASE"/> <map acpi="lid" value="OPEN" to_key="KEY_SLEEP" as="PRESS_RELEASE"/>
<map acpi="ac" value="ONLINE" to_key="KEY_WAKEUP"/> <map acpi="ac" value="ONLINE" to_key="KEY_WAKEUP"/>
<map acpi="ac" value="OFFLINE" to_key="KEY_SLEEP"/> <map acpi="ac" value="OFFLINE" to_key="KEY_SLEEP"/>
<map acpi="battery" value="0" to_key="KEY_BATTERY"/> <map acpi="battery" value="0" to_key="KEY_BATTERY"/>
@ -225,4 +225,30 @@ build_boot_image $boot_modules
append qemu_args "-nographic " 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

View File

@ -81,7 +81,7 @@ class Ec : Acpica::Callback<Ec> {
State::access_t state = ec->ec_cmdsta->inb(ec->ec_port_cmdsta); State::access_t state = ec->ec_cmdsta->inb(ec->ec_port_cmdsta);
if (!State::Sci_evt::get(state)) { 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 */ return ACPI_REENABLE_GPE; /* gpe is acked and re-enabled */
} }

View File

@ -116,6 +116,9 @@ struct Acpica::Main
static struct Irq_handler { static struct Irq_handler {
UINT32 irq; UINT32 irq;
Genode::Irq_session::Trigger trigger;
Genode::Irq_session::Polarity polarity;
ACPI_OSD_HANDLER handler; ACPI_OSD_HANDLER handler;
void *context; void *context;
} irq_handler; } irq_handler;
@ -152,9 +155,10 @@ struct Acpica::Main
return; 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->sigh(sci_irq);
sci_conn->ack_irq(); sci_conn->ack_irq();
@ -276,6 +280,67 @@ void Acpica::Main::init_acpica(Wait_acpi_ready wait_acpi_ready,
return; 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<ACPI_MADT_INTERRUPT_OVERRIDE const * const>(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); status = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION);
if (status != AE_OK) { if (status != AE_OK) {
Genode::error("AcpiEnableSubsystem failed, status=", status); 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, ACPI_STATUS AcpiOsInstallInterruptHandler(UINT32 irq, ACPI_OSD_HANDLER handler,
void *context) 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.handler = handler;
Acpica::Main::irq_handler.context = context; Acpica::Main::irq_handler.context = context;
return AE_OK; return AE_OK;

View File

@ -16,21 +16,12 @@
#include "util.h" #include "util.h"
#include "bridge.h" #include "bridge.h"
using namespace Acpica;
using Genode::Reporter; using Genode::Reporter;
extern void AcpiGenodeFreeIOMem(ACPI_PHYSICAL_ADDRESS const phys, ACPI_SIZE const size); extern void AcpiGenodeFreeIOMem(ACPI_PHYSICAL_ADDRESS const phys, ACPI_SIZE const size);
template <typename H, typename S, typename F, typename FSIZE>
void for_each_element(H const head, S *, F const &fn, FSIZE const &fn_size)
{
for(S const * e = reinterpret_cast<S const * const>(head + 1);
e < reinterpret_cast<S const *>(reinterpret_cast<char const *>(head) + head->Header.Length);
e = reinterpret_cast<S const *>(reinterpret_cast<char const *>(e) + fn_size(e)))
{
fn(e);
}
}
static void add_madt(ACPI_TABLE_MADT const * const madt, static void add_madt(ACPI_TABLE_MADT const * const madt,
Reporter::Xml_generator &xml) Reporter::Xml_generator &xml)
{ {

View File

@ -10,6 +10,9 @@
* under the terms of the GNU Affero General Public License version 3. * under the terms of the GNU Affero General Public License version 3.
*/ */
#ifndef _ACPICA__UTIL_H_
#define _ACPICA__UTIL_H_
extern "C" { extern "C" {
#include "acpi.h" #include "acpi.h"
} }
@ -20,6 +23,9 @@ namespace Acpica {
template<typename> class Buffer; template<typename> class Buffer;
template<typename> class Callback; template<typename> class Callback;
void generate_report(Genode::Env &, Bridge *); void generate_report(Genode::Env &, Bridge *);
template <typename H, typename S, typename F, typename FSIZE>
void for_each_element(H const head, S *, F const &fn, FSIZE const &fn_size);
} }
template <typename T> template <typename T>
@ -48,3 +54,17 @@ class Acpica::Callback : public Genode::List<Acpica::Callback<T> >::Element
reinterpret_cast<T *>(this)->generate(xml); reinterpret_cast<T *>(this)->generate(xml);
} }
}; };
template <typename H, typename S, typename F, typename FSIZE>
void Acpica::for_each_element(H const head, S *, F const &fn, FSIZE const &fn_size)
{
for(S const * e = reinterpret_cast<S const * const>(head + 1);
e < reinterpret_cast<S const *>(reinterpret_cast<char const *>(head) + head->Header.Length);
e = reinterpret_cast<S const *>(reinterpret_cast<char const *>(e) + fn_size(e)))
{
fn(e);
}
}
#endif /* _ACPICA__UTIL_H_ */