mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-21 14:37:50 +00:00
acpica: make battery report working for thinkpads
tested on T460p, X201, T470p by periodically checking and reporting. Issue #4631
This commit is contained in:
parent
9079a083d2
commit
00ac4afb9f
@ -1,4 +1,4 @@
|
||||
<runtime ram="6M" caps="150" binary="acpica">
|
||||
<runtime ram="6M" caps="200" binary="acpica">
|
||||
|
||||
<requires>
|
||||
<io_mem/>
|
||||
@ -16,6 +16,6 @@
|
||||
<rom label="acpica"/>
|
||||
</content>
|
||||
|
||||
<config reset="yes" poweroff="yes" report="yes"/>
|
||||
<config reset="yes" poweroff="yes" report="yes" report_period_ms="20000"/>
|
||||
|
||||
</runtime>
|
||||
|
@ -184,7 +184,7 @@ set config {
|
||||
|
||||
<start name="acpica" caps="200">
|
||||
<resource name="RAM" quantum="8M"/>
|
||||
<config ld_verbose="yes" reset="yes" poweroff="yes" report="yes">
|
||||
<config ld_verbose="yes" reset="yes" poweroff="yes" report="yes" report_period_ms="0">
|
||||
</config>
|
||||
<route>
|
||||
<service name="ROM" label="system"> <child name="dynamic_rom"/> </service>
|
||||
|
@ -46,7 +46,7 @@ Excerpt of important parts of the acpica configuration
|
||||
!<start name="acpica">
|
||||
! <!-- <binary name="debug-acpica"/> -->
|
||||
! ...
|
||||
! <config reset="no" poweroff="no" report="yes"/>
|
||||
! <config reset="no" poweroff="no" report="yes" report_period_ms="2000"/>
|
||||
! <route>
|
||||
! <service name="ROM" label="system"> <child name="..."/> </service>
|
||||
! <service name="Report"> <child name="..."/> </service>
|
||||
|
@ -80,10 +80,8 @@ class Ec : Acpica::Callback<Ec> {
|
||||
|
||||
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));
|
||||
if (!State::Sci_evt::get(state))
|
||||
return ACPI_REENABLE_GPE; /* gpe is acked and re-enabled */
|
||||
}
|
||||
|
||||
ec->ec_cmdsta->outb(ec->ec_port_cmdsta, QR_EC);
|
||||
do {
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016-2017 Genode Labs GmbH
|
||||
* Copyright (C) 2016-2022 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
@ -20,6 +20,7 @@
|
||||
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
#include <os/reporter.h>
|
||||
#include <timer_session/connection.h>
|
||||
|
||||
#include <util/reconstructible.h>
|
||||
#include <util/xml_node.h>
|
||||
@ -45,14 +46,17 @@ namespace Acpica {
|
||||
#include "fixed.h"
|
||||
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
struct Acpica::Statechange
|
||||
{
|
||||
Genode::Signal_handler<Acpica::Statechange> _dispatcher;
|
||||
Genode::Attached_rom_dataspace _system_state;
|
||||
Signal_handler<Acpica::Statechange> _dispatcher;
|
||||
Attached_rom_dataspace _system_state;
|
||||
bool _enable_reset;
|
||||
bool _enable_poweroff;
|
||||
|
||||
Statechange(Genode::Env &env, bool reset, bool poweroff)
|
||||
Statechange(Env &env, bool reset, bool poweroff)
|
||||
:
|
||||
_dispatcher(env.ep(), *this, &Statechange::state_changed),
|
||||
_system_state(env, "system"),
|
||||
@ -69,17 +73,16 @@ struct Acpica::Statechange
|
||||
|
||||
if (!_system_state.valid()) return;
|
||||
|
||||
Genode::Xml_node system(_system_state.local_addr<char>(),
|
||||
_system_state.size());
|
||||
Xml_node system(_system_state.local_addr<char>(),
|
||||
_system_state.size());
|
||||
|
||||
typedef Genode::String<32> State;
|
||||
typedef String<32> State;
|
||||
State const state = system.attribute_value("state", State());
|
||||
|
||||
if (_enable_poweroff && state == "poweroff") {
|
||||
ACPI_STATUS res0 = AcpiEnterSleepStatePrep(5);
|
||||
ACPI_STATUS res1 = AcpiEnterSleepState(5);
|
||||
Genode::error("system poweroff failed - "
|
||||
"res=", Genode::Hex(res0), ",", Genode::Hex(res1));
|
||||
error("system poweroff failed - res=", Hex(res0), ",", Hex(res1));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -89,25 +92,29 @@ struct Acpica::Statechange
|
||||
res = AcpiReset();
|
||||
} catch (...) { }
|
||||
|
||||
Genode::uint64_t const space_addr = AcpiGbl_FADT.ResetRegister.Address;
|
||||
Genode::error("system reset failed - "
|
||||
"err=", res, " "
|
||||
"reset=", !!(AcpiGbl_FADT.Flags & ACPI_FADT_RESET_REGISTER), " "
|
||||
"spaceid=", Genode::Hex(AcpiGbl_FADT.ResetRegister.SpaceId), " "
|
||||
"addr=", Genode::Hex(space_addr));
|
||||
uint64_t const space_addr = AcpiGbl_FADT.ResetRegister.Address;
|
||||
error("system reset failed - err=", res,
|
||||
" reset=", !!(AcpiGbl_FADT.Flags & ACPI_FADT_RESET_REGISTER),
|
||||
" spaceid=", Hex(AcpiGbl_FADT.ResetRegister.SpaceId),
|
||||
" addr=", Hex(space_addr));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Acpica::Main
|
||||
{
|
||||
Genode::Env &env;
|
||||
Genode::Heap heap { env.ram(), env.rm() };
|
||||
Env &env;
|
||||
Heap heap { env.ram(), env.rm() };
|
||||
|
||||
Genode::Attached_rom_dataspace config { env, "config" };
|
||||
Attached_rom_dataspace config { env, "config" };
|
||||
|
||||
Genode::Signal_handler<Acpica::Main> sci_irq;
|
||||
Genode::Constructible<Genode::Irq_connection> sci_conn;
|
||||
Signal_handler<Acpica::Main> sci_irq;
|
||||
Constructible<Irq_connection> sci_conn;
|
||||
|
||||
Timer::Connection timer { env };
|
||||
Signal_handler<Acpica::Main> timer_trigger { env.ep(), *this,
|
||||
&Main::handle_timer };
|
||||
|
||||
Acpica::Reportstate * report { nullptr };
|
||||
|
||||
@ -115,25 +122,25 @@ struct Acpica::Main
|
||||
unsigned unchanged_state_max;
|
||||
|
||||
static struct Irq_handler {
|
||||
UINT32 irq;
|
||||
Genode::Irq_session::Trigger trigger;
|
||||
Genode::Irq_session::Polarity polarity;
|
||||
|
||||
ACPI_OSD_HANDLER handler;
|
||||
void *context;
|
||||
UINT32 irq;
|
||||
Irq_session::Trigger trigger;
|
||||
Irq_session::Polarity polarity;
|
||||
ACPI_OSD_HANDLER handler;
|
||||
void *context;
|
||||
} irq_handler;
|
||||
|
||||
void init_acpica();
|
||||
|
||||
Main(Genode::Env &env)
|
||||
Main(Env &env)
|
||||
:
|
||||
env(env),
|
||||
sci_irq(env.ep(), *this, &Main::acpi_irq),
|
||||
unchanged_state_max(config.xml().attribute_value("update_unchanged", 20U))
|
||||
unchanged_state_max(config.xml().attribute_value("update_unchanged", 10U))
|
||||
{
|
||||
bool const enable_reset = config.xml().attribute_value("reset", false);
|
||||
bool const enable_poweroff = config.xml().attribute_value("poweroff", false);
|
||||
bool const enable_report = config.xml().attribute_value("report", false);
|
||||
auto const periodic_ms = config.xml().attribute_value("report_period_ms", 0ULL);
|
||||
|
||||
if (enable_report)
|
||||
report = new (heap) Acpica::Reportstate(env);
|
||||
@ -148,19 +155,37 @@ struct Acpica::Main
|
||||
|
||||
/* setup IRQ */
|
||||
if (!irq_handler.handler) {
|
||||
Genode::warning("no IRQ handling available");
|
||||
warning("no IRQ handling available");
|
||||
return;
|
||||
}
|
||||
|
||||
sci_conn.construct(env, irq_handler.irq, irq_handler.trigger, irq_handler.polarity);
|
||||
|
||||
Genode::log("SCI IRQ: ", irq_handler.irq,
|
||||
" (", irq_handler.trigger, "-", irq_handler.polarity, ")");
|
||||
log("SCI IRQ: ", irq_handler.irq, " (", irq_handler.trigger, "-",
|
||||
irq_handler.polarity, ")");
|
||||
|
||||
sci_conn->sigh(sci_irq);
|
||||
sci_conn->ack_irq();
|
||||
|
||||
if (periodic_ms) {
|
||||
timer.sigh(timer_trigger);
|
||||
timer.trigger_periodic(Microseconds(periodic_ms * 1000).value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void handle_timer()
|
||||
{
|
||||
if (!irq_handler.handler)
|
||||
return;
|
||||
|
||||
irq_handler.handler(irq_handler.context);
|
||||
|
||||
if (report)
|
||||
report->generate_report(true /* force */);
|
||||
}
|
||||
|
||||
|
||||
void acpi_irq()
|
||||
{
|
||||
if (!irq_handler.handler)
|
||||
@ -182,9 +207,6 @@ struct Acpica::Main
|
||||
unchanged_state_count ++;
|
||||
|
||||
if (unchanged_state_count >= unchanged_state_max) {
|
||||
Genode::log("generate report because of ",
|
||||
unchanged_state_count, " irqs without state "
|
||||
"changes");
|
||||
report->generate_report(true);
|
||||
unchanged_state_count = 0;
|
||||
}
|
||||
@ -228,31 +250,29 @@ void Acpica::Main::init_acpica()
|
||||
if (false) {
|
||||
AcpiDbgLevel |= ACPI_LV_IO | ACPI_LV_INTERRUPTS | ACPI_LV_INIT_NAMES;
|
||||
AcpiDbgLayer |= ACPI_TABLES;
|
||||
Genode::log("debugging level=", Genode::Hex(AcpiDbgLevel),
|
||||
" layers=", Genode::Hex(AcpiDbgLayer));
|
||||
log("debugging level=", Hex(AcpiDbgLevel),
|
||||
" layers=", Hex(AcpiDbgLayer));
|
||||
}
|
||||
|
||||
ACPI_STATUS status = AcpiInitializeSubsystem();
|
||||
if (status != AE_OK) {
|
||||
Genode::error("AcpiInitializeSubsystem failed, status=", status);
|
||||
error("AcpiInitializeSubsystem failed, status=", status);
|
||||
return;
|
||||
}
|
||||
|
||||
status = AcpiInitializeTables(nullptr, 0, true);
|
||||
if (status != AE_OK) {
|
||||
Genode::error("AcpiInitializeTables failed, status=", status);
|
||||
error("AcpiInitializeTables failed, status=", status);
|
||||
return;
|
||||
}
|
||||
|
||||
status = AcpiLoadTables();
|
||||
if (status != AE_OK) {
|
||||
Genode::error("AcpiLoadTables failed, status=", status);
|
||||
error("AcpiLoadTables failed, status=", status);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
using Genode::Irq_session;
|
||||
|
||||
/*
|
||||
* ACPI Spec 2.1 General ACPI Terminology
|
||||
*
|
||||
@ -269,8 +289,6 @@ void Acpica::Main::init_acpica()
|
||||
|
||||
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) {
|
||||
|
||||
@ -313,89 +331,88 @@ void Acpica::Main::init_acpica()
|
||||
|
||||
status = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION);
|
||||
if (status != AE_OK) {
|
||||
Genode::error("AcpiEnableSubsystem failed, status=", status);
|
||||
error("AcpiEnableSubsystem failed, status=", status);
|
||||
return;
|
||||
}
|
||||
|
||||
status = AcpiInitializeObjects(ACPI_NO_DEVICE_INIT);
|
||||
if (status != AE_OK) {
|
||||
Genode::error("AcpiInitializeObjects (no devices) failed, status=", status);
|
||||
error("AcpiInitializeObjects (no devices) failed, status=", status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* set APIC mode */
|
||||
status = init_pic_mode();
|
||||
if (status != AE_OK) {
|
||||
Genode::error("Setting PIC mode failed, status=", status);
|
||||
error("Setting PIC mode failed, status=", status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Embedded controller */
|
||||
status = AcpiGetDevices(ACPI_STRING("PNP0C09"), Ec::detect, this, nullptr);
|
||||
if (status != AE_OK) {
|
||||
Genode::error("AcpiGetDevices failed, status=", status);
|
||||
error("AcpiGetDevices failed, status=", status);
|
||||
return;
|
||||
}
|
||||
|
||||
status = AcpiInitializeObjects(ACPI_FULL_INITIALIZATION);
|
||||
if (status != AE_OK) {
|
||||
Genode::error("AcpiInitializeObjects (full init) failed, status=", status);
|
||||
error("AcpiInitializeObjects (full init) failed, status=", status);
|
||||
return;
|
||||
}
|
||||
|
||||
status = AcpiUpdateAllGpes();
|
||||
if (status != AE_OK) {
|
||||
Genode::error("AcpiUpdateAllGpes failed, status=", status);
|
||||
error("AcpiUpdateAllGpes failed, status=", status);
|
||||
return;
|
||||
}
|
||||
|
||||
status = AcpiEnableAllRuntimeGpes();
|
||||
if (status != AE_OK) {
|
||||
Genode::error("AcpiEnableAllRuntimeGpes failed, status=", status);
|
||||
error("AcpiEnableAllRuntimeGpes failed, status=", status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* note: ACPI_EVENT_PMTIMER claimed by nova kernel - not usable by us */
|
||||
Fixed * acpi_fixed = new (heap) Fixed(report);
|
||||
|
||||
status = AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
|
||||
Fixed::handle_power_button,
|
||||
acpi_fixed);
|
||||
if (status != AE_OK)
|
||||
Genode::log("failed - power button registration - error=", status);
|
||||
log("failed - power button registration - error=", status);
|
||||
|
||||
status = AcpiInstallFixedEventHandler(ACPI_EVENT_SLEEP_BUTTON,
|
||||
Fixed::handle_sleep_button,
|
||||
acpi_fixed);
|
||||
if (status != AE_OK)
|
||||
Genode::log("failed - sleep button registration - error=", status);
|
||||
log("failed - sleep button registration - error=", status);
|
||||
|
||||
|
||||
/* AC Adapters and Power Source Objects */
|
||||
status = AcpiGetDevices(ACPI_STRING("ACPI0003"), Ac::detect, this, nullptr);
|
||||
if (status != AE_OK) {
|
||||
Genode::error("AcpiGetDevices (ACPI0003) failed, status=", status);
|
||||
error("AcpiGetDevices (ACPI0003) failed, status=", status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Smart battery control devices */
|
||||
status = AcpiGetDevices(ACPI_STRING("PNP0C0A"), Battery::detect, this, nullptr);
|
||||
if (status != AE_OK) {
|
||||
Genode::error("AcpiGetDevices (PNP0C0A) failed, status=", status);
|
||||
error("AcpiGetDevices (PNP0C0A) failed, status=", status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* LID device */
|
||||
status = AcpiGetDevices(ACPI_STRING("PNP0C0D"), Lid::detect, this, nullptr);
|
||||
if (status != AE_OK) {
|
||||
Genode::error("AcpiGetDevices (PNP0C0D) failed, status=", status);
|
||||
error("AcpiGetDevices (PNP0C0D) failed, status=", status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fujitsu HID device */
|
||||
status = AcpiGetDevices(ACPI_STRING("FUJ02E3"), Fuj02e3::detect, this, nullptr);
|
||||
if (status != AE_OK) {
|
||||
Genode::error("AcpiGetDevices (FUJ02E3) failed, status=", status);
|
||||
error("AcpiGetDevices (FUJ02E3) failed, status=", status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -408,7 +425,7 @@ ACPI_STATUS AcpiOsInstallInterruptHandler(UINT32 irq, ACPI_OSD_HANDLER handler,
|
||||
void *context)
|
||||
{
|
||||
if (irq != Acpica::Main::irq_handler.irq) {
|
||||
Genode::error("SCI interrupt is ", Acpica::Main::irq_handler.irq,
|
||||
error("SCI interrupt is ", Acpica::Main::irq_handler.irq,
|
||||
" but library requested ", irq);
|
||||
return AE_BAD_PARAMETER;
|
||||
}
|
||||
@ -419,7 +436,7 @@ ACPI_STATUS AcpiOsInstallInterruptHandler(UINT32 irq, ACPI_OSD_HANDLER handler,
|
||||
}
|
||||
|
||||
|
||||
void Component::construct(Genode::Env &env)
|
||||
void Component::construct(Env &env)
|
||||
{
|
||||
/* XXX execute constructors of global statics */
|
||||
env.exec_static_constructors();
|
||||
|
Loading…
Reference in New Issue
Block a user