platform/pc: implement IOMMU suspend/resume

genodelabs/genode#5180
This commit is contained in:
Johannes Schlatow 2024-04-17 14:19:24 +02:00 committed by Christian Helmuth
parent 7441aba6d5
commit 29e21bff7f
3 changed files with 57 additions and 0 deletions

View File

@ -403,6 +403,41 @@ void Intel::Io_mmu::default_mappings_complete()
}
void Intel::Io_mmu::suspend()
{
_s3_fec = read<Fault_event_control>();
_s3_fedata = read<Fault_event_data>();
_s3_feaddr = read<Fault_event_address>();
_s3_rta = read<Root_table_address>();
}
void Intel::Io_mmu::resume()
{
/* disable queued invalidation interface if it was re-enabled by kernel */
if (read<Global_status::Enabled>() && read<Global_status::Qies>())
_global_command<Global_command::Qie>(false);
/* restore fault events only if kernel did not enable IRQ remapping */
if (!read<Global_status::Ires>()) {
write<Fault_event_control>(_s3_fec);
write<Fault_event_data>(_s3_fedata);
write<Fault_event_address>(_s3_feaddr);
}
/* issue set root table pointer command */
write<Root_table_address>(_s3_rta);
_global_command<Global_command::Srtp>(1);
if (!read<Capability::Esrtps>())
invalidate_all();
/* enable IOMMU */
if (!read<Global_status::Enabled>())
_global_command<Global_command::Enable>(1);
}
Intel::Io_mmu::Io_mmu(Env & env,
Io_mmu_devices & io_mmu_devices,
Device::Name const & name,

View File

@ -408,6 +408,12 @@ class Intel::Io_mmu : private Attached_mmio<0x800>,
struct Did : Bitfield<32,16> { };
};
/* saved registers during suspend */
Fault_event_control::access_t _s3_fec { };
Fault_event_data ::access_t _s3_fedata { };
Fault_event_address ::access_t _s3_feaddr { };
Root_table_address::access_t _s3_rta { };
uint32_t _max_domains() {
return 1 << (4 + read<Capability::Domains>()*2); }
@ -543,6 +549,12 @@ class Intel::Io_mmu : private Attached_mmio<0x800>,
void flush_write_buffer();
/**
* Io_mmu suspend/resume interface
*/
void suspend() override;
void resume() override;
/**
* Io_mmu interface for default mappings
*/

View File

@ -100,7 +100,17 @@ void Driver::Main::_system_update()
_reset();
if (state == "suspend") {
/* save IOMMU state */
_common.io_mmu_devices().for_each([&] (Driver::Io_mmu & io_mmu) {
io_mmu.suspend();
});
try { _suspend("S3"); } catch (...) { error("suspend failed"); }
/* re-initialise IOMMU independent of result */
_common.io_mmu_devices().for_each([&] (Driver::Io_mmu & io_mmu) {
io_mmu.resume();
});
/* report independent of result */
_common.report_resume();
}