xref: /aosp_15_r20/external/virglrenderer/src/drm/msm/msm_renderer.c (revision bbecb9d118dfdb95f99bd754f8fa9be01f189df3)
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