| /* |
| * Copyright 2024 Advanced Micro Devices, Inc. |
| * |
| * SPDX-License-Identifier: MIT |
| */ |
| #ifndef AMDGPU_VIRTIO_PRIVATE_H |
| #define AMDGPU_VIRTIO_PRIVATE_H |
| |
| #include "drm-uapi/amdgpu_drm.h" |
| #include "drm-uapi/virtgpu_drm.h" |
| |
| #include "util/hash_table.h" |
| #include "util/simple_mtx.h" |
| |
| #include "amd_family.h" |
| |
| #include "virtio/vdrm/vdrm.h" |
| #include "virtio/virtio-gpu/drm_hw.h" |
| #include "amdgpu_virtio_proto.h" |
| #include "amdgpu_virtio.h" |
| |
| struct amdvgpu_host_blob; |
| struct amdvgpu_host_blob_allocator; |
| |
| /* Host context seqno handling. |
| * seqno are monotonically increasing integer, so we don't need |
| * to actually submit to know the value. This allows to not |
| * wait for the submission to go to the host (= no need to wait |
| * in the guest) and to know the seqno (= so we can take advantage |
| * of user fence). |
| */ |
| struct amdvgpu_context { |
| uint32_t refcount; |
| uint32_t host_context_id; |
| uint64_t ring_next_seqno[]; |
| }; |
| |
| struct amdvgpu_device { |
| struct vdrm_device * vdev; |
| |
| /* List of existing devices */ |
| int refcount; |
| struct amdvgpu_device *next; |
| |
| int fd; |
| |
| /* Table mapping kms handles to amdvgpu_bo instances. |
| * Used to maintain a 1-to-1 mapping between the 2. |
| */ |
| simple_mtx_t handle_to_vbo_mutex; |
| struct hash_table *handle_to_vbo; |
| |
| /* Submission through virtio-gpu are ring based. |
| * Ring 0 is used for CPU jobs, then N rings are allocated: 1 |
| * per IP type per instance (so if the GPU has 1 gfx queue and 2 |
| * queues -> ring0 + 3 hw rings = 4 rings total). |
| */ |
| uint32_t num_virtio_rings; |
| uint32_t virtio_ring_mapping[AMD_NUM_IP_TYPES]; |
| |
| struct drm_amdgpu_info_device dev_info; |
| |
| /* Blob id are per drm_file identifiers of host blobs. |
| * Use a monotically increased integer to assign the blob id. |
| */ |
| uint32_t next_blob_id; |
| |
| /* GPU VA management (allocation / release). */ |
| amdgpu_va_manager_handle va_mgr; |
| |
| /* Debug option to make some protocol commands synchronous. |
| * If bit N is set, then the specific command will be sync. |
| */ |
| int64_t sync_cmd; |
| |
| /* virtio-gpu uses a single context per drm_file and expects that |
| * any 2 jobs submitted to the same {context, ring} will execute in |
| * order. |
| * amdgpu on the other hand allows for multiple context per drm_file, |
| * so we either have to open multiple virtio-gpu drm_file to be able to |
| * have 1 virtio-gpu context per amdgpu-context or use a single amdgpu |
| * context. |
| * Using multiple drm_file might cause BO sharing issues so for now limit |
| * ourselves to a single amdgpu context. Each amdgpu_ctx object can schedule |
| * parallel work on 1 gfx, 2 sdma, 4 compute, 1 of each vcn queue. |
| */ |
| simple_mtx_t contexts_mutex; |
| struct hash_table contexts; |
| bool allow_multiple_amdgpu_ctx; |
| }; |
| |
| /* Refcounting helpers. Returns true when dst reaches 0. */ |
| static inline bool update_references(int *dst, int *src) |
| { |
| if (dst != src) { |
| /* bump src first */ |
| if (src) { |
| assert(p_atomic_read(src) > 0); |
| p_atomic_inc(src); |
| } |
| if (dst) { |
| return p_atomic_dec_zero(dst); |
| } |
| } |
| return false; |
| } |
| |
| #define virtio_ioctl(fd, name, args) ({ \ |
| int ret = drmIoctl((fd), DRM_IOCTL_ ## name, (args)); \ |
| ret; \ |
| }) |
| |
| struct amdvgpu_host_blob_creation_params { |
| struct drm_virtgpu_resource_create_blob args; |
| struct amdgpu_ccmd_gem_new_req req; |
| }; |
| |
| struct amdvgpu_bo { |
| struct amdvgpu_device *dev; |
| |
| /* Importing the same kms handle must return the same |
| * amdvgpu_pointer, so we need a refcount. |
| */ |
| int refcount; |
| |
| /* The size of the BO (might be smaller that the host |
| * bo' size). |
| */ |
| unsigned size; |
| |
| /* The host blob backing this bo. */ |
| struct amdvgpu_host_blob *host_blob; |
| }; |
| |
| |
| uint32_t amdvgpu_get_resource_id(amdvgpu_bo_handle bo); |
| |
| /* There are 2 return-code: |
| * - the virtio one, returned by vdrm_send_req |
| * - the host one, which only makes sense for sync |
| * requests. |
| */ |
| static inline |
| int vdrm_send_req_wrapper(amdvgpu_device_handle dev, |
| struct vdrm_ccmd_req *req, |
| struct amdgpu_ccmd_rsp *rsp, |
| bool sync) { |
| if (dev->sync_cmd & (1u << req->cmd)) |
| sync = true; |
| |
| int r = vdrm_send_req(dev->vdev, req, sync); |
| |
| if (r) |
| return r; |
| |
| if (sync) |
| return rsp->ret; |
| |
| return 0; |
| } |
| #endif /* AMDGPU_VIRTIO_PRIVATE_H */ |