platform_drv: sync startup between acpica

- platform_drv announces a separate "Acpi" session
- platform_drv waits for ROM "system" to change state to "acpi_ready"
- acpica waits for "Acpi" announcement
- acpica uses the platform driver via "Acpi" to reconfigure PCI devices
- acpica changes "system" state to "acpi_ready" after it ready with initialization
- platform_drv reacts on "system" state change to "acpi_ready" by announcing "Platform" session
- drivers start to operate as usual

Issue #2009
This commit is contained in:
Alexander Boettcher 2016-06-01 22:26:54 +02:00 committed by Christian Helmuth
parent 2030ae678e
commit 4e9aeb45ea
7 changed files with 175 additions and 57 deletions

View File

@ -119,6 +119,9 @@ proc append_platform_drv_config {} {
<provides> <provides>
<service name="Platform"/>} <service name="Platform"/>}
append_if [have_spec acpi] config {
<service name="Acpi"/>}
append_if [have_spec arm] config { append_if [have_spec arm] config {
<service name="Regulator"/>} <service name="Regulator"/>}

View File

@ -30,13 +30,14 @@ proc platform_drv_policy {} {
# add routing information to dynamically generate change of 'system' ROM # add routing information to dynamically generate change of 'system' ROM
proc platform_drv_add_routing {} { proc platform_drv_add_routing {} {
return { return {
<service name="ROM" label="system"> <child name="dynamic_rom"/> </service>} <service name="ROM" label="system"> <child name="dynamic_rom"/> </service>
<service name="ROM" label="acpi_ready"> <child name="acpi_state"/> </service>}
} }
# override default config to react on 'system' ROM changes for reset # override default config to react on 'system' ROM changes for reset
proc platform_drv_config_config {} { proc platform_drv_config_config {} {
return { return {
<config acpi="yes" system="no">} <config acpi="yes" system="yes">}
} }
append_platform_drv_build_components append_platform_drv_build_components
@ -66,7 +67,7 @@ set config {
<start name="acpica"> <start name="acpica">
<!-- <binary name="debug-acpica"/> --> <!-- <binary name="debug-acpica"/> -->
<resource name="RAM" quantum="4M"/> <resource name="RAM" quantum="4M"/>
<config ld_verbose="yes" reset="no" poweroff="no" report="yes"> <config ld_verbose="yes" reset="no" poweroff="no" report="yes" acpi_ready="yes">
<!-- required for "debug-acpica": <!-- required for "debug-acpica":
<libc stdout="/dev/log"> <libc stdout="/dev/log">
<vfs> <dir name="dev"> <log/> </dir> </vfs> <vfs> <dir name="dev"> <log/> </dir> </vfs>
@ -89,6 +90,7 @@ append config {
<service name="Report" /> <service name="Report" />
</provides> </provides>
<config verbose="yes"> <config verbose="yes">
<policy label="platform_drv -> acpi_ready" report="acpica -> acpi_ready"/>
</config> </config>
<route> <route>
<service name="LOG"> <parent/> </service> <service name="LOG"> <parent/> </service>

View File

@ -27,6 +27,15 @@ changes of the 'state' attribute:
!<system state="something"/> !<system state="something"/>
Additionally, if the config attributes 'acpi_ready' is set to yes, the
application generates a reports named 'acpi_ready' and set the state to
!<system state="acpi_ready"/>
after finishing the ACPI bring up. This is used by platform_drv to finally
announce the Platform session, so that drivers can start after acpica has
finished.
If the ROM changes to 'state="reset"' the application tries to reset the If the ROM changes to 'state="reset"' the application tries to reset the
machine immediately. machine immediately.
If the ROM changes to 'state="poweroff"' the application tries to poweroff If the ROM changes to 'state="poweroff"' the application tries to poweroff
@ -51,7 +60,7 @@ Excerpt of important parts of the acpica configuration
!<start name="acpica"> !<start name="acpica">
! <!-- <binary name="debug-acpica"/> --> ! <!-- <binary name="debug-acpica"/> -->
! ... ! ...
! <config reset="no" poweroff="no" report="yes"/> ! <config reset="no" poweroff="no" report="yes" acpi_ready="yes"/>
! <route> ! <route>
! <service name="ROM" label="system"> <child name="..."/> </service> ! <service name="ROM" label="system"> <child name="..."/> </service>
! <service name="Report"> <child name="..."/> </service> ! <service name="Report"> <child name="..."/> </service>

View File

@ -10,6 +10,7 @@
* under the terms of the GNU General Public License version 2. * under the terms of the GNU General Public License version 2.
*/ */
#include <base/allocator_avl.h>
#include <base/component.h> #include <base/component.h>
#include <base/printf.h> #include <base/printf.h>
#include <base/signal.h> #include <base/signal.h>
@ -215,6 +216,7 @@ struct Acpica::Main {
bool enable_reset = Genode::config()->xml_node().attribute_value("reset", false); bool enable_reset = Genode::config()->xml_node().attribute_value("reset", false);
bool enable_poweroff = Genode::config()->xml_node().attribute_value("poweroff", false); bool enable_poweroff = Genode::config()->xml_node().attribute_value("poweroff", false);
bool enable_report = Genode::config()->xml_node().attribute_value("report", false); bool enable_report = Genode::config()->xml_node().attribute_value("report", false);
bool enable_ready = Genode::config()->xml_node().attribute_value("acpi_ready", false);
if (enable_report) if (enable_report)
_report = new (Genode::env()->heap()) Acpica::Reportstate(); _report = new (Genode::env()->heap()) Acpica::Reportstate();
@ -229,16 +231,29 @@ struct Acpica::Main {
enable_poweroff); enable_poweroff);
/* setup IRQ */ /* setup IRQ */
if (irq_handler.handler) { if (!irq_handler.handler) {
_sci_conn.construct(irq_handler.irq);
PINF("SCI IRQ: %u", irq_handler.irq);
_sci_conn->sigh(_sci_irq);
_sci_conn->ack_irq();
} else
PWRN("no IRQ handling available"); PWRN("no IRQ handling available");
return;
}
_sci_conn.construct(irq_handler.irq);
PINF("SCI IRQ: %u", irq_handler.irq);
_sci_conn->sigh(_sci_irq);
_sci_conn->ack_irq();
if (!enable_ready)
return;
/* we are ready - signal it via changing system state */
const char * system_file = "system";
static Genode::Reporter _system_rom { "system", "acpi_ready" };
_system_rom.enabled(true);
Genode::Reporter::Xml_generator xml(_system_rom, [&] () {
xml.attribute("state", "acpi_ready");
});
} }
void acpi_irq() void acpi_irq()

View File

@ -12,20 +12,46 @@
*/ */
#include <base/printf.h> #include <base/printf.h>
#include <platform_session/connection.h> #include <base/env.h>
#include <parent/parent.h>
#include <platform_session/client.h>
extern "C" { extern "C" {
#include "acpi.h" #include "acpi.h"
#include "acpiosxf.h" #include "acpiosxf.h"
} }
static Platform::Client & platform()
{
static bool connected = false;
typedef Genode::Capability<Platform::Session> Platform_session_capability;
Platform_session_capability platform_cap;
if (!connected) {
Genode::Parent::Service_name announce_for_acpica("Acpi");
Genode::Native_capability cap = Genode::env()->parent()->session(announce_for_acpica, "ram_quota=20K");
platform_cap = Genode::reinterpret_cap_cast<Platform::Session>(cap);
connected = true;
}
static Platform::Client conn(platform_cap);
return conn;
}
ACPI_STATUS AcpiOsInitialize (void) ACPI_STATUS AcpiOsInitialize (void)
{ {
/* XXX - acpi_drv uses IOMEM concurrently to us - wait until it is done */ /* acpi_drv uses IOMEM concurrently to us - wait until it is done */
PINF("wait for platform drv"); PINF("wait for platform drv");
try { try {
Platform::Connection conn; platform();
} catch (...) { PERR("did not get Platform connection"); } } catch (...) {
PERR("did not get Platform connection");
Genode::Lock lock(Genode::Lock::LOCKED);
lock.lock();
}
PINF("wait for platform drv - done"); PINF("wait for platform drv - done");
return AE_OK; return AE_OK;
} }
@ -33,8 +59,7 @@ ACPI_STATUS AcpiOsInitialize (void)
ACPI_STATUS AcpiOsReadPciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg, ACPI_STATUS AcpiOsReadPciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg,
UINT64 *value, UINT32 width) UINT64 *value, UINT32 width)
{ {
Platform::Connection conn; Platform::Device_capability cap = platform().first_device();
Platform::Device_capability cap = conn.first_device();
while (cap.valid()) { while (cap.valid()) {
Platform::Device_client client(cap); Platform::Device_client client(cap);
@ -58,7 +83,7 @@ ACPI_STATUS AcpiOsReadPciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg,
break; break;
default: default:
PERR("%s : unsupported access size %u", __func__, width); PERR("%s : unsupported access size %u", __func__, width);
conn.release_device(client); platform().release_device(client);
return AE_ERROR; return AE_ERROR;
}; };
@ -67,13 +92,13 @@ ACPI_STATUS AcpiOsReadPciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg,
PINF("%s: %x:%x.%x reg=0x%x width=%u -> value=0x%llx", PINF("%s: %x:%x.%x reg=0x%x width=%u -> value=0x%llx",
__func__, bus, dev, fn, reg, width, *value); __func__, bus, dev, fn, reg, width, *value);
conn.release_device(client); platform().release_device(client);
return AE_OK; return AE_OK;
} }
cap = conn.next_device(cap); cap = platform().next_device(cap);
conn.release_device(client); platform().release_device(client);
} }
PERR("%s unknown device - segment=%u bdf=%x:%x.%x reg=0x%x width=0x%x", PERR("%s unknown device - segment=%u bdf=%x:%x.%x reg=0x%x width=0x%x",
@ -86,8 +111,7 @@ ACPI_STATUS AcpiOsReadPciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg,
ACPI_STATUS AcpiOsWritePciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg, ACPI_STATUS AcpiOsWritePciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg,
UINT64 value, UINT32 width) UINT64 value, UINT32 width)
{ {
Platform::Connection conn; Platform::Device_capability cap = platform().first_device();
Platform::Device_capability cap = conn.first_device();
while (cap.valid()) { while (cap.valid()) {
Platform::Device_client client(cap); Platform::Device_client client(cap);
@ -111,7 +135,7 @@ ACPI_STATUS AcpiOsWritePciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg,
break; break;
default: default:
PERR("%s : unsupported access size %u", __func__, width); PERR("%s : unsupported access size %u", __func__, width);
conn.release_device(client); platform().release_device(client);
return AE_ERROR; return AE_ERROR;
}; };
@ -120,13 +144,13 @@ ACPI_STATUS AcpiOsWritePciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg,
PWRN("%s: %x:%x.%x reg=0x%x width=%u value=0x%llx", PWRN("%s: %x:%x.%x reg=0x%x width=%u value=0x%llx",
__func__, bus, dev, fn, reg, width, value); __func__, bus, dev, fn, reg, width, value);
conn.release_device(client); platform().release_device(client);
return AE_OK; return AE_OK;
} }
cap = conn.next_device(cap); cap = platform().next_device(cap);
conn.release_device(client); platform().release_device(client);
} }
PERR("%s unknown device - segment=%u bdf=%x:%x.%x reg=0x%x width=0x%x", PERR("%s unknown device - segment=%u bdf=%x:%x.%x reg=0x%x width=0x%x",

View File

@ -98,8 +98,8 @@ in the following:
!<start name="platform_drv"> !<start name="platform_drv">
! ... ! ...
! <route> ! <route>
! <service name="ROM"> ! <service name="ROM" label="acpi">
! <if-arg key="label" value="acpi"/> <child name="acpi_report_rom"/> ! <child name="acpi_report_rom"/>
! </service> ! </service>
! ... ! ...
! </route> ! </route>
@ -111,26 +111,56 @@ configured to not wait for the acpi report:
!<start name="platform_drv"> !<start name="platform_drv">
! ... ! ...
! <config acpi="no"> ! <config acpi="no" system="no">
! ... ! ...
! </config> ! </config>
! ... ! ...
Synchronize ACPI startup and platform driver
--------------------------------------------
If the config attribute 'system' is set to 'yes', the platform driver monitors
a ROM in XML format named 'system'.
!<start name="platform_drv">
! <config acpi="yes" system="yes">
Additionally, the platform driver will announce the service as 'Acpi' first.
An ACPI application like acpica can connect to the platform driver and may
reconfigure hardware devices according to the ACPI table findings. If the
system state changes to "acpi_ready in the XML ROM 'acpi_ready':
!<system state="acpi_ready"/>
the platform driver will announce the platform session, so that drivers may
start to operate with the platform driver.
Hardware reset
--------------
If the attribute 'state' in the system XML ROM turns to 'reset'
!<system state="reset"/>
the platform driver will try to reset the machine, if the required I/O ports
are owned by it.
Supported PCI class aliases Supported PCI class aliases
--------------------------- ---------------------------
The following class names are supported which corresponds to the The following class names are supported which corresponds to the
specified PCI class(C), subclass(S) and programming interface(P): specified PCI class(C), subclass(S) and programming interface(P):
alias C S P alias C S P
********************* **********************
ALL 0x0 0x00 0x0 ALL 0x0 0x00 0x0
AHCI 0x1 0x06 0x0 AHCI 0x1 0x06 0x0
AUDIO 0x4 0x00 0x0 AUDIO 0x4 0x01 0x0
ETHERNET 0x2 0x00 0x0 ETHERNET 0x2 0x00 0x0
USB 0xc 0x03 0x0 HDAUDIO 0x4 0x03 0x0
VGA 0x3 0x00 0x0 USB 0xc 0x03 0x0
WIFI 0x2 0x80 0x0 VGA 0x3 0x00 0x0
WIFI 0x2 0x80 0x0
ISABRIDGE 0x6 0x01 0x0
Supported non PCI devices Supported non PCI devices

View File

@ -40,10 +40,15 @@ struct Platform::Main
Genode::Lazy_volatile_object<Platform::Root> root; Genode::Lazy_volatile_object<Platform::Root> root;
Genode::Lazy_volatile_object<Genode::Attached_rom_dataspace> system_state; Genode::Lazy_volatile_object<Genode::Attached_rom_dataspace> system_state;
Genode::Lazy_volatile_object<Genode::Attached_rom_dataspace> acpi_ready;
Genode::Signal_handler<Platform::Main> _acpi_report; Genode::Signal_handler<Platform::Main> _acpi_report;
Genode::Signal_handler<Platform::Main> _system_report; Genode::Signal_handler<Platform::Main> _system_report;
Genode::Capability<Genode::Typed_root<Platform::Session_component> > root_cap;
bool _system_rom = false;
void acpi_update() void acpi_update()
{ {
acpi_rom->update(); acpi_rom->update();
@ -54,24 +59,50 @@ struct Platform::Main
const char * report_addr = acpi_rom->local_addr<const char>(); const char * report_addr = acpi_rom->local_addr<const char>();
root.construct(_env, &sliced_heap, report_addr); root.construct(_env, &sliced_heap, report_addr);
_env.parent().announce(_env.ep().manage(*root));
root_cap = _env.ep().manage(*root);
if (_system_rom) {
Genode::Parent::Service_name announce_for_acpi("Acpi");
_env.parent().announce(announce_for_acpi, root_cap);
} else
_env.parent().announce(root_cap);
} }
void system_update() void system_update()
{ {
system_state->update(); if (!_system_rom || !system_state.is_constructed() ||
!acpi_ready.is_constructed())
if (!system_state->is_valid() || !root.is_constructed())
return; return;
Genode::Xml_node system(system_state->local_addr<char>(), system_state->update();
system_state->size()); acpi_ready->update();
typedef Genode::String<16> Value; if (!root.is_constructed())
const Value state = system.attribute_value("state", Value("unknown")); return;
if (state == "reset") if (system_state->is_valid()) {
root->system_reset(); 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();
}
if (acpi_ready->is_valid()) {
Genode::Xml_node system(acpi_ready->local_addr<char>(),
acpi_ready->size());
typedef Genode::String<16> Value;
const Value state = system.attribute_value("state", Value("unknown"));
if (state == "acpi_ready" && root_cap.valid()) {
_env.parent().announce(root_cap);
root_cap = Genode::Capability<Genode::Typed_root<Platform::Session_component> > ();
}
}
} }
Main(Genode::Env &env) Main(Genode::Env &env)
@ -83,22 +114,26 @@ struct Platform::Main
{ {
const Genode::Xml_node &config = Genode::config()->xml_node(); const Genode::Xml_node &config = Genode::config()->xml_node();
_system_rom = config.attribute_value("system", false);
typedef Genode::String<8> Value; typedef Genode::String<8> Value;
Value const wait_for_acpi = config.attribute_value("acpi", Value("yes")); Value const wait_for_acpi = config.attribute_value("acpi", Value("yes"));
if (wait_for_acpi == "yes") { if (_system_rom) {
bool system_reset = config.attribute_value("system", false); /* wait for system state changes, e.g. reset and acpi_ready */
if (system_reset) { system_state.construct("system");
/* wait for system state changes and react upon, e.g. reset */ system_state->sigh(_system_report);
system_state.construct("system"); acpi_ready.construct("acpi_ready");
system_state->sigh(_system_report); acpi_ready->sigh(_system_report);
} }
if (wait_for_acpi == "yes") {
/* for ACPI support, wait for the first valid acpi report */ /* for ACPI support, wait for the first valid acpi report */
acpi_rom.construct("acpi"); acpi_rom.construct("acpi");
acpi_rom->sigh(_acpi_report); acpi_rom->sigh(_acpi_report);
/* check if already valid */ /* check if already valid */
acpi_update(); acpi_update();
system_update();
return; return;
} }