mirror of
https://github.com/genodelabs/genode.git
synced 2025-05-28 21:24:26 +00:00
platform/pc: support to suspend via system_control
When the "system" ROM state turns to "suspend", the S3 state information of the sleep_states ROM are determined and are used to invoke the privileged Pd::system_control call. Issue #5180
This commit is contained in:
parent
94b3e30f90
commit
4c79f948ab
@ -419,6 +419,8 @@ install_config {
|
|||||||
<child name="config_fs_rom" label="managed/modem"/> </service>
|
<child name="config_fs_rom" label="managed/modem"/> </service>
|
||||||
<service name="ROM" label_last="audio.config">
|
<service name="ROM" label_last="audio.config">
|
||||||
<child name="config_fs_rom" label="managed/audio"/> </service>
|
<child name="config_fs_rom" label="managed/audio"/> </service>
|
||||||
|
<service name="ROM" label_last="sleep_states">
|
||||||
|
<child name="report_fs_rom" label="runtime/acpi_support/sleep_states"/> </service>
|
||||||
<service name="Timer"> <child name="timer"/> </service>
|
<service name="Timer"> <child name="timer"/> </service>
|
||||||
<service name="Capture"> <child name="nitpicker"/> </service>
|
<service name="Capture"> <child name="nitpicker"/> </service>
|
||||||
<service name="Event"> <child name="event_filter"/> </service>
|
<service name="Event"> <child name="event_filter"/> </service>
|
||||||
|
@ -89,6 +89,7 @@
|
|||||||
<provides> <service name="Platform"/> </provides>
|
<provides> <service name="Platform"/> </provides>
|
||||||
<route>
|
<route>
|
||||||
<service name="ROM" label="system"> <parent label="system"/> </service>
|
<service name="ROM" label="system"> <parent label="system"/> </service>
|
||||||
|
<service name="ROM" label="sleep_states"> <parent label="sleep_states"/> </service>
|
||||||
<service name="ROM" label="devices"> <child name="report_rom"/> </service>
|
<service name="ROM" label="devices"> <child name="report_rom"/> </service>
|
||||||
<service name="ROM" label="acpi"> <child name="report_rom"/> </service>
|
<service name="ROM" label="acpi"> <child name="report_rom"/> </service>
|
||||||
<service name="Report" label="devices"> <child name="report_rom"/> </service>
|
<service name="Report" label="devices"> <child name="report_rom"/> </service>
|
||||||
|
@ -49,6 +49,8 @@ class Driver::Common : Device_reporter,
|
|||||||
Constructible<Expanding_reporter> _dev_reporter { };
|
Constructible<Expanding_reporter> _dev_reporter { };
|
||||||
Constructible<Expanding_reporter> _iommu_reporter { };
|
Constructible<Expanding_reporter> _iommu_reporter { };
|
||||||
|
|
||||||
|
uint64_t _resume_counter { };
|
||||||
|
|
||||||
void _handle_devices();
|
void _handle_devices();
|
||||||
bool _iommu();
|
bool _iommu();
|
||||||
|
|
||||||
@ -67,6 +69,7 @@ class Driver::Common : Device_reporter,
|
|||||||
void handle_config(Xml_node config);
|
void handle_config(Xml_node config);
|
||||||
void acquire_io_mmu_devices();
|
void acquire_io_mmu_devices();
|
||||||
|
|
||||||
|
void report_resume();
|
||||||
|
|
||||||
/*********************
|
/*********************
|
||||||
** Device_reporter **
|
** Device_reporter **
|
||||||
@ -174,6 +177,7 @@ void Driver::Common::update_report()
|
|||||||
{
|
{
|
||||||
if (_dev_reporter.constructed())
|
if (_dev_reporter.constructed())
|
||||||
_dev_reporter->generate([&] (Xml_generator & xml) {
|
_dev_reporter->generate([&] (Xml_generator & xml) {
|
||||||
|
xml.attribute("resumed", _resume_counter);
|
||||||
_devices.generate(xml); });
|
_devices.generate(xml); });
|
||||||
if (_iommu_reporter.constructed())
|
if (_iommu_reporter.constructed())
|
||||||
_iommu_reporter->generate([&] (Xml_generator & xml) {
|
_iommu_reporter->generate([&] (Xml_generator & xml) {
|
||||||
@ -182,6 +186,12 @@ void Driver::Common::update_report()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Driver::Common::report_resume()
|
||||||
|
{
|
||||||
|
_resume_counter ++;
|
||||||
|
update_report();
|
||||||
|
}
|
||||||
|
|
||||||
void Driver::Common::disable_device(Device const & device)
|
void Driver::Common::disable_device(Device const & device)
|
||||||
{
|
{
|
||||||
_io_mmu_devices.for_each([&] (Io_mmu & io_mmu) {
|
_io_mmu_devices.for_each([&] (Io_mmu & io_mmu) {
|
||||||
|
@ -24,6 +24,7 @@ struct Driver::Main
|
|||||||
Attached_rom_dataspace _config_rom { _env, "config" };
|
Attached_rom_dataspace _config_rom { _env, "config" };
|
||||||
Attached_rom_dataspace _acpi_rom { _env, "acpi" };
|
Attached_rom_dataspace _acpi_rom { _env, "acpi" };
|
||||||
Attached_rom_dataspace _system_rom { _env, "system" };
|
Attached_rom_dataspace _system_rom { _env, "system" };
|
||||||
|
Attached_rom_dataspace _sleep_rom { _env, "sleep_states" };
|
||||||
Common _common { _env, _config_rom };
|
Common _common { _env, _config_rom };
|
||||||
Signal_handler<Main> _config_handler { _env.ep(), *this,
|
Signal_handler<Main> _config_handler { _env.ep(), *this,
|
||||||
&Main::_handle_config };
|
&Main::_handle_config };
|
||||||
@ -33,6 +34,7 @@ struct Driver::Main
|
|||||||
Intel::Io_mmu_factory _intel_iommu { _env, _common.io_mmu_factories() };
|
Intel::Io_mmu_factory _intel_iommu { _env, _common.io_mmu_factories() };
|
||||||
|
|
||||||
void _handle_config();
|
void _handle_config();
|
||||||
|
void _suspend();
|
||||||
void _reset();
|
void _reset();
|
||||||
void _system_update();
|
void _system_update();
|
||||||
|
|
||||||
@ -40,10 +42,13 @@ struct Driver::Main
|
|||||||
: _env(e)
|
: _env(e)
|
||||||
{
|
{
|
||||||
_config_rom.sigh(_config_handler);
|
_config_rom.sigh(_config_handler);
|
||||||
_acpi_rom.sigh(_system_handler);
|
_acpi_rom .sigh(_system_handler);
|
||||||
_system_rom.sigh(_system_handler);
|
_system_rom.sigh(_system_handler);
|
||||||
|
_sleep_rom .sigh(_system_handler);
|
||||||
|
|
||||||
_handle_config();
|
_handle_config();
|
||||||
_system_update();
|
_system_update();
|
||||||
|
|
||||||
_common.acquire_io_mmu_devices();
|
_common.acquire_io_mmu_devices();
|
||||||
_common.announce_service();
|
_common.announce_service();
|
||||||
}
|
}
|
||||||
@ -53,13 +58,19 @@ struct Driver::Main
|
|||||||
void Driver::Main::_handle_config()
|
void Driver::Main::_handle_config()
|
||||||
{
|
{
|
||||||
_config_rom.update();
|
_config_rom.update();
|
||||||
_common.handle_config(_config_rom.xml());
|
|
||||||
|
if (_config_rom.valid())
|
||||||
|
_common.handle_config(_config_rom.xml());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Driver::Main::_reset()
|
void Driver::Main::_reset()
|
||||||
{
|
{
|
||||||
_acpi_rom.update();
|
_acpi_rom.update();
|
||||||
|
|
||||||
|
if (!_acpi_rom.valid())
|
||||||
|
return;
|
||||||
|
|
||||||
_acpi_rom.xml().with_optional_sub_node("reset", [&] (Xml_node reset)
|
_acpi_rom.xml().with_optional_sub_node("reset", [&] (Xml_node reset)
|
||||||
{
|
{
|
||||||
uint16_t const io_port = reset.attribute_value<uint16_t>("io_port", 0);
|
uint16_t const io_port = reset.attribute_value<uint16_t>("io_port", 0);
|
||||||
@ -79,8 +90,68 @@ void Driver::Main::_reset()
|
|||||||
void Driver::Main::_system_update()
|
void Driver::Main::_system_update()
|
||||||
{
|
{
|
||||||
_system_rom.update();
|
_system_rom.update();
|
||||||
if (_system_rom.xml().attribute_value("state", String<16>()) == "reset")
|
|
||||||
|
if (!_system_rom.valid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto const state = _system_rom.xml().attribute_value("state", String<16>());
|
||||||
|
|
||||||
|
if (state == "reset")
|
||||||
_reset();
|
_reset();
|
||||||
|
|
||||||
|
if (state == "suspend") {
|
||||||
|
try { _suspend(); } catch (...) { error("suspend failed"); }
|
||||||
|
/* report independent of result */
|
||||||
|
_common.report_resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Driver::Main::_suspend()
|
||||||
|
{
|
||||||
|
_sleep_rom .update();
|
||||||
|
|
||||||
|
if (!_sleep_rom.valid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct Client: Genode::Rpc_client<Pd_session::System_control>
|
||||||
|
{
|
||||||
|
explicit Client(Genode::Capability<Pd_session::System_control> cap)
|
||||||
|
: Rpc_client<Pd_session::System_control>(cap) { }
|
||||||
|
|
||||||
|
Pd_session::Managing_system_state system_control(Pd_session::Managing_system_state const &state) override {
|
||||||
|
return call<Rpc_system_control>(state); }
|
||||||
|
} system_control { _env.pd().system_control_cap(Affinity::Location()) };
|
||||||
|
|
||||||
|
_sleep_rom.xml().with_sub_node("S3", [&] (auto const &node) {
|
||||||
|
|
||||||
|
auto const typea = "SLP_TYPa";
|
||||||
|
auto const typeb = "SLP_TYPb";
|
||||||
|
auto const valid = node.attribute_value("supported", false) &&
|
||||||
|
node.has_attribute(typea) &&
|
||||||
|
node.has_attribute(typeb);
|
||||||
|
|
||||||
|
if (!valid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto s3_sleep_typea = uint8_t(node.attribute_value(typea, 0u));
|
||||||
|
auto s3_sleep_typeb = uint8_t(node.attribute_value(typeb, 0u));
|
||||||
|
|
||||||
|
Pd_session::Managing_system_state in { }, out { };
|
||||||
|
|
||||||
|
in.trapno = Pd_session::Managing_system_state::ACPI_SUSPEND_REQUEST;
|
||||||
|
in.ip = s3_sleep_typea;
|
||||||
|
in.sp = s3_sleep_typeb;
|
||||||
|
|
||||||
|
out = system_control.system_control(in);
|
||||||
|
|
||||||
|
if (!out.trapno)
|
||||||
|
error("S3 suspend failed");
|
||||||
|
else
|
||||||
|
log("resumed from S3");
|
||||||
|
}, [&] {
|
||||||
|
warning("S3 suspend not supported");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user