From 29e21bff7f056406f0c21507cb67fb55830e9353 Mon Sep 17 00:00:00 2001 From: Johannes Schlatow Date: Wed, 17 Apr 2024 14:19:24 +0200 Subject: [PATCH] platform/pc: implement IOMMU suspend/resume genodelabs/genode#5180 --- .../src/drivers/platform/pc/intel/io_mmu.cc | 35 +++++++++++++++++++ .../pc/src/drivers/platform/pc/intel/io_mmu.h | 12 +++++++ .../drivers/platform/pc/spec/x86_64/main.cc | 10 ++++++ 3 files changed, 57 insertions(+) diff --git a/repos/pc/src/drivers/platform/pc/intel/io_mmu.cc b/repos/pc/src/drivers/platform/pc/intel/io_mmu.cc index 31dfcb7b56..be49fa3291 100644 --- a/repos/pc/src/drivers/platform/pc/intel/io_mmu.cc +++ b/repos/pc/src/drivers/platform/pc/intel/io_mmu.cc @@ -403,6 +403,41 @@ void Intel::Io_mmu::default_mappings_complete() } +void Intel::Io_mmu::suspend() +{ + _s3_fec = read(); + _s3_fedata = read(); + _s3_feaddr = read(); + _s3_rta = read(); +} + + +void Intel::Io_mmu::resume() +{ + /* disable queued invalidation interface if it was re-enabled by kernel */ + if (read() && read()) + _global_command(false); + + /* restore fault events only if kernel did not enable IRQ remapping */ + if (!read()) { + write(_s3_fec); + write(_s3_fedata); + write(_s3_feaddr); + } + + /* issue set root table pointer command */ + write(_s3_rta); + _global_command(1); + + if (!read()) + invalidate_all(); + + /* enable IOMMU */ + if (!read()) + _global_command(1); +} + + Intel::Io_mmu::Io_mmu(Env & env, Io_mmu_devices & io_mmu_devices, Device::Name const & name, diff --git a/repos/pc/src/drivers/platform/pc/intel/io_mmu.h b/repos/pc/src/drivers/platform/pc/intel/io_mmu.h index b831f4d042..2760073d81 100644 --- a/repos/pc/src/drivers/platform/pc/intel/io_mmu.h +++ b/repos/pc/src/drivers/platform/pc/intel/io_mmu.h @@ -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()*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 */ diff --git a/repos/pc/src/drivers/platform/pc/spec/x86_64/main.cc b/repos/pc/src/drivers/platform/pc/spec/x86_64/main.cc index 8df17317eb..b82f6c9934 100644 --- a/repos/pc/src/drivers/platform/pc/spec/x86_64/main.cc +++ b/repos/pc/src/drivers/platform/pc/spec/x86_64/main.cc @@ -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(); }