From 1727de30b773a2c8576abbf5c6cb545440b0696f Mon Sep 17 00:00:00 2001 From: Sebastian Sumpf Date: Fri, 23 Jul 2021 14:21:44 +0200 Subject: [PATCH] gpu/intel: free DMA, clear ggtt * free DMA caps in case platform client's session is closed * clear GGTT of platform client upon session close issue #4233 --- repos/os/src/drivers/gpu/intel/main.cc | 106 +++++++----------- .../src/drivers/gpu/intel/platform_session.h | 58 +++++++--- repos/os/src/drivers/gpu/intel/resources.h | 85 +++++++++++--- 3 files changed, 154 insertions(+), 95 deletions(-) diff --git a/repos/os/src/drivers/gpu/intel/main.cc b/repos/os/src/drivers/gpu/intel/main.cc index 77e3afd9d5..55c82298b2 100644 --- a/repos/os/src/drivers/gpu/intel/main.cc +++ b/repos/os/src/drivers/gpu/intel/main.cc @@ -85,23 +85,8 @@ struct Igd::Device Env &_env; Allocator &_md_alloc; - /*********** - ** Timer ** - ***********/ - - Timer::Connection _timer { _env }; - enum { WATCHDOG_TIMEOUT = 1*1000*1000, }; - struct Timer_delayer : Genode::Mmio::Delayer - { - Timer::Connection &_timer; - Timer_delayer(Timer::Connection &timer) : _timer(timer) { } - - void usleep(uint64_t us) override { _timer.usleep(us); } - - } _delayer { _timer }; - /********* ** PCI ** *********/ @@ -193,7 +178,7 @@ struct Igd::Device ** MMIO ** **********/ - Genode::Constructible _mmio { }; + Igd::Mmio &_mmio { _resources.mmio() }; /************ ** MEMORY ** @@ -732,7 +717,7 @@ struct Igd::Device { Execlist &el = *engine.execlist; - int const port = _mmio->read(); + int const port = _mmio.read(); el.schedule(port); @@ -742,10 +727,10 @@ struct Igd::Device desc[1] = el.elem0().high(); desc[0] = el.elem0().low(); - _mmio->write(desc[3]); - _mmio->write(desc[2]); - _mmio->write(desc[1]); - _mmio->write(desc[0]); + _mmio.write(desc[3]); + _mmio.write(desc[2]); + _mmio.write(desc[1]); + _mmio.write(desc[0]); } Vgpu *_unschedule_current_vgpu() @@ -774,19 +759,19 @@ struct Igd::Device Engine &rcs = gpu->rcs; - _mmio->flush_gfx_tlb(); + _mmio.flush_gfx_tlb(); /* * XXX check if HWSP is shared across contexts and if not when * we actually need to write the register */ Mmio::HWS_PGA_RCSUNIT::access_t const addr = rcs.hw_status_page(); - _mmio->write_post(addr); + _mmio.write_post(addr); _submit_execlist(rcs); _active_vgpu = gpu; - _timer.trigger_once(WATCHDOG_TIMEOUT); + _resources.timer().trigger_once(WATCHDOG_TIMEOUT); } /********** @@ -795,7 +780,7 @@ struct Igd::Device void _clear_rcs_iir(Mmio::GT_0_INTERRUPT_IIR::access_t const v) { - _mmio->write_post(v); + _mmio.write_post(v); } /** @@ -830,7 +815,7 @@ struct Igd::Device uint32_t _get_free_fence() { - return _mmio->find_free_fence(); + return _mmio.find_free_fence(); } uint32_t _update_fence(uint32_t const id, @@ -839,12 +824,12 @@ struct Igd::Device uint32_t const pitch, bool const tile_x) { - return _mmio->update_fence(id, lower, upper, pitch, tile_x); + return _mmio.update_fence(id, lower, upper, pitch, tile_x); } void _clear_fence(uint32_t const id) { - _mmio->clear_fence(id); + _mmio.clear_fence(id); } /********************** @@ -857,10 +842,10 @@ struct Igd::Device Genode::error("watchdog triggered: engine stuck," " vGPU=", _active_vgpu->id()); - _mmio->dump(); - _mmio->error_dump(); - _mmio->fault_dump(); - _mmio->execlist_status_dump(); + _mmio.dump(); + _mmio.error_dump(); + _mmio.fault_dump(); + _mmio.execlist_status_dump(); _active_vgpu->rcs.context->dump(); _active_vgpu->rcs.context->dump_hw_status_page(); @@ -883,11 +868,11 @@ struct Igd::Device void _device_reset_and_init() { - _mmio->reset(); - _mmio->clear_errors(); - _mmio->init(); - _mmio->enable_intr(); - _mmio->forcewake_enable(); + _mmio.reset(); + _mmio.clear_errors(); + _mmio.init(); + _mmio.enable_intr(); + _mmio.forcewake_enable(); } /** @@ -928,11 +913,9 @@ struct Igd::Device /* map PCI resources */ addr_t gttmmadr_base = _resources.map_gttmmadr(); - _mmio.construct(_delayer, gttmmadr_base); /* GGTT */ - Ram_dataspace_capability scratch_page_ds = _pci_backend_alloc.alloc(PAGE_SIZE); - addr_t const scratch_page = Dataspace_client(scratch_page_ds).phys_addr(); + addr_t const scratch_page = _resources.scratch_page(); /* reserverd size for framebuffer */ size_t const aperture_reserved = resources.gmadr_platform_size(); @@ -940,18 +923,17 @@ struct Igd::Device size_t const ggtt_size = (1u << MGGC_0_2_0_PCI::Gtt_graphics_memory_size::get(v)) << 20; addr_t const ggtt_base = gttmmadr_base + (_resources.gttmmadr_size() / 2); size_t const gmadr_size = _resources.gmadr_size(); - _ggtt.construct(*_mmio, ggtt_base, ggtt_size, gmadr_size, scratch_page, aperture_reserved); + _ggtt.construct(_mmio, ggtt_base, ggtt_size, gmadr_size, scratch_page, aperture_reserved); _ggtt->dump(); _vgpu_avail = (gmadr_size - aperture_reserved) / Vgpu::APERTURE_SIZE; _device_reset_and_init(); + _mmio.dump(); + _mmio.context_status_pointer_dump(); - _mmio->dump(); - _mmio->context_status_pointer_dump(); - - _timer.sigh(_watchdog_timeout_sigh); + _resources.timer().sigh(_watchdog_timeout_sigh); } /********************* @@ -1105,7 +1087,7 @@ struct Igd::Device uint32_t set_tiling(Ggtt::Offset const start, size_t const size, uint32_t const mode) { - uint32_t const id = _mmio->find_free_fence(); + uint32_t const id = _mmio.find_free_fence(); if (id == INVALID_FENCE) { Genode::warning("could not find free FENCE"); return id; @@ -1130,15 +1112,15 @@ struct Igd::Device unsigned handle_irq() { - Mmio::MASTER_INT_CTL::access_t master = _mmio->read(); + Mmio::MASTER_INT_CTL::access_t master = _mmio.read(); /* handle render interrupts only */ if (Mmio::MASTER_INT_CTL::Render_interrupts_pending::get(master) == 0) return master; - _mmio->disable_master_irq(); + _mmio.disable_master_irq(); - Mmio::GT_0_INTERRUPT_IIR::access_t const v = _mmio->read(); + Mmio::GT_0_INTERRUPT_IIR::access_t const v = _mmio.read(); bool const ctx_switch = Mmio::GT_0_INTERRUPT_IIR::Cs_ctx_switch_interrupt::get(v); (void)ctx_switch; @@ -1153,10 +1135,10 @@ struct Igd::Device notify_gpu->user_complete(); } - bool const fault_valid = _mmio->fault_regs_valid(); + bool const fault_valid = _mmio.fault_regs_valid(); if (fault_valid) { Genode::error("FAULT_REG valid"); } - _mmio->update_context_status_pointer(); + _mmio.update_context_status_pointer(); if (user_complete) { _unschedule_current_vgpu(); @@ -1176,7 +1158,7 @@ struct Igd::Device return master; } - void enable_master_irq() { _mmio->enable_master_irq(); } + void enable_master_irq() { _mmio.enable_master_irq(); } private: @@ -1623,9 +1605,10 @@ struct Main Genode::Sliced_heap _root_heap { _env.ram(), _env.rm() }; Gpu::Root _gpu_root { _env, _root_heap }; - Genode::Heap _device_md_alloc; + Genode::Heap _device_md_alloc { _env.ram(), _env.rm() }; Genode::Constructible _device { }; - Igd::Resources _gpu_resources { _env, *this, &Main::ack_irq }; + Igd::Resources _gpu_resources { _env, _device_md_alloc, + *this, &Main::ack_irq }; Genode::Irq_session_client _irq { _gpu_resources.gpu_client().irq(0) }; Genode::Signal_handler
_irq_dispatcher { @@ -1635,24 +1618,21 @@ struct Main Main(Genode::Env &env) : - _env(env), _device_md_alloc(_env.ram(), _env.rm()) + _env(env) { /* IRQ */ _irq.sigh(_irq_dispatcher); _irq.ack_irq(); - /* platform service */ - _platform_root.construct(_env, _device_md_alloc, _gpu_resources); - /* GPU */ try { _device.construct(_env, _device_md_alloc, _gpu_resources); - } catch (...) { - return; - } + _gpu_root.manage(*_device); + _env.parent().announce(_env.ep().manage(_gpu_root)); + } catch (...) { } - _gpu_root.manage(*_device); - _env.parent().announce(_env.ep().manage(_gpu_root)); + /* platform service */ + _platform_root.construct(_env, _device_md_alloc, _gpu_resources); } void handle_irq() diff --git a/repos/os/src/drivers/gpu/intel/platform_session.h b/repos/os/src/drivers/gpu/intel/platform_session.h index ec98b2b90c..e891f86734 100644 --- a/repos/os/src/drivers/gpu/intel/platform_session.h +++ b/repos/os/src/drivers/gpu/intel/platform_session.h @@ -1,7 +1,6 @@ /* * \brief Platform service implementation * \author Sebastian Sumpf - * \author Josef Soentgen * \date 2021-07-16 */ @@ -196,6 +195,23 @@ class Platform::Session_component : public Rpc_object Device_component _device_component; Connection &_platform; Device_capability _bridge; + Igd::Resources &_resources; + + struct Dma_cap + { + Ram_dataspace_capability cap; + + Dma_cap(Ram_dataspace_capability cap) + : cap(cap) { } + + virtual ~Dma_cap() { } + }; + + /* + * track DMA memory allocations so we can free them at session + * destruction + */ + Registry> _dma_registry { }; public: @@ -204,7 +220,8 @@ class Platform::Session_component : public Rpc_object _env(env), _device_component(env, resources), _platform(resources.platform()), - _bridge(resources.host_bridge_cap()) + _bridge(resources.host_bridge_cap()), + _resources(resources) { _env.ep().rpc_ep().manage(&_device_component); } @@ -212,13 +229,21 @@ class Platform::Session_component : public Rpc_object ~Session_component() { _env.ep().rpc_ep().dissolve(&_device_component); + + /* clear ggtt */ + _resources.gtt_platform_reset(); + + /* free DMA allocations */ + _dma_registry.for_each([&](Dma_cap &dma) { + _platform.free_dma_buffer(dma.cap); + destroy(&_resources.heap(), &dma); + }); } - Device_capability first_device(unsigned device_class, unsigned class_mask) override + Device_capability first_device(unsigned device_class, unsigned) override { - enum { ISA_BRIDGE = 0x601u << 8 }; - if (device_class == ISA_BRIDGE) - return _platform.first_device(device_class, class_mask); + if (device_class == _resources.isa_bridge_class()) + return _resources.isa_bridge_cap(); return _bridge; } @@ -232,14 +257,9 @@ class Platform::Session_component : public Rpc_object return Device_capability(); } - void release_device(Device_capability device) override + void release_device(Device_capability) override { - if (device.valid() == false) return; - - if (_device_component.cap() == device || device == _bridge) { - return; - } - _platform.release_device(device); + return; } Device_capability device(Device_name const & /* string */) override @@ -250,12 +270,20 @@ class Platform::Session_component : public Rpc_object Ram_dataspace_capability alloc_dma_buffer(size_t size, Cache cache) override { - return _platform.alloc_dma_buffer(size, cache); + Ram_dataspace_capability cap = _platform.alloc_dma_buffer(size, cache); + new (&_resources.heap()) Registered(_dma_registry, cap); + return cap; } void free_dma_buffer(Ram_dataspace_capability cap) override { - _platform.free_dma_buffer(cap); + if (!cap.valid()) return; + + _dma_registry.for_each([&](Dma_cap &dma) { + if ((dma.cap == cap) == false) return; + _platform.free_dma_buffer(cap); + destroy(&_resources.heap(), &dma); + }); } addr_t dma_addr(Ram_dataspace_capability cap) override diff --git a/repos/os/src/drivers/gpu/intel/resources.h b/repos/os/src/drivers/gpu/intel/resources.h index cd34f8f2bb..a81b8289a7 100644 --- a/repos/os/src/drivers/gpu/intel/resources.h +++ b/repos/os/src/drivers/gpu/intel/resources.h @@ -31,8 +31,22 @@ class Igd::Resources : Genode::Noncopyable using Io_mem_connection = Genode::Io_mem_connection; using Io_mem_dataspace_capability = Genode::Io_mem_dataspace_capability; + using Ram_dataspace_capability = Genode::Ram_dataspace_capability; - Genode::Env &_env; + Genode::Env &_env; + Genode::Heap &_heap; + + /* timer */ + Timer::Connection _timer { _env }; + + struct Timer_delayer : Genode::Mmio::Delayer + { + Timer::Connection &_timer; + Timer_delayer(Timer::Connection &timer) : _timer(timer) { } + + void usleep(uint64_t us) override { _timer.usleep(us); } + + } _delayer { _timer }; /* irq callback */ Main &_obj; @@ -43,15 +57,26 @@ class Igd::Resources : Genode::Noncopyable Platform::Device_capability _gpu_cap { }; Platform::Device_capability _host_bridge_cap { }; + Platform::Device_capability _isa_bridge_cap { }; Genode::Constructible _gpu_client { }; - /* mmio + gtt */ + /* mmio + ggtt */ Platform::Device::Resource _gttmmadr { }; Io_mem_dataspace_capability _gttmmadr_ds { }; Genode::Constructible _gttmmadr_io { }; + addr_t _gttmmadr_local { 0 }; + + Genode::Constructible _mmio { }; + + /* scratch page for ggtt */ + Ram_dataspace_capability _scratch_page_ds { + _platform.with_upgrade([&] () { + return _platform.alloc_dma_buffer(PAGE_SIZE, Genode::UNCACHED); }) }; + + addr_t _scratch_page { + Genode::Dataspace_client(_scratch_page_ds).phys_addr() }; /* aperture */ - Platform::Device::Resource _gmadr { }; enum { /* reserved aperture for platform service */ APERTURE_RESERVED = 64u<<20, @@ -59,14 +84,12 @@ class Igd::Resources : Genode::Noncopyable GTT_RESERVED = (APERTURE_RESERVED/PAGE_SIZE) * 8, }; + Platform::Device::Resource _gmadr { }; + /* managed dataspace for local platform service */ Genode::Rm_connection _rm_connection { _env }; Genode::Constructible _gttmmadr_rm { }; - /********** - ** Mmio ** - **********/ - void _create_gttmmadr_rm() { using off_t = Genode::off_t; @@ -135,6 +158,12 @@ class Igd::Resources : Genode::Noncopyable continue; } + if (device.class_code() == isa_bridge_class()) { + _isa_bridge_cap = cap; + release = false; + continue; + } + release = true; } } @@ -185,9 +214,10 @@ class Igd::Resources : Genode::Noncopyable public: - Resources(Genode::Env &env, Main &obj, void (Main::*ack_irq) ()) + Resources(Genode::Env &env, Genode::Heap &heap, + Main &obj, void (Main::*ack_irq) ()) : - _env(env), _obj(obj), _ack_irq(ack_irq) + _env(env), _heap(heap), _obj(obj), _ack_irq(ack_irq) { /* initial donation for device pd */ _platform.upgrade_ram(1024*1024); @@ -207,9 +237,9 @@ class Igd::Resources : Genode::Noncopyable _enable_pci_bus_master(); - Genode::log("Reserved beginning ", - Genode::Number_of_bytes(APERTURE_RESERVED), - " of aperture for platform service"); + log("Reserved beginning ", + Genode::Number_of_bytes(APERTURE_RESERVED), + " of aperture for platform service"); } ~Resources() @@ -223,14 +253,16 @@ class Igd::Resources : Genode::Noncopyable if (!_gttmmadr_ds.valid()) throw Initialization_failed(); - addr_t addr = (addr_t)(_env.rm().attach(_gttmmadr_ds, _gttmmadr.size())); + if (_gttmmadr_local) return _gttmmadr_local; + + _gttmmadr_local = (addr_t)(_env.rm().attach(_gttmmadr_ds, _gttmmadr.size())); log("Map res:", 0, " base:", Genode::Hex(_gttmmadr.base()), " size:", Genode::Hex(_gttmmadr.size()), - " vaddr:", Genode::Hex(addr)); + " vaddr:", Genode::Hex(_gttmmadr_local)); - return addr; + return _gttmmadr_local; } template @@ -254,19 +286,24 @@ class Igd::Resources : Genode::Noncopyable void ack_irq() { (_obj.*_ack_irq)(); } + Genode::Heap &heap() { return _heap; } + Timer::Connection &timer() { return _timer; }; + addr_t scratch_page() const { return _scratch_page; } + Platform::Connection &platform() { return _platform; } Platform::Device_client &gpu_client() { return *_gpu_client; } Platform::Device_capability host_bridge_cap() { return _host_bridge_cap; } + Platform::Device_capability isa_bridge_cap() { return _isa_bridge_cap; } + unsigned isa_bridge_class() const { return 0x601u << 8; } addr_t gmadr_base() const { return _gmadr.base(); } size_t gmadr_size() const { return _gmadr.size(); } addr_t gttmmadr_base() const { return _gttmmadr.base(); } - addr_t gttmmadr_size() const { return _gttmmadr.size(); } + size_t gttmmadr_size() const { return _gttmmadr.size(); } size_t gmadr_platform_size() const { return APERTURE_RESERVED; } size_t gttmmadr_platform_size() const { return GTT_RESERVED; } - Io_mem_dataspace_capability gttmmadr_platform_ds() { using namespace Genode; @@ -276,5 +313,19 @@ class Igd::Resources : Genode::Noncopyable return static_cap_cast(_gttmmadr_rm->dataspace()); } + + void gtt_platform_reset() + { + addr_t const base = map_gttmmadr() + (gttmmadr_size() / 2); + Igd::Ggtt(mmio(), base, gttmmadr_platform_size(), 0, scratch_page(), 0); + } + + Igd::Mmio &mmio() + { + if (!_mmio.constructed()) + _mmio.construct(_delayer, map_gttmmadr()); + + return *_mmio; + } };