From 96ab58691ad9924b5934c47d4f008db0996c6d6a Mon Sep 17 00:00:00 2001 From: Sebastian Sumpf Date: Wed, 13 Oct 2021 06:42:09 +0200 Subject: [PATCH] gpu/intel: PPGTT allocation optimization Use range allocator as cache for page mappings instead of allocating from platform driver for each page table. issue #4380 --- repos/os/src/drivers/gpu/intel/main.cc | 19 +++--- .../src/drivers/gpu/intel/ppgtt_allocator.h | 53 +++++++++------ repos/os/src/drivers/gpu/intel/utils.h | 67 ++++++++++--------- 3 files changed, 81 insertions(+), 58 deletions(-) diff --git a/repos/os/src/drivers/gpu/intel/main.cc b/repos/os/src/drivers/gpu/intel/main.cc index ab10e16012..8e536862b8 100644 --- a/repos/os/src/drivers/gpu/intel/main.cc +++ b/repos/os/src/drivers/gpu/intel/main.cc @@ -447,7 +447,7 @@ struct Igd::Device : 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), + ppgtt_allocator(alloc, device._env.rm(), device._pci_backend_alloc), ppgtt_scratch(device._pci_backend_alloc) { /* PPGTT */ @@ -1570,8 +1570,16 @@ class Gpu::Session_component : public Genode::Session_object Igd::Ggtt::Mapping map { }; + addr_t phys_addr { 0 }; + size_t size { 0 }; + Buffer(Gpu::Buffer_id id, Genode::Dataspace_capability cap) - : id { id }, cap { cap } { } + : id { id }, cap { cap } + { + Dataspace_client buf(cap); + phys_addr = buf.phys_addr(); + size = buf.size(); + } virtual ~Buffer() { } }; @@ -1592,7 +1600,6 @@ class Gpu::Session_component : public Genode::Session_object Genode::uint64_t seqno { 0 }; - public: /** @@ -1867,11 +1874,7 @@ class Gpu::Session_component : public Genode::Session_object 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(); - Genode::addr_t const phys_addr = buf.phys_addr(); - _vgpu.rcs_map_ppgtt(va, phys_addr, actual_size); + _vgpu.rcs_map_ppgtt(va, buffer.phys_addr, buffer.size); buffer.ppgtt_va = va; buffer.ppgtt_va_valid = true; result = OK; diff --git a/repos/os/src/drivers/gpu/intel/ppgtt_allocator.h b/repos/os/src/drivers/gpu/intel/ppgtt_allocator.h index 4aa3bade9f..49d3882ba4 100644 --- a/repos/os/src/drivers/gpu/intel/ppgtt_allocator.h +++ b/repos/os/src/drivers/gpu/intel/ppgtt_allocator.h @@ -32,28 +32,46 @@ class Igd::Ppgtt_allocator : public Genode::Translation_table_allocator Genode::Region_map &_rm; Utils::Backend_alloc &_backend; - enum { ELEMENTS = 256, }; + enum { ELEMENTS = 128, }; /* max 128M for page tables */ Utils::Address_map _map { }; + Genode::Allocator_avl _range; + public: - Ppgtt_allocator(Genode::Region_map &rm, + Ppgtt_allocator(Genode::Allocator &md_alloc, + Genode::Region_map &rm, Utils::Backend_alloc &backend) : _rm { rm }, - _backend { backend } + _backend { backend }, + _range { &md_alloc } { } + ~Ppgtt_allocator() + { + _map.for_each([&](Utils::Address_map::Element &elem) { + _rm.detach(elem.va); + _backend.free(elem.ds_cap); + elem.invalidate(); + }); + } + /************************* ** Allocator interface ** *************************/ Alloc_result try_alloc(size_t size) override { + Alloc_result result = _range.alloc_aligned(size, 12); + if (result.ok()) return result; + Genode::Ram_dataspace_capability ds { }; + size_t alloc_size = 1024*1024; + try { - ds = _backend.alloc(size, _caps_guard, _ram_guard); + ds = _backend.alloc(alloc_size); } catch (Genode::Out_of_ram) { return Alloc_error::OUT_OF_RAM; } catch (Genode::Out_of_caps) { return Alloc_error::OUT_OF_CAPS; } @@ -64,8 +82,11 @@ class Igd::Ppgtt_allocator : public Genode::Translation_table_allocator try { void * const ptr = _rm.attach(ds); - if (_map.add(ds, ptr)) - return ptr; + if (_map.add(ds, ptr) == true) { + _range.add_range((Genode::addr_t)ptr, alloc_size); + result = _range.alloc_aligned(size, 12); + return result; + } /* _map.add failed, roll back _rm.attach */ _rm.detach(ptr); @@ -76,22 +97,14 @@ class Igd::Ppgtt_allocator : public Genode::Translation_table_allocator /* roll back allocation */ _backend.free(ds); - return alloc_error; } - void free(void *addr, size_t) override + void free(void *addr, size_t size) override { if (addr == nullptr) { return; } - Genode::Ram_dataspace_capability cap = _map.remove(addr); - if (!cap.valid()) { - Genode::error("could not lookup capability for addr: ", addr); - return; - } - - _rm.detach(addr); - _backend.free(cap); + _range.free(addr, size); } bool need_size_for_free() const override { return false; } @@ -104,15 +117,15 @@ class Igd::Ppgtt_allocator : public Genode::Translation_table_allocator void *phys_addr(void *va) override { if (va == nullptr) { return nullptr; } - typename Utils::Address_map::Element *e = _map.phys_addr(va); - return e ? (void*)e->pa : nullptr; + addr_t pa = _map.phys_addr(va); + return pa ? (void *)pa : nullptr; } void *virt_addr(void *pa) override { if (pa == nullptr) { return nullptr; } - typename Utils::Address_map::Element *e = _map.virt_addr(pa); - return e ? (void*)e->va : nullptr; + addr_t virt = _map.virt_addr(pa); + return virt ? (void*)virt : nullptr; } }; diff --git a/repos/os/src/drivers/gpu/intel/utils.h b/repos/os/src/drivers/gpu/intel/utils.h index 4547be33b4..85b99ea9e3 100644 --- a/repos/os/src/drivers/gpu/intel/utils.h +++ b/repos/os/src/drivers/gpu/intel/utils.h @@ -45,29 +45,30 @@ namespace Utils { template class Utils::Address_map { + using addr_t = Genode::addr_t; + public: struct Element { - Ram ds_cap { }; - void *va { nullptr }; - void *pa { nullptr }; - uint32_t index { 0 }; + Ram ds_cap { }; + addr_t va { 0 }; + addr_t pa { 0 }; + size_t size { 0 }; Element() { } - Element(uint32_t index, Ram ds_cap, void *va) + Element(Ram ds_cap, void *va) : ds_cap(ds_cap), - va(va), - pa((void *)Genode::Dataspace_client(ds_cap).phys_addr()), - index(index) + va((addr_t)va), + pa(Genode::Dataspace_client(ds_cap).phys_addr()), + size(Genode::Dataspace_client(ds_cap).size()) { } Element(Element const &other) : - ds_cap(other.ds_cap), va(other.va), pa(other.pa), - index(other.index) + ds_cap(other.ds_cap), va(other.va), pa(other.pa) { } Element &operator = (Element const &other) @@ -75,11 +76,12 @@ class Utils::Address_map ds_cap = other.ds_cap; va = other.va; pa = other.pa; - index = other.index; + size = other.size; return *this; } - bool valid() { return va && pa; } + bool valid() { return size > 0; } + void invalidate() { *this = Element(); }; }; private: @@ -108,41 +110,46 @@ class Utils::Address_map for (uint32_t i = 0; i < ELEMENTS; i++) { if (_map[i].valid()) { continue; } - _map[i] = Element(i, ds_cap, va); + _map[i] = Element(ds_cap, va); return true; } return false; } - Ram remove(void *va) + template + void for_each(FN const &fn) { - Ram cap; - - for (uint32_t i = 0; i < ELEMENTS; i++) { - if (_map[i].va != va) { continue; } - - cap = _map[i].ds_cap; - _map[i] = Element(); - break; + for (unsigned i = 0; i < ELEMENTS; i++) { + if (_map[i].valid()) fn(_map[i]); } - - return cap; } - Element *phys_addr(void *va) + addr_t phys_addr(void *va) { + addr_t virt = (addr_t)va; for (uint32_t i = 0; i < ELEMENTS; i++) { - if (_map[i].va == va) { return &_map[i]; } + if (virt >= _map[i].va && virt < (_map[i].va + _map[i].size)) + { + Genode::off_t offset = virt - _map[i].va; + return _map[i].pa + offset; + } } - return nullptr; + Genode::error("phys_addr not found for ", va); + return 0; } - Element *virt_addr(void *pa) + addr_t virt_addr(void *pa) { + addr_t phys = (addr_t)pa; for (uint32_t i = 0; i < ELEMENTS; i++) { - if (_map[i].pa == pa) { return &_map[i]; } + if (phys >= _map[i].pa && phys < (_map[i].pa + _map[i].size)) + { + Genode::off_t offset = phys - _map[i].pa; + return _map[i].va + offset; + } } - return nullptr; + Genode::error("virt_addr not found for ", pa); + return 0; } };