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:
Alexander Boettcher 2024-04-12 15:11:29 +02:00 committed by Christian Helmuth
parent 94b3e30f90
commit 4c79f948ab
4 changed files with 87 additions and 3 deletions

View File

@ -419,6 +419,8 @@ install_config {
<child name="config_fs_rom" label="managed/modem"/> </service>
<service name="ROM" label_last="audio.config">
<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="Capture"> <child name="nitpicker"/> </service>
<service name="Event"> <child name="event_filter"/> </service>

View File

@ -89,6 +89,7 @@
<provides> <service name="Platform"/> </provides>
<route>
<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="acpi"> <child name="report_rom"/> </service>
<service name="Report" label="devices"> <child name="report_rom"/> </service>

View File

@ -49,6 +49,8 @@ class Driver::Common : Device_reporter,
Constructible<Expanding_reporter> _dev_reporter { };
Constructible<Expanding_reporter> _iommu_reporter { };
uint64_t _resume_counter { };
void _handle_devices();
bool _iommu();
@ -67,6 +69,7 @@ class Driver::Common : Device_reporter,
void handle_config(Xml_node config);
void acquire_io_mmu_devices();
void report_resume();
/*********************
** Device_reporter **
@ -174,6 +177,7 @@ void Driver::Common::update_report()
{
if (_dev_reporter.constructed())
_dev_reporter->generate([&] (Xml_generator & xml) {
xml.attribute("resumed", _resume_counter);
_devices.generate(xml); });
if (_iommu_reporter.constructed())
_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)
{
_io_mmu_devices.for_each([&] (Io_mmu & io_mmu) {

View File

@ -24,6 +24,7 @@ struct Driver::Main
Attached_rom_dataspace _config_rom { _env, "config" };
Attached_rom_dataspace _acpi_rom { _env, "acpi" };
Attached_rom_dataspace _system_rom { _env, "system" };
Attached_rom_dataspace _sleep_rom { _env, "sleep_states" };
Common _common { _env, _config_rom };
Signal_handler<Main> _config_handler { _env.ep(), *this,
&Main::_handle_config };
@ -33,6 +34,7 @@ struct Driver::Main
Intel::Io_mmu_factory _intel_iommu { _env, _common.io_mmu_factories() };
void _handle_config();
void _suspend();
void _reset();
void _system_update();
@ -40,10 +42,13 @@ struct Driver::Main
: _env(e)
{
_config_rom.sigh(_config_handler);
_acpi_rom.sigh(_system_handler);
_acpi_rom .sigh(_system_handler);
_system_rom.sigh(_system_handler);
_sleep_rom .sigh(_system_handler);
_handle_config();
_system_update();
_common.acquire_io_mmu_devices();
_common.announce_service();
}
@ -53,13 +58,19 @@ struct Driver::Main
void Driver::Main::_handle_config()
{
_config_rom.update();
_common.handle_config(_config_rom.xml());
if (_config_rom.valid())
_common.handle_config(_config_rom.xml());
}
void Driver::Main::_reset()
{
_acpi_rom.update();
if (!_acpi_rom.valid())
return;
_acpi_rom.xml().with_optional_sub_node("reset", [&] (Xml_node reset)
{
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()
{
_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();
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");
});
}