1*bbecb9d1SAndroid Build Coastguard Worker /*
2*bbecb9d1SAndroid Build Coastguard Worker * Copyright 2022 Google LLC
3*bbecb9d1SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
4*bbecb9d1SAndroid Build Coastguard Worker */
5*bbecb9d1SAndroid Build Coastguard Worker
6*bbecb9d1SAndroid Build Coastguard Worker #include <errno.h>
7*bbecb9d1SAndroid Build Coastguard Worker #include <fcntl.h>
8*bbecb9d1SAndroid Build Coastguard Worker #include <stdlib.h>
9*bbecb9d1SAndroid Build Coastguard Worker #include <string.h>
10*bbecb9d1SAndroid Build Coastguard Worker #include <unistd.h>
11*bbecb9d1SAndroid Build Coastguard Worker #include <sys/mman.h>
12*bbecb9d1SAndroid Build Coastguard Worker #include <sys/types.h>
13*bbecb9d1SAndroid Build Coastguard Worker
14*bbecb9d1SAndroid Build Coastguard Worker #include <xf86drm.h>
15*bbecb9d1SAndroid Build Coastguard Worker
16*bbecb9d1SAndroid Build Coastguard Worker #include "virgl_context.h"
17*bbecb9d1SAndroid Build Coastguard Worker #include "virgl_util.h"
18*bbecb9d1SAndroid Build Coastguard Worker #include "virglrenderer.h"
19*bbecb9d1SAndroid Build Coastguard Worker
20*bbecb9d1SAndroid Build Coastguard Worker #include "util/anon_file.h"
21*bbecb9d1SAndroid Build Coastguard Worker #include "util/hash_table.h"
22*bbecb9d1SAndroid Build Coastguard Worker #include "util/macros.h"
23*bbecb9d1SAndroid Build Coastguard Worker #include "util/os_file.h"
24*bbecb9d1SAndroid Build Coastguard Worker #include "util/u_atomic.h"
25*bbecb9d1SAndroid Build Coastguard Worker #include "util/u_thread.h"
26*bbecb9d1SAndroid Build Coastguard Worker
27*bbecb9d1SAndroid Build Coastguard Worker #include "drm_fence.h"
28*bbecb9d1SAndroid Build Coastguard Worker
29*bbecb9d1SAndroid Build Coastguard Worker #include "msm_drm.h"
30*bbecb9d1SAndroid Build Coastguard Worker #include "msm_proto.h"
31*bbecb9d1SAndroid Build Coastguard Worker #include "msm_renderer.h"
32*bbecb9d1SAndroid Build Coastguard Worker
33*bbecb9d1SAndroid Build Coastguard Worker static unsigned nr_timelines;
34*bbecb9d1SAndroid Build Coastguard Worker
35*bbecb9d1SAndroid Build Coastguard Worker /**
36*bbecb9d1SAndroid Build Coastguard Worker * A single context (from the PoV of the virtio-gpu protocol) maps to
37*bbecb9d1SAndroid Build Coastguard Worker * a single drm device open. Other drm/msm constructs (ie. submitqueue)
38*bbecb9d1SAndroid Build Coastguard Worker * are opaque to the protocol.
39*bbecb9d1SAndroid Build Coastguard Worker *
40*bbecb9d1SAndroid Build Coastguard Worker * Typically each guest process will open a single virtio-gpu "context".
41*bbecb9d1SAndroid Build Coastguard Worker * The single drm device open maps to an individual msm_gem_address_space
42*bbecb9d1SAndroid Build Coastguard Worker * on the kernel side, providing GPU address space isolation between
43*bbecb9d1SAndroid Build Coastguard Worker * guest processes.
44*bbecb9d1SAndroid Build Coastguard Worker *
45*bbecb9d1SAndroid Build Coastguard Worker * GEM buffer objects are tracked via one of two id's:
46*bbecb9d1SAndroid Build Coastguard Worker * - resource-id: global, assigned by guest kernel
47*bbecb9d1SAndroid Build Coastguard Worker * - blob-id: context specific, assigned by guest userspace
48*bbecb9d1SAndroid Build Coastguard Worker *
49*bbecb9d1SAndroid Build Coastguard Worker * The blob-id is used to link the bo created via MSM_CCMD_GEM_NEW and
50*bbecb9d1SAndroid Build Coastguard Worker * the get_blob() cb. It is unused in the case of a bo that is imported
51*bbecb9d1SAndroid Build Coastguard Worker * from another context. An object is added to the blob table in GEM_NEW
52*bbecb9d1SAndroid Build Coastguard Worker * and removed in ctx->get_blob() (where it is added to resource_table).
53*bbecb9d1SAndroid Build Coastguard Worker * By avoiding having an obj in both tables, we can safely free remaining
54*bbecb9d1SAndroid Build Coastguard Worker * entries in either hashtable at context teardown.
55*bbecb9d1SAndroid Build Coastguard Worker */
56*bbecb9d1SAndroid Build Coastguard Worker struct msm_context {
57*bbecb9d1SAndroid Build Coastguard Worker struct virgl_context base;
58*bbecb9d1SAndroid Build Coastguard Worker
59*bbecb9d1SAndroid Build Coastguard Worker struct msm_shmem *shmem;
60*bbecb9d1SAndroid Build Coastguard Worker uint8_t *rsp_mem;
61*bbecb9d1SAndroid Build Coastguard Worker uint32_t rsp_mem_sz;
62*bbecb9d1SAndroid Build Coastguard Worker
63*bbecb9d1SAndroid Build Coastguard Worker struct msm_ccmd_rsp *current_rsp;
64*bbecb9d1SAndroid Build Coastguard Worker
65*bbecb9d1SAndroid Build Coastguard Worker int fd;
66*bbecb9d1SAndroid Build Coastguard Worker
67*bbecb9d1SAndroid Build Coastguard Worker struct hash_table *blob_table;
68*bbecb9d1SAndroid Build Coastguard Worker struct hash_table *resource_table;
69*bbecb9d1SAndroid Build Coastguard Worker
70*bbecb9d1SAndroid Build Coastguard Worker /**
71*bbecb9d1SAndroid Build Coastguard Worker * Maps submit-queue id to ring_idx
72*bbecb9d1SAndroid Build Coastguard Worker */
73*bbecb9d1SAndroid Build Coastguard Worker struct hash_table *sq_to_ring_idx_table;
74*bbecb9d1SAndroid Build Coastguard Worker
75*bbecb9d1SAndroid Build Coastguard Worker int eventfd;
76*bbecb9d1SAndroid Build Coastguard Worker
77*bbecb9d1SAndroid Build Coastguard Worker /**
78*bbecb9d1SAndroid Build Coastguard Worker * Indexed by ring_idx-1, which is the same as the submitqueue priority+1.
79*bbecb9d1SAndroid Build Coastguard Worker * On the kernel side, there is some drm_sched_entity per {drm_file, prio}
80*bbecb9d1SAndroid Build Coastguard Worker * tuple, and the sched entity determines the fence timeline, ie. submits
81*bbecb9d1SAndroid Build Coastguard Worker * against a single sched entity complete in fifo order.
82*bbecb9d1SAndroid Build Coastguard Worker */
83*bbecb9d1SAndroid Build Coastguard Worker struct drm_timeline timelines[];
84*bbecb9d1SAndroid Build Coastguard Worker };
DEFINE_CAST(virgl_context,msm_context)85*bbecb9d1SAndroid Build Coastguard Worker DEFINE_CAST(virgl_context, msm_context)
86*bbecb9d1SAndroid Build Coastguard Worker
87*bbecb9d1SAndroid Build Coastguard Worker #define valid_payload_len(req) ((req)->len <= ((req)->hdr.len - sizeof(*(req))))
88*bbecb9d1SAndroid Build Coastguard Worker
89*bbecb9d1SAndroid Build Coastguard Worker static struct hash_entry *
90*bbecb9d1SAndroid Build Coastguard Worker table_search(struct hash_table *ht, uint32_t key)
91*bbecb9d1SAndroid Build Coastguard Worker {
92*bbecb9d1SAndroid Build Coastguard Worker /* zero is not a valid key for u32_keys hashtable: */
93*bbecb9d1SAndroid Build Coastguard Worker if (!key)
94*bbecb9d1SAndroid Build Coastguard Worker return NULL;
95*bbecb9d1SAndroid Build Coastguard Worker return _mesa_hash_table_search(ht, (void *)(uintptr_t)key);
96*bbecb9d1SAndroid Build Coastguard Worker }
97*bbecb9d1SAndroid Build Coastguard Worker
98*bbecb9d1SAndroid Build Coastguard Worker static int
gem_info(struct msm_context * mctx,uint32_t handle,uint32_t param,uint64_t * val)99*bbecb9d1SAndroid Build Coastguard Worker gem_info(struct msm_context *mctx, uint32_t handle, uint32_t param, uint64_t *val)
100*bbecb9d1SAndroid Build Coastguard Worker {
101*bbecb9d1SAndroid Build Coastguard Worker struct drm_msm_gem_info args = {
102*bbecb9d1SAndroid Build Coastguard Worker .handle = handle,
103*bbecb9d1SAndroid Build Coastguard Worker .info = param,
104*bbecb9d1SAndroid Build Coastguard Worker .value = *val,
105*bbecb9d1SAndroid Build Coastguard Worker };
106*bbecb9d1SAndroid Build Coastguard Worker int ret;
107*bbecb9d1SAndroid Build Coastguard Worker
108*bbecb9d1SAndroid Build Coastguard Worker ret = drmCommandWriteRead(mctx->fd, DRM_MSM_GEM_INFO, &args, sizeof(args));
109*bbecb9d1SAndroid Build Coastguard Worker if (ret)
110*bbecb9d1SAndroid Build Coastguard Worker return ret;
111*bbecb9d1SAndroid Build Coastguard Worker
112*bbecb9d1SAndroid Build Coastguard Worker *val = args.value;
113*bbecb9d1SAndroid Build Coastguard Worker return 0;
114*bbecb9d1SAndroid Build Coastguard Worker }
115*bbecb9d1SAndroid Build Coastguard Worker
116*bbecb9d1SAndroid Build Coastguard Worker static int
gem_close(int fd,uint32_t handle)117*bbecb9d1SAndroid Build Coastguard Worker gem_close(int fd, uint32_t handle)
118*bbecb9d1SAndroid Build Coastguard Worker {
119*bbecb9d1SAndroid Build Coastguard Worker struct drm_gem_close close_req = {
120*bbecb9d1SAndroid Build Coastguard Worker .handle = handle,
121*bbecb9d1SAndroid Build Coastguard Worker };
122*bbecb9d1SAndroid Build Coastguard Worker return drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close_req);
123*bbecb9d1SAndroid Build Coastguard Worker }
124*bbecb9d1SAndroid Build Coastguard Worker
125*bbecb9d1SAndroid Build Coastguard Worker struct msm_object {
126*bbecb9d1SAndroid Build Coastguard Worker uint32_t blob_id;
127*bbecb9d1SAndroid Build Coastguard Worker uint32_t res_id;
128*bbecb9d1SAndroid Build Coastguard Worker uint32_t handle;
129*bbecb9d1SAndroid Build Coastguard Worker uint32_t flags;
130*bbecb9d1SAndroid Build Coastguard Worker uint32_t size;
131*bbecb9d1SAndroid Build Coastguard Worker bool exported : 1;
132*bbecb9d1SAndroid Build Coastguard Worker bool exportable : 1;
133*bbecb9d1SAndroid Build Coastguard Worker struct virgl_resource *res;
134*bbecb9d1SAndroid Build Coastguard Worker void *map;
135*bbecb9d1SAndroid Build Coastguard Worker };
136*bbecb9d1SAndroid Build Coastguard Worker
137*bbecb9d1SAndroid Build Coastguard Worker static struct msm_object *
msm_object_create(uint32_t handle,uint32_t flags,uint32_t size)138*bbecb9d1SAndroid Build Coastguard Worker msm_object_create(uint32_t handle, uint32_t flags, uint32_t size)
139*bbecb9d1SAndroid Build Coastguard Worker {
140*bbecb9d1SAndroid Build Coastguard Worker struct msm_object *obj = calloc(1, sizeof(*obj));
141*bbecb9d1SAndroid Build Coastguard Worker
142*bbecb9d1SAndroid Build Coastguard Worker if (!obj)
143*bbecb9d1SAndroid Build Coastguard Worker return NULL;
144*bbecb9d1SAndroid Build Coastguard Worker
145*bbecb9d1SAndroid Build Coastguard Worker obj->handle = handle;
146*bbecb9d1SAndroid Build Coastguard Worker obj->flags = flags;
147*bbecb9d1SAndroid Build Coastguard Worker obj->size = size;
148*bbecb9d1SAndroid Build Coastguard Worker
149*bbecb9d1SAndroid Build Coastguard Worker return obj;
150*bbecb9d1SAndroid Build Coastguard Worker }
151*bbecb9d1SAndroid Build Coastguard Worker
152*bbecb9d1SAndroid Build Coastguard Worker static bool
valid_blob_id(struct msm_context * mctx,uint32_t blob_id)153*bbecb9d1SAndroid Build Coastguard Worker valid_blob_id(struct msm_context *mctx, uint32_t blob_id)
154*bbecb9d1SAndroid Build Coastguard Worker {
155*bbecb9d1SAndroid Build Coastguard Worker /* must be non-zero: */
156*bbecb9d1SAndroid Build Coastguard Worker if (blob_id == 0)
157*bbecb9d1SAndroid Build Coastguard Worker return false;
158*bbecb9d1SAndroid Build Coastguard Worker
159*bbecb9d1SAndroid Build Coastguard Worker /* must not already be in-use: */
160*bbecb9d1SAndroid Build Coastguard Worker if (table_search(mctx->blob_table, blob_id))
161*bbecb9d1SAndroid Build Coastguard Worker return false;
162*bbecb9d1SAndroid Build Coastguard Worker
163*bbecb9d1SAndroid Build Coastguard Worker return true;
164*bbecb9d1SAndroid Build Coastguard Worker }
165*bbecb9d1SAndroid Build Coastguard Worker
166*bbecb9d1SAndroid Build Coastguard Worker static void
msm_object_set_blob_id(struct msm_context * mctx,struct msm_object * obj,uint32_t blob_id)167*bbecb9d1SAndroid Build Coastguard Worker msm_object_set_blob_id(struct msm_context *mctx, struct msm_object *obj, uint32_t blob_id)
168*bbecb9d1SAndroid Build Coastguard Worker {
169*bbecb9d1SAndroid Build Coastguard Worker assert(valid_blob_id(mctx, blob_id));
170*bbecb9d1SAndroid Build Coastguard Worker
171*bbecb9d1SAndroid Build Coastguard Worker obj->blob_id = blob_id;
172*bbecb9d1SAndroid Build Coastguard Worker _mesa_hash_table_insert(mctx->blob_table, (void *)(uintptr_t)obj->blob_id, obj);
173*bbecb9d1SAndroid Build Coastguard Worker }
174*bbecb9d1SAndroid Build Coastguard Worker
175*bbecb9d1SAndroid Build Coastguard Worker static bool
valid_res_id(struct msm_context * mctx,uint32_t res_id)176*bbecb9d1SAndroid Build Coastguard Worker valid_res_id(struct msm_context *mctx, uint32_t res_id)
177*bbecb9d1SAndroid Build Coastguard Worker {
178*bbecb9d1SAndroid Build Coastguard Worker return !table_search(mctx->resource_table, res_id);
179*bbecb9d1SAndroid Build Coastguard Worker }
180*bbecb9d1SAndroid Build Coastguard Worker
181*bbecb9d1SAndroid Build Coastguard Worker static void
msm_object_set_res_id(struct msm_context * mctx,struct msm_object * obj,uint32_t res_id)182*bbecb9d1SAndroid Build Coastguard Worker msm_object_set_res_id(struct msm_context *mctx, struct msm_object *obj, uint32_t res_id)
183*bbecb9d1SAndroid Build Coastguard Worker {
184*bbecb9d1SAndroid Build Coastguard Worker assert(valid_res_id(mctx, res_id));
185*bbecb9d1SAndroid Build Coastguard Worker
186*bbecb9d1SAndroid Build Coastguard Worker obj->res_id = res_id;
187*bbecb9d1SAndroid Build Coastguard Worker _mesa_hash_table_insert(mctx->resource_table, (void *)(uintptr_t)obj->res_id, obj);
188*bbecb9d1SAndroid Build Coastguard Worker }
189*bbecb9d1SAndroid Build Coastguard Worker
190*bbecb9d1SAndroid Build Coastguard Worker static void
msm_remove_object(struct msm_context * mctx,struct msm_object * obj)191*bbecb9d1SAndroid Build Coastguard Worker msm_remove_object(struct msm_context *mctx, struct msm_object *obj)
192*bbecb9d1SAndroid Build Coastguard Worker {
193*bbecb9d1SAndroid Build Coastguard Worker drm_dbg("obj=%p, blob_id=%u, res_id=%u", obj, obj->blob_id, obj->res_id);
194*bbecb9d1SAndroid Build Coastguard Worker _mesa_hash_table_remove_key(mctx->resource_table, (void *)(uintptr_t)obj->res_id);
195*bbecb9d1SAndroid Build Coastguard Worker }
196*bbecb9d1SAndroid Build Coastguard Worker
197*bbecb9d1SAndroid Build Coastguard Worker static struct msm_object *
msm_retrieve_object_from_blob_id(struct msm_context * mctx,uint64_t blob_id)198*bbecb9d1SAndroid Build Coastguard Worker msm_retrieve_object_from_blob_id(struct msm_context *mctx, uint64_t blob_id)
199*bbecb9d1SAndroid Build Coastguard Worker {
200*bbecb9d1SAndroid Build Coastguard Worker assert((blob_id >> 32) == 0);
201*bbecb9d1SAndroid Build Coastguard Worker uint32_t id = blob_id;
202*bbecb9d1SAndroid Build Coastguard Worker struct hash_entry *entry = table_search(mctx->blob_table, id);
203*bbecb9d1SAndroid Build Coastguard Worker if (!entry)
204*bbecb9d1SAndroid Build Coastguard Worker return NULL;
205*bbecb9d1SAndroid Build Coastguard Worker struct msm_object *obj = entry->data;
206*bbecb9d1SAndroid Build Coastguard Worker _mesa_hash_table_remove(mctx->blob_table, entry);
207*bbecb9d1SAndroid Build Coastguard Worker return obj;
208*bbecb9d1SAndroid Build Coastguard Worker }
209*bbecb9d1SAndroid Build Coastguard Worker
210*bbecb9d1SAndroid Build Coastguard Worker static struct msm_object *
msm_get_object_from_res_id(struct msm_context * mctx,uint32_t res_id)211*bbecb9d1SAndroid Build Coastguard Worker msm_get_object_from_res_id(struct msm_context *mctx, uint32_t res_id)
212*bbecb9d1SAndroid Build Coastguard Worker {
213*bbecb9d1SAndroid Build Coastguard Worker const struct hash_entry *entry = table_search(mctx->resource_table, res_id);
214*bbecb9d1SAndroid Build Coastguard Worker return likely(entry) ? entry->data : NULL;
215*bbecb9d1SAndroid Build Coastguard Worker }
216*bbecb9d1SAndroid Build Coastguard Worker
217*bbecb9d1SAndroid Build Coastguard Worker static uint32_t
handle_from_res_id(struct msm_context * mctx,uint32_t res_id)218*bbecb9d1SAndroid Build Coastguard Worker handle_from_res_id(struct msm_context *mctx, uint32_t res_id)
219*bbecb9d1SAndroid Build Coastguard Worker {
220*bbecb9d1SAndroid Build Coastguard Worker struct msm_object *obj = msm_get_object_from_res_id(mctx, res_id);
221*bbecb9d1SAndroid Build Coastguard Worker if (!obj)
222*bbecb9d1SAndroid Build Coastguard Worker return 0; /* zero is an invalid GEM handle */
223*bbecb9d1SAndroid Build Coastguard Worker return obj->handle;
224*bbecb9d1SAndroid Build Coastguard Worker }
225*bbecb9d1SAndroid Build Coastguard Worker
226*bbecb9d1SAndroid Build Coastguard Worker static bool
has_cached_coherent(int fd)227*bbecb9d1SAndroid Build Coastguard Worker has_cached_coherent(int fd)
228*bbecb9d1SAndroid Build Coastguard Worker {
229*bbecb9d1SAndroid Build Coastguard Worker struct drm_msm_gem_new new_req = {
230*bbecb9d1SAndroid Build Coastguard Worker .size = 0x1000,
231*bbecb9d1SAndroid Build Coastguard Worker .flags = MSM_BO_CACHED_COHERENT,
232*bbecb9d1SAndroid Build Coastguard Worker };
233*bbecb9d1SAndroid Build Coastguard Worker
234*bbecb9d1SAndroid Build Coastguard Worker /* Do a test allocation to see if cached-coherent is supported: */
235*bbecb9d1SAndroid Build Coastguard Worker if (!drmCommandWriteRead(fd, DRM_MSM_GEM_NEW, &new_req, sizeof(new_req))) {
236*bbecb9d1SAndroid Build Coastguard Worker gem_close(fd, new_req.handle);
237*bbecb9d1SAndroid Build Coastguard Worker return true;
238*bbecb9d1SAndroid Build Coastguard Worker }
239*bbecb9d1SAndroid Build Coastguard Worker
240*bbecb9d1SAndroid Build Coastguard Worker return false;
241*bbecb9d1SAndroid Build Coastguard Worker }
242*bbecb9d1SAndroid Build Coastguard Worker
243*bbecb9d1SAndroid Build Coastguard Worker static int
get_param64(int fd,uint32_t param,uint64_t * value)244*bbecb9d1SAndroid Build Coastguard Worker get_param64(int fd, uint32_t param, uint64_t *value)
245*bbecb9d1SAndroid Build Coastguard Worker {
246*bbecb9d1SAndroid Build Coastguard Worker struct drm_msm_param req = {
247*bbecb9d1SAndroid Build Coastguard Worker .pipe = MSM_PIPE_3D0,
248*bbecb9d1SAndroid Build Coastguard Worker .param = param,
249*bbecb9d1SAndroid Build Coastguard Worker };
250*bbecb9d1SAndroid Build Coastguard Worker int ret;
251*bbecb9d1SAndroid Build Coastguard Worker
252*bbecb9d1SAndroid Build Coastguard Worker *value = 0;
253*bbecb9d1SAndroid Build Coastguard Worker
254*bbecb9d1SAndroid Build Coastguard Worker ret = drmCommandWriteRead(fd, DRM_MSM_GET_PARAM, &req, sizeof(req));
255*bbecb9d1SAndroid Build Coastguard Worker if (ret)
256*bbecb9d1SAndroid Build Coastguard Worker return ret;
257*bbecb9d1SAndroid Build Coastguard Worker
258*bbecb9d1SAndroid Build Coastguard Worker *value = req.value;
259*bbecb9d1SAndroid Build Coastguard Worker
260*bbecb9d1SAndroid Build Coastguard Worker return 0;
261*bbecb9d1SAndroid Build Coastguard Worker }
262*bbecb9d1SAndroid Build Coastguard Worker
263*bbecb9d1SAndroid Build Coastguard Worker static int
get_param32(int fd,uint32_t param,uint32_t * value)264*bbecb9d1SAndroid Build Coastguard Worker get_param32(int fd, uint32_t param, uint32_t *value)
265*bbecb9d1SAndroid Build Coastguard Worker {
266*bbecb9d1SAndroid Build Coastguard Worker uint64_t v64;
267*bbecb9d1SAndroid Build Coastguard Worker int ret = get_param64(fd, param, &v64);
268*bbecb9d1SAndroid Build Coastguard Worker *value = v64;
269*bbecb9d1SAndroid Build Coastguard Worker return ret;
270*bbecb9d1SAndroid Build Coastguard Worker }
271*bbecb9d1SAndroid Build Coastguard Worker
272*bbecb9d1SAndroid Build Coastguard Worker /**
273*bbecb9d1SAndroid Build Coastguard Worker * Probe capset params.
274*bbecb9d1SAndroid Build Coastguard Worker */
275*bbecb9d1SAndroid Build Coastguard Worker int
msm_renderer_probe(int fd,struct virgl_renderer_capset_drm * capset)276*bbecb9d1SAndroid Build Coastguard Worker msm_renderer_probe(int fd, struct virgl_renderer_capset_drm *capset)
277*bbecb9d1SAndroid Build Coastguard Worker {
278*bbecb9d1SAndroid Build Coastguard Worker drm_log("");
279*bbecb9d1SAndroid Build Coastguard Worker
280*bbecb9d1SAndroid Build Coastguard Worker /* Require MSM_SUBMIT_FENCE_SN_IN: */
281*bbecb9d1SAndroid Build Coastguard Worker if (capset->version_minor < 9) {
282*bbecb9d1SAndroid Build Coastguard Worker drm_log("Host kernel too old");
283*bbecb9d1SAndroid Build Coastguard Worker return -ENOTSUP;
284*bbecb9d1SAndroid Build Coastguard Worker }
285*bbecb9d1SAndroid Build Coastguard Worker
286*bbecb9d1SAndroid Build Coastguard Worker capset->wire_format_version = 2;
287*bbecb9d1SAndroid Build Coastguard Worker capset->u.msm.has_cached_coherent = has_cached_coherent(fd);
288*bbecb9d1SAndroid Build Coastguard Worker
289*bbecb9d1SAndroid Build Coastguard Worker get_param32(fd, MSM_PARAM_PRIORITIES, &capset->u.msm.priorities);
290*bbecb9d1SAndroid Build Coastguard Worker get_param64(fd, MSM_PARAM_VA_START, &capset->u.msm.va_start);
291*bbecb9d1SAndroid Build Coastguard Worker get_param64(fd, MSM_PARAM_VA_SIZE, &capset->u.msm.va_size);
292*bbecb9d1SAndroid Build Coastguard Worker get_param32(fd, MSM_PARAM_GPU_ID, &capset->u.msm.gpu_id);
293*bbecb9d1SAndroid Build Coastguard Worker get_param32(fd, MSM_PARAM_GMEM_SIZE, &capset->u.msm.gmem_size);
294*bbecb9d1SAndroid Build Coastguard Worker get_param64(fd, MSM_PARAM_GMEM_BASE, &capset->u.msm.gmem_base);
295*bbecb9d1SAndroid Build Coastguard Worker get_param64(fd, MSM_PARAM_CHIP_ID, &capset->u.msm.chip_id);
296*bbecb9d1SAndroid Build Coastguard Worker get_param32(fd, MSM_PARAM_MAX_FREQ, &capset->u.msm.max_freq);
297*bbecb9d1SAndroid Build Coastguard Worker
298*bbecb9d1SAndroid Build Coastguard Worker nr_timelines = capset->u.msm.priorities;
299*bbecb9d1SAndroid Build Coastguard Worker
300*bbecb9d1SAndroid Build Coastguard Worker drm_log("wire_format_version: %u", capset->wire_format_version);
301*bbecb9d1SAndroid Build Coastguard Worker drm_log("version_major: %u", capset->version_major);
302*bbecb9d1SAndroid Build Coastguard Worker drm_log("version_minor: %u", capset->version_minor);
303*bbecb9d1SAndroid Build Coastguard Worker drm_log("version_patchlevel: %u", capset->version_patchlevel);
304*bbecb9d1SAndroid Build Coastguard Worker drm_log("has_cached_coherent: %u", capset->u.msm.has_cached_coherent);
305*bbecb9d1SAndroid Build Coastguard Worker drm_log("priorities: %u", capset->u.msm.priorities);
306*bbecb9d1SAndroid Build Coastguard Worker drm_log("va_start: 0x%0" PRIx64, capset->u.msm.va_start);
307*bbecb9d1SAndroid Build Coastguard Worker drm_log("va_size: 0x%0" PRIx64, capset->u.msm.va_size);
308*bbecb9d1SAndroid Build Coastguard Worker drm_log("gpu_id: %u", capset->u.msm.gpu_id);
309*bbecb9d1SAndroid Build Coastguard Worker drm_log("gmem_size: %u", capset->u.msm.gmem_size);
310*bbecb9d1SAndroid Build Coastguard Worker drm_log("gmem_base: 0x%0" PRIx64, capset->u.msm.gmem_base);
311*bbecb9d1SAndroid Build Coastguard Worker drm_log("chip_id: 0x%0" PRIx64, capset->u.msm.chip_id);
312*bbecb9d1SAndroid Build Coastguard Worker drm_log("max_freq: %u", capset->u.msm.max_freq);
313*bbecb9d1SAndroid Build Coastguard Worker
314*bbecb9d1SAndroid Build Coastguard Worker if (!capset->u.msm.va_size) {
315*bbecb9d1SAndroid Build Coastguard Worker drm_log("Host kernel does not support userspace allocated IOVA");
316*bbecb9d1SAndroid Build Coastguard Worker return -ENOTSUP;
317*bbecb9d1SAndroid Build Coastguard Worker }
318*bbecb9d1SAndroid Build Coastguard Worker
319*bbecb9d1SAndroid Build Coastguard Worker return 0;
320*bbecb9d1SAndroid Build Coastguard Worker }
321*bbecb9d1SAndroid Build Coastguard Worker
322*bbecb9d1SAndroid Build Coastguard Worker static void
resource_delete_fxn(struct hash_entry * entry)323*bbecb9d1SAndroid Build Coastguard Worker resource_delete_fxn(struct hash_entry *entry)
324*bbecb9d1SAndroid Build Coastguard Worker {
325*bbecb9d1SAndroid Build Coastguard Worker free((void *)entry->data);
326*bbecb9d1SAndroid Build Coastguard Worker }
327*bbecb9d1SAndroid Build Coastguard Worker
328*bbecb9d1SAndroid Build Coastguard Worker static void
msm_renderer_destroy(struct virgl_context * vctx)329*bbecb9d1SAndroid Build Coastguard Worker msm_renderer_destroy(struct virgl_context *vctx)
330*bbecb9d1SAndroid Build Coastguard Worker {
331*bbecb9d1SAndroid Build Coastguard Worker struct msm_context *mctx = to_msm_context(vctx);
332*bbecb9d1SAndroid Build Coastguard Worker
333*bbecb9d1SAndroid Build Coastguard Worker for (unsigned i = 0; i < nr_timelines; i++)
334*bbecb9d1SAndroid Build Coastguard Worker drm_timeline_fini(&mctx->timelines[i]);
335*bbecb9d1SAndroid Build Coastguard Worker
336*bbecb9d1SAndroid Build Coastguard Worker close(mctx->eventfd);
337*bbecb9d1SAndroid Build Coastguard Worker
338*bbecb9d1SAndroid Build Coastguard Worker if (mctx->shmem)
339*bbecb9d1SAndroid Build Coastguard Worker munmap(mctx->shmem, sizeof(*mctx->shmem));
340*bbecb9d1SAndroid Build Coastguard Worker
341*bbecb9d1SAndroid Build Coastguard Worker _mesa_hash_table_destroy(mctx->resource_table, resource_delete_fxn);
342*bbecb9d1SAndroid Build Coastguard Worker _mesa_hash_table_destroy(mctx->blob_table, resource_delete_fxn);
343*bbecb9d1SAndroid Build Coastguard Worker _mesa_hash_table_destroy(mctx->sq_to_ring_idx_table, NULL);
344*bbecb9d1SAndroid Build Coastguard Worker
345*bbecb9d1SAndroid Build Coastguard Worker close(mctx->fd);
346*bbecb9d1SAndroid Build Coastguard Worker free(mctx);
347*bbecb9d1SAndroid Build Coastguard Worker }
348*bbecb9d1SAndroid Build Coastguard Worker
349*bbecb9d1SAndroid Build Coastguard Worker static void
msm_renderer_attach_resource(struct virgl_context * vctx,struct virgl_resource * res)350*bbecb9d1SAndroid Build Coastguard Worker msm_renderer_attach_resource(struct virgl_context *vctx, struct virgl_resource *res)
351*bbecb9d1SAndroid Build Coastguard Worker {
352*bbecb9d1SAndroid Build Coastguard Worker struct msm_context *mctx = to_msm_context(vctx);
353*bbecb9d1SAndroid Build Coastguard Worker struct msm_object *obj = msm_get_object_from_res_id(mctx, res->res_id);
354*bbecb9d1SAndroid Build Coastguard Worker
355*bbecb9d1SAndroid Build Coastguard Worker drm_dbg("obj=%p, res_id=%u", obj, res->res_id);
356*bbecb9d1SAndroid Build Coastguard Worker
357*bbecb9d1SAndroid Build Coastguard Worker if (!obj) {
358*bbecb9d1SAndroid Build Coastguard Worker int fd;
359*bbecb9d1SAndroid Build Coastguard Worker enum virgl_resource_fd_type fd_type = virgl_resource_export_fd(res, &fd);
360*bbecb9d1SAndroid Build Coastguard Worker
361*bbecb9d1SAndroid Build Coastguard Worker /* If importing a dmabuf resource created by another context (or
362*bbecb9d1SAndroid Build Coastguard Worker * externally), then import it to create a gem obj handle in our
363*bbecb9d1SAndroid Build Coastguard Worker * context:
364*bbecb9d1SAndroid Build Coastguard Worker */
365*bbecb9d1SAndroid Build Coastguard Worker if (fd_type == VIRGL_RESOURCE_FD_DMABUF) {
366*bbecb9d1SAndroid Build Coastguard Worker uint32_t handle;
367*bbecb9d1SAndroid Build Coastguard Worker int ret;
368*bbecb9d1SAndroid Build Coastguard Worker
369*bbecb9d1SAndroid Build Coastguard Worker ret = drmPrimeFDToHandle(mctx->fd, fd, &handle);
370*bbecb9d1SAndroid Build Coastguard Worker if (ret) {
371*bbecb9d1SAndroid Build Coastguard Worker drm_log("Could not import: %s", strerror(errno));
372*bbecb9d1SAndroid Build Coastguard Worker close(fd);
373*bbecb9d1SAndroid Build Coastguard Worker return;
374*bbecb9d1SAndroid Build Coastguard Worker }
375*bbecb9d1SAndroid Build Coastguard Worker
376*bbecb9d1SAndroid Build Coastguard Worker /* lseek() to get bo size */
377*bbecb9d1SAndroid Build Coastguard Worker int size = lseek(fd, 0, SEEK_END);
378*bbecb9d1SAndroid Build Coastguard Worker if (size < 0)
379*bbecb9d1SAndroid Build Coastguard Worker drm_log("lseek failed: %d (%s)", size, strerror(errno));
380*bbecb9d1SAndroid Build Coastguard Worker close(fd);
381*bbecb9d1SAndroid Build Coastguard Worker
382*bbecb9d1SAndroid Build Coastguard Worker obj = msm_object_create(handle, 0, size);
383*bbecb9d1SAndroid Build Coastguard Worker if (!obj)
384*bbecb9d1SAndroid Build Coastguard Worker return;
385*bbecb9d1SAndroid Build Coastguard Worker
386*bbecb9d1SAndroid Build Coastguard Worker msm_object_set_res_id(mctx, obj, res->res_id);
387*bbecb9d1SAndroid Build Coastguard Worker
388*bbecb9d1SAndroid Build Coastguard Worker drm_dbg("obj=%p, res_id=%u, handle=%u", obj, obj->res_id, obj->handle);
389*bbecb9d1SAndroid Build Coastguard Worker } else {
390*bbecb9d1SAndroid Build Coastguard Worker if (fd_type != VIRGL_RESOURCE_FD_INVALID)
391*bbecb9d1SAndroid Build Coastguard Worker close(fd);
392*bbecb9d1SAndroid Build Coastguard Worker return;
393*bbecb9d1SAndroid Build Coastguard Worker }
394*bbecb9d1SAndroid Build Coastguard Worker }
395*bbecb9d1SAndroid Build Coastguard Worker
396*bbecb9d1SAndroid Build Coastguard Worker obj->res = res;
397*bbecb9d1SAndroid Build Coastguard Worker }
398*bbecb9d1SAndroid Build Coastguard Worker
399*bbecb9d1SAndroid Build Coastguard Worker static void
msm_renderer_detach_resource(struct virgl_context * vctx,struct virgl_resource * res)400*bbecb9d1SAndroid Build Coastguard Worker msm_renderer_detach_resource(struct virgl_context *vctx, struct virgl_resource *res)
401*bbecb9d1SAndroid Build Coastguard Worker {
402*bbecb9d1SAndroid Build Coastguard Worker struct msm_context *mctx = to_msm_context(vctx);
403*bbecb9d1SAndroid Build Coastguard Worker struct msm_object *obj = msm_get_object_from_res_id(mctx, res->res_id);
404*bbecb9d1SAndroid Build Coastguard Worker
405*bbecb9d1SAndroid Build Coastguard Worker drm_dbg("obj=%p, res_id=%u", obj, res->res_id);
406*bbecb9d1SAndroid Build Coastguard Worker
407*bbecb9d1SAndroid Build Coastguard Worker if (!obj || (obj->res != res))
408*bbecb9d1SAndroid Build Coastguard Worker return;
409*bbecb9d1SAndroid Build Coastguard Worker
410*bbecb9d1SAndroid Build Coastguard Worker if (res->fd_type == VIRGL_RESOURCE_FD_SHM) {
411*bbecb9d1SAndroid Build Coastguard Worker munmap(mctx->shmem, sizeof(*mctx->shmem));
412*bbecb9d1SAndroid Build Coastguard Worker
413*bbecb9d1SAndroid Build Coastguard Worker mctx->shmem = NULL;
414*bbecb9d1SAndroid Build Coastguard Worker mctx->rsp_mem = NULL;
415*bbecb9d1SAndroid Build Coastguard Worker mctx->rsp_mem_sz = 0;
416*bbecb9d1SAndroid Build Coastguard Worker
417*bbecb9d1SAndroid Build Coastguard Worker /* shmem resources don't have an backing host GEM bo:, so bail now: */
418*bbecb9d1SAndroid Build Coastguard Worker return;
419*bbecb9d1SAndroid Build Coastguard Worker }
420*bbecb9d1SAndroid Build Coastguard Worker
421*bbecb9d1SAndroid Build Coastguard Worker msm_remove_object(mctx, obj);
422*bbecb9d1SAndroid Build Coastguard Worker
423*bbecb9d1SAndroid Build Coastguard Worker if (obj->map)
424*bbecb9d1SAndroid Build Coastguard Worker munmap(obj->map, obj->size);
425*bbecb9d1SAndroid Build Coastguard Worker
426*bbecb9d1SAndroid Build Coastguard Worker gem_close(mctx->fd, obj->handle);
427*bbecb9d1SAndroid Build Coastguard Worker
428*bbecb9d1SAndroid Build Coastguard Worker free(obj);
429*bbecb9d1SAndroid Build Coastguard Worker }
430*bbecb9d1SAndroid Build Coastguard Worker
431*bbecb9d1SAndroid Build Coastguard Worker static enum virgl_resource_fd_type
msm_renderer_export_opaque_handle(struct virgl_context * vctx,struct virgl_resource * res,int * out_fd)432*bbecb9d1SAndroid Build Coastguard Worker msm_renderer_export_opaque_handle(struct virgl_context *vctx, struct virgl_resource *res,
433*bbecb9d1SAndroid Build Coastguard Worker int *out_fd)
434*bbecb9d1SAndroid Build Coastguard Worker {
435*bbecb9d1SAndroid Build Coastguard Worker struct msm_context *mctx = to_msm_context(vctx);
436*bbecb9d1SAndroid Build Coastguard Worker struct msm_object *obj = msm_get_object_from_res_id(mctx, res->res_id);
437*bbecb9d1SAndroid Build Coastguard Worker int ret;
438*bbecb9d1SAndroid Build Coastguard Worker
439*bbecb9d1SAndroid Build Coastguard Worker drm_dbg("obj=%p, res_id=%u", obj, res->res_id);
440*bbecb9d1SAndroid Build Coastguard Worker
441*bbecb9d1SAndroid Build Coastguard Worker if (!obj) {
442*bbecb9d1SAndroid Build Coastguard Worker drm_log("invalid res_id %u", res->res_id);
443*bbecb9d1SAndroid Build Coastguard Worker return VIRGL_RESOURCE_FD_INVALID;
444*bbecb9d1SAndroid Build Coastguard Worker }
445*bbecb9d1SAndroid Build Coastguard Worker
446*bbecb9d1SAndroid Build Coastguard Worker if (!obj->exportable) {
447*bbecb9d1SAndroid Build Coastguard Worker /* crosvm seems to like to export things it doesn't actually need an
448*bbecb9d1SAndroid Build Coastguard Worker * fd for.. don't let it spam our fd table!
449*bbecb9d1SAndroid Build Coastguard Worker */
450*bbecb9d1SAndroid Build Coastguard Worker return VIRGL_RESOURCE_FD_INVALID;
451*bbecb9d1SAndroid Build Coastguard Worker }
452*bbecb9d1SAndroid Build Coastguard Worker
453*bbecb9d1SAndroid Build Coastguard Worker ret = drmPrimeHandleToFD(mctx->fd, obj->handle, DRM_CLOEXEC | DRM_RDWR, out_fd);
454*bbecb9d1SAndroid Build Coastguard Worker if (ret) {
455*bbecb9d1SAndroid Build Coastguard Worker drm_log("failed to get dmabuf fd: %s", strerror(errno));
456*bbecb9d1SAndroid Build Coastguard Worker return VIRGL_RESOURCE_FD_INVALID;
457*bbecb9d1SAndroid Build Coastguard Worker }
458*bbecb9d1SAndroid Build Coastguard Worker
459*bbecb9d1SAndroid Build Coastguard Worker return VIRGL_RESOURCE_FD_DMABUF;
460*bbecb9d1SAndroid Build Coastguard Worker }
461*bbecb9d1SAndroid Build Coastguard Worker
462*bbecb9d1SAndroid Build Coastguard Worker static int
msm_renderer_transfer_3d(UNUSED struct virgl_context * vctx,UNUSED struct virgl_resource * res,UNUSED const struct vrend_transfer_info * info,UNUSED int transfer_mode)463*bbecb9d1SAndroid Build Coastguard Worker msm_renderer_transfer_3d(UNUSED struct virgl_context *vctx,
464*bbecb9d1SAndroid Build Coastguard Worker UNUSED struct virgl_resource *res,
465*bbecb9d1SAndroid Build Coastguard Worker UNUSED const struct vrend_transfer_info *info,
466*bbecb9d1SAndroid Build Coastguard Worker UNUSED int transfer_mode)
467*bbecb9d1SAndroid Build Coastguard Worker {
468*bbecb9d1SAndroid Build Coastguard Worker drm_log("unsupported");
469*bbecb9d1SAndroid Build Coastguard Worker return -1;
470*bbecb9d1SAndroid Build Coastguard Worker }
471*bbecb9d1SAndroid Build Coastguard Worker
472*bbecb9d1SAndroid Build Coastguard Worker static int
msm_renderer_get_blob(struct virgl_context * vctx,uint32_t res_id,uint64_t blob_id,uint64_t blob_size,uint32_t blob_flags,struct virgl_context_blob * blob)473*bbecb9d1SAndroid Build Coastguard Worker msm_renderer_get_blob(struct virgl_context *vctx, uint32_t res_id, uint64_t blob_id,
474*bbecb9d1SAndroid Build Coastguard Worker uint64_t blob_size, uint32_t blob_flags,
475*bbecb9d1SAndroid Build Coastguard Worker struct virgl_context_blob *blob)
476*bbecb9d1SAndroid Build Coastguard Worker {
477*bbecb9d1SAndroid Build Coastguard Worker struct msm_context *mctx = to_msm_context(vctx);
478*bbecb9d1SAndroid Build Coastguard Worker
479*bbecb9d1SAndroid Build Coastguard Worker drm_dbg("blob_id=%" PRIu64 ", res_id=%u, blob_size=%" PRIu64 ", blob_flags=0x%x",
480*bbecb9d1SAndroid Build Coastguard Worker blob_id, res_id, blob_size, blob_flags);
481*bbecb9d1SAndroid Build Coastguard Worker
482*bbecb9d1SAndroid Build Coastguard Worker if ((blob_id >> 32) != 0) {
483*bbecb9d1SAndroid Build Coastguard Worker drm_log("invalid blob_id: %" PRIu64, blob_id);
484*bbecb9d1SAndroid Build Coastguard Worker return -EINVAL;
485*bbecb9d1SAndroid Build Coastguard Worker }
486*bbecb9d1SAndroid Build Coastguard Worker
487*bbecb9d1SAndroid Build Coastguard Worker /* blob_id of zero is reserved for the shmem buffer: */
488*bbecb9d1SAndroid Build Coastguard Worker if (blob_id == 0) {
489*bbecb9d1SAndroid Build Coastguard Worker int fd;
490*bbecb9d1SAndroid Build Coastguard Worker
491*bbecb9d1SAndroid Build Coastguard Worker if (blob_flags != VIRGL_RENDERER_BLOB_FLAG_USE_MAPPABLE) {
492*bbecb9d1SAndroid Build Coastguard Worker drm_log("invalid blob_flags: 0x%x", blob_flags);
493*bbecb9d1SAndroid Build Coastguard Worker return -EINVAL;
494*bbecb9d1SAndroid Build Coastguard Worker }
495*bbecb9d1SAndroid Build Coastguard Worker
496*bbecb9d1SAndroid Build Coastguard Worker if (mctx->shmem) {
497*bbecb9d1SAndroid Build Coastguard Worker drm_log("There can be only one!");
498*bbecb9d1SAndroid Build Coastguard Worker return -EINVAL;
499*bbecb9d1SAndroid Build Coastguard Worker }
500*bbecb9d1SAndroid Build Coastguard Worker
501*bbecb9d1SAndroid Build Coastguard Worker fd = os_create_anonymous_file(blob_size, "msm-shmem");
502*bbecb9d1SAndroid Build Coastguard Worker if (fd < 0) {
503*bbecb9d1SAndroid Build Coastguard Worker drm_log("Failed to create shmem file: %s", strerror(errno));
504*bbecb9d1SAndroid Build Coastguard Worker return -ENOMEM;
505*bbecb9d1SAndroid Build Coastguard Worker }
506*bbecb9d1SAndroid Build Coastguard Worker
507*bbecb9d1SAndroid Build Coastguard Worker int ret = fcntl(fd, F_ADD_SEALS, F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW);
508*bbecb9d1SAndroid Build Coastguard Worker if (ret) {
509*bbecb9d1SAndroid Build Coastguard Worker drm_log("fcntl failed: %s", strerror(errno));
510*bbecb9d1SAndroid Build Coastguard Worker close(fd);
511*bbecb9d1SAndroid Build Coastguard Worker return -ENOMEM;
512*bbecb9d1SAndroid Build Coastguard Worker }
513*bbecb9d1SAndroid Build Coastguard Worker
514*bbecb9d1SAndroid Build Coastguard Worker mctx->shmem = mmap(NULL, blob_size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
515*bbecb9d1SAndroid Build Coastguard Worker if (mctx->shmem == MAP_FAILED) {
516*bbecb9d1SAndroid Build Coastguard Worker drm_log("shmem mmap failed: %s", strerror(errno));
517*bbecb9d1SAndroid Build Coastguard Worker close(fd);
518*bbecb9d1SAndroid Build Coastguard Worker return -ENOMEM;
519*bbecb9d1SAndroid Build Coastguard Worker }
520*bbecb9d1SAndroid Build Coastguard Worker
521*bbecb9d1SAndroid Build Coastguard Worker mctx->shmem->rsp_mem_offset = sizeof(*mctx->shmem);
522*bbecb9d1SAndroid Build Coastguard Worker
523*bbecb9d1SAndroid Build Coastguard Worker uint8_t *ptr = (uint8_t *)mctx->shmem;
524*bbecb9d1SAndroid Build Coastguard Worker mctx->rsp_mem = &ptr[mctx->shmem->rsp_mem_offset];
525*bbecb9d1SAndroid Build Coastguard Worker mctx->rsp_mem_sz = blob_size - mctx->shmem->rsp_mem_offset;
526*bbecb9d1SAndroid Build Coastguard Worker
527*bbecb9d1SAndroid Build Coastguard Worker blob->type = VIRGL_RESOURCE_FD_SHM;
528*bbecb9d1SAndroid Build Coastguard Worker blob->u.fd = fd;
529*bbecb9d1SAndroid Build Coastguard Worker blob->map_info = VIRGL_RENDERER_MAP_CACHE_CACHED;
530*bbecb9d1SAndroid Build Coastguard Worker
531*bbecb9d1SAndroid Build Coastguard Worker return 0;
532*bbecb9d1SAndroid Build Coastguard Worker }
533*bbecb9d1SAndroid Build Coastguard Worker
534*bbecb9d1SAndroid Build Coastguard Worker if (!valid_res_id(mctx, res_id)) {
535*bbecb9d1SAndroid Build Coastguard Worker drm_log("Invalid res_id %u", res_id);
536*bbecb9d1SAndroid Build Coastguard Worker return -EINVAL;
537*bbecb9d1SAndroid Build Coastguard Worker }
538*bbecb9d1SAndroid Build Coastguard Worker
539*bbecb9d1SAndroid Build Coastguard Worker struct msm_object *obj = msm_retrieve_object_from_blob_id(mctx, blob_id);
540*bbecb9d1SAndroid Build Coastguard Worker
541*bbecb9d1SAndroid Build Coastguard Worker /* If GEM_NEW fails, we can end up here without a backing obj: */
542*bbecb9d1SAndroid Build Coastguard Worker if (!obj) {
543*bbecb9d1SAndroid Build Coastguard Worker drm_log("No object");
544*bbecb9d1SAndroid Build Coastguard Worker return -ENOENT;
545*bbecb9d1SAndroid Build Coastguard Worker }
546*bbecb9d1SAndroid Build Coastguard Worker
547*bbecb9d1SAndroid Build Coastguard Worker /* a memory can only be exported once; we don't want two resources to point
548*bbecb9d1SAndroid Build Coastguard Worker * to the same storage.
549*bbecb9d1SAndroid Build Coastguard Worker */
550*bbecb9d1SAndroid Build Coastguard Worker if (obj->exported) {
551*bbecb9d1SAndroid Build Coastguard Worker drm_log("Already exported!");
552*bbecb9d1SAndroid Build Coastguard Worker return -EINVAL;
553*bbecb9d1SAndroid Build Coastguard Worker }
554*bbecb9d1SAndroid Build Coastguard Worker
555*bbecb9d1SAndroid Build Coastguard Worker msm_object_set_res_id(mctx, obj, res_id);
556*bbecb9d1SAndroid Build Coastguard Worker
557*bbecb9d1SAndroid Build Coastguard Worker if (blob_flags & VIRGL_RENDERER_BLOB_FLAG_USE_SHAREABLE) {
558*bbecb9d1SAndroid Build Coastguard Worker int fd, ret;
559*bbecb9d1SAndroid Build Coastguard Worker
560*bbecb9d1SAndroid Build Coastguard Worker ret = drmPrimeHandleToFD(mctx->fd, obj->handle, DRM_CLOEXEC | DRM_RDWR, &fd);
561*bbecb9d1SAndroid Build Coastguard Worker if (ret) {
562*bbecb9d1SAndroid Build Coastguard Worker drm_log("Export to fd failed");
563*bbecb9d1SAndroid Build Coastguard Worker return -EINVAL;
564*bbecb9d1SAndroid Build Coastguard Worker }
565*bbecb9d1SAndroid Build Coastguard Worker
566*bbecb9d1SAndroid Build Coastguard Worker blob->type = VIRGL_RESOURCE_FD_DMABUF;
567*bbecb9d1SAndroid Build Coastguard Worker blob->u.fd = fd;
568*bbecb9d1SAndroid Build Coastguard Worker } else {
569*bbecb9d1SAndroid Build Coastguard Worker blob->type = VIRGL_RESOURCE_OPAQUE_HANDLE;
570*bbecb9d1SAndroid Build Coastguard Worker blob->u.opaque_handle = obj->handle;
571*bbecb9d1SAndroid Build Coastguard Worker }
572*bbecb9d1SAndroid Build Coastguard Worker
573*bbecb9d1SAndroid Build Coastguard Worker if (obj->flags & MSM_BO_CACHED_COHERENT) {
574*bbecb9d1SAndroid Build Coastguard Worker blob->map_info = VIRGL_RENDERER_MAP_CACHE_CACHED;
575*bbecb9d1SAndroid Build Coastguard Worker } else {
576*bbecb9d1SAndroid Build Coastguard Worker blob->map_info = VIRGL_RENDERER_MAP_CACHE_WC;
577*bbecb9d1SAndroid Build Coastguard Worker }
578*bbecb9d1SAndroid Build Coastguard Worker
579*bbecb9d1SAndroid Build Coastguard Worker obj->exported = true;
580*bbecb9d1SAndroid Build Coastguard Worker obj->exportable = !!(blob_flags & VIRGL_RENDERER_BLOB_FLAG_USE_MAPPABLE);
581*bbecb9d1SAndroid Build Coastguard Worker
582*bbecb9d1SAndroid Build Coastguard Worker return 0;
583*bbecb9d1SAndroid Build Coastguard Worker }
584*bbecb9d1SAndroid Build Coastguard Worker
585*bbecb9d1SAndroid Build Coastguard Worker static void *
msm_context_rsp_noshadow(struct msm_context * mctx,const struct msm_ccmd_req * hdr)586*bbecb9d1SAndroid Build Coastguard Worker msm_context_rsp_noshadow(struct msm_context *mctx, const struct msm_ccmd_req *hdr)
587*bbecb9d1SAndroid Build Coastguard Worker {
588*bbecb9d1SAndroid Build Coastguard Worker return &mctx->rsp_mem[hdr->rsp_off];
589*bbecb9d1SAndroid Build Coastguard Worker }
590*bbecb9d1SAndroid Build Coastguard Worker
591*bbecb9d1SAndroid Build Coastguard Worker static void *
msm_context_rsp(struct msm_context * mctx,const struct msm_ccmd_req * hdr,unsigned len)592*bbecb9d1SAndroid Build Coastguard Worker msm_context_rsp(struct msm_context *mctx, const struct msm_ccmd_req *hdr, unsigned len)
593*bbecb9d1SAndroid Build Coastguard Worker {
594*bbecb9d1SAndroid Build Coastguard Worker unsigned rsp_mem_sz = mctx->rsp_mem_sz;
595*bbecb9d1SAndroid Build Coastguard Worker unsigned off = hdr->rsp_off;
596*bbecb9d1SAndroid Build Coastguard Worker
597*bbecb9d1SAndroid Build Coastguard Worker if ((off > rsp_mem_sz) || (len > rsp_mem_sz - off)) {
598*bbecb9d1SAndroid Build Coastguard Worker drm_log("invalid shm offset: off=%u, len=%u (shmem_size=%u)", off, len, rsp_mem_sz);
599*bbecb9d1SAndroid Build Coastguard Worker return NULL;
600*bbecb9d1SAndroid Build Coastguard Worker }
601*bbecb9d1SAndroid Build Coastguard Worker
602*bbecb9d1SAndroid Build Coastguard Worker struct msm_ccmd_rsp *rsp = msm_context_rsp_noshadow(mctx, hdr);
603*bbecb9d1SAndroid Build Coastguard Worker
604*bbecb9d1SAndroid Build Coastguard Worker assert(len >= sizeof(*rsp));
605*bbecb9d1SAndroid Build Coastguard Worker
606*bbecb9d1SAndroid Build Coastguard Worker /* With newer host and older guest, we could end up wanting a larger rsp struct
607*bbecb9d1SAndroid Build Coastguard Worker * than guest expects, so allocate a shadow buffer in this case rather than
608*bbecb9d1SAndroid Build Coastguard Worker * having to deal with this in all the different ccmd handlers. This is similar
609*bbecb9d1SAndroid Build Coastguard Worker * in a way to what drm_ioctl() does.
610*bbecb9d1SAndroid Build Coastguard Worker */
611*bbecb9d1SAndroid Build Coastguard Worker if (len > rsp->len) {
612*bbecb9d1SAndroid Build Coastguard Worker rsp = malloc(len);
613*bbecb9d1SAndroid Build Coastguard Worker if (!rsp)
614*bbecb9d1SAndroid Build Coastguard Worker return NULL;
615*bbecb9d1SAndroid Build Coastguard Worker rsp->len = len;
616*bbecb9d1SAndroid Build Coastguard Worker }
617*bbecb9d1SAndroid Build Coastguard Worker
618*bbecb9d1SAndroid Build Coastguard Worker mctx->current_rsp = rsp;
619*bbecb9d1SAndroid Build Coastguard Worker
620*bbecb9d1SAndroid Build Coastguard Worker return rsp;
621*bbecb9d1SAndroid Build Coastguard Worker }
622*bbecb9d1SAndroid Build Coastguard Worker
623*bbecb9d1SAndroid Build Coastguard Worker static int
msm_ccmd_nop(UNUSED struct msm_context * mctx,UNUSED const struct msm_ccmd_req * hdr)624*bbecb9d1SAndroid Build Coastguard Worker msm_ccmd_nop(UNUSED struct msm_context *mctx, UNUSED const struct msm_ccmd_req *hdr)
625*bbecb9d1SAndroid Build Coastguard Worker {
626*bbecb9d1SAndroid Build Coastguard Worker return 0;
627*bbecb9d1SAndroid Build Coastguard Worker }
628*bbecb9d1SAndroid Build Coastguard Worker
629*bbecb9d1SAndroid Build Coastguard Worker static int
msm_ccmd_ioctl_simple(struct msm_context * mctx,const struct msm_ccmd_req * hdr)630*bbecb9d1SAndroid Build Coastguard Worker msm_ccmd_ioctl_simple(struct msm_context *mctx, const struct msm_ccmd_req *hdr)
631*bbecb9d1SAndroid Build Coastguard Worker {
632*bbecb9d1SAndroid Build Coastguard Worker const struct msm_ccmd_ioctl_simple_req *req = to_msm_ccmd_ioctl_simple_req(hdr);
633*bbecb9d1SAndroid Build Coastguard Worker unsigned payload_len = _IOC_SIZE(req->cmd);
634*bbecb9d1SAndroid Build Coastguard Worker unsigned req_len = size_add(sizeof(*req), payload_len);
635*bbecb9d1SAndroid Build Coastguard Worker
636*bbecb9d1SAndroid Build Coastguard Worker if (hdr->len != req_len) {
637*bbecb9d1SAndroid Build Coastguard Worker drm_log("%u != %u", hdr->len, req_len);
638*bbecb9d1SAndroid Build Coastguard Worker return -EINVAL;
639*bbecb9d1SAndroid Build Coastguard Worker }
640*bbecb9d1SAndroid Build Coastguard Worker
641*bbecb9d1SAndroid Build Coastguard Worker /* Apply a reasonable upper bound on ioctl size: */
642*bbecb9d1SAndroid Build Coastguard Worker if (payload_len > 128) {
643*bbecb9d1SAndroid Build Coastguard Worker drm_log("invalid ioctl payload length: %u", payload_len);
644*bbecb9d1SAndroid Build Coastguard Worker return -EINVAL;
645*bbecb9d1SAndroid Build Coastguard Worker }
646*bbecb9d1SAndroid Build Coastguard Worker
647*bbecb9d1SAndroid Build Coastguard Worker /* Allow-list of supported ioctls: */
648*bbecb9d1SAndroid Build Coastguard Worker unsigned iocnr = _IOC_NR(req->cmd) - DRM_COMMAND_BASE;
649*bbecb9d1SAndroid Build Coastguard Worker switch (iocnr) {
650*bbecb9d1SAndroid Build Coastguard Worker case DRM_MSM_GET_PARAM:
651*bbecb9d1SAndroid Build Coastguard Worker case DRM_MSM_SUBMITQUEUE_NEW:
652*bbecb9d1SAndroid Build Coastguard Worker case DRM_MSM_SUBMITQUEUE_CLOSE:
653*bbecb9d1SAndroid Build Coastguard Worker break;
654*bbecb9d1SAndroid Build Coastguard Worker default:
655*bbecb9d1SAndroid Build Coastguard Worker drm_log("invalid ioctl: %08x (%u)", req->cmd, iocnr);
656*bbecb9d1SAndroid Build Coastguard Worker return -EINVAL;
657*bbecb9d1SAndroid Build Coastguard Worker }
658*bbecb9d1SAndroid Build Coastguard Worker
659*bbecb9d1SAndroid Build Coastguard Worker struct msm_ccmd_ioctl_simple_rsp *rsp;
660*bbecb9d1SAndroid Build Coastguard Worker unsigned rsp_len = sizeof(*rsp);
661*bbecb9d1SAndroid Build Coastguard Worker
662*bbecb9d1SAndroid Build Coastguard Worker if (req->cmd & IOC_OUT)
663*bbecb9d1SAndroid Build Coastguard Worker rsp_len = size_add(rsp_len, payload_len);
664*bbecb9d1SAndroid Build Coastguard Worker
665*bbecb9d1SAndroid Build Coastguard Worker rsp = msm_context_rsp(mctx, hdr, rsp_len);
666*bbecb9d1SAndroid Build Coastguard Worker
667*bbecb9d1SAndroid Build Coastguard Worker if (!rsp)
668*bbecb9d1SAndroid Build Coastguard Worker return -ENOMEM;
669*bbecb9d1SAndroid Build Coastguard Worker
670*bbecb9d1SAndroid Build Coastguard Worker /* Copy the payload because the kernel can write (if IOC_OUT bit
671*bbecb9d1SAndroid Build Coastguard Worker * is set) and to avoid casting away the const:
672*bbecb9d1SAndroid Build Coastguard Worker */
673*bbecb9d1SAndroid Build Coastguard Worker char payload[payload_len];
674*bbecb9d1SAndroid Build Coastguard Worker memcpy(payload, req->payload, payload_len);
675*bbecb9d1SAndroid Build Coastguard Worker
676*bbecb9d1SAndroid Build Coastguard Worker rsp->ret = drmIoctl(mctx->fd, req->cmd, payload);
677*bbecb9d1SAndroid Build Coastguard Worker
678*bbecb9d1SAndroid Build Coastguard Worker if (req->cmd & IOC_OUT)
679*bbecb9d1SAndroid Build Coastguard Worker memcpy(rsp->payload, payload, payload_len);
680*bbecb9d1SAndroid Build Coastguard Worker
681*bbecb9d1SAndroid Build Coastguard Worker if (iocnr == DRM_MSM_SUBMITQUEUE_NEW && !rsp->ret) {
682*bbecb9d1SAndroid Build Coastguard Worker struct drm_msm_submitqueue *args = (void *)payload;
683*bbecb9d1SAndroid Build Coastguard Worker
684*bbecb9d1SAndroid Build Coastguard Worker drm_dbg("submitqueue %u, prio %u", args->id, args->prio);
685*bbecb9d1SAndroid Build Coastguard Worker
686*bbecb9d1SAndroid Build Coastguard Worker _mesa_hash_table_insert(mctx->sq_to_ring_idx_table, (void *)(uintptr_t)args->id,
687*bbecb9d1SAndroid Build Coastguard Worker (void *)(uintptr_t)args->prio);
688*bbecb9d1SAndroid Build Coastguard Worker }
689*bbecb9d1SAndroid Build Coastguard Worker
690*bbecb9d1SAndroid Build Coastguard Worker return 0;
691*bbecb9d1SAndroid Build Coastguard Worker }
692*bbecb9d1SAndroid Build Coastguard Worker
693*bbecb9d1SAndroid Build Coastguard Worker static int
msm_ccmd_gem_new(struct msm_context * mctx,const struct msm_ccmd_req * hdr)694*bbecb9d1SAndroid Build Coastguard Worker msm_ccmd_gem_new(struct msm_context *mctx, const struct msm_ccmd_req *hdr)
695*bbecb9d1SAndroid Build Coastguard Worker {
696*bbecb9d1SAndroid Build Coastguard Worker const struct msm_ccmd_gem_new_req *req = to_msm_ccmd_gem_new_req(hdr);
697*bbecb9d1SAndroid Build Coastguard Worker int ret = 0;
698*bbecb9d1SAndroid Build Coastguard Worker
699*bbecb9d1SAndroid Build Coastguard Worker if (!valid_blob_id(mctx, req->blob_id)) {
700*bbecb9d1SAndroid Build Coastguard Worker drm_log("Invalid blob_id %u", req->blob_id);
701*bbecb9d1SAndroid Build Coastguard Worker ret = -EINVAL;
702*bbecb9d1SAndroid Build Coastguard Worker goto out_error;
703*bbecb9d1SAndroid Build Coastguard Worker }
704*bbecb9d1SAndroid Build Coastguard Worker
705*bbecb9d1SAndroid Build Coastguard Worker /*
706*bbecb9d1SAndroid Build Coastguard Worker * First part, allocate the GEM bo:
707*bbecb9d1SAndroid Build Coastguard Worker */
708*bbecb9d1SAndroid Build Coastguard Worker struct drm_msm_gem_new gem_new = {
709*bbecb9d1SAndroid Build Coastguard Worker .size = req->size,
710*bbecb9d1SAndroid Build Coastguard Worker .flags = req->flags,
711*bbecb9d1SAndroid Build Coastguard Worker };
712*bbecb9d1SAndroid Build Coastguard Worker
713*bbecb9d1SAndroid Build Coastguard Worker ret = drmCommandWriteRead(mctx->fd, DRM_MSM_GEM_NEW, &gem_new, sizeof(gem_new));
714*bbecb9d1SAndroid Build Coastguard Worker if (ret) {
715*bbecb9d1SAndroid Build Coastguard Worker drm_log("GEM_NEW failed: %d (%s)", ret, strerror(errno));
716*bbecb9d1SAndroid Build Coastguard Worker goto out_error;
717*bbecb9d1SAndroid Build Coastguard Worker }
718*bbecb9d1SAndroid Build Coastguard Worker
719*bbecb9d1SAndroid Build Coastguard Worker /*
720*bbecb9d1SAndroid Build Coastguard Worker * Second part, set the iova:
721*bbecb9d1SAndroid Build Coastguard Worker */
722*bbecb9d1SAndroid Build Coastguard Worker uint64_t iova = req->iova;
723*bbecb9d1SAndroid Build Coastguard Worker ret = gem_info(mctx, gem_new.handle, MSM_INFO_SET_IOVA, &iova);
724*bbecb9d1SAndroid Build Coastguard Worker if (ret) {
725*bbecb9d1SAndroid Build Coastguard Worker drm_log("SET_IOVA failed: %d (%s)", ret, strerror(errno));
726*bbecb9d1SAndroid Build Coastguard Worker goto out_close;
727*bbecb9d1SAndroid Build Coastguard Worker }
728*bbecb9d1SAndroid Build Coastguard Worker
729*bbecb9d1SAndroid Build Coastguard Worker /*
730*bbecb9d1SAndroid Build Coastguard Worker * And then finally create our msm_object for tracking the resource,
731*bbecb9d1SAndroid Build Coastguard Worker * and add to blob table:
732*bbecb9d1SAndroid Build Coastguard Worker */
733*bbecb9d1SAndroid Build Coastguard Worker struct msm_object *obj = msm_object_create(gem_new.handle, req->flags, req->size);
734*bbecb9d1SAndroid Build Coastguard Worker
735*bbecb9d1SAndroid Build Coastguard Worker if (!obj) {
736*bbecb9d1SAndroid Build Coastguard Worker ret = -ENOMEM;
737*bbecb9d1SAndroid Build Coastguard Worker goto out_close;
738*bbecb9d1SAndroid Build Coastguard Worker }
739*bbecb9d1SAndroid Build Coastguard Worker
740*bbecb9d1SAndroid Build Coastguard Worker msm_object_set_blob_id(mctx, obj, req->blob_id);
741*bbecb9d1SAndroid Build Coastguard Worker
742*bbecb9d1SAndroid Build Coastguard Worker drm_dbg("obj=%p, blob_id=%u, handle=%u, iova=%" PRIx64, obj, obj->blob_id,
743*bbecb9d1SAndroid Build Coastguard Worker obj->handle, iova);
744*bbecb9d1SAndroid Build Coastguard Worker
745*bbecb9d1SAndroid Build Coastguard Worker return 0;
746*bbecb9d1SAndroid Build Coastguard Worker
747*bbecb9d1SAndroid Build Coastguard Worker out_close:
748*bbecb9d1SAndroid Build Coastguard Worker gem_close(mctx->fd, gem_new.handle);
749*bbecb9d1SAndroid Build Coastguard Worker out_error:
750*bbecb9d1SAndroid Build Coastguard Worker if (mctx->shmem)
751*bbecb9d1SAndroid Build Coastguard Worker mctx->shmem->async_error++;
752*bbecb9d1SAndroid Build Coastguard Worker return ret;
753*bbecb9d1SAndroid Build Coastguard Worker }
754*bbecb9d1SAndroid Build Coastguard Worker
755*bbecb9d1SAndroid Build Coastguard Worker static int
msm_ccmd_gem_set_iova(struct msm_context * mctx,const struct msm_ccmd_req * hdr)756*bbecb9d1SAndroid Build Coastguard Worker msm_ccmd_gem_set_iova(struct msm_context *mctx, const struct msm_ccmd_req *hdr)
757*bbecb9d1SAndroid Build Coastguard Worker {
758*bbecb9d1SAndroid Build Coastguard Worker const struct msm_ccmd_gem_set_iova_req *req = to_msm_ccmd_gem_set_iova_req(hdr);
759*bbecb9d1SAndroid Build Coastguard Worker struct msm_object *obj = msm_get_object_from_res_id(mctx, req->res_id);
760*bbecb9d1SAndroid Build Coastguard Worker int ret = 0;
761*bbecb9d1SAndroid Build Coastguard Worker
762*bbecb9d1SAndroid Build Coastguard Worker if (!obj) {
763*bbecb9d1SAndroid Build Coastguard Worker drm_log("Could not lookup obj: res_id=%u", req->res_id);
764*bbecb9d1SAndroid Build Coastguard Worker ret = -ENOENT;
765*bbecb9d1SAndroid Build Coastguard Worker goto out_error;
766*bbecb9d1SAndroid Build Coastguard Worker }
767*bbecb9d1SAndroid Build Coastguard Worker
768*bbecb9d1SAndroid Build Coastguard Worker uint64_t iova = req->iova;
769*bbecb9d1SAndroid Build Coastguard Worker if (iova) {
770*bbecb9d1SAndroid Build Coastguard Worker TRACE_SCOPE_BEGIN("SET_IOVA");
771*bbecb9d1SAndroid Build Coastguard Worker ret = gem_info(mctx, obj->handle, MSM_INFO_SET_IOVA, &iova);
772*bbecb9d1SAndroid Build Coastguard Worker TRACE_SCOPE_END("SET_IOVA");
773*bbecb9d1SAndroid Build Coastguard Worker } else {
774*bbecb9d1SAndroid Build Coastguard Worker TRACE_SCOPE_BEGIN("CLEAR_IOVA");
775*bbecb9d1SAndroid Build Coastguard Worker ret = gem_info(mctx, obj->handle, MSM_INFO_SET_IOVA, &iova);
776*bbecb9d1SAndroid Build Coastguard Worker TRACE_SCOPE_END("CLEAR_IOVA");
777*bbecb9d1SAndroid Build Coastguard Worker }
778*bbecb9d1SAndroid Build Coastguard Worker if (ret) {
779*bbecb9d1SAndroid Build Coastguard Worker drm_log("SET_IOVA failed: %d (%s)", ret, strerror(errno));
780*bbecb9d1SAndroid Build Coastguard Worker goto out_error;
781*bbecb9d1SAndroid Build Coastguard Worker }
782*bbecb9d1SAndroid Build Coastguard Worker
783*bbecb9d1SAndroid Build Coastguard Worker drm_dbg("obj=%p, blob_id=%u, handle=%u, iova=%" PRIx64, obj, obj->blob_id,
784*bbecb9d1SAndroid Build Coastguard Worker obj->handle, iova);
785*bbecb9d1SAndroid Build Coastguard Worker
786*bbecb9d1SAndroid Build Coastguard Worker return 0;
787*bbecb9d1SAndroid Build Coastguard Worker
788*bbecb9d1SAndroid Build Coastguard Worker out_error:
789*bbecb9d1SAndroid Build Coastguard Worker if (mctx->shmem)
790*bbecb9d1SAndroid Build Coastguard Worker mctx->shmem->async_error++;
791*bbecb9d1SAndroid Build Coastguard Worker return 0;
792*bbecb9d1SAndroid Build Coastguard Worker }
793*bbecb9d1SAndroid Build Coastguard Worker
794*bbecb9d1SAndroid Build Coastguard Worker static int
msm_ccmd_gem_cpu_prep(struct msm_context * mctx,const struct msm_ccmd_req * hdr)795*bbecb9d1SAndroid Build Coastguard Worker msm_ccmd_gem_cpu_prep(struct msm_context *mctx, const struct msm_ccmd_req *hdr)
796*bbecb9d1SAndroid Build Coastguard Worker {
797*bbecb9d1SAndroid Build Coastguard Worker const struct msm_ccmd_gem_cpu_prep_req *req = to_msm_ccmd_gem_cpu_prep_req(hdr);
798*bbecb9d1SAndroid Build Coastguard Worker struct msm_ccmd_gem_cpu_prep_rsp *rsp = msm_context_rsp(mctx, hdr, sizeof(*rsp));
799*bbecb9d1SAndroid Build Coastguard Worker
800*bbecb9d1SAndroid Build Coastguard Worker if (!rsp)
801*bbecb9d1SAndroid Build Coastguard Worker return -ENOMEM;
802*bbecb9d1SAndroid Build Coastguard Worker
803*bbecb9d1SAndroid Build Coastguard Worker struct drm_msm_gem_cpu_prep args = {
804*bbecb9d1SAndroid Build Coastguard Worker .handle = handle_from_res_id(mctx, req->res_id),
805*bbecb9d1SAndroid Build Coastguard Worker .op = req->op | MSM_PREP_NOSYNC,
806*bbecb9d1SAndroid Build Coastguard Worker };
807*bbecb9d1SAndroid Build Coastguard Worker
808*bbecb9d1SAndroid Build Coastguard Worker rsp->ret = drmCommandWrite(mctx->fd, DRM_MSM_GEM_CPU_PREP, &args, sizeof(args));
809*bbecb9d1SAndroid Build Coastguard Worker
810*bbecb9d1SAndroid Build Coastguard Worker return 0;
811*bbecb9d1SAndroid Build Coastguard Worker }
812*bbecb9d1SAndroid Build Coastguard Worker
813*bbecb9d1SAndroid Build Coastguard Worker static int
msm_ccmd_gem_set_name(struct msm_context * mctx,const struct msm_ccmd_req * hdr)814*bbecb9d1SAndroid Build Coastguard Worker msm_ccmd_gem_set_name(struct msm_context *mctx, const struct msm_ccmd_req *hdr)
815*bbecb9d1SAndroid Build Coastguard Worker {
816*bbecb9d1SAndroid Build Coastguard Worker const struct msm_ccmd_gem_set_name_req *req = to_msm_ccmd_gem_set_name_req(hdr);
817*bbecb9d1SAndroid Build Coastguard Worker
818*bbecb9d1SAndroid Build Coastguard Worker struct drm_msm_gem_info args = {
819*bbecb9d1SAndroid Build Coastguard Worker .handle = handle_from_res_id(mctx, req->res_id),
820*bbecb9d1SAndroid Build Coastguard Worker .info = MSM_INFO_SET_NAME,
821*bbecb9d1SAndroid Build Coastguard Worker .value = VOID2U64(req->payload),
822*bbecb9d1SAndroid Build Coastguard Worker .len = req->len,
823*bbecb9d1SAndroid Build Coastguard Worker };
824*bbecb9d1SAndroid Build Coastguard Worker
825*bbecb9d1SAndroid Build Coastguard Worker if (!valid_payload_len(req))
826*bbecb9d1SAndroid Build Coastguard Worker return -EINVAL;
827*bbecb9d1SAndroid Build Coastguard Worker
828*bbecb9d1SAndroid Build Coastguard Worker int ret = drmCommandWrite(mctx->fd, DRM_MSM_GEM_INFO, &args, sizeof(args));
829*bbecb9d1SAndroid Build Coastguard Worker if (ret)
830*bbecb9d1SAndroid Build Coastguard Worker drm_log("ret=%d, len=%u, name=%.*s", ret, req->len, req->len, req->payload);
831*bbecb9d1SAndroid Build Coastguard Worker
832*bbecb9d1SAndroid Build Coastguard Worker return 0;
833*bbecb9d1SAndroid Build Coastguard Worker }
834*bbecb9d1SAndroid Build Coastguard Worker
835*bbecb9d1SAndroid Build Coastguard Worker static void
msm_dump_submit(struct drm_msm_gem_submit * req)836*bbecb9d1SAndroid Build Coastguard Worker msm_dump_submit(struct drm_msm_gem_submit *req)
837*bbecb9d1SAndroid Build Coastguard Worker {
838*bbecb9d1SAndroid Build Coastguard Worker #ifndef NDEBUG
839*bbecb9d1SAndroid Build Coastguard Worker drm_log(" flags=0x%x, queueid=%u", req->flags, req->queueid);
840*bbecb9d1SAndroid Build Coastguard Worker for (unsigned i = 0; i < req->nr_bos; i++) {
841*bbecb9d1SAndroid Build Coastguard Worker struct drm_msm_gem_submit_bo *bos = U642VOID(req->bos);
842*bbecb9d1SAndroid Build Coastguard Worker struct drm_msm_gem_submit_bo *bo = &bos[i];
843*bbecb9d1SAndroid Build Coastguard Worker drm_log(" bos[%d]: handle=%u, flags=%x", i, bo->handle, bo->flags);
844*bbecb9d1SAndroid Build Coastguard Worker }
845*bbecb9d1SAndroid Build Coastguard Worker for (unsigned i = 0; i < req->nr_cmds; i++) {
846*bbecb9d1SAndroid Build Coastguard Worker struct drm_msm_gem_submit_cmd *cmds = U642VOID(req->cmds);
847*bbecb9d1SAndroid Build Coastguard Worker struct drm_msm_gem_submit_cmd *cmd = &cmds[i];
848*bbecb9d1SAndroid Build Coastguard Worker drm_log(" cmd[%d]: type=%u, submit_idx=%u, submit_offset=%u, size=%u", i,
849*bbecb9d1SAndroid Build Coastguard Worker cmd->type, cmd->submit_idx, cmd->submit_offset, cmd->size);
850*bbecb9d1SAndroid Build Coastguard Worker }
851*bbecb9d1SAndroid Build Coastguard Worker #else
852*bbecb9d1SAndroid Build Coastguard Worker (void)req;
853*bbecb9d1SAndroid Build Coastguard Worker #endif
854*bbecb9d1SAndroid Build Coastguard Worker }
855*bbecb9d1SAndroid Build Coastguard Worker
856*bbecb9d1SAndroid Build Coastguard Worker static int
msm_ccmd_gem_submit(struct msm_context * mctx,const struct msm_ccmd_req * hdr)857*bbecb9d1SAndroid Build Coastguard Worker msm_ccmd_gem_submit(struct msm_context *mctx, const struct msm_ccmd_req *hdr)
858*bbecb9d1SAndroid Build Coastguard Worker {
859*bbecb9d1SAndroid Build Coastguard Worker const struct msm_ccmd_gem_submit_req *req = to_msm_ccmd_gem_submit_req(hdr);
860*bbecb9d1SAndroid Build Coastguard Worker
861*bbecb9d1SAndroid Build Coastguard Worker size_t sz = sizeof(*req);
862*bbecb9d1SAndroid Build Coastguard Worker sz = size_add(sz, size_mul(req->nr_bos, sizeof(struct drm_msm_gem_submit_bo)));
863*bbecb9d1SAndroid Build Coastguard Worker sz = size_add(sz, size_mul(req->nr_cmds, sizeof(struct drm_msm_gem_submit_cmd)));
864*bbecb9d1SAndroid Build Coastguard Worker
865*bbecb9d1SAndroid Build Coastguard Worker /* Normally kernel would validate out of bounds situations and return -EFAULT,
866*bbecb9d1SAndroid Build Coastguard Worker * but since we are copying the bo handles, we need to validate that the
867*bbecb9d1SAndroid Build Coastguard Worker * guest can't trigger us to make an out of bounds memory access:
868*bbecb9d1SAndroid Build Coastguard Worker */
869*bbecb9d1SAndroid Build Coastguard Worker if (sz > hdr->len) {
870*bbecb9d1SAndroid Build Coastguard Worker drm_log("out of bounds: nr_bos=%u, nr_cmds=%u", req->nr_bos, req->nr_cmds);
871*bbecb9d1SAndroid Build Coastguard Worker return -ENOSPC;
872*bbecb9d1SAndroid Build Coastguard Worker }
873*bbecb9d1SAndroid Build Coastguard Worker
874*bbecb9d1SAndroid Build Coastguard Worker const unsigned bo_limit = 8192 / sizeof(struct drm_msm_gem_submit_bo);
875*bbecb9d1SAndroid Build Coastguard Worker bool bos_on_stack = req->nr_bos < bo_limit;
876*bbecb9d1SAndroid Build Coastguard Worker struct drm_msm_gem_submit_bo _bos[bos_on_stack ? req->nr_bos : 0];
877*bbecb9d1SAndroid Build Coastguard Worker struct drm_msm_gem_submit_bo *bos;
878*bbecb9d1SAndroid Build Coastguard Worker
879*bbecb9d1SAndroid Build Coastguard Worker if (bos_on_stack) {
880*bbecb9d1SAndroid Build Coastguard Worker bos = _bos;
881*bbecb9d1SAndroid Build Coastguard Worker } else {
882*bbecb9d1SAndroid Build Coastguard Worker bos = malloc(req->nr_bos * sizeof(bos[0]));
883*bbecb9d1SAndroid Build Coastguard Worker if (!bos)
884*bbecb9d1SAndroid Build Coastguard Worker return -ENOMEM;
885*bbecb9d1SAndroid Build Coastguard Worker }
886*bbecb9d1SAndroid Build Coastguard Worker
887*bbecb9d1SAndroid Build Coastguard Worker memcpy(bos, req->payload, req->nr_bos * sizeof(bos[0]));
888*bbecb9d1SAndroid Build Coastguard Worker
889*bbecb9d1SAndroid Build Coastguard Worker for (uint32_t i = 0; i < req->nr_bos; i++)
890*bbecb9d1SAndroid Build Coastguard Worker bos[i].handle = handle_from_res_id(mctx, bos[i].handle);
891*bbecb9d1SAndroid Build Coastguard Worker
892*bbecb9d1SAndroid Build Coastguard Worker struct drm_msm_gem_submit args = {
893*bbecb9d1SAndroid Build Coastguard Worker .flags = req->flags | MSM_SUBMIT_FENCE_FD_OUT | MSM_SUBMIT_FENCE_SN_IN,
894*bbecb9d1SAndroid Build Coastguard Worker .fence = req->fence,
895*bbecb9d1SAndroid Build Coastguard Worker .nr_bos = req->nr_bos,
896*bbecb9d1SAndroid Build Coastguard Worker .nr_cmds = req->nr_cmds,
897*bbecb9d1SAndroid Build Coastguard Worker .bos = VOID2U64(bos),
898*bbecb9d1SAndroid Build Coastguard Worker .cmds = VOID2U64(&req->payload[req->nr_bos * sizeof(struct drm_msm_gem_submit_bo)]),
899*bbecb9d1SAndroid Build Coastguard Worker .queueid = req->queue_id,
900*bbecb9d1SAndroid Build Coastguard Worker };
901*bbecb9d1SAndroid Build Coastguard Worker
902*bbecb9d1SAndroid Build Coastguard Worker int ret = drmCommandWriteRead(mctx->fd, DRM_MSM_GEM_SUBMIT, &args, sizeof(args));
903*bbecb9d1SAndroid Build Coastguard Worker drm_dbg("fence=%u, ret=%d", args.fence, ret);
904*bbecb9d1SAndroid Build Coastguard Worker
905*bbecb9d1SAndroid Build Coastguard Worker if (unlikely(ret)) {
906*bbecb9d1SAndroid Build Coastguard Worker drm_log("submit failed: %s", strerror(errno));
907*bbecb9d1SAndroid Build Coastguard Worker msm_dump_submit(&args);
908*bbecb9d1SAndroid Build Coastguard Worker if (mctx->shmem)
909*bbecb9d1SAndroid Build Coastguard Worker mctx->shmem->async_error++;
910*bbecb9d1SAndroid Build Coastguard Worker } else {
911*bbecb9d1SAndroid Build Coastguard Worker const struct hash_entry *entry =
912*bbecb9d1SAndroid Build Coastguard Worker table_search(mctx->sq_to_ring_idx_table, args.queueid);
913*bbecb9d1SAndroid Build Coastguard Worker
914*bbecb9d1SAndroid Build Coastguard Worker if (!entry) {
915*bbecb9d1SAndroid Build Coastguard Worker drm_log("unknown submitqueue: %u", args.queueid);
916*bbecb9d1SAndroid Build Coastguard Worker goto out;
917*bbecb9d1SAndroid Build Coastguard Worker }
918*bbecb9d1SAndroid Build Coastguard Worker
919*bbecb9d1SAndroid Build Coastguard Worker unsigned prio = (uintptr_t)entry->data;
920*bbecb9d1SAndroid Build Coastguard Worker
921*bbecb9d1SAndroid Build Coastguard Worker drm_timeline_set_last_fence_fd(&mctx->timelines[prio], args.fence_fd);
922*bbecb9d1SAndroid Build Coastguard Worker }
923*bbecb9d1SAndroid Build Coastguard Worker
924*bbecb9d1SAndroid Build Coastguard Worker out:
925*bbecb9d1SAndroid Build Coastguard Worker if (!bos_on_stack)
926*bbecb9d1SAndroid Build Coastguard Worker free(bos);
927*bbecb9d1SAndroid Build Coastguard Worker return 0;
928*bbecb9d1SAndroid Build Coastguard Worker }
929*bbecb9d1SAndroid Build Coastguard Worker
930*bbecb9d1SAndroid Build Coastguard Worker static int
map_object(struct msm_context * mctx,struct msm_object * obj)931*bbecb9d1SAndroid Build Coastguard Worker map_object(struct msm_context *mctx, struct msm_object *obj)
932*bbecb9d1SAndroid Build Coastguard Worker {
933*bbecb9d1SAndroid Build Coastguard Worker uint64_t offset;
934*bbecb9d1SAndroid Build Coastguard Worker int ret;
935*bbecb9d1SAndroid Build Coastguard Worker
936*bbecb9d1SAndroid Build Coastguard Worker if (obj->map)
937*bbecb9d1SAndroid Build Coastguard Worker return 0;
938*bbecb9d1SAndroid Build Coastguard Worker
939*bbecb9d1SAndroid Build Coastguard Worker uint32_t handle = handle_from_res_id(mctx, obj->res_id);
940*bbecb9d1SAndroid Build Coastguard Worker ret = gem_info(mctx, handle, MSM_INFO_GET_OFFSET, &offset);
941*bbecb9d1SAndroid Build Coastguard Worker if (ret) {
942*bbecb9d1SAndroid Build Coastguard Worker drm_log("alloc failed: %s", strerror(errno));
943*bbecb9d1SAndroid Build Coastguard Worker return ret;
944*bbecb9d1SAndroid Build Coastguard Worker }
945*bbecb9d1SAndroid Build Coastguard Worker
946*bbecb9d1SAndroid Build Coastguard Worker uint8_t *map =
947*bbecb9d1SAndroid Build Coastguard Worker mmap(0, obj->size, PROT_READ | PROT_WRITE, MAP_SHARED, mctx->fd, offset);
948*bbecb9d1SAndroid Build Coastguard Worker if (map == MAP_FAILED) {
949*bbecb9d1SAndroid Build Coastguard Worker drm_log("mmap failed: %s", strerror(errno));
950*bbecb9d1SAndroid Build Coastguard Worker return -ENOMEM;
951*bbecb9d1SAndroid Build Coastguard Worker }
952*bbecb9d1SAndroid Build Coastguard Worker
953*bbecb9d1SAndroid Build Coastguard Worker obj->map = map;
954*bbecb9d1SAndroid Build Coastguard Worker
955*bbecb9d1SAndroid Build Coastguard Worker return 0;
956*bbecb9d1SAndroid Build Coastguard Worker }
957*bbecb9d1SAndroid Build Coastguard Worker
958*bbecb9d1SAndroid Build Coastguard Worker static int
msm_ccmd_gem_upload(struct msm_context * mctx,const struct msm_ccmd_req * hdr)959*bbecb9d1SAndroid Build Coastguard Worker msm_ccmd_gem_upload(struct msm_context *mctx, const struct msm_ccmd_req *hdr)
960*bbecb9d1SAndroid Build Coastguard Worker {
961*bbecb9d1SAndroid Build Coastguard Worker const struct msm_ccmd_gem_upload_req *req = to_msm_ccmd_gem_upload_req(hdr);
962*bbecb9d1SAndroid Build Coastguard Worker int ret;
963*bbecb9d1SAndroid Build Coastguard Worker
964*bbecb9d1SAndroid Build Coastguard Worker if (req->pad || !valid_payload_len(req)) {
965*bbecb9d1SAndroid Build Coastguard Worker drm_log("Invalid upload ccmd");
966*bbecb9d1SAndroid Build Coastguard Worker return -EINVAL;
967*bbecb9d1SAndroid Build Coastguard Worker }
968*bbecb9d1SAndroid Build Coastguard Worker
969*bbecb9d1SAndroid Build Coastguard Worker struct msm_object *obj = msm_get_object_from_res_id(mctx, req->res_id);
970*bbecb9d1SAndroid Build Coastguard Worker if (!obj) {
971*bbecb9d1SAndroid Build Coastguard Worker drm_log("No obj: res_id=%u", req->res_id);
972*bbecb9d1SAndroid Build Coastguard Worker return -ENOENT;
973*bbecb9d1SAndroid Build Coastguard Worker }
974*bbecb9d1SAndroid Build Coastguard Worker
975*bbecb9d1SAndroid Build Coastguard Worker ret = map_object(mctx, obj);
976*bbecb9d1SAndroid Build Coastguard Worker if (ret)
977*bbecb9d1SAndroid Build Coastguard Worker return ret;
978*bbecb9d1SAndroid Build Coastguard Worker
979*bbecb9d1SAndroid Build Coastguard Worker memcpy(&obj->map[req->off], req->payload, req->len);
980*bbecb9d1SAndroid Build Coastguard Worker
981*bbecb9d1SAndroid Build Coastguard Worker return 0;
982*bbecb9d1SAndroid Build Coastguard Worker }
983*bbecb9d1SAndroid Build Coastguard Worker
984*bbecb9d1SAndroid Build Coastguard Worker static int
msm_ccmd_submitqueue_query(struct msm_context * mctx,const struct msm_ccmd_req * hdr)985*bbecb9d1SAndroid Build Coastguard Worker msm_ccmd_submitqueue_query(struct msm_context *mctx, const struct msm_ccmd_req *hdr)
986*bbecb9d1SAndroid Build Coastguard Worker {
987*bbecb9d1SAndroid Build Coastguard Worker const struct msm_ccmd_submitqueue_query_req *req =
988*bbecb9d1SAndroid Build Coastguard Worker to_msm_ccmd_submitqueue_query_req(hdr);
989*bbecb9d1SAndroid Build Coastguard Worker struct msm_ccmd_submitqueue_query_rsp *rsp =
990*bbecb9d1SAndroid Build Coastguard Worker msm_context_rsp(mctx, hdr, size_add(sizeof(*rsp), req->len));
991*bbecb9d1SAndroid Build Coastguard Worker
992*bbecb9d1SAndroid Build Coastguard Worker if (!rsp)
993*bbecb9d1SAndroid Build Coastguard Worker return -ENOMEM;
994*bbecb9d1SAndroid Build Coastguard Worker
995*bbecb9d1SAndroid Build Coastguard Worker struct drm_msm_submitqueue_query args = {
996*bbecb9d1SAndroid Build Coastguard Worker .data = VOID2U64(rsp->payload),
997*bbecb9d1SAndroid Build Coastguard Worker .id = req->queue_id,
998*bbecb9d1SAndroid Build Coastguard Worker .param = req->param,
999*bbecb9d1SAndroid Build Coastguard Worker .len = req->len,
1000*bbecb9d1SAndroid Build Coastguard Worker };
1001*bbecb9d1SAndroid Build Coastguard Worker
1002*bbecb9d1SAndroid Build Coastguard Worker rsp->ret =
1003*bbecb9d1SAndroid Build Coastguard Worker drmCommandWriteRead(mctx->fd, DRM_MSM_SUBMITQUEUE_QUERY, &args, sizeof(args));
1004*bbecb9d1SAndroid Build Coastguard Worker
1005*bbecb9d1SAndroid Build Coastguard Worker rsp->out_len = args.len;
1006*bbecb9d1SAndroid Build Coastguard Worker
1007*bbecb9d1SAndroid Build Coastguard Worker return 0;
1008*bbecb9d1SAndroid Build Coastguard Worker }
1009*bbecb9d1SAndroid Build Coastguard Worker
1010*bbecb9d1SAndroid Build Coastguard Worker static int
msm_ccmd_wait_fence(struct msm_context * mctx,const struct msm_ccmd_req * hdr)1011*bbecb9d1SAndroid Build Coastguard Worker msm_ccmd_wait_fence(struct msm_context *mctx, const struct msm_ccmd_req *hdr)
1012*bbecb9d1SAndroid Build Coastguard Worker {
1013*bbecb9d1SAndroid Build Coastguard Worker const struct msm_ccmd_wait_fence_req *req = to_msm_ccmd_wait_fence_req(hdr);
1014*bbecb9d1SAndroid Build Coastguard Worker struct msm_ccmd_wait_fence_rsp *rsp = msm_context_rsp(mctx, hdr, sizeof(*rsp));
1015*bbecb9d1SAndroid Build Coastguard Worker
1016*bbecb9d1SAndroid Build Coastguard Worker if (!rsp)
1017*bbecb9d1SAndroid Build Coastguard Worker return -ENOMEM;
1018*bbecb9d1SAndroid Build Coastguard Worker
1019*bbecb9d1SAndroid Build Coastguard Worker struct timespec t;
1020*bbecb9d1SAndroid Build Coastguard Worker
1021*bbecb9d1SAndroid Build Coastguard Worker /* Use current time as timeout, to avoid blocking: */
1022*bbecb9d1SAndroid Build Coastguard Worker clock_gettime(CLOCK_MONOTONIC, &t);
1023*bbecb9d1SAndroid Build Coastguard Worker
1024*bbecb9d1SAndroid Build Coastguard Worker struct drm_msm_wait_fence args = {
1025*bbecb9d1SAndroid Build Coastguard Worker .fence = req->fence,
1026*bbecb9d1SAndroid Build Coastguard Worker .queueid = req->queue_id,
1027*bbecb9d1SAndroid Build Coastguard Worker .timeout =
1028*bbecb9d1SAndroid Build Coastguard Worker {
1029*bbecb9d1SAndroid Build Coastguard Worker .tv_sec = t.tv_sec,
1030*bbecb9d1SAndroid Build Coastguard Worker .tv_nsec = t.tv_nsec,
1031*bbecb9d1SAndroid Build Coastguard Worker },
1032*bbecb9d1SAndroid Build Coastguard Worker };
1033*bbecb9d1SAndroid Build Coastguard Worker
1034*bbecb9d1SAndroid Build Coastguard Worker rsp->ret = drmCommandWrite(mctx->fd, DRM_MSM_WAIT_FENCE, &args, sizeof(args));
1035*bbecb9d1SAndroid Build Coastguard Worker
1036*bbecb9d1SAndroid Build Coastguard Worker return 0;
1037*bbecb9d1SAndroid Build Coastguard Worker }
1038*bbecb9d1SAndroid Build Coastguard Worker
1039*bbecb9d1SAndroid Build Coastguard Worker static int
msm_ccmd_set_debuginfo(struct msm_context * mctx,const struct msm_ccmd_req * hdr)1040*bbecb9d1SAndroid Build Coastguard Worker msm_ccmd_set_debuginfo(struct msm_context *mctx, const struct msm_ccmd_req *hdr)
1041*bbecb9d1SAndroid Build Coastguard Worker {
1042*bbecb9d1SAndroid Build Coastguard Worker const struct msm_ccmd_set_debuginfo_req *req = to_msm_ccmd_set_debuginfo_req(hdr);
1043*bbecb9d1SAndroid Build Coastguard Worker
1044*bbecb9d1SAndroid Build Coastguard Worker size_t sz = sizeof(*req);
1045*bbecb9d1SAndroid Build Coastguard Worker sz = size_add(sz, req->comm_len);
1046*bbecb9d1SAndroid Build Coastguard Worker sz = size_add(sz, req->cmdline_len);
1047*bbecb9d1SAndroid Build Coastguard Worker
1048*bbecb9d1SAndroid Build Coastguard Worker if (sz > hdr->len) {
1049*bbecb9d1SAndroid Build Coastguard Worker drm_log("out of bounds: comm_len=%u, cmdline_len=%u", req->comm_len, req->cmdline_len);
1050*bbecb9d1SAndroid Build Coastguard Worker return -ENOSPC;
1051*bbecb9d1SAndroid Build Coastguard Worker }
1052*bbecb9d1SAndroid Build Coastguard Worker
1053*bbecb9d1SAndroid Build Coastguard Worker struct drm_msm_param set_comm = {
1054*bbecb9d1SAndroid Build Coastguard Worker .pipe = MSM_PIPE_3D0,
1055*bbecb9d1SAndroid Build Coastguard Worker .param = MSM_PARAM_COMM,
1056*bbecb9d1SAndroid Build Coastguard Worker .value = VOID2U64(&req->payload[0]),
1057*bbecb9d1SAndroid Build Coastguard Worker .len = req->comm_len,
1058*bbecb9d1SAndroid Build Coastguard Worker };
1059*bbecb9d1SAndroid Build Coastguard Worker
1060*bbecb9d1SAndroid Build Coastguard Worker drmCommandWriteRead(mctx->fd, DRM_MSM_SET_PARAM, &set_comm, sizeof(set_comm));
1061*bbecb9d1SAndroid Build Coastguard Worker
1062*bbecb9d1SAndroid Build Coastguard Worker struct drm_msm_param set_cmdline = {
1063*bbecb9d1SAndroid Build Coastguard Worker .pipe = MSM_PIPE_3D0,
1064*bbecb9d1SAndroid Build Coastguard Worker .param = MSM_PARAM_CMDLINE,
1065*bbecb9d1SAndroid Build Coastguard Worker .value = VOID2U64(&req->payload[req->comm_len]),
1066*bbecb9d1SAndroid Build Coastguard Worker .len = req->cmdline_len,
1067*bbecb9d1SAndroid Build Coastguard Worker };
1068*bbecb9d1SAndroid Build Coastguard Worker
1069*bbecb9d1SAndroid Build Coastguard Worker drmCommandWriteRead(mctx->fd, DRM_MSM_SET_PARAM, &set_cmdline, sizeof(set_cmdline));
1070*bbecb9d1SAndroid Build Coastguard Worker
1071*bbecb9d1SAndroid Build Coastguard Worker return 0;
1072*bbecb9d1SAndroid Build Coastguard Worker }
1073*bbecb9d1SAndroid Build Coastguard Worker
1074*bbecb9d1SAndroid Build Coastguard Worker static const struct ccmd {
1075*bbecb9d1SAndroid Build Coastguard Worker const char *name;
1076*bbecb9d1SAndroid Build Coastguard Worker int (*handler)(struct msm_context *mctx, const struct msm_ccmd_req *hdr);
1077*bbecb9d1SAndroid Build Coastguard Worker size_t size;
1078*bbecb9d1SAndroid Build Coastguard Worker } ccmd_dispatch[] = {
1079*bbecb9d1SAndroid Build Coastguard Worker #define HANDLER(N, n) \
1080*bbecb9d1SAndroid Build Coastguard Worker [MSM_CCMD_##N] = {#N, msm_ccmd_##n, sizeof(struct msm_ccmd_##n##_req)}
1081*bbecb9d1SAndroid Build Coastguard Worker HANDLER(NOP, nop),
1082*bbecb9d1SAndroid Build Coastguard Worker HANDLER(IOCTL_SIMPLE, ioctl_simple),
1083*bbecb9d1SAndroid Build Coastguard Worker HANDLER(GEM_NEW, gem_new),
1084*bbecb9d1SAndroid Build Coastguard Worker HANDLER(GEM_SET_IOVA, gem_set_iova),
1085*bbecb9d1SAndroid Build Coastguard Worker HANDLER(GEM_CPU_PREP, gem_cpu_prep),
1086*bbecb9d1SAndroid Build Coastguard Worker HANDLER(GEM_SET_NAME, gem_set_name),
1087*bbecb9d1SAndroid Build Coastguard Worker HANDLER(GEM_SUBMIT, gem_submit),
1088*bbecb9d1SAndroid Build Coastguard Worker HANDLER(GEM_UPLOAD, gem_upload),
1089*bbecb9d1SAndroid Build Coastguard Worker HANDLER(SUBMITQUEUE_QUERY, submitqueue_query),
1090*bbecb9d1SAndroid Build Coastguard Worker HANDLER(WAIT_FENCE, wait_fence),
1091*bbecb9d1SAndroid Build Coastguard Worker HANDLER(SET_DEBUGINFO, set_debuginfo),
1092*bbecb9d1SAndroid Build Coastguard Worker };
1093*bbecb9d1SAndroid Build Coastguard Worker
1094*bbecb9d1SAndroid Build Coastguard Worker static int
submit_cmd_dispatch(struct msm_context * mctx,const struct msm_ccmd_req * hdr)1095*bbecb9d1SAndroid Build Coastguard Worker submit_cmd_dispatch(struct msm_context *mctx, const struct msm_ccmd_req *hdr)
1096*bbecb9d1SAndroid Build Coastguard Worker {
1097*bbecb9d1SAndroid Build Coastguard Worker int ret;
1098*bbecb9d1SAndroid Build Coastguard Worker
1099*bbecb9d1SAndroid Build Coastguard Worker if (hdr->cmd >= ARRAY_SIZE(ccmd_dispatch)) {
1100*bbecb9d1SAndroid Build Coastguard Worker drm_log("invalid cmd: %u", hdr->cmd);
1101*bbecb9d1SAndroid Build Coastguard Worker return -EINVAL;
1102*bbecb9d1SAndroid Build Coastguard Worker }
1103*bbecb9d1SAndroid Build Coastguard Worker
1104*bbecb9d1SAndroid Build Coastguard Worker const struct ccmd *ccmd = &ccmd_dispatch[hdr->cmd];
1105*bbecb9d1SAndroid Build Coastguard Worker
1106*bbecb9d1SAndroid Build Coastguard Worker if (!ccmd->handler) {
1107*bbecb9d1SAndroid Build Coastguard Worker drm_log("no handler: %u", hdr->cmd);
1108*bbecb9d1SAndroid Build Coastguard Worker return -EINVAL;
1109*bbecb9d1SAndroid Build Coastguard Worker }
1110*bbecb9d1SAndroid Build Coastguard Worker
1111*bbecb9d1SAndroid Build Coastguard Worker drm_dbg("%s: hdr={cmd=%u, len=%u, seqno=%u, rsp_off=0x%x)", ccmd->name, hdr->cmd,
1112*bbecb9d1SAndroid Build Coastguard Worker hdr->len, hdr->seqno, hdr->rsp_off);
1113*bbecb9d1SAndroid Build Coastguard Worker
1114*bbecb9d1SAndroid Build Coastguard Worker TRACE_SCOPE_BEGIN(ccmd->name);
1115*bbecb9d1SAndroid Build Coastguard Worker
1116*bbecb9d1SAndroid Build Coastguard Worker /* If the request length from the guest is smaller than the expected
1117*bbecb9d1SAndroid Build Coastguard Worker * size, ie. newer host and older guest, we need to make a copy of
1118*bbecb9d1SAndroid Build Coastguard Worker * the request with the new fields at the end zero initialized.
1119*bbecb9d1SAndroid Build Coastguard Worker */
1120*bbecb9d1SAndroid Build Coastguard Worker if (ccmd->size > hdr->len) {
1121*bbecb9d1SAndroid Build Coastguard Worker uint8_t buf[ccmd->size];
1122*bbecb9d1SAndroid Build Coastguard Worker
1123*bbecb9d1SAndroid Build Coastguard Worker memcpy(&buf[0], hdr, hdr->len);
1124*bbecb9d1SAndroid Build Coastguard Worker memset(&buf[hdr->len], 0, ccmd->size - hdr->len);
1125*bbecb9d1SAndroid Build Coastguard Worker
1126*bbecb9d1SAndroid Build Coastguard Worker ret = ccmd->handler(mctx, (struct msm_ccmd_req *)buf);
1127*bbecb9d1SAndroid Build Coastguard Worker } else {
1128*bbecb9d1SAndroid Build Coastguard Worker ret = ccmd->handler(mctx, hdr);
1129*bbecb9d1SAndroid Build Coastguard Worker }
1130*bbecb9d1SAndroid Build Coastguard Worker
1131*bbecb9d1SAndroid Build Coastguard Worker TRACE_SCOPE_END(ccmd->name);
1132*bbecb9d1SAndroid Build Coastguard Worker
1133*bbecb9d1SAndroid Build Coastguard Worker if (ret) {
1134*bbecb9d1SAndroid Build Coastguard Worker drm_log("%s: dispatch failed: %d (%s)", ccmd->name, ret, strerror(errno));
1135*bbecb9d1SAndroid Build Coastguard Worker return ret;
1136*bbecb9d1SAndroid Build Coastguard Worker }
1137*bbecb9d1SAndroid Build Coastguard Worker
1138*bbecb9d1SAndroid Build Coastguard Worker /* If the response length from the guest is smaller than the
1139*bbecb9d1SAndroid Build Coastguard Worker * expected size, ie. newer host and older guest, then a shadow
1140*bbecb9d1SAndroid Build Coastguard Worker * copy is used, and we need to copy back to the actual rsp
1141*bbecb9d1SAndroid Build Coastguard Worker * buffer.
1142*bbecb9d1SAndroid Build Coastguard Worker */
1143*bbecb9d1SAndroid Build Coastguard Worker struct msm_ccmd_rsp *rsp = msm_context_rsp_noshadow(mctx, hdr);
1144*bbecb9d1SAndroid Build Coastguard Worker if (mctx->current_rsp && (mctx->current_rsp != rsp)) {
1145*bbecb9d1SAndroid Build Coastguard Worker unsigned len = rsp->len;
1146*bbecb9d1SAndroid Build Coastguard Worker memcpy(rsp, mctx->current_rsp, len);
1147*bbecb9d1SAndroid Build Coastguard Worker rsp->len = len;
1148*bbecb9d1SAndroid Build Coastguard Worker free(mctx->current_rsp);
1149*bbecb9d1SAndroid Build Coastguard Worker }
1150*bbecb9d1SAndroid Build Coastguard Worker mctx->current_rsp = NULL;
1151*bbecb9d1SAndroid Build Coastguard Worker
1152*bbecb9d1SAndroid Build Coastguard Worker /* Note that commands with no response, like SET_DEBUGINFO, could
1153*bbecb9d1SAndroid Build Coastguard Worker * be sent before the shmem buffer is allocated:
1154*bbecb9d1SAndroid Build Coastguard Worker */
1155*bbecb9d1SAndroid Build Coastguard Worker if (mctx->shmem) {
1156*bbecb9d1SAndroid Build Coastguard Worker /* TODO better way to do this? We need ACQ_REL semanatics (AFAIU)
1157*bbecb9d1SAndroid Build Coastguard Worker * to ensure that writes to response buffer are visible to the
1158*bbecb9d1SAndroid Build Coastguard Worker * guest process before the update of the seqno. Otherwise we
1159*bbecb9d1SAndroid Build Coastguard Worker * could just use p_atomic_set.
1160*bbecb9d1SAndroid Build Coastguard Worker */
1161*bbecb9d1SAndroid Build Coastguard Worker uint32_t seqno = hdr->seqno;
1162*bbecb9d1SAndroid Build Coastguard Worker p_atomic_xchg(&mctx->shmem->seqno, seqno);
1163*bbecb9d1SAndroid Build Coastguard Worker }
1164*bbecb9d1SAndroid Build Coastguard Worker
1165*bbecb9d1SAndroid Build Coastguard Worker return 0;
1166*bbecb9d1SAndroid Build Coastguard Worker }
1167*bbecb9d1SAndroid Build Coastguard Worker
1168*bbecb9d1SAndroid Build Coastguard Worker static int
msm_renderer_submit_cmd(struct virgl_context * vctx,const void * _buffer,size_t size)1169*bbecb9d1SAndroid Build Coastguard Worker msm_renderer_submit_cmd(struct virgl_context *vctx, const void *_buffer, size_t size)
1170*bbecb9d1SAndroid Build Coastguard Worker {
1171*bbecb9d1SAndroid Build Coastguard Worker struct msm_context *mctx = to_msm_context(vctx);
1172*bbecb9d1SAndroid Build Coastguard Worker const uint8_t *buffer = _buffer;
1173*bbecb9d1SAndroid Build Coastguard Worker
1174*bbecb9d1SAndroid Build Coastguard Worker while (size >= sizeof(struct msm_ccmd_req)) {
1175*bbecb9d1SAndroid Build Coastguard Worker const struct msm_ccmd_req *hdr = (const struct msm_ccmd_req *)buffer;
1176*bbecb9d1SAndroid Build Coastguard Worker
1177*bbecb9d1SAndroid Build Coastguard Worker /* Sanity check first: */
1178*bbecb9d1SAndroid Build Coastguard Worker if ((hdr->len > size) || (hdr->len < sizeof(*hdr)) || (hdr->len % 4)) {
1179*bbecb9d1SAndroid Build Coastguard Worker drm_log("bad size, %u vs %zu (%u)", hdr->len, size, hdr->cmd);
1180*bbecb9d1SAndroid Build Coastguard Worker return -EINVAL;
1181*bbecb9d1SAndroid Build Coastguard Worker }
1182*bbecb9d1SAndroid Build Coastguard Worker
1183*bbecb9d1SAndroid Build Coastguard Worker if (hdr->rsp_off % 4) {
1184*bbecb9d1SAndroid Build Coastguard Worker drm_log("bad rsp_off, %u", hdr->rsp_off);
1185*bbecb9d1SAndroid Build Coastguard Worker return -EINVAL;
1186*bbecb9d1SAndroid Build Coastguard Worker }
1187*bbecb9d1SAndroid Build Coastguard Worker
1188*bbecb9d1SAndroid Build Coastguard Worker int ret = submit_cmd_dispatch(mctx, hdr);
1189*bbecb9d1SAndroid Build Coastguard Worker if (ret) {
1190*bbecb9d1SAndroid Build Coastguard Worker drm_log("dispatch failed: %d (%u)", ret, hdr->cmd);
1191*bbecb9d1SAndroid Build Coastguard Worker return ret;
1192*bbecb9d1SAndroid Build Coastguard Worker }
1193*bbecb9d1SAndroid Build Coastguard Worker
1194*bbecb9d1SAndroid Build Coastguard Worker buffer += hdr->len;
1195*bbecb9d1SAndroid Build Coastguard Worker size -= hdr->len;
1196*bbecb9d1SAndroid Build Coastguard Worker }
1197*bbecb9d1SAndroid Build Coastguard Worker
1198*bbecb9d1SAndroid Build Coastguard Worker if (size > 0) {
1199*bbecb9d1SAndroid Build Coastguard Worker drm_log("bad size, %zu trailing bytes", size);
1200*bbecb9d1SAndroid Build Coastguard Worker return -EINVAL;
1201*bbecb9d1SAndroid Build Coastguard Worker }
1202*bbecb9d1SAndroid Build Coastguard Worker
1203*bbecb9d1SAndroid Build Coastguard Worker return 0;
1204*bbecb9d1SAndroid Build Coastguard Worker }
1205*bbecb9d1SAndroid Build Coastguard Worker
1206*bbecb9d1SAndroid Build Coastguard Worker static int
msm_renderer_get_fencing_fd(struct virgl_context * vctx)1207*bbecb9d1SAndroid Build Coastguard Worker msm_renderer_get_fencing_fd(struct virgl_context *vctx)
1208*bbecb9d1SAndroid Build Coastguard Worker {
1209*bbecb9d1SAndroid Build Coastguard Worker struct msm_context *mctx = to_msm_context(vctx);
1210*bbecb9d1SAndroid Build Coastguard Worker return mctx->eventfd;
1211*bbecb9d1SAndroid Build Coastguard Worker }
1212*bbecb9d1SAndroid Build Coastguard Worker
1213*bbecb9d1SAndroid Build Coastguard Worker static void
msm_renderer_retire_fences(UNUSED struct virgl_context * vctx)1214*bbecb9d1SAndroid Build Coastguard Worker msm_renderer_retire_fences(UNUSED struct virgl_context *vctx)
1215*bbecb9d1SAndroid Build Coastguard Worker {
1216*bbecb9d1SAndroid Build Coastguard Worker /* No-op as VIRGL_RENDERER_ASYNC_FENCE_CB is required */
1217*bbecb9d1SAndroid Build Coastguard Worker }
1218*bbecb9d1SAndroid Build Coastguard Worker
1219*bbecb9d1SAndroid Build Coastguard Worker static int
msm_renderer_submit_fence(struct virgl_context * vctx,uint32_t flags,uint32_t ring_idx,uint64_t fence_id)1220*bbecb9d1SAndroid Build Coastguard Worker msm_renderer_submit_fence(struct virgl_context *vctx, uint32_t flags, uint32_t ring_idx,
1221*bbecb9d1SAndroid Build Coastguard Worker uint64_t fence_id)
1222*bbecb9d1SAndroid Build Coastguard Worker {
1223*bbecb9d1SAndroid Build Coastguard Worker struct msm_context *mctx = to_msm_context(vctx);
1224*bbecb9d1SAndroid Build Coastguard Worker
1225*bbecb9d1SAndroid Build Coastguard Worker drm_dbg("flags=0x%x, ring_idx=%" PRIu32 ", fence_id=%" PRIu64, flags,
1226*bbecb9d1SAndroid Build Coastguard Worker ring_idx, fence_id);
1227*bbecb9d1SAndroid Build Coastguard Worker
1228*bbecb9d1SAndroid Build Coastguard Worker /* timeline is ring_idx-1 (because ring_idx 0 is host CPU timeline) */
1229*bbecb9d1SAndroid Build Coastguard Worker if (ring_idx > nr_timelines) {
1230*bbecb9d1SAndroid Build Coastguard Worker drm_log("invalid ring_idx: %" PRIu32, ring_idx);
1231*bbecb9d1SAndroid Build Coastguard Worker return -EINVAL;
1232*bbecb9d1SAndroid Build Coastguard Worker }
1233*bbecb9d1SAndroid Build Coastguard Worker
1234*bbecb9d1SAndroid Build Coastguard Worker /* ring_idx zero is used for the guest to synchronize with host CPU,
1235*bbecb9d1SAndroid Build Coastguard Worker * meaning by the time ->submit_fence() is called, the fence has
1236*bbecb9d1SAndroid Build Coastguard Worker * already passed.. so just immediate signal:
1237*bbecb9d1SAndroid Build Coastguard Worker */
1238*bbecb9d1SAndroid Build Coastguard Worker if (ring_idx == 0) {
1239*bbecb9d1SAndroid Build Coastguard Worker vctx->fence_retire(vctx, ring_idx, fence_id);
1240*bbecb9d1SAndroid Build Coastguard Worker return 0;
1241*bbecb9d1SAndroid Build Coastguard Worker }
1242*bbecb9d1SAndroid Build Coastguard Worker
1243*bbecb9d1SAndroid Build Coastguard Worker return drm_timeline_submit_fence(&mctx->timelines[ring_idx - 1], flags, fence_id);
1244*bbecb9d1SAndroid Build Coastguard Worker }
1245*bbecb9d1SAndroid Build Coastguard Worker
1246*bbecb9d1SAndroid Build Coastguard Worker struct virgl_context *
msm_renderer_create(int fd)1247*bbecb9d1SAndroid Build Coastguard Worker msm_renderer_create(int fd)
1248*bbecb9d1SAndroid Build Coastguard Worker {
1249*bbecb9d1SAndroid Build Coastguard Worker struct msm_context *mctx;
1250*bbecb9d1SAndroid Build Coastguard Worker
1251*bbecb9d1SAndroid Build Coastguard Worker drm_log("");
1252*bbecb9d1SAndroid Build Coastguard Worker
1253*bbecb9d1SAndroid Build Coastguard Worker mctx = calloc(1, sizeof(*mctx) + (nr_timelines * sizeof(mctx->timelines[0])));
1254*bbecb9d1SAndroid Build Coastguard Worker if (!mctx)
1255*bbecb9d1SAndroid Build Coastguard Worker return NULL;
1256*bbecb9d1SAndroid Build Coastguard Worker
1257*bbecb9d1SAndroid Build Coastguard Worker mctx->fd = fd;
1258*bbecb9d1SAndroid Build Coastguard Worker
1259*bbecb9d1SAndroid Build Coastguard Worker /* Indexed by blob_id, but only lower 32b of blob_id are used: */
1260*bbecb9d1SAndroid Build Coastguard Worker mctx->blob_table = _mesa_hash_table_create_u32_keys(NULL);
1261*bbecb9d1SAndroid Build Coastguard Worker /* Indexed by res_id: */
1262*bbecb9d1SAndroid Build Coastguard Worker mctx->resource_table = _mesa_hash_table_create_u32_keys(NULL);
1263*bbecb9d1SAndroid Build Coastguard Worker /* Indexed by submitqueue-id: */
1264*bbecb9d1SAndroid Build Coastguard Worker mctx->sq_to_ring_idx_table = _mesa_hash_table_create_u32_keys(NULL);
1265*bbecb9d1SAndroid Build Coastguard Worker
1266*bbecb9d1SAndroid Build Coastguard Worker mctx->eventfd = create_eventfd(0);
1267*bbecb9d1SAndroid Build Coastguard Worker
1268*bbecb9d1SAndroid Build Coastguard Worker for (unsigned i = 0; i < nr_timelines; i++) {
1269*bbecb9d1SAndroid Build Coastguard Worker unsigned ring_idx = i + 1; /* ring_idx 0 is host CPU */
1270*bbecb9d1SAndroid Build Coastguard Worker drm_timeline_init(&mctx->timelines[i], &mctx->base, "msm-sync", mctx->eventfd,
1271*bbecb9d1SAndroid Build Coastguard Worker ring_idx);
1272*bbecb9d1SAndroid Build Coastguard Worker }
1273*bbecb9d1SAndroid Build Coastguard Worker
1274*bbecb9d1SAndroid Build Coastguard Worker mctx->base.destroy = msm_renderer_destroy;
1275*bbecb9d1SAndroid Build Coastguard Worker mctx->base.attach_resource = msm_renderer_attach_resource;
1276*bbecb9d1SAndroid Build Coastguard Worker mctx->base.detach_resource = msm_renderer_detach_resource;
1277*bbecb9d1SAndroid Build Coastguard Worker mctx->base.export_opaque_handle = msm_renderer_export_opaque_handle;
1278*bbecb9d1SAndroid Build Coastguard Worker mctx->base.transfer_3d = msm_renderer_transfer_3d;
1279*bbecb9d1SAndroid Build Coastguard Worker mctx->base.get_blob = msm_renderer_get_blob;
1280*bbecb9d1SAndroid Build Coastguard Worker mctx->base.submit_cmd = msm_renderer_submit_cmd;
1281*bbecb9d1SAndroid Build Coastguard Worker mctx->base.get_fencing_fd = msm_renderer_get_fencing_fd;
1282*bbecb9d1SAndroid Build Coastguard Worker mctx->base.retire_fences = msm_renderer_retire_fences;
1283*bbecb9d1SAndroid Build Coastguard Worker mctx->base.submit_fence = msm_renderer_submit_fence;
1284*bbecb9d1SAndroid Build Coastguard Worker
1285*bbecb9d1SAndroid Build Coastguard Worker return &mctx->base;
1286*bbecb9d1SAndroid Build Coastguard Worker }
1287