diff --git a/repos/os/src/drivers/gpu/intel/main.cc b/repos/os/src/drivers/gpu/intel/main.cc index 48f966b15f..ab10e16012 100644 --- a/repos/os/src/drivers/gpu/intel/main.cc +++ b/repos/os/src/drivers/gpu/intel/main.cc @@ -102,43 +102,6 @@ struct Igd::Device return _pci.alloc_dma_buffer(size, Genode::UNCACHED); }); } - Ram_dataspace_capability alloc(size_t size, - Cap_quota_guard &caps_guard, - Ram_quota_guard &ram_guard) override - { - /* - * For now we only reflect quota exceptions on explicit user - * allocations, e.g., buffers. - */ - try { - Genode::size_t donate = size; - return retry( - [&] () { - return retry( - [&] () { - return _pci.alloc_dma_buffer(size, Genode::UNCACHED); - }, - [&] () { - enum { UPGRADE_CAP_QUOTA = 2, }; - Cap_quota const caps { 2 }; - caps_guard.withdraw(caps); - _pci.upgrade_caps(caps.value); - } - ); - }, - [&] () { - Ram_quota const ram { donate }; - ram_guard.withdraw(ram); - _pci.upgrade_ram(ram.value); - } - ); - } catch (Ram_quota_guard::Limit_exceeded) { - throw Out_of_ram(); - } catch (Cap_quota_guard::Limit_exceeded) { - throw Out_of_caps(); - } - } - void free(Ram_dataspace_capability cap) override { if (!cap.valid()) { @@ -480,13 +443,11 @@ struct Igd::Device Engine(Igd::Device &device, uint32_t id, - Allocator &alloc, - Cap_quota_guard &caps_guard, - Ram_quota_guard &ram_guard) + Allocator &alloc) : ctx (device._env.rm(), alloc, device, CONTEXT::CONTEXT_PAGES, 1 /* omit GuC page */), ring(device._env.rm(), alloc, device, CONTEXT::RING_PAGES, 0), - ppgtt_allocator(device._env.rm(), device._pci_backend_alloc, caps_guard, ram_guard), + ppgtt_allocator(device._env.rm(), device._pci_backend_alloc), ppgtt_scratch(device._pci_backend_alloc) { /* PPGTT */ @@ -596,13 +557,11 @@ struct Igd::Device } Vgpu(Device &device, Allocator &alloc, - Ram_allocator &ram, Region_map &rm, - Cap_quota_guard &caps_guard, - Ram_quota_guard &ram_guard) + Ram_allocator &ram, Region_map &rm) : _device(device), _id(_id_alloc()), - rcs(_device, _id + Rcs_context::HW_ID, alloc, caps_guard, ram_guard), + rcs(_device, _id + Rcs_context::HW_ID, alloc), _info_dataspace(ram, rm, INFO_SIZE) { _device.vgpu_created(); @@ -1345,11 +1304,9 @@ struct Igd::Device * \throw Out_of_memory */ Genode::Dataspace_capability alloc_buffer(Allocator &, - size_t const size, - Cap_quota_guard &cap_guard, - Ram_quota_guard &ram_guard) + size_t const size) { - return _pci_backend_alloc.alloc(size, cap_guard, ram_guard); + return _pci_backend_alloc.alloc(size); } /** @@ -1513,6 +1470,7 @@ class Gpu::Session_component : public Genode::Session_object { private: + Genode::Env &_env; Genode::Region_map &_rm; Constrained_ram_allocator _ram; Heap _heap { _ram, _rm }; @@ -1520,6 +1478,85 @@ class Gpu::Session_component : public Genode::Session_object Igd::Device &_device; Igd::Device::Vgpu _vgpu; + struct Resource_guard + { + /* + * Estimations that work well enough with the current + * test-cases. + */ + Cap_quota const map_buffer_cap_amount { 2 }; + Ram_quota const map_buffer_ram_amount { 1024 }; + Cap_quota const map_buffer_ppgtt_cap_amount { 2 }; + Ram_quota const map_buffer_ppgtt_ram_amount { 4096 }; + Cap_quota const alloc_buffer_cap_amount { 4 }; + + struct Reservation + { + Cap_quota_guard::Reservation _cap_reserve; + Ram_quota_guard::Reservation _ram_reserve; + + Reservation(Cap_quota_guard &cap, Cap_quota cap_amount, + Ram_quota_guard &ram, Ram_quota ram_amount) + : + _cap_reserve { cap, cap_amount }, + _ram_reserve { ram, ram_amount } + { } + + void acknowledge() + { + _cap_reserve.acknowledge(); + _ram_reserve.acknowledge(); + } + }; + + Cap_quota_guard &_cap_quota_guard; + Ram_quota_guard &_ram_quota_guard; + + Resource_guard(Cap_quota_guard &cap, Ram_quota_guard &ram) + : + _cap_quota_guard { cap }, + _ram_quota_guard { ram } + { } + + Reservation map_buffer() + { + return Reservation { _cap_quota_guard, map_buffer_cap_amount, + _ram_quota_guard, map_buffer_ram_amount }; + } + + void unmap_buffer() + { + _cap_quota_guard.replenish(map_buffer_cap_amount); + _ram_quota_guard.replenish(map_buffer_ram_amount); + } + + Reservation map_buffer_ppgtt() + { + return Reservation { _cap_quota_guard, map_buffer_ppgtt_cap_amount, + _ram_quota_guard, map_buffer_ppgtt_ram_amount }; + } + + void unmap_buffer_ppgtt() + { + _cap_quota_guard.replenish(map_buffer_ppgtt_cap_amount); + _ram_quota_guard.replenish(map_buffer_ppgtt_ram_amount); + } + + Reservation alloc_buffer(Ram_quota ram_amount) + { + return Reservation { _cap_quota_guard, alloc_buffer_cap_amount, + _ram_quota_guard, ram_amount }; + } + + void free_buffer(Ram_quota ram_amount) + { + _cap_quota_guard.replenish(alloc_buffer_cap_amount); + _ram_quota_guard.replenish(ram_amount); + } + }; + + Resource_guard _resource_guard { _cap_quota_guard(), _ram_quota_guard() }; + struct Buffer { Gpu::Buffer_id const id; @@ -1555,41 +1592,6 @@ class Gpu::Session_component : public Genode::Session_object Genode::uint64_t seqno { 0 }; - void _free_buffers() - { - auto lookup_and_free = [&] (Buffer &buffer) { - - if (buffer.map.offset != Igd::Ggtt::Mapping::INVALID_OFFSET) { - _device.unmap_buffer(_heap, buffer.map); - } - - if (buffer.fenced != Buffer::INVALID_FENCE) { - _device.clear_tiling(buffer.fenced); - _vgpu.active_fences--; - } - - Genode::Dataspace_client buf(buffer.cap); - Genode::size_t const actual_size = buf.size(); - _vgpu.rcs_unmap_ppgtt(buffer.ppgtt_va, actual_size); - - _device.free_buffer(_heap, buffer.cap); - Genode::destroy(&_heap, &buffer); - }; - _buffer_registry.for_each(lookup_and_free); - } - - void _throw_if_avail_quota_insufficient(Cap_quota caps, Ram_quota ram) - { - Cap_quota const c = _cap_quota_guard().avail(); - if (c.value < caps.value) - throw Out_of_caps(); - - Ram_quota const r = _ram_quota_guard().avail(); - enum { MINIMAL_RAM_AMOUNT = 4096, }; - if (r.value < ram.value) - throw Out_of_ram(); - } - public: @@ -1601,7 +1603,8 @@ class Gpu::Session_component : public Genode::Session_object * \param ram_quota initial ram quota * \param device reference to the physical device */ - Session_component(Entrypoint &ep, + Session_component(Env &env, + Entrypoint &ep, Ram_allocator &ram, Region_map &rm, Resources resources, @@ -1610,21 +1613,58 @@ class Gpu::Session_component : public Genode::Session_object Igd::Device &device) : Session_object(ep, resources, label, diag), + _env(env), _rm(rm), _ram(ram, _ram_quota_guard(), _cap_quota_guard()), _device(device), - _vgpu(_device, _heap, ram, rm, _cap_quota_guard(), _ram_quota_guard()) + _vgpu(_device, _heap, ram, rm) { } ~Session_component() { - _free_buffers(); + auto lookup_and_free = [&] (Buffer &buffer) { + + if (buffer.map.offset != Igd::Ggtt::Mapping::INVALID_OFFSET) { + _device.unmap_buffer(_heap, buffer.map); + _resource_guard.unmap_buffer(); + } + + if (buffer.fenced != Buffer::INVALID_FENCE) { + _device.clear_tiling(buffer.fenced); + _vgpu.active_fences--; + } + + Genode::Dataspace_client buf(buffer.cap); + Genode::size_t const actual_size = buf.size(); + _vgpu.rcs_unmap_ppgtt(buffer.ppgtt_va, actual_size); + _resource_guard.unmap_buffer_ppgtt(); + + _device.free_buffer(_heap, buffer.cap); + Genode::destroy(&_heap, &buffer); + + _resource_guard.free_buffer(Ram_quota { actual_size }); + }; + _buffer_registry.for_each(lookup_and_free); } /********************************* ** Session_component interface ** *********************************/ + void upgrade_resources(Session::Resources resources) + { + upgrade(resources.ram_quota); + upgrade(resources.cap_quota); + } + + void dump_resources() + { + Genode::error(__func__, ": session (cap: ", _cap_quota_guard(), + " ram: ", _ram_quota_guard(), ") env: (cap: ", + "avail=", _env.pd().avail_caps(), " used=", _env.pd().used_caps(), + " ram: avail=", _env.pd().avail_ram(), " used=", _env.pd().used_ram()); + } + bool vgpu_active() const { return _device.vgpu_active(_vgpu); @@ -1693,8 +1733,11 @@ class Gpu::Session_component : public Genode::Session_object size = ((size + 0xffful) & ~0xffful); try { + Resource_guard::Reservation reserve = + _resource_guard.alloc_buffer(Ram_quota { size }); + Genode::Dataspace_capability cap = - _device.alloc_buffer(_heap, size, _cap_quota_guard(), _ram_quota_guard()); + _device.alloc_buffer(_heap, size); try { new (&_heap) Genode::Registered(_buffer_registry, id, cap); @@ -1703,11 +1746,18 @@ class Gpu::Session_component : public Genode::Session_object _device.free_buffer(_heap, cap); throw Gpu::Session_component::Out_of_ram(); } + + reserve.acknowledge(); return cap; } catch (Igd::Device::Out_of_caps) { throw Gpu::Session_component::Out_of_caps(); } catch (Igd::Device::Out_of_ram) { throw Gpu::Session_component::Out_of_ram(); + + } catch (Cap_quota_guard::Limit_exceeded) { + throw Gpu::Session_component::Out_of_caps(); + } catch (Ram_quota_guard::Limit_exceeded) { + throw Gpu::Session_component::Out_of_ram(); } return Genode::Dataspace_capability(); @@ -1722,8 +1772,12 @@ class Gpu::Session_component : public Genode::Session_object /* XXX throw */ } + Genode::size_t const size = Genode::Dataspace_client(buffer.cap).size(); + _device.free_buffer(_heap, buffer.cap); Genode::destroy(&_heap, &buffer); + + _resource_guard.free_buffer(Ram_quota { size }); }; _apply_buffer(id, lookup_and_free); } @@ -1732,13 +1786,6 @@ class Gpu::Session_component : public Genode::Session_object bool aperture, Gpu::Mapping_attributes attrs) override { - enum { - CAP_AMOUNT = 2, - RAM_AMOUNT = 4096, - }; - _throw_if_avail_quota_insufficient(Cap_quota { CAP_AMOUNT }, - Ram_quota { RAM_AMOUNT }); - /* treat GGTT mapped buffers as rw */ if (!(attrs.readable && attrs.writeable)) return Genode::Dataspace_capability(); @@ -1753,13 +1800,23 @@ class Gpu::Session_component : public Genode::Session_object } try { + Resource_guard::Reservation reserve = _resource_guard.map_buffer(); + Igd::Ggtt::Mapping const &map = _device.map_buffer(_heap, buffer.cap, aperture); buffer.map.cap = map.cap; buffer.map.offset = map.offset; map_cap = buffer.map.cap; + + reserve.acknowledge(); + } catch (Cap_quota_guard::Limit_exceeded) { + throw Gpu::Session::Out_of_caps(); } catch (Ram_quota_guard::Limit_exceeded) { throw Gpu::Session::Out_of_ram(); + } catch (Igd::Device::Out_of_caps) { + throw Gpu::Session::Out_of_caps(); + } catch (Igd::Device::Out_of_ram) { + throw Gpu::Session::Out_of_ram(); } }; _apply_buffer(id, lookup_and_map); @@ -1782,6 +1839,8 @@ class Gpu::Session_component : public Genode::Session_object _device.unmap_buffer(_heap, buffer.map); buffer.map.offset = Igd::Ggtt::Mapping::INVALID_OFFSET; unmapped = true; + + _resource_guard.unmap_buffer(); }; _apply_buffer(id, lookup_and_unmap); @@ -1790,13 +1849,6 @@ class Gpu::Session_component : public Genode::Session_object bool map_buffer_ppgtt(Gpu::Buffer_id id, Gpu::addr_t va) override { - enum { - CAP_AMOUNT = 32, - RAM_AMOUNT = 8192, - }; - _throw_if_avail_quota_insufficient(Cap_quota { CAP_AMOUNT }, - Ram_quota { RAM_AMOUNT }); - enum { ALLOC_FAILED_RAM, ALLOC_FAILED_CAPS, @@ -1812,6 +1864,9 @@ class Gpu::Session_component : public Genode::Session_object } try { + + Resource_guard::Reservation reserve = _resource_guard.map_buffer_ppgtt(); + Genode::Dataspace_client buf(buffer.cap); /* XXX check that actual_size matches alloc_buffer size */ Genode::size_t const actual_size = buf.size(); @@ -1820,6 +1875,14 @@ class Gpu::Session_component : public Genode::Session_object buffer.ppgtt_va = va; buffer.ppgtt_va_valid = true; result = OK; + + reserve.acknowledge(); + } catch (Cap_quota_guard::Limit_exceeded) { + result = ALLOC_FAILED_CAPS; + return; + } catch (Ram_quota_guard::Limit_exceeded) { + result = ALLOC_FAILED_RAM; + return; } catch (Igd::Device::Out_of_caps) { result = ALLOC_FAILED_CAPS; return; @@ -1864,6 +1927,8 @@ class Gpu::Session_component : public Genode::Session_object Genode::size_t const actual_size = buf.size(); _vgpu.rcs_unmap_ppgtt(va, actual_size); buffer.ppgtt_va_valid = false; + + _resource_guard.unmap_buffer_ppgtt(); }; _apply_buffer(id, lookup_and_unmap); } @@ -1940,20 +2005,12 @@ class Gpu::Root : public Gpu::Root_component } Genode::Session::Resources resources = session_resources_from_args(args); - Cap_quota const minimal_caps { 220 }; - resources.cap_quota.value -= minimal_caps.value; - _device->resources().platform().upgrade_caps(minimal_caps.value); - - Ram_quota const minimal_ram { 128u << 10 }; - resources.ram_quota.value -= minimal_ram.value; - _device->resources().platform().upgrade_ram(minimal_ram.value); - try { using namespace Genode; return new (md_alloc()) - Session_component(_env.ep(), _env.ram(), _env.rm(), + Session_component(_env, _env.ep(), _env.ram(), _env.rm(), resources, session_label_from_args(args), session_diag_from_args(args), @@ -1963,13 +2020,8 @@ class Gpu::Root : public Gpu::Root_component void _upgrade_session(Session_component *s, const char *args) override { - Genode::Ram_quota ram_quota = ram_quota_from_args(args); - ram_quota.value /= 2; - Genode::Cap_quota caps_quota = cap_quota_from_args(args); - caps_quota.value /= 2; - - s->upgrade(ram_quota); - s->upgrade(caps_quota); + Session::Resources const res = session_resources_from_args(args); + s->upgrade_resources(res); } void _destroy_session(Session_component *s) override diff --git a/repos/os/src/drivers/gpu/intel/ppgtt_allocator.h b/repos/os/src/drivers/gpu/intel/ppgtt_allocator.h index e344fd0a09..4aa3bade9f 100644 --- a/repos/os/src/drivers/gpu/intel/ppgtt_allocator.h +++ b/repos/os/src/drivers/gpu/intel/ppgtt_allocator.h @@ -35,20 +35,13 @@ class Igd::Ppgtt_allocator : public Genode::Translation_table_allocator enum { ELEMENTS = 256, }; Utils::Address_map _map { }; - Genode::Cap_quota_guard &_caps_guard; - Genode::Ram_quota_guard &_ram_guard; - public: Ppgtt_allocator(Genode::Region_map &rm, - Utils::Backend_alloc &backend, - Genode::Cap_quota_guard &caps_guard, - Genode::Ram_quota_guard &ram_guard) + Utils::Backend_alloc &backend) : _rm { rm }, - _backend { backend }, - _caps_guard { caps_guard }, - _ram_guard { ram_guard } + _backend { backend } { } /************************* diff --git a/repos/os/src/drivers/gpu/intel/utils.h b/repos/os/src/drivers/gpu/intel/utils.h index bf5d00d3de..4547be33b4 100644 --- a/repos/os/src/drivers/gpu/intel/utils.h +++ b/repos/os/src/drivers/gpu/intel/utils.h @@ -30,7 +30,6 @@ namespace Utils { struct Backend_alloc : Genode::Interface { virtual Ram alloc(Genode::size_t) = 0; - virtual Ram alloc(Genode::size_t, Genode::Cap_quota_guard &, Genode::Ram_quota_guard&) = 0; virtual void free(Ram) = 0; };