mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-21 03:55:04 +00:00
platform_drv/x86: support ACPI reset
Evaluate fadt xml node in report from acpi_drv. If the io ports in the range of 0xcf8+4 are necessary for the reset than the platform driver will react on the 'system' state 'reset' and reboot. Issue #1962
This commit is contained in:
parent
38c5abbaad
commit
57f47db823
@ -51,6 +51,24 @@ proc platform_drv_policy {} {
|
||||
}
|
||||
|
||||
proc platform_drv_priority {} { return "" }
|
||||
proc platform_drv_add_routing {} {
|
||||
if {[have_spec acpi]} {
|
||||
return {
|
||||
<service name="ROM" label="system"> <child name="acpi_report_rom"/> </service>}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
proc platform_drv_config_config {} {
|
||||
if {[have_spec acpi] || [have_spec arm] || [have_spec hw_x86_64_muen]} {
|
||||
return {
|
||||
<config>}
|
||||
}
|
||||
|
||||
return {
|
||||
<config acpi="no">}
|
||||
}
|
||||
|
||||
proc append_platform_drv_config {} {
|
||||
global config
|
||||
@ -108,6 +126,8 @@ proc append_platform_drv_config {} {
|
||||
</provides>
|
||||
<route>}
|
||||
|
||||
append config "[platform_drv_add_routing]"
|
||||
|
||||
append_if [have_spec acpi] config {
|
||||
<service name="ROM" label="acpi"> <child name="acpi_report_rom"/> </service>}
|
||||
|
||||
@ -118,18 +138,7 @@ proc append_platform_drv_config {} {
|
||||
<any-service> <parent/> </any-service>
|
||||
</route>}
|
||||
|
||||
if {[have_spec acpi] || [have_spec arm] || [have_spec hw_x86_64_muen]} {
|
||||
|
||||
append config {
|
||||
<config>}
|
||||
|
||||
} else {
|
||||
|
||||
append config {
|
||||
<config acpi="no">}
|
||||
|
||||
}
|
||||
|
||||
append config [platform_drv_config_config]
|
||||
append config [platform_drv_policy]
|
||||
|
||||
append config {
|
||||
|
@ -27,6 +27,18 @@ proc platform_drv_policy {} {
|
||||
<policy label="acpica"> <pci class="ALL"/> </policy>}
|
||||
}
|
||||
|
||||
# add routing information to dynamically generate change of 'system' ROM
|
||||
proc platform_drv_add_routing {} {
|
||||
return {
|
||||
<service name="ROM" label="system"> <child name="dynamic_rom"/> </service>}
|
||||
}
|
||||
|
||||
# override default config to react on 'system' ROM changes for reset
|
||||
proc platform_drv_config_config {} {
|
||||
return {
|
||||
<config acpi="yes" system="no">}
|
||||
}
|
||||
|
||||
append_platform_drv_build_components
|
||||
|
||||
build $build_components
|
||||
|
@ -39,7 +39,10 @@ struct Platform::Main
|
||||
Genode::Lazy_volatile_object<Genode::Attached_rom_dataspace> acpi_rom;
|
||||
Genode::Lazy_volatile_object<Platform::Root> root;
|
||||
|
||||
Genode::Lazy_volatile_object<Genode::Attached_rom_dataspace> system_state;
|
||||
|
||||
Genode::Signal_handler<Platform::Main> _acpi_report;
|
||||
Genode::Signal_handler<Platform::Main> _system_report;
|
||||
|
||||
void acpi_update()
|
||||
{
|
||||
@ -54,19 +57,48 @@ struct Platform::Main
|
||||
_env.parent().announce(_env.ep().manage(*root));
|
||||
}
|
||||
|
||||
void system_update()
|
||||
{
|
||||
system_state->update();
|
||||
|
||||
if (!system_state->is_valid() || !root.is_constructed())
|
||||
return;
|
||||
|
||||
Genode::Xml_node system(system_state->local_addr<char>(),
|
||||
system_state->size());
|
||||
|
||||
typedef Genode::String<16> Value;
|
||||
const Value state = system.attribute_value("state", Value("unknown"));
|
||||
|
||||
if (state == "reset")
|
||||
root->system_reset();
|
||||
}
|
||||
|
||||
Main(Genode::Env &env)
|
||||
:
|
||||
sliced_heap(env.ram(), env.rm()),
|
||||
_env(env),
|
||||
_acpi_report(_env.ep(), *this, &Main::acpi_update)
|
||||
_acpi_report(_env.ep(), *this, &Main::acpi_update),
|
||||
_system_report(_env.ep(), *this, &Main::system_update)
|
||||
{
|
||||
const Genode::Xml_node &config = Genode::config()->xml_node();
|
||||
|
||||
typedef Genode::String<8> Value;
|
||||
Value const wait_for_acpi = Genode::config()->xml_node().attribute_value("acpi", Value("yes"));
|
||||
Value const wait_for_acpi = config.attribute_value("acpi", Value("yes"));
|
||||
|
||||
if (wait_for_acpi == "yes") {
|
||||
bool system_reset = config.attribute_value("system", false);
|
||||
if (system_reset) {
|
||||
/* wait for system state changes and react upon, e.g. reset */
|
||||
system_state.construct("system");
|
||||
system_state->sigh(_system_report);
|
||||
}
|
||||
|
||||
/* for ACPI support, wait for the first valid acpi report */
|
||||
acpi_rom.construct("acpi");
|
||||
acpi_rom->sigh(_acpi_report);
|
||||
/* check if already valid */
|
||||
acpi_update();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ namespace Platform {
|
||||
{
|
||||
private:
|
||||
|
||||
enum { REG_ADDR = 0xcf8, REG_DATA = 0xcfc };
|
||||
enum { REG_ADDR = 0xcf8, REG_DATA = 0xcfc, REG_SIZE = 4 };
|
||||
|
||||
/**
|
||||
* Request interface to access an I/O port
|
||||
@ -47,7 +47,7 @@ namespace Platform {
|
||||
* Once created, each I/O-port session persists until
|
||||
* the PCI driver gets killed by its parent.
|
||||
*/
|
||||
static Genode::Io_port_connection io_port(port, 4);
|
||||
static Genode::Io_port_connection io_port(port, REG_SIZE);
|
||||
return &io_port;
|
||||
}
|
||||
|
||||
@ -177,6 +177,32 @@ namespace Platform {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool reset_support(unsigned reg, unsigned reg_size) const
|
||||
{
|
||||
return (REG_ADDR <= reg) &&
|
||||
reg + reg_size <= REG_ADDR + REG_SIZE;
|
||||
}
|
||||
|
||||
bool system_reset(unsigned reg, unsigned long long value,
|
||||
const Device::Access_size &access_size)
|
||||
{
|
||||
switch (access_size) {
|
||||
case Device::ACCESS_8BIT:
|
||||
_io_port<REG_ADDR>()->outb(reg, value);
|
||||
break;
|
||||
case Device::ACCESS_16BIT:
|
||||
_io_port<REG_ADDR>()->outw(reg, value);
|
||||
break;
|
||||
case Device::ACCESS_32BIT:
|
||||
_io_port<REG_ADDR>()->outl(reg, value);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <root/component.h>
|
||||
#include <root/client.h>
|
||||
|
||||
#include <util/mmio.h>
|
||||
#include <util/retry.h>
|
||||
#include <util/volatile_object.h>
|
||||
|
||||
@ -853,6 +854,27 @@ class Platform::Root : public Genode::Root_component<Session_component>
|
||||
{
|
||||
private:
|
||||
|
||||
struct Fadt {
|
||||
Genode::uint32_t features = 0, reset_type = 0, reset_value = 0;
|
||||
Genode::uint64_t reset_addr = 0;
|
||||
|
||||
/* Table 5-35 Fixed ACPI Description Table Fixed Feature Flags */
|
||||
struct Features : Genode::Register<32> {
|
||||
struct Reset : Bitfield<10, 1> { };
|
||||
};
|
||||
|
||||
/* ACPI spec - 5.2.3.2 Generic Address Structure */
|
||||
struct Gas : Genode::Register<32>
|
||||
{
|
||||
struct Address_space : Bitfield <0, 8> {
|
||||
enum { SYSTEM_IO = 1 };
|
||||
};
|
||||
struct Access_size : Bitfield<24,8> {
|
||||
enum { UNDEFINED = 0, BYTE = 1, WORD = 2, DWORD = 3, QWORD = 4};
|
||||
};
|
||||
};
|
||||
} fadt;
|
||||
|
||||
Genode::Rpc_entrypoint _device_pd_ep;
|
||||
|
||||
void _parse_report_rom(const char * acpi_rom)
|
||||
@ -938,6 +960,13 @@ class Platform::Root : public Genode::Root_component<Session_component>
|
||||
}
|
||||
}
|
||||
|
||||
if (node.has_type("fadt")) {
|
||||
node.attribute("features").value(&fadt.features);
|
||||
node.attribute("reset_type").value(&fadt.reset_type);
|
||||
node.attribute("reset_addr").value(&fadt.reset_addr);
|
||||
node.attribute("reset_value").value(&fadt.reset_value);
|
||||
}
|
||||
|
||||
if (!node.has_type("routing"))
|
||||
continue;
|
||||
|
||||
@ -1029,4 +1058,47 @@ class Platform::Root : public Genode::Root_component<Session_component>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void system_reset()
|
||||
{
|
||||
const bool io_port_space = (Fadt::Gas::Address_space::get(fadt.reset_type) == Fadt::Gas::Address_space::SYSTEM_IO);
|
||||
|
||||
if (!io_port_space)
|
||||
return;
|
||||
|
||||
Config_access config_access;
|
||||
const unsigned raw_access_size = Fadt::Gas::Access_size::get(fadt.reset_type);
|
||||
const bool reset_support = config_access.reset_support(fadt.reset_addr, raw_access_size);
|
||||
if (!reset_support)
|
||||
return;
|
||||
|
||||
const bool feature_reset = Fadt::Features::Reset::get(fadt.features);
|
||||
|
||||
if (!feature_reset) {
|
||||
PWRN("system reset failed - feature not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
Device::Access_size access_size = Device::ACCESS_8BIT;
|
||||
|
||||
unsigned raw_size = Fadt::Gas::Access_size::get(fadt.reset_type);
|
||||
switch (raw_size) {
|
||||
case Fadt::Gas::Access_size::WORD:
|
||||
access_size = Device::ACCESS_16BIT;
|
||||
break;
|
||||
case Fadt::Gas::Access_size::DWORD:
|
||||
access_size = Device::ACCESS_32BIT;
|
||||
break;
|
||||
case Fadt::Gas::Access_size::QWORD:
|
||||
PERR("system reset failed - unsupported access size");
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
config_access.system_reset(fadt.reset_addr, fadt.reset_value,
|
||||
access_size);
|
||||
/* if we are getting here - the reset failed */
|
||||
PINF("system reset failed");
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user