/* * \brief Gpu session interface. * \author Josef Soentgen * \author Sebastian Sumpf * \date 2017-04-28 * * Notes: * * Because of different GPU driver architectures, functions here may have * different semantics. In short, libdrm or any other client must be aware of * the semantics of the respective GPU driver. * * Here a short explanation of the difference of Intel and Lima. * * Intel: * * 'alloc_vram' is used by Iris to create an internal buffer object cache on the * internal Mesa side. Because the allocated memory is RAM, Iris 'mmap's it * directly into the clients address space (Genode::attach) Iris assigns Gpu * virtual addresses to buffers, these addresses may change when buffers are * reused later. On DRM side, Iris calls DRM_MAP_PPGTT, which we implement * through 'map_gpu' (establish a GPU mapping) on the client and multiplexer * side. Graphics memory can be also mapped through the aperture (for example, * when tiling/untiling buffers, which we currently do not see, but have seen in * the past). This is what 'map_cpu' is used for on Intel. It adds a GTT mapping * into the aperture (IOMEM) and returns a dataspace with the physical address * within the aperture. This dataspace has a different physical address than the * one returned by 'alloc_vram' but in the end points to the same RAM through * the GTT. This is now a nop because it is not used, which may change in newer * Mesa versions again. * * Lima: * * The ported Lima driver assigns a GPU virtual address during buffer * allocation. We found a way to at least tell the driver what virtual address * to use, because on default it will use an arbitrary fitting GPU virtual * address, which means unlike Iris, the GPU driver manages the virtual address * space on Lima. So on Lima the semantic is as follows now: * * 'alloc_vram' is a nop because we cannot hand a GPU virtual address over, * instead 'map_gpu' will actually allocate a buffer of given size at a given * Gpu::Virtual_address in the GPU page tables. On the Mesa side, we implemented * a virtual address-allocator, and therefore, handle the GPU address space * ourselves as Iris does in contrib Mesa code. 'map_cpu' will return the * Dataspace_capability of the allocated buffer that then can be directly * attached by Mesa because the GPU memory is again ordinary RAM. */ /* * Copyright (C) 2017-2023 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ #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 Vram; using Vram_id_space = Genode::Id_space; using Vram_id = Vram_id_space::Id; using Vram_capability = Genode::Capability; /* * Attributes for mapping a buffer */ struct Mapping_attributes { bool readable; bool writeable; static Mapping_attributes ro() { return { .readable = true, .writeable = false }; } static Mapping_attributes rw() { return { .readable = true, .writeable = true }; } static Mapping_attributes wo() { return { .readable = false, .writeable = true }; } }; struct Sequence_number; struct Session; struct Virtual_address; } /* * Execution buffer sequence number */ struct Gpu::Sequence_number { Genode::uint64_t value; }; struct Gpu::Virtual_address { Genode::uint64_t value; }; /* * Gpu session interface */ struct Gpu::Session : public Genode::Session { struct Out_of_ram : Genode::Exception { }; struct Out_of_caps : Genode::Exception { }; struct Invalid_state : Genode::Exception { }; struct Conflicting_id : Genode::Exception { }; struct Mapping_vram_failed : Genode::Exception { }; static constexpr Genode::size_t REQUIRED_QUOTA = 1024*1024; static constexpr unsigned CAP_QUOTA = 32; static const char *service_name() { return "Gpu"; } virtual ~Session() { } /*********************** ** Session interface ** ***********************/ /** * Get GPU information dataspace */ virtual Genode::Dataspace_capability info_dataspace() const = 0; /** * Execute commands in vram * * \param id vram id * \param offset offset in vram to start execution * * \return execution sequence number for complete checks * * \throw Invalid_state is thrown if the provided vram is not valid, e.g not mapped */ virtual Gpu::Sequence_number execute(Vram_id id, Genode::off_t offset) = 0; /** * Check if execution has been completed * * \param seqno sequence number of the execution * * \return true if execution has been finished, otherwise * false is returned */ virtual bool complete(Sequence_number seqno) = 0; /** * Register completion signal handler * * \param sigh signal handler that is called when the execution * has completed */ virtual void completion_sigh(Genode::Signal_context_capability sigh) = 0; /** * Allocate video ram * * \param id id to be associated with the vram * \param size size of memory in bytes * * \throw Out_of_ram * \throw Out_of_caps * \throw Conflicting_id */ virtual Genode::Dataspace_capability alloc_vram(Vram_id id, Genode::size_t size) = 0; /** * Free vram * * \param id id of vram */ virtual void free_vram(Vram_id id) = 0; /** * Export vram dataspace from GPU session * * \param id id of associated vram * * \return cability of exported vram */ virtual Vram_capability export_vram(Vram_id id) = 0; /** * Import vram to GPU session * * \param cap capability of vram as retrieved by 'exportvram' * \param id vram id to be associated to this vram in the session * * \throw Conflicting_id * \throw Out_of_caps * \throw Out_of_ram * \throw Invalid_state (cap is no longer valid) */ virtual void import_vram(Vram_capability cap, Vram_id id) = 0; /** * Map vram at CPU * * \param id id of vram * \param attrs specify how the buffer is mapped * * \throw Mapping_vram_failed * \throw Out_of_caps * \throw Out_of_ram */ virtual Genode::Dataspace_capability map_cpu(Vram_id id, Mapping_attributes attrs) = 0; /** * Unmap vram * * \param id id of vram */ virtual void unmap_cpu(Vram_id id) = 0; /** * Map vram at GPU * * \param id vram id * \param size size of vram to be mapped * \pram offset offset in vram * \param va GPU virtual address * * \return true on success, false otherwise * \throw Mapping_vram_failed * \throw Out_of_caps * \throw Out_of_ram */ virtual bool map_gpu(Vram_id id, Genode::size_t size, Genode::off_t offset, Virtual_address va) = 0; /** * Unmap vram on GPU * * \param id vram id * \param offset offset in vram * \param va GPU virtual address */ virtual void unmap_gpu(Vram_id id, Genode::off_t offset, Virtual_address va) = 0; /** * Set tiling for vram on GPU * * \param id vram id * \param offset offset in vram * \param mode tiling mode */ virtual bool set_tiling_gpu(Vram_id id, Genode::off_t offset, unsigned mode) = 0; /******************* ** RPC interface ** *******************/ GENODE_RPC(Rpc_info_dataspace, Genode::Dataspace_capability, info_dataspace); GENODE_RPC(Rpc_complete, bool, complete, Gpu::Sequence_number); GENODE_RPC(Rpc_completion_sigh, void, completion_sigh, Genode::Signal_context_capability); GENODE_RPC_THROW(Rpc_execute, Gpu::Sequence_number, execute, GENODE_TYPE_LIST(Invalid_state), Gpu::Vram_id, Genode::off_t); GENODE_RPC_THROW(Rpc_alloc_vram, Genode::Dataspace_capability, alloc_vram, GENODE_TYPE_LIST(Out_of_caps, Out_of_ram), Gpu::Vram_id, Genode::size_t); GENODE_RPC(Rpc_free_vram, void, free_vram, Gpu::Vram_id); GENODE_RPC(Rpc_export_vram, Gpu::Vram_capability, export_vram, Gpu::Vram_id); GENODE_RPC_THROW(Rpc_import_vram, void, import_vram, GENODE_TYPE_LIST(Out_of_caps, Out_of_ram, Conflicting_id, Invalid_state), Gpu::Vram_capability, Gpu::Vram_id); GENODE_RPC_THROW(Rpc_map_cpu, Genode::Dataspace_capability, map_cpu, GENODE_TYPE_LIST(Mapping_vram_failed, Out_of_caps, Out_of_ram), Gpu::Vram_id, Gpu::Mapping_attributes); GENODE_RPC(Rpc_unmap_cpu, void, unmap_cpu, Gpu::Vram_id); GENODE_RPC_THROW(Rpc_map_gpu, bool, map_gpu, GENODE_TYPE_LIST(Mapping_vram_failed, Out_of_caps, Out_of_ram), Gpu::Vram_id, Genode::size_t, Genode::off_t, Gpu::Virtual_address); GENODE_RPC(Rpc_unmap_gpu, void, unmap_gpu, Gpu::Vram_id, Genode::off_t, Gpu::Virtual_address); GENODE_RPC(Rpc_set_tiling_gpu, bool, set_tiling_gpu, Gpu::Vram_id, Genode::off_t, unsigned); GENODE_RPC_INTERFACE(Rpc_info_dataspace, Rpc_complete, Rpc_completion_sigh, Rpc_execute, Rpc_alloc_vram, Rpc_free_vram, Rpc_export_vram, Rpc_import_vram, Rpc_map_cpu, Rpc_unmap_cpu, Rpc_map_gpu, Rpc_unmap_gpu, Rpc_set_tiling_gpu); }; #endif /* _INCLUDE__GPU_SESSION__GPU_SESSION_H_ */