1 /*
2 * Copyright 2024 Advanced Micro Devices, Inc.
3 *
4 * SPDX-License-Identifier: MIT
5 */
6 #ifndef AMDGPU_VIRTIO_PRIVATE_H
7 #define AMDGPU_VIRTIO_PRIVATE_H
8
9 #include "drm-uapi/amdgpu_drm.h"
10 #include "drm-uapi/virtgpu_drm.h"
11
12 #include "util/hash_table.h"
13 #include "util/simple_mtx.h"
14
15 #include "amd_family.h"
16
17 #include "virtio/vdrm/vdrm.h"
18 #include "virtio/virtio-gpu/drm_hw.h"
19 #include "amdgpu_virtio_proto.h"
20 #include "amdgpu_virtio.h"
21
22 struct amdvgpu_host_blob;
23 struct amdvgpu_host_blob_allocator;
24
25 /* Host context seqno handling.
26 * seqno are monotonically increasing integer, so we don't need
27 * to actually submit to know the value. This allows to not
28 * wait for the submission to go to the host (= no need to wait
29 * in the guest) and to know the seqno (= so we can take advantage
30 * of user fence).
31 */
32 struct amdvgpu_context {
33 uint32_t refcount;
34 uint32_t host_context_id;
35 uint64_t ring_next_seqno[];
36 };
37
38 struct amdvgpu_device {
39 struct vdrm_device * vdev;
40
41 /* List of existing devices */
42 int refcount;
43 struct amdvgpu_device *next;
44
45 int fd;
46
47 /* Table mapping kms handles to amdvgpu_bo instances.
48 * Used to maintain a 1-to-1 mapping between the 2.
49 */
50 simple_mtx_t handle_to_vbo_mutex;
51 struct hash_table *handle_to_vbo;
52
53 /* Submission through virtio-gpu are ring based.
54 * Ring 0 is used for CPU jobs, then N rings are allocated: 1
55 * per IP type per instance (so if the GPU has 1 gfx queue and 2
56 * queues -> ring0 + 3 hw rings = 4 rings total).
57 */
58 uint32_t num_virtio_rings;
59 uint32_t virtio_ring_mapping[AMD_NUM_IP_TYPES];
60
61 struct drm_amdgpu_info_device dev_info;
62
63 /* Blob id are per drm_file identifiers of host blobs.
64 * Use a monotically increased integer to assign the blob id.
65 */
66 uint32_t next_blob_id;
67
68 /* GPU VA management (allocation / release). */
69 amdgpu_va_manager_handle va_mgr;
70
71 /* Debug option to make some protocol commands synchronous.
72 * If bit N is set, then the specific command will be sync.
73 */
74 int64_t sync_cmd;
75
76 /* virtio-gpu uses a single context per drm_file and expects that
77 * any 2 jobs submitted to the same {context, ring} will execute in
78 * order.
79 * amdgpu on the other hand allows for multiple context per drm_file,
80 * so we either have to open multiple virtio-gpu drm_file to be able to
81 * have 1 virtio-gpu context per amdgpu-context or use a single amdgpu
82 * context.
83 * Using multiple drm_file might cause BO sharing issues so for now limit
84 * ourselves to a single amdgpu context. Each amdgpu_ctx object can schedule
85 * parallel work on 1 gfx, 2 sdma, 4 compute, 1 of each vcn queue.
86 */
87 simple_mtx_t contexts_mutex;
88 struct hash_table contexts;
89 bool allow_multiple_amdgpu_ctx;
90 };
91
92 /* Refcounting helpers. Returns true when dst reaches 0. */
update_references(int * dst,int * src)93 static inline bool update_references(int *dst, int *src)
94 {
95 if (dst != src) {
96 /* bump src first */
97 if (src) {
98 assert(p_atomic_read(src) > 0);
99 p_atomic_inc(src);
100 }
101 if (dst) {
102 return p_atomic_dec_zero(dst);
103 }
104 }
105 return false;
106 }
107
108 #define virtio_ioctl(fd, name, args) ({ \
109 int ret = drmIoctl((fd), DRM_IOCTL_ ## name, (args)); \
110 ret; \
111 })
112
113 struct amdvgpu_host_blob_creation_params {
114 struct drm_virtgpu_resource_create_blob args;
115 struct amdgpu_ccmd_gem_new_req req;
116 };
117
118 struct amdvgpu_bo {
119 struct amdvgpu_device *dev;
120
121 /* Importing the same kms handle must return the same
122 * amdvgpu_pointer, so we need a refcount.
123 */
124 int refcount;
125
126 /* The size of the BO (might be smaller that the host
127 * bo' size).
128 */
129 unsigned size;
130
131 /* The host blob backing this bo. */
132 struct amdvgpu_host_blob *host_blob;
133 };
134
135
136 uint32_t amdvgpu_get_resource_id(amdvgpu_bo_handle bo);
137
138 /* There are 2 return-code:
139 * - the virtio one, returned by vdrm_send_req
140 * - the host one, which only makes sense for sync
141 * requests.
142 */
143 static inline
vdrm_send_req_wrapper(amdvgpu_device_handle dev,struct vdrm_ccmd_req * req,struct amdgpu_ccmd_rsp * rsp,bool sync)144 int vdrm_send_req_wrapper(amdvgpu_device_handle dev,
145 struct vdrm_ccmd_req *req,
146 struct amdgpu_ccmd_rsp *rsp,
147 bool sync) {
148 if (dev->sync_cmd & (1u << req->cmd))
149 sync = true;
150
151 int r = vdrm_send_req(dev->vdev, req, sync);
152
153 if (r)
154 return r;
155
156 if (sync)
157 return rsp->ret;
158
159 return 0;
160 }
161 #endif /* AMDGPU_VIRTIO_PRIVATE_H */
162