From 3b40790e029a51b6512bcb83344a0ab1e71a5799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20S=C3=B6ntgen?= Date: Thu, 23 Sep 2021 17:37:51 +0200 Subject: [PATCH] gpu: use Buffer_id to identify buffers Rather than using the dataspace capability directly, let the client choose its own local identifier that is linked to the underlying capability. Fixes #4265. --- repos/libports/src/lib/libdrm/ioctl_iris.cc | 439 ++++++++++---------- repos/os/include/gpu_session/client.h | 33 +- repos/os/include/gpu_session/gpu_session.h | 58 +-- repos/os/src/drivers/gpu/intel/main.cc | 87 ++-- 4 files changed, 310 insertions(+), 307 deletions(-) diff --git a/repos/libports/src/lib/libdrm/ioctl_iris.cc b/repos/libports/src/lib/libdrm/ioctl_iris.cc index 5e0c791e96..e55ef0642a 100644 --- a/repos/libports/src/lib/libdrm/ioctl_iris.cc +++ b/repos/libports/src/lib/libdrm/ioctl_iris.cc @@ -152,6 +152,70 @@ static void dump_ioctl(unsigned long request) } +namespace { + using Offset = unsigned long; + + struct Gpu_virtual_address { + uint64_t addr; + }; + +} /* anonymous namespace */ + + +struct Gpu::Buffer +{ + Gpu::Connection &_gpu; + + Genode::Id_space::Element const _elem; + + Genode::Dataspace_capability const cap; + Genode::size_t const size; + + Constructible buffer_attached { }; + + Genode::Dataspace_capability map_cap { }; + Offset map_offset { 0 }; + + Gpu_virtual_address gpu_vaddr { }; + Gpu::Info::Execution_buffer_sequence seqno { }; + + bool gpu_vaddr_valid { false }; + bool busy { false }; + + Buffer(Gpu::Connection &gpu, + Genode::size_t size, + Genode::Id_space &space) + : + _gpu { gpu }, + _elem { *this, space }, + cap { _gpu.alloc_buffer(_elem.id(), size) }, + size { size } + { } + + virtual ~Buffer() + { + _gpu.free_buffer(_elem.id()); + } + + bool mmap(Genode::Env &env) + { + if (!buffer_attached.constructed()) + buffer_attached.construct(env.rm(), cap); + + return buffer_attached.constructed(); + } + + addr_t mmap_addr() { + return reinterpret_cast(buffer_attached->local_addr()); + } + + Gpu::Buffer_id id() const + { + return _elem.id(); + } +}; + + class Drm_call { private: @@ -163,69 +227,9 @@ class Drm_call size_t _available_gtt_size { _gpu_info.aperture_size }; bool _complete { false }; - using Offset = unsigned long; + using Buffer = Gpu::Buffer; - struct Gpu_virtual_address { - uint64_t addr; - }; - - struct Buffer_handle; - typedef Genode::Id_space::Element Handle; - typedef Genode::Id_space::Id Handle_id; - - struct Buffer_handle - { - Genode::Dataspace_capability const cap; - Genode::size_t const size; - Handle const handle; - - Constructible buffer_attached { }; - - Genode::Dataspace_capability map_cap { }; - Offset map_offset { 0 }; - - Gpu_virtual_address gpu_vaddr { }; - Gpu::Info::Execution_buffer_sequence seqno { }; - - bool gpu_vaddr_valid { false }; - bool busy { false }; - - Buffer_handle(Genode::Dataspace_capability cap, - Genode::size_t size, - Genode::Id_space &space) - : - cap(cap), size(size), - handle(*this, space) - { - if (!cap.valid() || !size) - Genode::warning("invalid Buffer_handle ?"); - } - - virtual ~Buffer_handle() { } - - bool valid() const { return cap.valid() && size != 0; } - - bool mmap(Genode::Env &env) - { - if (!valid()) - return false; - - if (!buffer_attached.constructed()) - buffer_attached.construct(env.rm(), cap); - - return buffer_attached.constructed(); - } - - addr_t mmap_addr() { - return reinterpret_cast(buffer_attached->local_addr()); - } - }; - - Genode::Id_space _buffer_handles { }; - - using Buffer = Genode::Registered; - - Genode::Registry _buffer_registry { }; + Genode::Id_space _buffer_space { }; struct Sync_obj { @@ -241,7 +245,7 @@ class Drm_call Genode::Id_space _sync_objects { }; - bool _map_buffer_ppgtt(Buffer_handle &buffer, Gpu_virtual_address const vaddr) + bool _map_buffer_ppgtt(Buffer &buffer, Gpu_virtual_address const vaddr) { if (buffer.gpu_vaddr_valid) Genode::warning(__func__, " already have a gpu virtual address ", @@ -250,7 +254,7 @@ class Drm_call /* XXX out of cap XXX */ bool const ppgtt = Genode::retry( - [&]() { return _gpu_session.map_buffer_ppgtt(buffer.cap, + [&]() { return _gpu_session.map_buffer_ppgtt(buffer.id(), Utils::limit_to_48bit(vaddr.addr)); }, [&]() { _gpu_session.upgrade_ram(4096); } ); @@ -265,11 +269,12 @@ class Drm_call return true; } - void _unmap_buffer_ppgtt(Buffer_handle &buffer) + void _unmap_buffer_ppgtt(Buffer &buffer) { if (!buffer.gpu_vaddr_valid) return; - _gpu_session.unmap_buffer_ppgtt(buffer.cap, Utils::limit_to_48bit(buffer.gpu_vaddr.addr)); + _gpu_session.unmap_buffer_ppgtt(buffer.id(), + Utils::limit_to_48bit(buffer.gpu_vaddr.addr)); buffer.gpu_vaddr_valid = false; } @@ -277,115 +282,94 @@ class Drm_call void _alloc_buffer(uint64_t const size, FUNC const &fn) { Genode::size_t donate = size; - Genode::Dataspace_capability cap = Genode::retry( - [&] () { return _gpu_session.alloc_buffer(size); }, + Buffer *buffer = nullptr; + Genode::retry( + [&] () { + buffer = + new (&_heap) Buffer(_gpu_session, size, _buffer_space); + }, [&] () { _gpu_session.upgrade_ram(donate); donate /= 4; }); - try { - Buffer * buffer = new (&_heap) Buffer(_buffer_registry, cap, size, _buffer_handles); - fn(buffer->handle); - } catch (...) { - _gpu_session.free_buffer(cap); - throw; - } + if (buffer) + fn(*buffer); } - void _unmap_buffer(Buffer_handle &h) + void _unmap_buffer(Buffer &h) { _env.rm().detach(h.map_offset); h.map_offset = 0; - _gpu_session.unmap_buffer(h.map_cap); + _gpu_session.unmap_buffer(h.id()); h.map_cap = Genode::Dataspace_capability(); _available_gtt_size += h.size; } - int _free_buffer(Handle_id const &id) + int _free_buffer(Gpu::Buffer_id const id) { - bool const handled = _apply_buffer(id, [&] (Buffer_handle &bh) { - if (bh.map_cap.valid()) - _unmap_buffer(bh); + try { + _buffer_space.apply(id, [&] (Buffer &b) { + if (b.map_cap.valid()) + _unmap_buffer(b); - if (bh.gpu_vaddr_valid) { - _gpu_session.unmap_buffer_ppgtt(bh.cap, bh.gpu_vaddr.addr); - bh.gpu_vaddr_valid = false; - } - _gpu_session.free_buffer(bh.cap); - - Genode::destroy(&_heap, &bh); - }); - - if (!handled) { + if (b.gpu_vaddr_valid) { + _gpu_session.unmap_buffer_ppgtt(b.id(), b.gpu_vaddr.addr); + b.gpu_vaddr_valid = false; + } + Genode::destroy(&_heap, &b); + }); + return 0; + } catch (Genode::Id_space::Unknown_id) { Genode::error(__func__, ": invalid handle ", id.value); - Genode::sleep_forever(); + return -1; } - - return handled ? 0 : -1; } - Offset _map_buffer(Buffer_handle &bh) + Offset _map_buffer(Buffer &b) { Offset offset = 0; - if (bh.map_cap.valid()) { - offset = bh.map_offset; + if (b.map_cap.valid()) { + offset = b.map_offset; return offset; } try { _gpu_session.upgrade_ram(4096); - bh.map_cap = _gpu_session.map_buffer(bh.cap, true); - bh.map_offset = static_cast(_env.rm().attach(bh.map_cap)); - offset = bh.map_offset; + b.map_cap = _gpu_session.map_buffer(b.id(), true); + b.map_offset = static_cast(_env.rm().attach(b.map_cap)); + offset = b.map_offset; - _available_gtt_size -= bh.size; + _available_gtt_size -= b.size; } catch (...) { - if (bh.map_cap.valid()) { _gpu_session.unmap_buffer(bh.map_cap); } - bh.map_cap = Genode::Dataspace_capability(); - Genode::error("could not attach GEM buffer handle: ", bh.handle); + if (b.map_cap.valid()) + _gpu_session.unmap_buffer(b.id()); + + b.map_cap = Genode::Dataspace_capability(); + Genode::error("could not attach GEM buffer handle: ", b.id().value); Genode::sleep_forever(); } return offset; } - Offset _map_buffer(Handle_id const &id) + Offset _map_buffer(Gpu::Buffer_id const id) { Offset offset = 0; - - bool handled = _apply_buffer(id, [&] (Buffer_handle &bh) { - offset = _map_buffer(bh); - }); - - if (!handled) { + try { + _buffer_space.apply(id, [&] (Buffer &b) { + offset = _map_buffer(b); + }); + } catch (Genode::Id_space::Unknown_id) { Genode::error(__func__, ": invalid handle ", id.value); Genode::sleep_forever(); } - return offset; } - /******************* - ** lookup buffer ** - *******************/ - - template - bool _apply_buffer(Handle_id const &id, FUNC const &fn) - { - bool found = false; - - _buffer_handles.apply(id, [&](Buffer_handle &bh) { - fn(bh); - found = true; - }); - - return found; - } - /*************************** ** execbuffer completion ** ***************************/ @@ -419,42 +403,46 @@ class Drm_call uint64_t const size = (p->size + 0xfff) & ~0xfff; - _alloc_buffer(size, [&](Handle const &handle) { - p->size = size; - p->handle = handle.id().value; + try { + _alloc_buffer(size, [&](Buffer const &b) { + p->size = size; + p->handle = b.id().value; - if (verbose_ioctl) { - Genode::error(__func__, ": ", "handle: ", handle.id().value, - " size: ", size); - } - }); - - return 0; + if (verbose_ioctl) { + Genode::error(__func__, ": ", "handle: ", b.id().value, + " size: ", size); + } + }); + return 0; + } catch (...) { + return -1; + } } int _device_gem_mmap(void *arg) { auto const p = reinterpret_cast(arg); - Handle_id const handle { .value = p->handle }; + Gpu::Buffer_id const id { .value = p->handle }; bool map_failed { true }; - bool handled = _apply_buffer(handle, [&] (Buffer_handle &bh) { - if (bh.mmap(_env)) { - p->addr_ptr = bh.mmap_addr(); - map_failed = false; - } - }); + try { + _buffer_space.apply(id, [&] (Buffer &b) { + if (b.mmap(_env)) { + p->addr_ptr = b.mmap_addr(); + map_failed = false; + } + }); + } catch (Genode::Id_space::Unknown_id) { } if (verbose_ioctl) { - Genode::error(__func__, ": ", "handle: ", handle, - !handled ? " buffer unknown" : "", + Genode::error(__func__, ": ", "handle: ", id, map_failed ? " buffer inaccessible" : "", " flags=", p->flags, " addr=", Genode::Hex(p->addr_ptr)); } - if (!handled || map_failed) + if (map_failed) return -1; return 0; @@ -463,7 +451,7 @@ class Drm_call int _device_gem_mmap_gtt(void *arg) { auto const p = reinterpret_cast(arg); - Handle_id const id { .value = p->handle }; + Gpu::Buffer_id const id { .value = p->handle }; if (verbose_ioctl) { Genode::error(__func__, ": ", "handle: ", id.value, @@ -499,7 +487,7 @@ class Drm_call { /* XXX check read_domains/write_domain */ auto const p = reinterpret_cast(arg); - Handle_id const id { .value = p->handle }; + Gpu::Buffer_id const id { .value = p->handle }; uint32_t const rd = p->read_domains; uint32_t const wd = p->write_domain; @@ -610,7 +598,7 @@ class Drm_call int _device_gem_set_tiling(void *arg) { auto const p = reinterpret_cast(arg); - Handle_id const id { .value = p->handle }; + Gpu::Buffer_id const id { .value = p->handle }; uint32_t const mode = p->tiling_mode; uint32_t const stride = p->stride; uint32_t const swizzle = p->swizzle_mode; @@ -623,21 +611,20 @@ class Drm_call "swizzle: ", swizzle); } - bool ok = false; - bool handled = _apply_buffer(id, [&] (Buffer_handle &bh) { - if (!bh.cap.valid()) - return; + bool ok = false; + try { + _buffer_space.apply(id, [&] (Buffer &b) { - /* we need a valid GGTT mapping for fencing */ - if (!bh.map_cap.valid() && !_map_buffer(bh)) - return; + /* we need a valid GGTT mapping for fencing */ + if (!b.map_cap.valid() && !_map_buffer(b)) + return; - uint32_t const m = (stride << 16) | (mode == 1 ? 1 : 0); - ok = _gpu_session.set_tiling(bh.map_cap, m); - }); - - if (!handled) + uint32_t const m = (stride << 16) | (mode == 1 ? 1 : 0); + ok = _gpu_session.set_tiling(b.id(), m); + }); + } catch (Genode::Id_space::Unknown_id) { Genode::error(__func__, ": invalid handle: ", id.value); + } return ok ? 0 : -1; } @@ -657,7 +644,7 @@ class Drm_call /* batch-buffer index and cap */ unsigned const bb_id = (p->flags & I915_EXEC_BATCH_FIRST) ? 0 : p->buffer_count - 1; - Buffer_handle *command_buffer = nullptr; + Buffer *command_buffer = nullptr; if (verbose_ioctl) { uint64_t const ctx_id = p->rsvd1; @@ -722,38 +709,40 @@ class Drm_call return -1; } - int ret = -1; - Handle_id const id { .value = obj[i].handle }; + int ret = -1; + Gpu::Buffer_id const id { .value = obj[i].handle }; - bool handled = _apply_buffer(id, [&](Buffer_handle &bh) { - if (!bh.valid()) - return; + try { + _buffer_space.apply(id, [&](Buffer &b) { - if (bh.busy) - Genode::warning("handle: ", obj[i].handle, " reused but is busy"); + if (b.busy) + Genode::warning("handle: ", obj[i].handle, " reused but is busy"); - if (bh.gpu_vaddr_valid && bh.gpu_vaddr.addr != obj[i].offset) { - Genode::error("unmap already mapped ", bh.handle, " ", Genode::Hex(bh.gpu_vaddr.addr), "->", Genode::Hex(obj[i].offset)); - _unmap_buffer_ppgtt(bh); - } + if (b.gpu_vaddr_valid && b.gpu_vaddr.addr != obj[i].offset) { + Genode::error("unmap already mapped ", b.id().value, " ", + Genode::Hex(b.gpu_vaddr.addr), "->", + Genode::Hex(obj[i].offset)); + _unmap_buffer_ppgtt(b); + } - if (!bh.gpu_vaddr_valid) - _map_buffer_ppgtt(bh, Gpu_virtual_address { .addr = obj[i].offset }); + if (!b.gpu_vaddr_valid) + _map_buffer_ppgtt(b, Gpu_virtual_address { .addr = obj[i].offset }); - if (!bh.gpu_vaddr_valid) { - Genode::error("handle: ", obj[i].handle, " gpu_vaddr invalid"); - return; - } + if (!b.gpu_vaddr_valid) { + Genode::error("handle: ", obj[i].handle, " gpu_vaddr invalid"); + return; + } - bh.busy = true; + b.busy = true; - if (i == bb_id) - command_buffer = &bh; + if (i == bb_id) + command_buffer = &b; - ret = 0; - }); + ret = 0; + }); + } catch (Genode::Id_space::Unknown_id) { } - if (!handled || ret) { + if (ret) { Genode::error("handle: ", obj[i].handle, " invalid, ret=", ret); return ret; } @@ -762,13 +751,13 @@ class Drm_call if (!command_buffer) return -1; - command_buffer->seqno = _gpu_session.exec_buffer(command_buffer->cap, + command_buffer->seqno = _gpu_session.exec_buffer(command_buffer->id(), p->batch_len); for (uint64_t i = 0; i < p->buffer_count; i++) { - Handle_id const id { .value = obj[i].handle }; - _apply_buffer(id, [&](Buffer_handle &bh) { - bh.seqno = command_buffer->seqno; + Gpu::Buffer_id const id { .value = obj[i].handle }; + _buffer_space.apply(id, [&](Buffer &b) { + b.seqno = command_buffer->seqno; }); } @@ -777,7 +766,7 @@ class Drm_call * of signal ep, the original drm_i915_gem_wait simply 0 now */ struct drm_i915_gem_wait wait = { - .bo_handle = (__u32)command_buffer->handle.id().value, + .bo_handle = (__u32)command_buffer->id().value, .flags = 0, .timeout_ns = -1LL }; @@ -789,13 +778,16 @@ class Drm_call int _device_gem_busy(void *arg) { auto const p = reinterpret_cast(arg); - Handle_id const id { .value = p->handle }; + Gpu::Buffer_id const id { .value = p->handle }; - bool handled = _apply_buffer(id, [&](Buffer_handle const &bh) { - p->busy = bh.busy; - }); - - return handled ? 0 : -1; + try { + _buffer_space.apply(id, [&](Buffer const &b) { + p->busy = b.busy; + }); + return 0; + } catch (Genode::Id_space::Unknown_id) { + return -1; + } } int _device_gem_madvise(void *arg) @@ -811,16 +803,17 @@ class Drm_call int _device_gem_wait(void *arg) { auto const p = reinterpret_cast(arg); - Handle_id const id { .value = p->bo_handle }; + Gpu::Buffer_id const id { .value = p->bo_handle }; bool busy = true; while (busy) { - bool handled = _apply_buffer(id, [&](Buffer_handle &bh) { - busy = bh.busy; - }); - if (!handled) { + try { + _buffer_space.apply(id, [&](Buffer &b) { + busy = b.busy; + }); + } catch (Genode::Id_space::Unknown_id) { Genode::error(__func__, ": handle ", p->bo_handle, " invalid"); return -1; } @@ -892,7 +885,7 @@ class Drm_call int _generic_gem_close(void *arg) { auto const p = reinterpret_cast(arg); - Handle_id const id { .value = p->handle }; + Gpu::Buffer_id const id { .value = p->handle }; return _free_buffer(id); } @@ -993,7 +986,7 @@ class Drm_call } int const prime_fd { 44 }; - Handle_id prime_handle { }; + Gpu::Buffer_id prime_handle { }; int _generic_prime_fd_to_handle(void *arg) { @@ -1010,16 +1003,18 @@ class Drm_call { auto const p = reinterpret_cast(arg); - Handle_id const handle { .value = p->handle }; - bool handled = _apply_buffer(handle, [&](Buffer_handle const &bh) { - if (!prime_handle.value) - prime_handle = handle; + Gpu::Buffer_id const id { .value = p->handle }; + try { + _buffer_space.apply(id, [&](Buffer const &b) { + if (!prime_handle.value) + prime_handle = id; - if (prime_handle.value != handle.value) - Genode::error("prime handle changed - ignored ", bh.handle); - }); - if (!handled) + if (prime_handle.value != id.value) + Genode::error("prime handle changed - ignored ", b.id().value); + }); + } catch (Genode::Id_space::Unknown_id) { return -1; + } p->fd = prime_fd; return 0; @@ -1069,7 +1064,7 @@ class Drm_call { bool result = false; - _buffer_registry.for_each([&] (Buffer_handle &h) { + _buffer_space.for_each([&] (Buffer &h) { if (h.map_offset != offset) { return; } if (length > h.size) { Genode::error("map_buffer_ggtt: size mismatch"); return; } result = true; @@ -1085,20 +1080,20 @@ class Drm_call { bool found = false; - _buffer_registry.for_each([&] (Buffer_handle &bh) { - if (found || !bh.buffer_attached.constructed()) + _buffer_space.for_each([&] (Buffer &b) { + if (found || !b.buffer_attached.constructed()) return; - if (reinterpret_cast(bh.mmap_addr()) != addr) + if (reinterpret_cast(b.mmap_addr()) != addr) return; - if (bh.buffer_attached->size() != length) { + if (b.buffer_attached->size() != length) { Genode::warning(__func__, " size mismatch"); Genode::sleep_forever(); return; } - bh.buffer_attached.destruct(); + b.buffer_attached.destruct(); found = true; }); @@ -1115,7 +1110,7 @@ class Drm_call bool handled = false; - _buffer_registry.for_each([&] (Buffer_handle &h) { + _buffer_space.for_each([&] (Buffer &h) { if (handled) return; if (h.map_offset != offset) return; if (length > h.size) { Genode::error("unmap_buffer_ggtt: size mismatch"); return; } @@ -1152,7 +1147,7 @@ class Drm_call /* make done buffer objects */ Gpu::Info gpu_info { _gpu_session.info() }; - _buffer_registry.for_each([&] (Buffer_handle &h) { + _buffer_space.for_each([&] (Buffer &h) { if (!h.busy) return; if (h.seqno.id > gpu_info.last_completed.id) return; h.busy = false; diff --git a/repos/os/include/gpu_session/client.h b/repos/os/include/gpu_session/client.h index 16548c2975..cb067ab5ac 100644 --- a/repos/os/include/gpu_session/client.h +++ b/repos/os/include/gpu_session/client.h @@ -40,35 +40,34 @@ class Gpu::Session_client : public Genode::Rpc_client Info info() const override { return call(); } - Gpu::Info::Execution_buffer_sequence exec_buffer(Genode::Dataspace_capability cap, + Gpu::Info::Execution_buffer_sequence exec_buffer(Buffer_id id, Genode::size_t size) override { - return call(cap, size); } + return call(id, size); } void completion_sigh(Genode::Signal_context_capability sigh) override { call(sigh); } - Genode::Dataspace_capability alloc_buffer(Genode::size_t size) override { - return call(size); } + Genode::Dataspace_capability alloc_buffer(Buffer_id id, Genode::size_t size) override { + return call(id, size); } - void free_buffer(Genode::Dataspace_capability ds) override { - call(ds); } + void free_buffer(Gpu::Buffer_id id) override { + call(id); } - Genode::Dataspace_capability map_buffer(Genode::Dataspace_capability ds, + Genode::Dataspace_capability map_buffer(Buffer_id id, bool aperture) override { - return call(ds, aperture); } + return call(id, aperture); } - void unmap_buffer(Genode::Dataspace_capability ds) override { - call(ds); } + void unmap_buffer(Buffer_id id) override { + call(id); } - bool map_buffer_ppgtt(Genode::Dataspace_capability ds, - Gpu::addr_t va) override { - return call(ds, va); } + bool map_buffer_ppgtt(Buffer_id id, Gpu::addr_t va) override { + return call(id, va); } - void unmap_buffer_ppgtt(Genode::Dataspace_capability ds, Gpu::addr_t va) override { - call(ds, va); } + void unmap_buffer_ppgtt(Buffer_id id, Gpu::addr_t va) override { + call(id, va); } - bool set_tiling(Genode::Dataspace_capability ds, unsigned mode) override { - return call(ds, mode); } + bool set_tiling(Buffer_id id, unsigned mode) override { + return call(id, mode); } }; #endif /* _INCLUDE__GPU_SESSION__CLIENT_H_ */ diff --git a/repos/os/include/gpu_session/gpu_session.h b/repos/os/include/gpu_session/gpu_session.h index 0a14889b7b..c6d129d1a3 100644 --- a/repos/os/include/gpu_session/gpu_session.h +++ b/repos/os/include/gpu_session/gpu_session.h @@ -14,12 +14,16 @@ #ifndef _INCLUDE__GPU_SESSION__GPU_SESSION_H_ #define _INCLUDE__GPU_SESSION__GPU_SESSION_H_ +#include #include namespace Gpu { using addr_t = Genode::uint64_t; + struct Buffer; + using Buffer_id = Genode::Id_space::Id; + struct Info; struct Session; } @@ -74,9 +78,10 @@ struct Gpu::Info */ struct Gpu::Session : public Genode::Session { - struct Out_of_ram : Genode::Exception { }; - struct Out_of_caps : Genode::Exception { }; - struct Invalid_state : Genode::Exception { }; + struct Out_of_ram : Genode::Exception { }; + struct Out_of_caps : Genode::Exception { }; + struct Invalid_state : Genode::Exception { }; + struct Conflicting_id : Genode::Exception { }; struct Mapping_buffer_failed : Genode::Exception { }; enum { REQUIRED_QUOTA = 1024 * 1024, CAP_QUOTA = 8, }; @@ -97,14 +102,14 @@ struct Gpu::Session : public Genode::Session /** * Execute commands from given buffer * - * \param cap capability to buffer object containing the exec buffer + * \param id buffer id * \param size size of the batch buffer in bytes * * \return execution buffer sequence number for complete checks * * \throw Invalid_state is thrown if the provided buffer is not valid, e.g not mapped */ - virtual Gpu::Info::Execution_buffer_sequence exec_buffer(Genode::Dataspace_capability cap, Genode::size_t size) = 0; + virtual Gpu::Info::Execution_buffer_sequence exec_buffer(Buffer_id id, Genode::size_t size) = 0; /** * Register completion signal handler @@ -117,65 +122,66 @@ struct Gpu::Session : public Genode::Session /** * Allocate buffer dataspace * + * \param id buffer id to be associated with the buffer * \param size size of buffer in bytes * * \throw Out_of_ram * \throw Out_of_caps + * \throw Conflicting_id */ - virtual Genode::Dataspace_capability alloc_buffer(Genode::size_t size) = 0; + virtual Genode::Dataspace_capability alloc_buffer(Buffer_id id, Genode::size_t size) = 0; /** * Free buffer dataspace * * \param ds dataspace capability for buffer */ - virtual void free_buffer(Genode::Dataspace_capability ds) = 0; + virtual void free_buffer(Buffer_id id) = 0; /** * Map buffer * - * \param ds dataspace capability for buffer + * \param id buffer id * \param aperture if true create CPU accessible mapping through * GGTT window, otherwise create PPGTT mapping * * \throw Mapping_buffer_failed */ - virtual Genode::Dataspace_capability map_buffer(Genode::Dataspace_capability ds, + virtual Genode::Dataspace_capability map_buffer(Buffer_id id, bool aperture) = 0; /** * Unmap buffer * - * \param ds dataspace capability for buffer + * \param id buffer id */ - virtual void unmap_buffer(Genode::Dataspace_capability ds) = 0; + virtual void unmap_buffer(Buffer_id id) = 0; /** * Map buffer in PPGTT * - * \param ds dataspace capability for buffer + * \param id buffer id * \param va virtual address * * \throw Mapping_buffer_failed * \throw Out_of_ram */ - virtual bool map_buffer_ppgtt(Genode::Dataspace_capability ds, - Gpu::addr_t va) = 0; + virtual bool map_buffer_ppgtt(Buffer_id id, Gpu::addr_t va) = 0; /** * Unmap buffer * - * \param ds dataspace capability for buffer + * \param id buffer id */ - virtual void unmap_buffer_ppgtt(Genode::Dataspace_capability ds, Gpu::addr_t) = 0; + virtual void unmap_buffer_ppgtt(Buffer_id id, Gpu::addr_t) = 0; /** * Set tiling for buffer * - * \param ds dataspace capability for buffer + * \param id buffer id * \param mode tiling mode */ - virtual bool set_tiling(Genode::Dataspace_capability ds, unsigned mode) = 0; + virtual bool set_tiling(Buffer_id id, unsigned mode) = 0; /******************* ** RPC interface ** @@ -184,25 +190,25 @@ struct Gpu::Session : public Genode::Session GENODE_RPC(Rpc_info, Info, info); GENODE_RPC_THROW(Rpc_exec_buffer, Gpu::Info::Execution_buffer_sequence, exec_buffer, GENODE_TYPE_LIST(Invalid_state), - Genode::Dataspace_capability, Genode::size_t); + Gpu::Buffer_id, Genode::size_t); GENODE_RPC(Rpc_completion_sigh, void, completion_sigh, Genode::Signal_context_capability); GENODE_RPC_THROW(Rpc_alloc_buffer, Genode::Dataspace_capability, alloc_buffer, GENODE_TYPE_LIST(Out_of_ram), - Genode::size_t); - GENODE_RPC(Rpc_free_buffer, void, free_buffer, Genode::Dataspace_capability); + Gpu::Buffer_id, Genode::size_t); + GENODE_RPC(Rpc_free_buffer, void, free_buffer, Gpu::Buffer_id); GENODE_RPC_THROW(Rpc_map_buffer, Genode::Dataspace_capability, map_buffer, GENODE_TYPE_LIST(Mapping_buffer_failed, Out_of_ram), - Genode::Dataspace_capability, bool); + Gpu::Buffer_id, bool); GENODE_RPC(Rpc_unmap_buffer, void, unmap_buffer, - Genode::Dataspace_capability); + Gpu::Buffer_id); GENODE_RPC_THROW(Rpc_map_buffer_ppgtt, bool, map_buffer_ppgtt, GENODE_TYPE_LIST(Mapping_buffer_failed, Out_of_ram), - Genode::Dataspace_capability, Gpu::addr_t); + Gpu::Buffer_id, Gpu::addr_t); GENODE_RPC(Rpc_unmap_buffer_ppgtt, void, unmap_buffer_ppgtt, - Genode::Dataspace_capability, Gpu::addr_t); + Gpu::Buffer_id, Gpu::addr_t); GENODE_RPC(Rpc_set_tiling, bool, set_tiling, - Genode::Dataspace_capability, unsigned); + Gpu::Buffer_id, unsigned); GENODE_RPC_INTERFACE(Rpc_info, Rpc_exec_buffer, Rpc_completion_sigh, Rpc_alloc_buffer, diff --git a/repos/os/src/drivers/gpu/intel/main.cc b/repos/os/src/drivers/gpu/intel/main.cc index 5f6b1ac98a..64c048aab4 100644 --- a/repos/os/src/drivers/gpu/intel/main.cc +++ b/repos/os/src/drivers/gpu/intel/main.cc @@ -1462,6 +1462,7 @@ class Gpu::Session_component : public Genode::Session_object struct Buffer { + Gpu::Buffer_id const id; Genode::Dataspace_capability cap; Gpu::addr_t ppgtt_va { }; @@ -1472,13 +1473,26 @@ class Gpu::Session_component : public Genode::Session_object Igd::Ggtt::Mapping map { }; - Buffer(Genode::Dataspace_capability cap) : cap(cap) { } + Buffer(Gpu::Buffer_id id, Genode::Dataspace_capability cap) + : id { id }, cap { cap } { } virtual ~Buffer() { } }; Genode::Registry> _buffer_registry { }; + template + void _apply_buffer(Gpu::Buffer_id id, FN const &fn) + { + _buffer_registry.for_each([&] (Buffer &buffer) { + if (id.value != buffer.id.value) { + return; + } + + fn(buffer); + }); + } + Genode::uint64_t seqno { 0 }; void _free_buffers() @@ -1559,13 +1573,12 @@ class Gpu::Session_component : public Genode::Session_object _device._subslices); } - Gpu::Info::Execution_buffer_sequence exec_buffer(Genode::Dataspace_capability cap, + Gpu::Info::Execution_buffer_sequence exec_buffer(Buffer_id id, Genode::size_t) override { bool found = false; - _buffer_registry.for_each([&] (Buffer &buffer) { - if (found || !(buffer.cap == cap)) { return; } + _apply_buffer(id, [&] (Buffer &buffer) { if (!buffer.ppgtt_va_valid) { Genode::error("Invalid execbuffer"); @@ -1588,8 +1601,15 @@ class Gpu::Session_component : public Genode::Session_object _vgpu.completion_sigh(sigh); } - Genode::Dataspace_capability alloc_buffer(Genode::size_t size) override + Genode::Dataspace_capability alloc_buffer(Gpu::Buffer_id id, + Genode::size_t size) override { + bool found = false; + _apply_buffer(id, [&] (Buffer &) { + found = true; + }); + if (found) { throw Conflicting_id(); } + /* * XXX allocator overhead is not * included, mapping costs are not included and we throw at @@ -1605,7 +1625,7 @@ class Gpu::Session_component : public Genode::Session_object Genode::Dataspace_capability cap = _device.alloc_buffer(_heap, size); try { - new (&_heap) Genode::Registered(_buffer_registry, cap); + new (&_heap) Genode::Registered(_buffer_registry, id, cap); } catch (...) { if (cap.valid()) _device.free_buffer(_heap, cap); @@ -1619,33 +1639,27 @@ class Gpu::Session_component : public Genode::Session_object return Genode::Dataspace_capability(); } - void free_buffer(Genode::Dataspace_capability cap) override + void free_buffer(Gpu::Buffer_id id) override { - if (!cap.valid()) { return; } - auto lookup_and_free = [&] (Buffer &buffer) { - if (!(buffer.cap == cap)) { return; } if (buffer.map.offset != Igd::Ggtt::Mapping::INVALID_OFFSET) { Genode::error("cannot free mapped buffer"); /* XXX throw */ } - _device.free_buffer(_heap, cap); + _device.free_buffer(_heap, buffer.cap); Genode::destroy(&_heap, &buffer); }; - _buffer_registry.for_each(lookup_and_free); + _apply_buffer(id, lookup_and_free); } - Genode::Dataspace_capability map_buffer(Genode::Dataspace_capability cap, + Genode::Dataspace_capability map_buffer(Gpu::Buffer_id id, bool aperture) override { - if (!cap.valid()) { return Genode::Dataspace_capability(); } - Genode::Dataspace_capability map_cap; auto lookup_and_map = [&] (Buffer &buffer) { - if (!(buffer.cap == cap)) { return; } if (buffer.map.offset != Igd::Ggtt::Mapping::INVALID_OFFSET) { Genode::error("buffer already mapped"); @@ -1653,7 +1667,8 @@ class Gpu::Session_component : public Genode::Session_object } try { - Igd::Ggtt::Mapping const &map = _device.map_buffer(_heap, cap, aperture); + Igd::Ggtt::Mapping const &map = + _device.map_buffer(_heap, buffer.cap, aperture); buffer.map.cap = map.cap; buffer.map.offset = map.offset; map_cap = buffer.map.cap; @@ -1662,19 +1677,17 @@ class Gpu::Session_component : public Genode::Session_object throw Gpu::Session::Out_of_ram(); } }; - _buffer_registry.for_each(lookup_and_map); + _apply_buffer(id, lookup_and_map); return map_cap; } - void unmap_buffer(Genode::Dataspace_capability cap) override + void unmap_buffer(Gpu::Buffer_id id) override { - if (!cap.valid()) { return; } - bool unmapped = false; auto lookup_and_unmap = [&] (Buffer &buffer) { - if (!(buffer.map.cap == cap)) { return; } + if (!buffer.map.cap.valid()) { return; } if (buffer.fenced != Buffer::INVALID_FENCE) { _device.clear_tiling(buffer.fenced); @@ -1685,20 +1698,16 @@ class Gpu::Session_component : public Genode::Session_object buffer.map.offset = Igd::Ggtt::Mapping::INVALID_OFFSET; unmapped = true; }; - _buffer_registry.for_each(lookup_and_unmap); + _apply_buffer(id, lookup_and_unmap); if (!unmapped) { Genode::error("buffer not mapped"); } } - bool map_buffer_ppgtt(Genode::Dataspace_capability cap, - Gpu::addr_t va) override + bool map_buffer_ppgtt(Gpu::Buffer_id id, Gpu::addr_t va) override { - if (!cap.valid()) { return false; } - enum { ALLOC_FAILED, MAP_FAILED, OK } result = ALLOC_FAILED; auto lookup_and_map = [&] (Buffer &buffer) { - if (!(buffer.cap == cap)) { return; } if (buffer.ppgtt_va_valid) { Genode::error("buffer already mapped"); @@ -1706,7 +1715,7 @@ class Gpu::Session_component : public Genode::Session_object } try { - Genode::Dataspace_client buf(cap); + Genode::Dataspace_client buf(buffer.cap); /* XXX check that actual_size matches alloc_buffer size */ Genode::size_t const actual_size = buf.size(); Genode::addr_t const phys_addr = buf.phys_addr(); @@ -1724,7 +1733,7 @@ class Gpu::Session_component : public Genode::Session_object return; } }; - _buffer_registry.for_each(lookup_and_map); + _apply_buffer(id, lookup_and_map); switch (result) { case ALLOC_FAILED: throw Gpu::Session::Out_of_ram(); @@ -1735,16 +1744,10 @@ class Gpu::Session_component : public Genode::Session_object } } - void unmap_buffer_ppgtt(Genode::Dataspace_capability cap, + void unmap_buffer_ppgtt(Gpu::Buffer_id id, Gpu::addr_t va) override { - if (!cap.valid()) { - Genode::error("invalid buffer capability"); - return; - } - auto lookup_and_unmap = [&] (Buffer &buffer) { - if (!(buffer.cap == cap)) { return; } if (!buffer.ppgtt_va_valid) { Genode::error("buffer not mapped"); @@ -1756,15 +1759,15 @@ class Gpu::Session_component : public Genode::Session_object return; } - Genode::Dataspace_client buf(cap); + Genode::Dataspace_client buf(buffer.cap); Genode::size_t const actual_size = buf.size(); _vgpu.rcs_unmap_ppgtt(va, actual_size); buffer.ppgtt_va_valid = false; }; - _buffer_registry.for_each(lookup_and_unmap); + _apply_buffer(id, lookup_and_unmap); } - bool set_tiling(Genode::Dataspace_capability cap, + bool set_tiling(Gpu::Buffer_id id, Genode::uint32_t const mode) override { if (_vgpu.active_fences > Igd::Device::Vgpu::MAX_FENCES) { @@ -1774,10 +1777,10 @@ class Gpu::Session_component : public Genode::Session_object Buffer *b = nullptr; auto lookup = [&] (Buffer &buffer) { - if (!(buffer.map.cap == cap)) { return; } + if (!buffer.map.cap.valid()) { return; } b = &buffer; }; - _buffer_registry.for_each(lookup); + _apply_buffer(id, lookup); if (b == nullptr) { Genode::error("attempt to set tiling for non-mapped buffer");