mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-24 15:56:41 +00:00
gpu/intel: add VRAM support
Remove buffer abstraction and replace it by VRAM objects. issue #4713
This commit is contained in:
parent
f72cb2b69b
commit
47f1eaac2a
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user