mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 00:24:51 +00:00
parent
198019edca
commit
947235ee34
@ -3,18 +3,8 @@
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
/**
|
||||
* On Genode the virtual address of MMAP_GTT is stored in the offset
|
||||
*/
|
||||
static inline void *drm_mmap(void *addr, size_t length, int prot, int flags,
|
||||
int fd, off_t offset)
|
||||
{
|
||||
return (void *)offset;
|
||||
}
|
||||
|
||||
static inline int drm_munmap(void *addr, size_t length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
void *drm_mmap(void *addr, size_t length, int prot, int flags,
|
||||
int fd, off_t offset);
|
||||
int drm_munmap(void *addr, size_t length);
|
||||
|
||||
#endif /* _INCLUDE__LIBDRM_MACROS_H_ */
|
||||
|
@ -1,7 +1,8 @@
|
||||
/**
|
||||
* \brief Called for every DRM function (implement me)
|
||||
/*
|
||||
* \brief DRM ioctl backend
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2017-08-17
|
||||
* \author Josef Soentgen
|
||||
* \date 2017-05-10
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -11,16 +12,873 @@
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/attached_dataspace.h>
|
||||
#include <base/heap.h>
|
||||
#include <base/log.h>
|
||||
#include <base/registry.h>
|
||||
// #include <drm/serialize.h>
|
||||
#include <gpu_session/connection.h>
|
||||
#include <os/backtrace.h>
|
||||
#include <util/retry.h>
|
||||
|
||||
extern "C" {
|
||||
#include <drm.h>
|
||||
#include <i915_drm.h>
|
||||
|
||||
#define DRM_NUMBER(req) ((req) & 0xff)
|
||||
}
|
||||
|
||||
#include <base/log.h>
|
||||
|
||||
enum { verbose_ioctl = false };
|
||||
|
||||
namespace Utils
|
||||
{
|
||||
uint64_t canonical_addr(uint64_t addr) {
|
||||
return (Genode::int64_t)(addr << 16) >> 16; }
|
||||
|
||||
uint64_t noncanonical_addr(uint64_t addr) {
|
||||
return addr & 0xffffffffffffu; }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get DRM command number
|
||||
*/
|
||||
static long command_number(long request)
|
||||
{
|
||||
return request & 0xff;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get device specific command number
|
||||
*/
|
||||
static long device_number(long request)
|
||||
{
|
||||
return command_number(request) - DRM_COMMAND_BASE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if request is device command
|
||||
*/
|
||||
static bool device_ioctl(long request)
|
||||
{
|
||||
long const cmd = command_number(request);
|
||||
return cmd >= DRM_COMMAND_BASE && cmd < DRM_COMMAND_END;
|
||||
}
|
||||
|
||||
|
||||
static const char *command_name(long request)
|
||||
{
|
||||
if (IOCGROUP(request) != DRM_IOCTL_BASE)
|
||||
return "<non-DRM>";
|
||||
|
||||
|
||||
if (!device_ioctl(request)) {
|
||||
long const cmd = command_number(request);
|
||||
switch (cmd) {
|
||||
case DRM_NUMBER(DRM_IOCTL_GEM_CLOSE): return "DRM_IOCTL_GEM_CLOSE";
|
||||
case DRM_NUMBER(DRM_IOCTL_GEM_FLINK): return "DRM_IOCTL_GEM_FLINK";
|
||||
default: return "<unknown command>";
|
||||
}
|
||||
}
|
||||
|
||||
switch (device_number(request)) {
|
||||
case DRM_I915_INIT: return "DRM_I915_INIT";
|
||||
case DRM_I915_FLUSH: return "DRM_I915_FLUSH";
|
||||
case DRM_I915_FLIP: return "DRM_I915_FLIP";
|
||||
case DRM_I915_BATCHBUFFER: return "DRM_I915_BATCHBUFFER";
|
||||
case DRM_I915_IRQ_EMIT: return "DRM_I915_IRQ_EMIT";
|
||||
case DRM_I915_IRQ_WAIT: return "DRM_I915_IRQ_WAIT";
|
||||
case DRM_I915_GETPARAM: return "DRM_I915_GETPARAM";
|
||||
case DRM_I915_SETPARAM: return "DRM_I915_SETPARAM";
|
||||
case DRM_I915_ALLOC: return "DRM_I915_ALLOC";
|
||||
case DRM_I915_FREE: return "DRM_I915_FREE";
|
||||
case DRM_I915_INIT_HEAP: return "DRM_I915_INIT_HEAP";
|
||||
case DRM_I915_CMDBUFFER: return "DRM_I915_CMDBUFFER";
|
||||
case DRM_I915_DESTROY_HEAP: return "DRM_I915_DESTROY_HEAP";
|
||||
case DRM_I915_SET_VBLANK_PIPE: return "DRM_I915_SET_VBLANK_PIPE";
|
||||
case DRM_I915_GET_VBLANK_PIPE: return "DRM_I915_GET_VBLANK_PIPE";
|
||||
case DRM_I915_VBLANK_SWAP: return "DRM_I915_VBLANK_SWAP";
|
||||
case DRM_I915_HWS_ADDR: return "DRM_I915_HWS_ADDR";
|
||||
case DRM_I915_GEM_INIT: return "DRM_I915_GEM_INIT";
|
||||
case DRM_I915_GEM_EXECBUFFER: return "DRM_I915_GEM_EXECBUFFER";
|
||||
case DRM_I915_GEM_PIN: return "DRM_I915_GEM_PIN";
|
||||
case DRM_I915_GEM_UNPIN: return "DRM_I915_GEM_UNPIN";
|
||||
case DRM_I915_GEM_BUSY: return "DRM_I915_GEM_BUSY";
|
||||
case DRM_I915_GEM_THROTTLE: return "DRM_I915_GEM_THROTTLE";
|
||||
case DRM_I915_GEM_ENTERVT: return "DRM_I915_GEM_ENTERVT";
|
||||
case DRM_I915_GEM_LEAVEVT: return "DRM_I915_GEM_LEAVEVT";
|
||||
case DRM_I915_GEM_CREATE: return "DRM_I915_GEM_CREATE";
|
||||
case DRM_I915_GEM_PREAD: return "DRM_I915_GEM_PREAD";
|
||||
case DRM_I915_GEM_PWRITE: return "DRM_I915_GEM_PWRITE";
|
||||
case DRM_I915_GEM_MMAP: return "DRM_I915_GEM_MMAP";
|
||||
case DRM_I915_GEM_SET_DOMAIN: return "DRM_I915_GEM_SET_DOMAIN";
|
||||
case DRM_I915_GEM_SW_FINISH: return "DRM_I915_GEM_SW_FINISH";
|
||||
case DRM_I915_GEM_SET_TILING: return "DRM_I915_GEM_SET_TILING";
|
||||
case DRM_I915_GEM_GET_TILING: return "DRM_I915_GEM_GET_TILING";
|
||||
case DRM_I915_GEM_GET_APERTURE: return "DRM_I915_GEM_GET_APERTURE";
|
||||
case DRM_I915_GEM_MMAP_GTT: return "DRM_I915_GEM_MMAP_GTT";
|
||||
case DRM_I915_GET_PIPE_FROM_CRTC_ID: return "DRM_I915_GET_PIPE_FROM_CRTC_ID";
|
||||
case DRM_I915_GEM_MADVISE: return "DRM_I915_GEM_MADVISE";
|
||||
case DRM_I915_OVERLAY_PUT_IMAGE: return "DRM_I915_OVERLAY_PUT_IMAGE";
|
||||
case DRM_I915_OVERLAY_ATTRS: return "DRM_I915_OVERLAY_ATTRS";
|
||||
case DRM_I915_GEM_EXECBUFFER2: return "DRM_I915_GEM_EXECBUFFER2";
|
||||
case DRM_I915_REG_READ: return "DRM_I915_REG_READ";
|
||||
case DRM_I915_GET_RESET_STATS: return "DRM_I915_GET_RESET_STATS";
|
||||
case DRM_I915_GEM_CONTEXT_CREATE: return "DRM_I915_GEM_CONTEXT_CREATE";
|
||||
default:
|
||||
Genode::backtrace();
|
||||
return "<unknown driver>";
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_ioctl(long request)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
log("ioctl(request=", Hex(request),
|
||||
(request & 0xe0000000) == IOC_OUT ? " out" :
|
||||
(request & 0xe0000000) == IOC_IN ? " in" :
|
||||
(request & 0xe0000000) == IOC_INOUT ? " inout" : " void",
|
||||
" len=", IOCPARM_LEN(request),
|
||||
" cmd=",command_name(request), " (", Hex(command_number(request)), ")");
|
||||
}
|
||||
|
||||
|
||||
class Drm_call
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Env &_env;
|
||||
Genode::Heap _heap { _env.ram(), _env.rm() };
|
||||
|
||||
Gpu::Connection _gpu_session { _env };
|
||||
Gpu::Info _gpu_info { _gpu_session.info() };
|
||||
|
||||
Genode::Lock _completion_lock { Genode::Lock::LOCKED };
|
||||
|
||||
size_t available_gtt_size { _gpu_info.aperture_size };
|
||||
|
||||
using Handle = uint32_t;
|
||||
using Offset = unsigned long;
|
||||
|
||||
enum { INVALID_HANDLE = 0, };
|
||||
struct Buffer_handle
|
||||
{
|
||||
Genode::Dataspace_capability cap;
|
||||
Genode::size_t size;
|
||||
Handle handle;
|
||||
Genode::addr_t addr;
|
||||
|
||||
Genode::Dataspace_capability map_cap;
|
||||
Offset map_offset;
|
||||
|
||||
Buffer_handle(Genode::Dataspace_capability cap,
|
||||
Genode::size_t size,
|
||||
Handle handle)
|
||||
: cap(cap), size(size), handle(handle) { }
|
||||
|
||||
virtual ~Buffer_handle() { }
|
||||
|
||||
bool valid() { return cap.valid() && size != 0; }
|
||||
};
|
||||
|
||||
using Buffer = Genode::Registered<Buffer_handle>;
|
||||
|
||||
Genode::Registry<Buffer> _buffer_registry;
|
||||
|
||||
Handle _alloc_buffer(uint64_t const size)
|
||||
{
|
||||
static uint32_t handle = INVALID_HANDLE;
|
||||
|
||||
Genode::size_t donate = size;
|
||||
Genode::Dataspace_capability cap = Genode::retry<Gpu::Session::Out_of_ram>(
|
||||
[&] () { return _gpu_session.alloc_buffer(size); },
|
||||
[&] () {
|
||||
_gpu_session.upgrade_ram(donate);
|
||||
donate /= 4;
|
||||
});
|
||||
|
||||
/*
|
||||
* Every buffer always is mapped into the PPGTT. To make things
|
||||
* simplish[sic], we reuse the client local virtual adress for the
|
||||
* PPGTT mapping.
|
||||
*/
|
||||
|
||||
Genode::addr_t const addr = static_cast<Genode::addr_t>(_env.rm().attach(cap));
|
||||
|
||||
bool const ppgtt = Genode::retry<Gpu::Session::Out_of_ram>(
|
||||
[&]() { return _gpu_session.map_buffer_ppgtt(cap, addr); },
|
||||
[&]() { _gpu_session.upgrade_ram(4096); }
|
||||
);
|
||||
|
||||
if (!ppgtt) {
|
||||
Genode::error("could not insert buffer into PPGTT");
|
||||
_env.rm().detach(addr);
|
||||
_gpu_session.free_buffer(cap);
|
||||
return INVALID_HANDLE;
|
||||
}
|
||||
|
||||
try {
|
||||
Buffer *buffer = new (&_heap) Buffer(_buffer_registry, cap, size, ++handle);
|
||||
buffer->addr = addr;
|
||||
return buffer->handle;
|
||||
} catch (...) {
|
||||
_env.rm().detach(addr);
|
||||
_gpu_session.free_buffer(cap);
|
||||
return INVALID_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
void _unmap_buffer(Buffer_handle &h)
|
||||
{
|
||||
_env.rm().detach(h.map_offset);
|
||||
h.map_offset = 0;
|
||||
|
||||
_gpu_session.unmap_buffer(h.map_cap);
|
||||
h.map_cap = Genode::Dataspace_capability();
|
||||
|
||||
available_gtt_size += h.size;
|
||||
}
|
||||
|
||||
int _free_buffer(Handle handle)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
auto lookup_buffer = [&] (Buffer_handle &h) {
|
||||
if (h.handle != handle) { return; }
|
||||
|
||||
if (h.map_cap.valid()) {
|
||||
// Genode::warning("free buffer, handle:", Genode::Hex(h.handle), " ggtt mapped");
|
||||
_unmap_buffer(h);
|
||||
}
|
||||
|
||||
_env.rm().detach(h.addr);
|
||||
_gpu_session.unmap_buffer_ppgtt(h.cap, h.addr);
|
||||
_gpu_session.free_buffer(h.cap);
|
||||
result = 0;
|
||||
};
|
||||
_buffer_registry.for_each(lookup_buffer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Offset _map_buffer(Handle handle)
|
||||
{
|
||||
Offset offset = 0;
|
||||
|
||||
auto lookup_buffer = [&] (Buffer_handle &h) {
|
||||
if (h.handle != handle) { return; }
|
||||
|
||||
if (h.map_cap.valid()) {
|
||||
offset = h.map_offset;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
_gpu_session.upgrade_ram(4096);
|
||||
h.map_cap = _gpu_session.map_buffer(h.cap, true);
|
||||
h.map_offset = static_cast<Offset>(_env.rm().attach(h.map_cap));
|
||||
offset = h.map_offset;
|
||||
|
||||
available_gtt_size -= h.size;
|
||||
} catch (...) {
|
||||
if (h.map_cap.valid()) { _gpu_session.unmap_buffer(h.map_cap); }
|
||||
h.map_cap = Genode::Dataspace_capability();
|
||||
Genode::error("could not attach GEM buffer handle: ", h.handle);
|
||||
}
|
||||
};
|
||||
_buffer_registry.for_each(lookup_buffer);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/*******************
|
||||
** lookup buffer **
|
||||
*******************/
|
||||
|
||||
Buffer_handle *_lookup_buffer(Handle handle)
|
||||
{
|
||||
Buffer_handle *bh = nullptr;
|
||||
|
||||
auto lookup_buffer = [&] (Buffer_handle &h) {
|
||||
if (h.handle != handle) { return; }
|
||||
bh = &h;
|
||||
};
|
||||
_buffer_registry.for_each(lookup_buffer);
|
||||
|
||||
return bh;
|
||||
}
|
||||
|
||||
Genode::Dataspace_capability _lookup_buffer_cap(Handle handle)
|
||||
{
|
||||
Genode::Dataspace_capability cap;
|
||||
|
||||
auto lookup_buffer = [&] (Buffer_handle &h) {
|
||||
if (h.handle != handle) { return; }
|
||||
if (!h.cap.valid()) { return; }
|
||||
cap = h.cap;
|
||||
};
|
||||
_buffer_registry.for_each(lookup_buffer);
|
||||
|
||||
return cap;
|
||||
}
|
||||
|
||||
Genode::Dataspace_capability _lookup_buffer_map_cap(Handle handle)
|
||||
{
|
||||
Genode::Dataspace_capability cap;
|
||||
|
||||
auto lookup_buffer = [&] (Buffer_handle &h) {
|
||||
if (h.handle != handle) { return; }
|
||||
if (!h.map_cap.valid()) { return; }
|
||||
cap = h.map_cap;
|
||||
};
|
||||
_buffer_registry.for_each(lookup_buffer);
|
||||
|
||||
return cap;
|
||||
}
|
||||
|
||||
bool _is_mapped(Genode::Dataspace_capability cap)
|
||||
{
|
||||
bool mapped = false;
|
||||
|
||||
auto lookup_buffer = [&] (Buffer_handle &h) {
|
||||
if (!(h.cap == cap)) { return; }
|
||||
if (!h.map_cap.valid()) { return; }
|
||||
mapped = true;
|
||||
};
|
||||
_buffer_registry.for_each(lookup_buffer);
|
||||
|
||||
return mapped;
|
||||
}
|
||||
|
||||
/***************************
|
||||
** execbuffer completion **
|
||||
***************************/
|
||||
|
||||
void _handle_completion() { _completion_lock.unlock(); }
|
||||
|
||||
Genode::Io_signal_handler<Drm_call> _completion_sigh {
|
||||
_env.ep(), *this, &Drm_call::_handle_completion };
|
||||
|
||||
|
||||
/************
|
||||
** ioctls **
|
||||
************/
|
||||
|
||||
int _device_gem_get_aperture_size(void *arg)
|
||||
{
|
||||
drm_i915_gem_get_aperture * const p = reinterpret_cast<drm_i915_gem_get_aperture*>(arg);
|
||||
p->aper_size = _gpu_info.aperture_size;
|
||||
p->aper_available_size = available_gtt_size;
|
||||
Genode::warning(__func__, ": available_gtt_size is not properly accounted");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _device_gem_create(void *arg)
|
||||
{
|
||||
drm_i915_gem_create * const p = reinterpret_cast<drm_i915_gem_create*>(arg);
|
||||
|
||||
uint64_t const size = (p->size + 0xfff) & ~0xfff;
|
||||
Handle handle = _alloc_buffer(size);
|
||||
if (handle == INVALID_HANDLE) { return -1; }
|
||||
|
||||
p->size = size;
|
||||
p->handle = handle;
|
||||
|
||||
if (verbose_ioctl) {
|
||||
Genode::error(__func__, ": ", "handle: ", handle, " size: ", size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _device_gem_mmap(void *arg)
|
||||
{
|
||||
drm_i915_gem_mmap * const p = reinterpret_cast<drm_i915_gem_mmap *>(arg);
|
||||
Handle const handle = p->handle;
|
||||
|
||||
Genode::addr_t addr = 0;
|
||||
auto lookup_buffer = [&] (Buffer_handle &h) {
|
||||
if (h.handle != handle) { return; }
|
||||
addr = h.addr;
|
||||
};
|
||||
_buffer_registry.for_each(lookup_buffer);
|
||||
|
||||
if (addr == 0) { return -1; }
|
||||
|
||||
if (verbose_ioctl) {
|
||||
Genode::error(__func__, ": ", "handle: ", handle, " addr: ", Genode::Hex(addr));
|
||||
}
|
||||
|
||||
p->addr_ptr = addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _device_gem_mmap_gtt(void *arg)
|
||||
{
|
||||
drm_i915_gem_mmap * const p = reinterpret_cast<drm_i915_gem_mmap *>(arg);
|
||||
Handle const handle = p->handle;
|
||||
|
||||
if (verbose_ioctl) {
|
||||
Genode::error(__func__, ": ", "handle: ", handle,
|
||||
" offset: ", Genode::Hex(p->offset));
|
||||
}
|
||||
|
||||
/*
|
||||
* We always map a buffer when the tiling is set. Since Mesa
|
||||
* sets the filing first and maps the buffer afterwards we might
|
||||
* already have a mapping at this point.
|
||||
*/
|
||||
p->offset = _map_buffer(handle);
|
||||
|
||||
if (verbose_ioctl) {
|
||||
Genode::error(__func__, ": ", "handle: ", handle,
|
||||
" offset: ", Genode::Hex(p->offset), " (mapped)");
|
||||
}
|
||||
|
||||
return p->offset ? 0 : -1;
|
||||
}
|
||||
|
||||
char const *_domain_name(uint32_t d)
|
||||
{
|
||||
if (d & I915_GEM_DOMAIN_CPU) { return "CPU"; }
|
||||
if (d & I915_GEM_DOMAIN_GTT) { return "CPU (GTT)"; }
|
||||
if (d & I915_GEM_DOMAIN_RENDER) { return "GPU (RC)"; }
|
||||
if (d & I915_GEM_DOMAIN_VERTEX) { return "GPU (VC)"; }
|
||||
if (d & I915_GEM_DOMAIN_INSTRUCTION) { return "GPU (IC)"; }
|
||||
if (d & I915_GEM_DOMAIN_SAMPLER) { return "GPU (SC)"; }
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
int _device_gem_set_domain(void *arg)
|
||||
{
|
||||
/* XXX check read_domains/write_domain */
|
||||
drm_i915_gem_set_domain * const p = reinterpret_cast<drm_i915_gem_set_domain*>(arg);
|
||||
Handle const handle = p->handle;
|
||||
uint32_t const rd = p->read_domains;
|
||||
uint32_t const wd = p->write_domain;
|
||||
|
||||
if (verbose_ioctl) {
|
||||
Genode::error(__func__, ": ", "handle: ", handle,
|
||||
" rd: ", _domain_name(rd),
|
||||
" wd: ", _domain_name(wd));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _device_getparam(void *arg)
|
||||
{
|
||||
drm_i915_getparam_t *p = reinterpret_cast<drm_i915_getparam_t*>(arg);
|
||||
int const param = p->param;
|
||||
int *value = p->value;
|
||||
|
||||
switch (param) {
|
||||
case I915_PARAM_CHIPSET_ID:
|
||||
*value = _gpu_info.chip_id;
|
||||
break;
|
||||
case I915_PARAM_HAS_RELAXED_FENCING:
|
||||
case I915_PARAM_HAS_RELAXED_DELTA:
|
||||
case I915_PARAM_HAS_EXECBUF2:
|
||||
case I915_PARAM_HAS_LLC:
|
||||
*value = 1;
|
||||
break;
|
||||
case I915_PARAM_HAS_BSD:
|
||||
case I915_PARAM_HAS_BLT:
|
||||
case I915_PARAM_HAS_VEBOX:
|
||||
case I915_PARAM_HAS_WAIT_TIMEOUT:
|
||||
case 36 /* I915_PARAM_HAS_RESOURCE_STREAMER */:
|
||||
*value = 0;
|
||||
break;
|
||||
case I915_PARAM_CMD_PARSER_VERSION:
|
||||
*value = 23;
|
||||
break;
|
||||
default:
|
||||
Genode::error("Unhandled device param:", Genode::Hex(param));
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _device_gem_context_create(void *arg)
|
||||
{
|
||||
drm_i915_gem_context_create * const p = reinterpret_cast<drm_i915_gem_context_create*>(arg);
|
||||
p->ctx_id = _gpu_info.ctx_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _device_gem_set_tiling(void *arg)
|
||||
{
|
||||
drm_i915_gem_set_tiling * const p = reinterpret_cast<drm_i915_gem_set_tiling*>(arg);
|
||||
Handle const handle = p->handle;
|
||||
uint32_t const mode = p->tiling_mode;
|
||||
uint32_t const stride = p->stride;
|
||||
uint32_t const swizzle = p->swizzle_mode;
|
||||
|
||||
if (verbose_ioctl) {
|
||||
Genode::error(__func__, ": ",
|
||||
"handle: ", handle, " "
|
||||
"mode: ", mode, " "
|
||||
"stride: ", stride , " "
|
||||
"swizzle: ", swizzle);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX instead of returning the buffer cap and later-on the map_cap
|
||||
* returning the buffer itself in the first place is better
|
||||
*/
|
||||
Genode::Dataspace_capability const cap = _lookup_buffer_cap(handle);
|
||||
if (!cap.valid()) { return -1; }
|
||||
|
||||
/* we need a valid GGTT mapping for fencing */
|
||||
if (!_is_mapped(cap) && !_map_buffer(handle)) { return -2; }
|
||||
|
||||
Genode::Dataspace_capability map_cap = _lookup_buffer_map_cap(handle);
|
||||
|
||||
uint32_t const m = (stride << 16) | (mode == 1 ? 1 : 0);
|
||||
bool const ok = _gpu_session.set_tiling(map_cap, m);
|
||||
return ok ? 0 : -1;
|
||||
}
|
||||
|
||||
int _device_gem_pwrite(void *arg)
|
||||
{
|
||||
drm_i915_gem_pwrite * const p = reinterpret_cast<drm_i915_gem_pwrite*>(arg);
|
||||
Handle const handle = p->handle;
|
||||
|
||||
Buffer_handle const *bh = _lookup_buffer(handle);
|
||||
if (bh == nullptr) {
|
||||
Genode::error(__func__, ": invalid handle: ", handle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bh->size < p->size) {
|
||||
Genode::error(__func__, ": request size: ", p->size, " "
|
||||
"does not fit buffer size: ", bh->size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!bh->addr) { return -1; }
|
||||
|
||||
if (verbose_ioctl) {
|
||||
Genode::error(__func__, ": ", "handle: ", handle, " size: ", p->size, " addr: ", Genode::Hex(bh->addr));
|
||||
}
|
||||
|
||||
Genode::memcpy((void*)bh->addr, reinterpret_cast<void*>(p->data_ptr), p->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _device_gem_sw_finish(void *arg)
|
||||
{
|
||||
// drm_i915_gem_sw_finish * const p = reinterpret_cast<drm_i915_gem_sw_finish*>(arg);
|
||||
// Handle const handle = p->handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool _relocate_batch_buffer(drm_i915_gem_exec_object2 &obj, size_t batch_len)
|
||||
{
|
||||
Buffer_handle const * const bb_handle = _lookup_buffer(obj.handle);
|
||||
if (bb_handle == nullptr) {
|
||||
Genode::error("batch buffer handle: ", obj.handle, " invalid");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *bb_addr = (uint8_t*)bb_handle->addr;
|
||||
|
||||
drm_i915_gem_relocation_entry *e =
|
||||
reinterpret_cast<drm_i915_gem_relocation_entry*>(obj.relocs_ptr);
|
||||
|
||||
uint32_t const count = obj.relocation_count;
|
||||
for (uint64_t i = 0; i < count; i++) {
|
||||
if (verbose_ioctl) {
|
||||
using namespace Genode;
|
||||
log("target_handle: ", e[i].target_handle, " "
|
||||
"delta: ", Hex(e[i].delta), " "
|
||||
"offset: ", Hex(e[i].offset), " "
|
||||
"presumed_offset: ", Hex(e[i].presumed_offset), " "
|
||||
"read_domains: ", Hex(e[i].read_domains),
|
||||
" (", _domain_name(e[i].read_domains), ") "
|
||||
"write_domain: ", Hex(e[i].write_domain),
|
||||
" (", _domain_name(e[i].write_domain), ") ");
|
||||
}
|
||||
|
||||
Buffer_handle * buffer = _lookup_buffer(e[i].target_handle);
|
||||
if (buffer == nullptr) {
|
||||
Genode::error("target_handle: ", e[i].target_handle, " invalid");
|
||||
return false;
|
||||
}
|
||||
uint64_t target_offset = Utils::canonical_addr(buffer->addr + e[i].delta);
|
||||
|
||||
uint32_t *addr = (uint32_t*)(bb_addr + e[i].offset);
|
||||
*addr = (target_offset & 0xffffffff);
|
||||
*(addr + 1) = (target_offset >> 32) & 0xffffffff;
|
||||
|
||||
e[i].presumed_offset = target_offset;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int _device_gem_execbuffer2(void *arg)
|
||||
{
|
||||
drm_i915_gem_execbuffer2 * const p = reinterpret_cast<drm_i915_gem_execbuffer2*>(arg);
|
||||
uint64_t const buffers_ptr = p->buffers_ptr;
|
||||
uint64_t const buffer_count = p->buffer_count;
|
||||
uint32_t const batch_start_offset = p->batch_start_offset;
|
||||
uint32_t const batch_len = p->batch_len;
|
||||
uint32_t const dr1 = p->DR1;
|
||||
uint32_t const dr4 = p->DR4;
|
||||
uint32_t const num_cliprects = p->num_cliprects;
|
||||
uint64_t const cliprects_ptr = p->cliprects_ptr;
|
||||
uint64_t const flags = p->flags;
|
||||
uint64_t const ctx_id = p->rsvd1;
|
||||
|
||||
uint64_t const batch_buffer_id = buffer_count - 1;
|
||||
|
||||
if (verbose_ioctl) {
|
||||
Genode::log(__func__, " "
|
||||
"buffers_ptr: ", Genode::Hex(buffers_ptr), " "
|
||||
"buffer_count: ", buffer_count, " "
|
||||
"batch_start_offset: ", Genode::Hex(batch_start_offset), " "
|
||||
"batch_len: ", batch_len, " "
|
||||
"dr1: ", Genode::Hex(dr1), " "
|
||||
"dr4: ", Genode::Hex(dr4), " "
|
||||
"num_cliprects: ", num_cliprects, " "
|
||||
"cliprects_ptr: ", Genode::Hex(cliprects_ptr), " "
|
||||
"flags: ", Genode::Hex(flags), " "
|
||||
"ctx_id: ", Genode::Hex(ctx_id));
|
||||
}
|
||||
|
||||
drm_i915_gem_exec_object2 *obj =
|
||||
reinterpret_cast<drm_i915_gem_exec_object2*>(buffers_ptr);
|
||||
|
||||
for (uint64_t i = 0; i < buffer_count; i++) {
|
||||
if (verbose_ioctl) {
|
||||
Genode::log(" obj[", i, "] ",
|
||||
"handle: ", obj[i].handle, " "
|
||||
"relocation_count: ", obj[i].relocation_count, " "
|
||||
"relocs_ptr: ", Genode::Hex(obj[i].relocs_ptr), " "
|
||||
"alignment: ", Genode::Hex(obj[i].alignment), " "
|
||||
"offset: ", Genode::Hex(obj[i].offset), " "
|
||||
"flags: ", Genode::Hex(obj[i].flags));
|
||||
}
|
||||
|
||||
Buffer_handle *bh = _lookup_buffer(obj[i].handle);
|
||||
if (!bh || !bh->cap.valid()) {
|
||||
Genode::error("handle: ", obj[i].handle, " invalid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
obj[i].offset = bh->addr;
|
||||
|
||||
if (obj[i].relocation_count > 0) {
|
||||
drm_i915_gem_relocation_entry *e =
|
||||
reinterpret_cast<drm_i915_gem_relocation_entry*>(obj[i].relocs_ptr);
|
||||
uint32_t const count = obj[i].relocation_count;
|
||||
for (uint64_t i = 0; i < count; i++) {
|
||||
if (verbose_ioctl) {
|
||||
Genode::log(" ",
|
||||
"target_handle: ", e[i].target_handle, " "
|
||||
"delta: ", Genode::Hex(e[i].delta), " "
|
||||
"offset: ", Genode::Hex(e[i].offset), " "
|
||||
"presumed_offset: ", Genode::Hex(e[i].presumed_offset), " "
|
||||
"read_domains: ", Genode::Hex(e[i].read_domains), " "
|
||||
"write_domain: ", Genode::Hex(e[i].write_domain));
|
||||
}
|
||||
|
||||
Genode::Dataspace_capability cap = _lookup_buffer_cap(e[i].target_handle);
|
||||
if (!cap.valid()) {
|
||||
Genode::error("target_handle: ", e[i].target_handle, " invalid");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* relocate in batch buffer and copy object to command buffer */
|
||||
drm_i915_gem_exec_object2 &bb = obj[batch_buffer_id];
|
||||
if (!_relocate_batch_buffer(bb, batch_len)) {
|
||||
Genode::error("could not relocate batch buffer objects");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Genode::Dataspace_capability bb_cap = _lookup_buffer_cap(bb.handle);
|
||||
if (!bb_cap.valid()) {
|
||||
Genode::error("batch buffer cap invalid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_gpu_session.exec_buffer(bb_cap, batch_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _device_gem_busy(void *arg)
|
||||
{
|
||||
drm_i915_gem_busy * const p = reinterpret_cast<drm_i915_gem_busy*>(arg);
|
||||
// Handle const handle = p->handle;
|
||||
// uint32_t busy = p->busy;
|
||||
/* TODO flag currently executed buffer */
|
||||
p->busy = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _device_gem_madvise(void *arg)
|
||||
{
|
||||
drm_i915_gem_madvise * const p = reinterpret_cast<drm_i915_gem_madvise*>(arg);
|
||||
// Handle const handle = p->handle;
|
||||
// uint32_t const madv = p->madv;
|
||||
/* all buffer are always available */
|
||||
p->retained = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _device_ioctl(unsigned cmd, void *arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case DRM_I915_GEM_GET_APERTURE: return _device_gem_get_aperture_size(arg);
|
||||
case DRM_I915_GETPARAM: return _device_getparam(arg);
|
||||
case DRM_I915_GEM_CREATE: return _device_gem_create(arg);
|
||||
case DRM_I915_GEM_MMAP: return _device_gem_mmap(arg);
|
||||
case DRM_I915_GEM_MMAP_GTT: return _device_gem_mmap_gtt(arg);
|
||||
case DRM_I915_GEM_SET_DOMAIN: return _device_gem_set_domain(arg);
|
||||
case DRM_I915_GEM_CONTEXT_CREATE: return _device_gem_context_create(arg);
|
||||
case DRM_I915_GEM_SET_TILING: return _device_gem_set_tiling(arg);
|
||||
case DRM_I915_GEM_PWRITE: return _device_gem_pwrite(arg);
|
||||
case DRM_I915_GEM_SW_FINISH: return _device_gem_sw_finish(arg);
|
||||
case DRM_I915_GEM_EXECBUFFER2: return _device_gem_execbuffer2(arg);
|
||||
case DRM_I915_GEM_BUSY: return _device_gem_busy(arg);
|
||||
case DRM_I915_GEM_MADVISE: return _device_gem_madvise(arg);
|
||||
default:
|
||||
Genode::error("Unhandled device specific ioctl:", Genode::Hex(cmd));
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _generic_gem_close(void *arg)
|
||||
{
|
||||
drm_gem_close * const p = reinterpret_cast<drm_gem_close*>(arg);
|
||||
return _free_buffer(p->handle);
|
||||
}
|
||||
|
||||
int _generic_gem_flink(void *arg)
|
||||
{
|
||||
drm_gem_flink * const p = reinterpret_cast<drm_gem_flink*>(arg);
|
||||
p->name = p->handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _generic_ioctl(unsigned cmd, void *arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case DRM_NUMBER(DRM_IOCTL_GEM_CLOSE): return _generic_gem_close(arg);
|
||||
case DRM_NUMBER(DRM_IOCTL_GEM_FLINK): return _generic_gem_flink(arg);
|
||||
default:
|
||||
Genode::error("Unhandled generic DRM ioctl:", Genode::Hex(cmd));
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Drm_call(Genode::Env &env, Genode::Entrypoint &signal_ep)
|
||||
: _env(env),
|
||||
_completion_sigh(signal_ep, *this, &Drm_call::_handle_completion)
|
||||
{
|
||||
_gpu_session.completion_sigh(_completion_sigh);
|
||||
}
|
||||
|
||||
bool map_buffer_ggtt(Offset offset, size_t length)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
auto lookup_buffer = [&] (Buffer_handle &h) {
|
||||
if (h.map_offset != offset) { return; }
|
||||
result = true;
|
||||
};
|
||||
_buffer_registry.for_each(lookup_buffer);
|
||||
|
||||
if (!result) {
|
||||
Genode::error("could not lookup buffer for offset: ", offset);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void unmap_buffer_ggtt(void *addr, size_t length)
|
||||
{
|
||||
Offset const offset = (Offset const)addr;
|
||||
|
||||
auto lookup_buffer = [&] (Buffer_handle &h) {
|
||||
if (h.map_offset != offset) { return; }
|
||||
|
||||
if (!h.map_cap.valid()) {
|
||||
Genode::error("no valid capability found for offset: ", Genode::Hex(offset));
|
||||
return;
|
||||
}
|
||||
|
||||
_unmap_buffer(h);
|
||||
};
|
||||
_buffer_registry.for_each(lookup_buffer);
|
||||
}
|
||||
|
||||
int ioctl(unsigned long request, void *arg)
|
||||
{
|
||||
bool const device = device_ioctl(request);
|
||||
return device ? _device_ioctl(device_number(request), arg)
|
||||
: _generic_ioctl(command_number(request), arg);
|
||||
}
|
||||
|
||||
void wait_for_completion() { _completion_lock.lock(); }
|
||||
};
|
||||
|
||||
|
||||
static Genode::Constructible<Drm_call> _call;
|
||||
|
||||
|
||||
void drm_init(Genode::Env &env, Genode::Entrypoint &signal_ep)
|
||||
{
|
||||
_call.construct(env, signal_ep);
|
||||
}
|
||||
|
||||
|
||||
void drm_complete() { _call->wait_for_completion(); }
|
||||
|
||||
|
||||
/**
|
||||
* Mmap buffer object
|
||||
*
|
||||
* On Genode the virtual address of MMAP_GTT is stored in the offset.
|
||||
*/
|
||||
extern "C" void *drm_mmap(void *addr, size_t length, int prot, int flags,
|
||||
int fd, off_t offset)
|
||||
{
|
||||
/* sanity check if we got a GTT mapped offset */
|
||||
bool const ok = _call->map_buffer_ggtt(offset, length);
|
||||
return ok ? (void *)offset : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmap buffer object
|
||||
*/
|
||||
extern "C" int drm_munmap(void *addr, size_t length)
|
||||
{
|
||||
_call->unmap_buffer_ggtt(addr, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
extern "C" int genode_ioctl(int fd, unsigned long request, void *arg)
|
||||
{
|
||||
Genode::error(__func__, " not implemented");
|
||||
return -1;
|
||||
if (verbose_ioctl) { dump_ioctl(request); }
|
||||
int const ret = _call->ioctl(request, arg);
|
||||
if (verbose_ioctl) { Genode::log("returned ", ret); }
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user