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
This commit is contained in:
Sebastian Sumpf 2021-10-13 06:42:09 +02:00 committed by Christian Helmuth
parent 94405e9280
commit 96ab58691a
3 changed files with 81 additions and 58 deletions

View File

@ -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<Gpu::Session>
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<Gpu::Session>
Genode::uint64_t seqno { 0 };
public:
/**
@ -1867,11 +1874,7 @@ class Gpu::Session_component : public Genode::Session_object<Gpu::Session>
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;

View File

@ -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<ELEMENTS> _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<ELEMENTS>::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<ELEMENTS>::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<ELEMENTS>::Element *e = _map.virt_addr(pa);
return e ? (void*)e->va : nullptr;
addr_t virt = _map.virt_addr(pa);
return virt ? (void*)virt : nullptr;
}
};

View File

@ -45,29 +45,30 @@ namespace Utils {
template <unsigned int ELEMENTS>
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 <typename FN>
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;
}
};