acpica: make battery report working for thinkpads

tested on T460p, X201, T470p

by periodically checking and reporting.

Issue #4631
This commit is contained in:
Alexander Boettcher 2022-10-13 09:04:58 +02:00 committed by Christian Helmuth
parent 9079a083d2
commit 00ac4afb9f
5 changed files with 81 additions and 66 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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 {

View File

@ -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();