gpu/intel: add VRAM support

Remove buffer abstraction and replace it by VRAM objects.

issue #4713
This commit is contained in:
Sebastian Sumpf 2022-12-18 18:19:08 +01:00 committed by Christian Helmuth
parent f72cb2b69b
commit 47f1eaac2a
2 changed files with 216 additions and 263 deletions

View File

@ -22,12 +22,12 @@
#include <base/rpc_server.h> #include <base/rpc_server.h>
#include <base/session_object.h> #include <base/session_object.h>
#include <dataspace/client.h> #include <dataspace/client.h>
#include <gpu_session/gpu_session.h>
#include <gpu/info_intel.h> #include <gpu/info_intel.h>
#include <platform_session/dma_buffer.h> #include <platform_session/dma_buffer.h>
#include <platform_session/device.h> #include <platform_session/device.h>
#include <root/component.h> #include <root/component.h>
#include <timer_session/connection.h> #include <timer_session/connection.h>
#include <util/dictionary.h>
#include <util/fifo.h> #include <util/fifo.h>
#include <util/mmio.h> #include <util/mmio.h>
#include <util/retry.h> #include <util/retry.h>
@ -72,7 +72,7 @@ struct Igd::Device
struct Unsupported_device : Genode::Exception { }; struct Unsupported_device : Genode::Exception { };
struct Out_of_caps : Genode::Exception { }; struct Out_of_caps : Genode::Exception { };
struct Out_of_ram : Genode::Exception { }; struct Out_of_ram : Genode::Exception { };
struct Could_not_map_buffer : Genode::Exception { }; struct Could_not_map_vram : Genode::Exception { };
enum { WATCHDOG_TIMEOUT = 1*1000*1000, }; enum { WATCHDOG_TIMEOUT = 1*1000*1000, };
@ -112,7 +112,7 @@ struct Igd::Device
[&] () [&] ()
{ {
if (_env.pd().avail_caps().value < UPGRADE_CAPS) { if (_env.pd().avail_caps().value < UPGRADE_CAPS) {
warning("alloc dma buffer: out if caps"); warning("alloc dma vram: out if caps");
throw Gpu::Session::Out_of_caps(); throw Gpu::Session::Out_of_caps();
} }
@ -123,7 +123,7 @@ struct Igd::Device
[&] () [&] ()
{ {
if (_env.pd().avail_ram().value < size) { if (_env.pd().avail_ram().value < size) {
warning("alloc dma buffer: out of ram"); warning("alloc dma vram: out of ram");
throw Gpu::Session::Out_of_ram(); throw Gpu::Session::Out_of_ram();
} }
_pci.upgrade_ram(size); _pci.upgrade_ram(size);
@ -379,9 +379,9 @@ struct Igd::Device
void schedule(int port) { _scheduled = port; } void schedule(int port) { _scheduled = port; }
int scheduled() const { return _scheduled; } int scheduled() const { return _scheduled; }
/*************************** /*************************
** Ring buffer interface ** ** Ring vram interface **
***************************/ *************************/
void ring_reset() { _ring.reset(); } void ring_reset() { _ring.reset(); }
Ring_buffer::Index ring_tail() const { return _ring.tail(); } Ring_buffer::Index ring_tail() const { return _ring.tail(); }
@ -652,7 +652,7 @@ struct Igd::Device
Gpu::Sequence_number { .value = _device.seqno() }; Gpu::Sequence_number { .value = _device.seqno() };
} }
bool setup_ring_buffer(Gpu::addr_t const buffer_addr) bool setup_ring_vram(Gpu::addr_t const vram_addr)
{ {
_current_seqno++; _current_seqno++;
@ -664,7 +664,7 @@ struct Igd::Device
Device_info::Stepping::A0, Device_info::Stepping::A0,
Device_info::Stepping::B0); Device_info::Stepping::B0);
size_t const need = 4 /* batchbuffer cmd */ + 6 /* prolog */ size_t const need = 4 /* batchvram cmd */ + 6 /* prolog */
+ ((_device.generation().value == 9) ? 6 : 0) + ((_device.generation().value == 9) ? 6 : 0)
+ ((_device.generation().value == 8) ? 20 : 22) /* epilog + w/a */ + ((_device.generation().value == 8) ? 20 : 22) /* epilog + w/a */
+ (dc_flush_wa ? 12 : 0); + (dc_flush_wa ? 12 : 0);
@ -753,7 +753,7 @@ struct Igd::Device
/* /*
* gen8_emit_bb_start_noarb, gen8 and render engine * gen8_emit_bb_start_noarb, gen8 and render engine
* *
* batch-buffer commands * batch-vram commands
*/ */
if (_device.generation().value == 8) if (_device.generation().value == 8)
{ {
@ -763,8 +763,8 @@ struct Igd::Device
cmd[0] = Mi_arb_on_off(false).value; cmd[0] = Mi_arb_on_off(false).value;
cmd[1] = mi.value; cmd[1] = mi.value;
cmd[2] = buffer_addr & 0xffffffff; cmd[2] = vram_addr & 0xffffffff;
cmd[3] = (buffer_addr >> 32) & 0xffff; cmd[3] = (vram_addr >> 32) & 0xffff;
for (size_t i = 0; i < CMD_NUM; i++) { for (size_t i = 0; i < CMD_NUM; i++) {
advance += el.ring_append(cmd[i]); advance += el.ring_append(cmd[i]);
@ -774,7 +774,7 @@ struct Igd::Device
/* /*
* gen8_emit_bb_start, gen9 * gen8_emit_bb_start, gen9
* *
* batch-buffer commands * batch-vram commands
*/ */
if (_device.generation().value >= 9) if (_device.generation().value >= 9)
{ {
@ -784,8 +784,8 @@ struct Igd::Device
cmd[0] = Mi_arb_on_off(true).value; cmd[0] = Mi_arb_on_off(true).value;
cmd[1] = mi.value; cmd[1] = mi.value;
cmd[2] = buffer_addr & 0xffffffff; cmd[2] = vram_addr & 0xffffffff;
cmd[3] = (buffer_addr >> 32) & 0xffff; cmd[3] = (vram_addr >> 32) & 0xffff;
cmd[4] = Mi_arb_on_off(false).value; cmd[4] = Mi_arb_on_off(false).value;
cmd[5] = Mi_noop().value; cmd[5] = Mi_noop().value;
@ -1370,21 +1370,21 @@ struct Igd::Device
return result; return result;
} }
/********************* /*******************
** Buffer handling ** ** Vram handling **
*********************/ *******************/
/** /**
* Allocate DMA buffer * Allocate DMA vram
* *
* \param guard resource allocator and guard * \param guard resource allocator and guard
* \param size size of the DMA buffer * \param size size of the DMA vram
* *
* \return DMA buffer capability * \return DMA vram capability
* *
* \throw Out_of_memory * \throw Out_of_memory
*/ */
Genode::Ram_dataspace_capability alloc_buffer(Allocator &, Genode::Ram_dataspace_capability alloc_vram(Allocator &,
size_t const size) size_t const size)
{ {
return _pci_backend_alloc.alloc(size); return _pci_backend_alloc.alloc(size);
@ -1392,7 +1392,7 @@ struct Igd::Device
/** /**
* Get physical address for DMA buffer * Get physical address for DMA vram
* *
* \param ds_cap ram dataspace capability * \param ds_cap ram dataspace capability
* *
@ -1404,12 +1404,12 @@ struct Igd::Device
} }
/** /**
* Free DMA buffer * Free DMA vram
* *
* \param guard resource allocator and guard * \param guard resource allocator and guard
* \param cap DMA buffer capability * \param cap DMA vram capability
*/ */
void free_buffer(Allocator &, void free_vram(Allocator &,
Dataspace_capability const cap) Dataspace_capability const cap)
{ {
if (!cap.valid()) { return; } if (!cap.valid()) { return; }
@ -1418,23 +1418,23 @@ struct Igd::Device
} }
/** /**
* Map DMA buffer in the GGTT * Map DMA vram in the GGTT
* *
* \param guard resource allocator and guard * \param guard resource allocator and guard
* \param cap DMA buffer capability * \param cap DMA vram capability
* \param aperture true if mapping should be accessible by CPU * \param aperture true if mapping should be accessible by CPU
* *
* \return GGTT mapping * \return GGTT mapping
* *
* \throw Could_not_map_buffer * \throw Could_not_map_vram
*/ */
Ggtt::Mapping const &map_buffer(Genode::Allocator &guard, Ggtt::Mapping const &map_vram(Genode::Allocator &guard,
Genode::Ram_dataspace_capability cap, Genode::Ram_dataspace_capability cap,
bool aperture) bool aperture)
{ {
if (aperture == false) { if (aperture == false) {
error("GGTT mapping outside aperture"); error("GGTT mapping outside aperture");
throw Could_not_map_buffer(); throw Could_not_map_vram();
} }
size_t const size = Genode::Dataspace_client(cap).size(); size_t const size = Genode::Dataspace_client(cap).size();
@ -1444,12 +1444,12 @@ struct Igd::Device
} }
/** /**
* Unmap DMA buffer from GGTT * Unmap DMA vram from GGTT
* *
* \param guard resource allocator and guard * \param guard resource allocator and guard
* \param mapping GGTT mapping * \param mapping GGTT mapping
*/ */
void unmap_buffer(Genode::Allocator &guard, Ggtt::Mapping mapping) void unmap_vram(Genode::Allocator &guard, Ggtt::Mapping mapping)
{ {
unmap_dataspace_ggtt(guard, mapping.cap); unmap_dataspace_ggtt(guard, mapping.cap);
} }
@ -1561,7 +1561,7 @@ namespace Gpu {
} }
struct Gpu::Buffer : Genode::Interface struct Gpu::Vram : Genode::Interface
{ {
GENODE_RPC_INTERFACE(); GENODE_RPC_INTERFACE();
}; };
@ -1637,9 +1637,9 @@ class Gpu::Session_component : public Genode::Session_object<Gpu::Session>
Resource_guard _resource_guard { _cap_quota_guard(), _ram_quota_guard() }; Resource_guard _resource_guard { _cap_quota_guard(), _ram_quota_guard() };
/* /*
* Buffer managed by session ep * Vram managed by session ep
*/ */
struct Buffer : Rpc_object<Gpu::Buffer> struct Vram : Rpc_object<Gpu::Vram>
{ {
Ram_dataspace_capability ds_cap; Ram_dataspace_capability ds_cap;
Session_capability owner_cap; Session_capability owner_cap;
@ -1655,7 +1655,7 @@ class Gpu::Session_component : public Genode::Session_object<Gpu::Session>
bool caps_used { false }; bool caps_used { false };
size_t ram_used { 0 }; size_t ram_used { 0 };
Buffer(Ram_dataspace_capability ds_cap, Genode::addr_t phys_addr, Vram(Ram_dataspace_capability ds_cap, Genode::addr_t phys_addr,
Session_capability owner_cap) Session_capability owner_cap)
: :
ds_cap { ds_cap }, owner_cap { owner_cap }, ds_cap { ds_cap }, owner_cap { owner_cap },
@ -1672,75 +1672,95 @@ class Gpu::Session_component : public Genode::Session_object<Gpu::Session>
}; };
/* /*
* Buffer session/gpu-context local buffer * Vram session/gpu-context local vram
*/ */
struct Buffer_local struct Vram_local
{ {
using Id_space = Genode::Id_space<Buffer_local>; /* keep track of mappings of different offsets */
struct Mapping : Dictionary<Mapping, off_t>::Element
{
addr_t ppgtt_va { 0 };
size_t ppgtt_va_size { 0 };
Buffer_capability const buffer_cap; Mapping(Dictionary<Mapping, off_t> &dict, off_t offset,
addr_t ppgtt_va, size_t ppgtt_va_size)
:
Dictionary<Mapping, off_t>::Element(dict, offset),
ppgtt_va(ppgtt_va), ppgtt_va_size(ppgtt_va_size)
{ }
};
using Id_space = Genode::Id_space<Vram_local>;
Vram_capability const vram_cap;
size_t size; size_t size;
Id_space::Element const elem; Id_space::Element const elem;
Dictionary<Mapping, off_t> mappings { };
addr_t ppgtt_va { 0 }; addr_t ppgtt_va { 0 };
bool ppgtt_va_valid { false }; bool ppgtt_va_valid { false };
Buffer_local(Buffer_capability buffer_cap, size_t size, Vram_local(Vram_capability vram_cap, size_t size,
Id_space &space, Buffer_id id) Id_space &space, Vram_id id)
: buffer_cap(buffer_cap), size(size), : vram_cap(vram_cap), size(size),
elem(*this, space, Id_space::Id { .value = id.value }) elem(*this, space, Id_space::Id { .value = id.value })
{ } { }
}; };
Id_space<Buffer_local> _buffer_space { }; Id_space<Vram_local> _vram_space { };
template <typename FN> template <typename FN>
void _apply_buffer(Buffer_local &buffer_local, FN const &fn) void _apply_vram(Vram_local &vram_local, FN const &fn)
{ {
Buffer *b = nullptr; Vram *v = nullptr;
bool free = _env.ep().rpc_ep().apply(buffer_local.buffer_cap, [&] (Buffer *buffer) { bool free = _env.ep().rpc_ep().apply(vram_local.vram_cap, [&] (Vram *vram) {
if (buffer) { if (vram) {
b = buffer; v = vram;
return fn(*buffer); return fn(*vram);
} }
return false; return false;
}); });
if (b && free) if (v && free)
destroy(&_heap, b); destroy(&_heap, v);
} }
bool _buffer_valid(Buffer_capability buffer_cap) bool _vram_valid(Vram_capability vram_cap)
{ {
bool valid = false; bool valid = false;
_env.ep().rpc_ep().apply(buffer_cap, [&] (Buffer *buffer) { _env.ep().rpc_ep().apply(vram_cap, [&] (Vram *vram) {
if (buffer) valid = true; if (vram) valid = true;
}); });
return valid; return valid;
} }
template <typename FN> template <typename FN>
void _apply_buffer_local(Gpu::Buffer_id id, FN const &fn) void _apply_vram_local(Gpu::Vram_id id, FN const &fn)
{ {
Buffer_local::Id_space::Id local_id { .value = id.value }; Vram_local::Id_space::Id local_id { .value = id.value };
try { try {
_buffer_space.apply<Buffer_local>(local_id, [&] (Buffer_local &buffer) { _vram_space.apply<Vram_local>(local_id, [&] (Vram_local &vram) {
fn(buffer); fn(vram);
}); });
} catch (Buffer_local::Id_space::Unknown_id) { } catch (Vram_local::Id_space::Unknown_id) {
error("Unknown id: ", id.value); error("Unknown id: ", id.value);
} }
} }
Genode::uint64_t seqno { 0 }; Genode::uint64_t seqno { 0 };
void _free_local_buffer(Buffer_local &buffer_local) void _free_local_vram(Vram_local &vram_local)
{ {
if (buffer_local.ppgtt_va_valid) { vram_local.mappings.for_each([&] (Vram_local::Mapping const &mapping) {
_vgpu.rcs_unmap_ppgtt(buffer_local.ppgtt_va, buffer_local.size); _vgpu.rcs_unmap_ppgtt(mapping.ppgtt_va, mapping.ppgtt_va_size);
} });
destroy(&_heap, &buffer_local); while (vram_local.mappings.with_any_element([&] (Vram_local::Mapping &mapping) {
destroy(_heap, &mapping);
})) { }
destroy(&_heap, &vram_local);
} }
public: public:
@ -1772,31 +1792,31 @@ class Gpu::Session_component : public Genode::Session_object<Gpu::Session>
~Session_component() ~Session_component()
{ {
auto lookup_and_free = [&] (Buffer_local &buffer_local) { auto lookup_and_free = [&] (Vram_local &vram_local) {
_apply_buffer(buffer_local, [&](Buffer &buffer) { _apply_vram(vram_local, [&](Vram &vram) {
if (buffer.owner(_session_cap) == false) return false; if (vram.owner(_session_cap) == false) return false;
if (buffer.map.offset != Igd::Ggtt::Mapping::INVALID_OFFSET) { if (vram.map.offset != Igd::Ggtt::Mapping::INVALID_OFFSET) {
_device.unmap_buffer(_heap, buffer.map); _device.unmap_vram(_heap, vram.map);
} }
if (buffer.fenced != Buffer::INVALID_FENCE) { if (vram.fenced != Vram::INVALID_FENCE) {
_device.clear_tiling(buffer.fenced); _device.clear_tiling(vram.fenced);
_vgpu.active_fences--; _vgpu.active_fences--;
} }
_env.ep().dissolve(buffer); _env.ep().dissolve(vram);
_device.free_buffer(_heap, buffer.ds_cap); _device.free_vram(_heap, vram.ds_cap);
return true; return true;
}); });
_free_local_buffer(buffer_local); _free_local_vram(vram_local);
}; };
while(_buffer_space.apply_any<Buffer_local>( while(_vram_space.apply_any<Vram_local>(
[&] (Buffer_local &buffer_local) { lookup_and_free(buffer_local); })); [&] (Vram_local &vram_local) { lookup_and_free(vram_local); }));
} }
/********************************* /*********************************
@ -1831,25 +1851,31 @@ class Gpu::Session_component : public Genode::Session_object<Gpu::Session>
return _vgpu.info_dataspace(); return _vgpu.info_dataspace();
} }
Gpu::Sequence_number exec_buffer(Buffer_id id, Gpu::Sequence_number execute(Vram_id id, off_t offset) override
Genode::size_t) override
{ {
bool found = false; bool found = false;
_apply_buffer_local(id, [&] (Buffer_local &buffer_local) { _apply_vram_local(id, [&] (Vram_local &vram_local) {
if (_buffer_valid(buffer_local.buffer_cap) == false) { if (_vram_valid(vram_local.vram_cap) == false) {
_free_local_buffer(buffer_local); _free_local_vram(vram_local);
return; return;
} }
if (!buffer_local.ppgtt_va_valid) { addr_t ppgtt_va { 0 };
Genode::error("Invalid execbuffer");
bool ppgtt_va_valid = vram_local.mappings.with_element(offset,
[&] (Vram_local::Mapping const &mapping) {
ppgtt_va = mapping.ppgtt_va; return true; },
[]() { return false; });
if (!ppgtt_va_valid) {
Genode::error("Invalid execvram");
Genode::Signal_transmitter(_vgpu.completion_sigh()).submit(); Genode::Signal_transmitter(_vgpu.completion_sigh()).submit();
throw Gpu::Session::Invalid_state(); throw Gpu::Session::Invalid_state();
} }
found = _vgpu.setup_ring_buffer(buffer_local.ppgtt_va); found = _vgpu.setup_ring_vram(ppgtt_va);
}); });
if (!found) if (!found)
@ -1869,7 +1895,7 @@ class Gpu::Session_component : public Genode::Session_object<Gpu::Session>
_vgpu.completion_sigh(sigh); _vgpu.completion_sigh(sigh);
} }
Genode::Dataspace_capability alloc_buffer(Gpu::Buffer_id id, Genode::Dataspace_capability alloc_vram(Gpu::Vram_id id,
Genode::size_t size) override Genode::size_t size) override
{ {
/* roundup to next page size */ /* roundup to next page size */
@ -1884,80 +1910,80 @@ class Gpu::Session_component : public Genode::Session_object<Gpu::Session>
size_t caps_before = _env.pd().avail_caps().value; size_t caps_before = _env.pd().avail_caps().value;
size_t ram_before = _env.pd().avail_ram().value; size_t ram_before = _env.pd().avail_ram().value;
Ram_dataspace_capability ds_cap = _device.alloc_buffer(_heap, size); Ram_dataspace_capability ds_cap = _device.alloc_vram(_heap, size);
addr_t phys_addr = _device.dma_addr(ds_cap); addr_t phys_addr = _device.dma_addr(ds_cap);
Buffer *buffer = new (&_heap) Buffer(ds_cap, phys_addr, _session_cap); Vram *vram = new (&_heap) Vram(ds_cap, phys_addr, _session_cap);
_env.ep().manage(*buffer); _env.ep().manage(*vram);
try { try {
new (&_heap) Buffer_local(buffer->cap(), size, _buffer_space, id); new (&_heap) Vram_local(vram->cap(), size, _vram_space, id);
} catch (Id_space<Buffer_local>::Conflicting_id) { } catch (Id_space<Vram_local>::Conflicting_id) {
_env.ep().dissolve(*buffer); _env.ep().dissolve(*vram);
destroy(&_heap, buffer); destroy(&_heap, vram);
_device.free_buffer(_heap, ds_cap); _device.free_vram(_heap, ds_cap);
return Dataspace_capability(); return Dataspace_capability();
} }
size_t caps_after = _env.pd().avail_caps().value; size_t caps_after = _env.pd().avail_caps().value;
size_t ram_after = _env.pd().avail_ram().value; size_t ram_after = _env.pd().avail_ram().value;
/* limit to buffer size for replenish */ /* limit to vram size for replenish */
buffer->ram_used = min(ram_before > ram_after ? ram_before - ram_after : 0, size); vram->ram_used = min(ram_before > ram_after ? ram_before - ram_after : 0, size);
buffer->caps_used = caps_before > caps_after ? true : false; vram->caps_used = caps_before > caps_after ? true : false;
_resource_guard.withdraw(caps_before, caps_after, ram_before, ram_after); _resource_guard.withdraw(caps_before, caps_after, ram_before, ram_after);
return ds_cap; return ds_cap;
} }
void free_buffer(Gpu::Buffer_id id) override void free_vram(Gpu::Vram_id id) override
{ {
auto lookup_and_free = [&] (Buffer_local &buffer_local) { auto lookup_and_free = [&] (Vram_local &vram_local) {
_apply_buffer(buffer_local, [&](Buffer &buffer) { _apply_vram(vram_local, [&](Vram &vram) {
if (buffer.owner(_session_cap) == false) return false; if (vram.owner(_session_cap) == false) return false;
if (buffer.map.offset != Igd::Ggtt::Mapping::INVALID_OFFSET) { if (vram.map.offset != Igd::Ggtt::Mapping::INVALID_OFFSET) {
Genode::error("cannot free mapped buffer"); Genode::error("cannot free mapped vram");
/* XXX throw */ /* XXX throw */
return false; return false;
} }
_env.ep().dissolve(buffer); _env.ep().dissolve(vram);
_device.free_buffer(_heap, buffer.ds_cap); _device.free_vram(_heap, vram.ds_cap);
_resource_guard.replenish(buffer.caps_used ? 1 : 0, _resource_guard.replenish(vram.caps_used ? 1 : 0,
buffer.ram_used); vram.ram_used);
return true; return true;
}); });
_free_local_buffer(buffer_local); _free_local_vram(vram_local);
}; };
_apply_buffer_local(id, lookup_and_free); _apply_vram_local(id, lookup_and_free);
} }
Buffer_capability export_buffer(Buffer_id id) override Vram_capability export_vram(Vram_id id) override
{ {
Buffer_capability cap { }; Vram_capability cap { };
_apply_buffer_local(id, [&] (Buffer_local &buffer_local) { _apply_vram_local(id, [&] (Vram_local &vram_local) {
if (_buffer_valid(buffer_local.buffer_cap)) if (_vram_valid(vram_local.vram_cap))
cap = buffer_local.buffer_cap; cap = vram_local.vram_cap;
}); });
return cap; return cap;
} }
void import_buffer(Buffer_capability cap, Buffer_id id) override void import_vram(Vram_capability cap, Vram_id id) override
{ {
if (_buffer_valid(cap) == false) if (_vram_valid(cap) == false)
throw Gpu::Session::Invalid_state(); throw Gpu::Session::Invalid_state();
try { try {
Buffer_local *buffer_local = new (_heap) Buffer_local(cap, 0, _buffer_space, id); Vram_local *vram_local = new (_heap) Vram_local(cap, 0, _vram_space, id);
_apply_buffer(*buffer_local, [&](Buffer &buffer) { _apply_vram(*vram_local, [&](Vram &vram) {
buffer_local->size = buffer.size; return false; }); vram_local->size = vram.size; return false; });
} catch (Id_space<Buffer_local>::Conflicting_id) { } catch (Id_space<Vram_local>::Conflicting_id) {
throw Gpu::Session::Conflicting_id(); throw Gpu::Session::Conflicting_id();
} catch (Cap_quota_guard::Limit_exceeded) { } catch (Cap_quota_guard::Limit_exceeded) {
throw Gpu::Session::Out_of_caps(); throw Gpu::Session::Out_of_caps();
@ -1966,107 +1992,50 @@ class Gpu::Session_component : public Genode::Session_object<Gpu::Session>
} }
} }
Genode::Dataspace_capability map_buffer(Gpu::Buffer_id id, Genode::Dataspace_capability map_cpu(Gpu::Vram_id,
bool aperture, Gpu::Mapping_attributes) override
Gpu::Mapping_attributes attrs) override
{ {
/* treat GGTT mapped buffers as rw */ error("map_cpu: called not implemented");
if (!(attrs.readable && attrs.writeable)) throw Mapping_vram_failed();
return Genode::Dataspace_capability();
Genode::Dataspace_capability map_cap;
auto lookup_and_map = [&] (Buffer &buffer) {
if (buffer.owner(_session_cap) == false) {
Genode::error("GGTT mappings can only be done by buffer owner");
return false;
} }
if (buffer.map.offset != Igd::Ggtt::Mapping::INVALID_OFFSET) { void unmap_cpu(Vram_id) override
Genode::error("buffer already mapped");
return false;
}
/* GGTT mappings only require the heap */
if (_resource_guard.avail_caps() == false)
throw Gpu::Session::Out_of_caps();
if (_resource_guard.avail_ram() == false)
throw Gpu::Session::Out_of_ram();
size_t caps_before = _env.pd().avail_caps().value;
size_t ram_before = _env.pd().avail_ram().value;
Igd::Ggtt::Mapping const &map =
_device.map_buffer(_heap, buffer.ds_cap, aperture);
buffer.map.cap = map.cap;
buffer.map.offset = map.offset;
map_cap = buffer.map.cap;
size_t caps_after = _env.pd().avail_caps().value;
size_t ram_after = _env.pd().avail_ram().value;
_resource_guard.withdraw(caps_before, caps_after,
ram_before , ram_after);
return true;
};
_apply_buffer_local(id, [&] (Buffer_local &buffer_local) {
_apply_buffer(buffer_local, lookup_and_map); });
return map_cap;
}
void unmap_buffer(Gpu::Buffer_id id) override
{ {
bool unmapped = false; error("unmap_cpu: called not implemented");
auto lookup_and_unmap = [&] (Buffer &buffer) {
if (buffer.owner(_session_cap) == false) {
Genode::error("GGTT unmappings can only be done by buffer owner");
return false;
} }
if (!buffer.map.cap.valid()) { return false; } bool map_gpu(Vram_id id, size_t size, off_t offset, Gpu::Virtual_address va) override
if (buffer.fenced != Buffer::INVALID_FENCE) {
_device.clear_tiling(buffer.fenced);
_vgpu.active_fences--;
}
_device.unmap_buffer(_heap, buffer.map);
buffer.map.offset = Igd::Ggtt::Mapping::INVALID_OFFSET;
unmapped = true;
return false;
};
_apply_buffer_local(id, [&](Buffer_local &buffer) {
_apply_buffer(buffer, lookup_and_unmap); });
if (!unmapped) { Genode::error("buffer not mapped"); }
}
bool map_buffer_ppgtt(Gpu::Buffer_id id, Gpu::addr_t va) override
{ {
auto lookup_and_map = [&] (Buffer_local &buffer_local) { auto lookup_and_map = [&] (Vram_local &vram_local) {
if (buffer_local.ppgtt_va_valid) { if (vram_local.mappings.exists(offset)) {
Genode::error("buffer already mapped"); Genode::error("vram already mapped at offset: ", Hex(offset));
return; return;
} }
addr_t phys_addr = 0; addr_t phys_addr = 0;
_apply_buffer(buffer_local, [&](Buffer &buffer) { _apply_vram(vram_local, [&](Vram &vram) {
phys_addr = buffer.phys_addr; return false; }); phys_addr = vram.phys_addr; return false; });
if (phys_addr == 0) { if (phys_addr == 0) {
_free_local_buffer(buffer_local); _free_local_vram(vram_local);
return; return;
} }
_vgpu.rcs_map_ppgtt(va, phys_addr, buffer_local.size); try {
buffer_local.ppgtt_va = va; _vgpu.rcs_map_ppgtt(va.va, phys_addr + offset, size);
buffer_local.ppgtt_va_valid = true; } catch (Level_4_translation_table::Double_insertion) {
error("PPGTT: Double insertion: va: ", Hex(va.va), " offset: ", Hex(offset),
"size: ", Hex(size));
throw Mapping_vram_failed();
} catch(...) {
error("PPGTT: invalid address/range/alignment: va: ", Hex(va.va),
" offset: ", Hex(offset),
"size: ", Hex(size));
throw Mapping_vram_failed();
}
new (_heap) Vram_local::Mapping(vram_local.mappings, offset, va.va, size);
}; };
if (_resource_guard.avail_caps() == false) if (_resource_guard.avail_caps() == false)
@ -2078,7 +2047,7 @@ class Gpu::Session_component : public Genode::Session_object<Gpu::Session>
size_t caps_before = _env.pd().avail_caps().value; size_t caps_before = _env.pd().avail_caps().value;
size_t ram_before = _env.pd().avail_ram().value; size_t ram_before = _env.pd().avail_ram().value;
_apply_buffer_local(id, lookup_and_map); _apply_vram_local(id, lookup_and_map);
size_t caps_after = _env.pd().avail_caps().value; size_t caps_after = _env.pd().avail_caps().value;
size_t ram_after = _env.pd().avail_ram().value; size_t ram_after = _env.pd().avail_ram().value;
@ -2089,77 +2058,59 @@ class Gpu::Session_component : public Genode::Session_object<Gpu::Session>
return true; return true;
} }
void unmap_buffer_ppgtt(Gpu::Buffer_id id, void unmap_gpu(Vram_id id, off_t offset, Gpu::Virtual_address va) override
Gpu::addr_t va) override
{ {
auto lookup_and_unmap = [&] (Buffer_local &buffer_local) { auto lookup_and_unmap = [&] (Vram_local &vram_local) {
if (!buffer_local.ppgtt_va_valid) { vram_local.mappings.with_element(offset,
Genode::error("buffer not mapped"); [&] (Vram_local::Mapping &mapping) {
if (mapping.ppgtt_va != va.va) {
Genode::error("VRAM: not mapped at ", Hex(va.va), " offset: ", Hex(offset));
return; return;
} }
_vgpu.rcs_unmap_ppgtt(va.va, mapping.ppgtt_va_size);
if (buffer_local.ppgtt_va != va) { destroy(_heap, &mapping);
Genode::error("buffer not mapped at ", Genode::Hex(va)); },
return; [&] () { error("VRAM: nothing mapped at offset ", Hex(offset)); }
} );
_vgpu.rcs_unmap_ppgtt(va, buffer_local.size);
buffer_local.ppgtt_va_valid = false;
}; };
_apply_buffer_local(id, lookup_and_unmap); _apply_vram_local(id, lookup_and_unmap);
} }
Gpu::addr_t query_buffer_ppgtt(Gpu::Buffer_id id) override bool set_tiling_gpu(Vram_id id, off_t offset,
{ unsigned mode) override
Gpu::addr_t result = (Gpu::addr_t)-1;
auto lookup_va = [&] (Buffer_local &buffer_local) {
if (!buffer_local.ppgtt_va_valid) {
Genode::error("buffer not mapped");
return;
}
result = buffer_local.ppgtt_va;
};
_apply_buffer_local(id, lookup_va);
return result;
}
bool set_tiling(Gpu::Buffer_id id,
Genode::uint32_t const mode) override
{ {
if (_vgpu.active_fences > Igd::Device::Vgpu::MAX_FENCES) { if (_vgpu.active_fences > Igd::Device::Vgpu::MAX_FENCES) {
Genode::error("no free fences left, already active: ", _vgpu.active_fences); Genode::error("no free fences left, already active: ", _vgpu.active_fences);
return false; return false;
} }
Buffer *b = nullptr; Vram *v = nullptr;
auto lookup = [&] (Buffer &buffer) { auto lookup = [&] (Vram &vram) {
if (!buffer.map.cap.valid() || !buffer.owner(_session_cap)) { return false; } if (!vram.map.cap.valid() || !vram.owner(_session_cap)) { return false; }
b = &buffer; v = &vram;
return false; return false;
}; };
_apply_buffer_local(id, [&](Buffer_local &buffer_local) { _apply_vram_local(id, [&](Vram_local &vram_local) {
_apply_buffer(buffer_local, lookup); _apply_vram(vram_local, lookup);
}); });
if (b == nullptr) { if (v == nullptr) {
Genode::error("attempt to set tiling for non-mapped or non-owned buffer"); Genode::error("attempt to set tiling for non-mapped or non-owned vram");
return false; return false;
} }
//XXX: support change of already fenced bo's fencing mode //XXX: support change of already fenced bo's fencing mode
if (b->fenced) return true; if (v->fenced) return true;
Igd::size_t const size = b->size; Igd::size_t const size = v->size;
Genode::uint32_t const fenced = _device.set_tiling(b->map.offset, size, mode); Genode::uint32_t const fenced = _device.set_tiling(v->map.offset + offset, size, mode);
b->fenced = fenced; v->fenced = fenced;
if (fenced != Buffer::INVALID_FENCE) { _vgpu.active_fences++; } if (fenced != Vram::INVALID_FENCE) { _vgpu.active_fences++; }
return fenced != Buffer::INVALID_FENCE; return fenced != Vram::INVALID_FENCE;
} }
}; };

View File

@ -215,6 +215,13 @@ namespace Genode
class Genode::Level_4_translation_table class Genode::Level_4_translation_table
{ {
public:
class Misaligned {};
class Invalid_address {};
class Invalid_range {};
class Double_insertion {};
private: private:
static constexpr size_t PAGE_SIZE_LOG2 = SIZE_LOG2_4KB; static constexpr size_t PAGE_SIZE_LOG2 = SIZE_LOG2_4KB;
@ -223,11 +230,6 @@ class Genode::Level_4_translation_table
static constexpr size_t PAGE_SIZE = 1UL << PAGE_SIZE_LOG2; static constexpr size_t PAGE_SIZE = 1UL << PAGE_SIZE_LOG2;
static constexpr size_t PAGE_MASK = ~((1UL << PAGE_SIZE_LOG2) - 1); static constexpr size_t PAGE_MASK = ~((1UL << PAGE_SIZE_LOG2) - 1);
class Misaligned {};
class Invalid_address {};
class Invalid_range {};
class Double_insertion {};
struct Descriptor : Common_descriptor struct Descriptor : Common_descriptor
{ {
using Common = Common_descriptor; using Common = Common_descriptor;