xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/vc4/vc4_simulator.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2014 Broadcom
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 /**
25  * @file vc4_simulator.c
26  *
27  * Implements VC4 simulation on top of a non-VC4 GEM fd.
28  *
29  * This file's goal is to emulate the VC4 ioctls' behavior in the kernel on
30  * top of the simpenrose software simulator.  Generally, VC4 driver BOs have a
31  * GEM-side copy of their contents and a simulator-side memory area that the
32  * GEM contents get copied into during simulation.  Once simulation is done,
33  * the simulator's data is copied back out to the GEM BOs, so that rendering
34  * appears on the screen as if actual hardware rendering had been done.
35  *
36  * One of the limitations of this code is that we shouldn't really need a
37  * GEM-side BO for non-window-system BOs.  However, do we need unique BO
38  * handles for each of our GEM bos so that this file can look up its state
39  * from the handle passed in at submit ioctl time (also, a couple of places
40  * outside of this file still call ioctls directly on the fd).
41  *
42  * Another limitation is that BO import doesn't work unless the underlying
43  * window system's BO size matches what VC4 is going to use, which of course
44  * doesn't work out in practice.  This means that for now, only DRI3 (VC4
45  * makes the winsys BOs) is supported, not DRI2 (window system makes the winys
46  * BOs).
47  */
48 
49 #ifdef USE_VC4_SIMULATOR
50 
51 #include <sys/mman.h>
52 #include "xf86drm.h"
53 #include "util/u_memory.h"
54 #include "util/u_mm.h"
55 #include "util/ralloc.h"
56 #include "util/simple_mtx.h"
57 
58 #include "vc4_screen.h"
59 #include "vc4_cl_dump.h"
60 #include "vc4_context.h"
61 #include "kernel/vc4_drv.h"
62 #include "vc4_simulator_validate.h"
63 #include "simpenrose/simpenrose.h"
64 
65 #include "drm-uapi/amdgpu_drm.h"
66 #include "drm-uapi/i915_drm.h"
67 
68 /** Global (across GEM fds) state for the simulator */
69 static struct vc4_simulator_state {
70         simple_mtx_t mutex;
71 
72         void *mem;
73         ssize_t mem_size;
74         struct mem_block *heap;
75         struct mem_block *overflow;
76 
77         /** Mapping from GEM handle to struct vc4_simulator_bo * */
78         struct hash_table *fd_map;
79 
80         int refcount;
81 } sim_state = {
82         .mutex = SIMPLE_MTX_INITIALIZER,
83 };
84 
85 enum gem_type {
86         GEM_I915,
87         GEM_AMDGPU,
88         GEM_DUMB
89 };
90 
91 /** Per-GEM-fd state for the simulator. */
92 struct vc4_simulator_file {
93         int fd;
94 
95         /* This is weird -- we make a "vc4_device" per file, even though on
96          * the kernel side this is a global.  We do this so that kernel code
97          * calling us for BO allocation can get to our screen.
98          */
99         struct drm_device dev;
100 
101         /** Mapping from GEM handle to struct vc4_simulator_bo * */
102         struct hash_table *bo_map;
103 
104         /** for specific gpus, use their create ioctl. Otherwise use dumb bo. */
105         enum gem_type gem_type;
106 };
107 
108 /** Wrapper for drm_vc4_bo tracking the simulator-specific state. */
109 struct vc4_simulator_bo {
110         struct drm_vc4_bo base;
111         struct vc4_simulator_file *file;
112 
113         /** Area for this BO within sim_state->mem */
114         struct mem_block *block;
115 
116         int handle;
117 
118         /* Mapping of the underlying GEM object that we copy in/out of
119          * simulator memory.
120          */
121         void *gem_vaddr;
122 };
123 
124 static void *
int_to_key(int key)125 int_to_key(int key)
126 {
127         return (void *)(uintptr_t)key;
128 }
129 
130 static struct vc4_simulator_file *
vc4_get_simulator_file_for_fd(int fd)131 vc4_get_simulator_file_for_fd(int fd)
132 {
133         struct hash_entry *entry = _mesa_hash_table_search(sim_state.fd_map,
134                                                            int_to_key(fd + 1));
135         return entry ? entry->data : NULL;
136 }
137 
138 /* A marker placed just after each BO, then checked after rendering to make
139  * sure it's still there.
140  */
141 #define BO_SENTINEL		0xfedcba98
142 
143 #define PAGE_ALIGN2		12
144 
145 static int
vc4_gem_mmap(int fd,uint32_t handle,uint64_t * offset)146 vc4_gem_mmap(int fd, uint32_t handle, uint64_t *offset)
147 {
148         struct vc4_simulator_file *file = vc4_get_simulator_file_for_fd(fd);
149         int ret;
150 
151         assert(offset);
152 
153         switch (file->gem_type) {
154         case GEM_I915:
155         {
156                 struct drm_i915_gem_mmap_gtt map = {
157                         .handle = handle,
158                 };
159                 ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &map);
160                 *offset = map.offset;
161                 break;
162         }
163         case GEM_AMDGPU:
164         {
165                 union drm_amdgpu_gem_mmap map = { 0 };
166                 map.in.handle = handle;
167                 ret = drmIoctl(fd, DRM_IOCTL_AMDGPU_GEM_MMAP, &map);
168                 *offset = map.out.addr_ptr;
169                 break;
170         }
171         default:
172         {
173                 struct drm_mode_map_dumb map = {
174                         .handle = handle,
175                 };
176                 ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);
177                 *offset = map.offset;
178         }
179         }
180 
181         return ret;
182 }
183 
184 static int
vc4_gem_create(int fd,uint64_t size,uint32_t * handle)185 vc4_gem_create(int fd, uint64_t size, uint32_t *handle)
186 {
187         struct vc4_simulator_file *file = vc4_get_simulator_file_for_fd(fd);
188         int ret;
189 
190         assert(handle);
191 
192         switch (file->gem_type) {
193         case GEM_I915:
194         {
195                 struct drm_i915_gem_create create = {
196                         .size = size,
197                 };
198                 ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
199                 *handle = create.handle;
200                 break;
201         }
202         case GEM_AMDGPU:
203         {
204                 union drm_amdgpu_gem_create create = { 0 };
205                 create.in.bo_size = size;
206                 ret = drmIoctl(fd, DRM_IOCTL_AMDGPU_GEM_CREATE, &create);
207                 *handle = create.out.handle;
208                 break;
209         }
210         default:
211         {
212                 struct drm_mode_create_dumb create = {
213                         .width = 128,
214                         .bpp = 8,
215                         .height = (size + 127) / 128,
216                 };
217                 ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);
218                 assert(create.size >= size);
219                 *handle = create.handle;
220         }
221         }
222 
223         return ret;
224 }
225 
226 /**
227  * Allocates space in simulator memory and returns a tracking struct for it
228  * that also contains the drm_gem_cma_object struct.
229  */
230 static struct vc4_simulator_bo *
vc4_create_simulator_bo(int fd,int handle,unsigned size)231 vc4_create_simulator_bo(int fd, int handle, unsigned size)
232 {
233         struct vc4_simulator_file *file = vc4_get_simulator_file_for_fd(fd);
234         struct vc4_simulator_bo *sim_bo = rzalloc(file,
235                                                   struct vc4_simulator_bo);
236         struct drm_vc4_bo *bo = &sim_bo->base;
237         struct drm_gem_cma_object *obj = &bo->base;
238         size = align(size, 4096);
239 
240         sim_bo->file = file;
241         sim_bo->handle = handle;
242 
243         /* Allocate space for the buffer in simulator memory. */
244         simple_mtx_lock(&sim_state.mutex);
245         sim_bo->block = u_mmAllocMem(sim_state.heap, size + 4, PAGE_ALIGN2, 0);
246         simple_mtx_unlock(&sim_state.mutex);
247         assert(sim_bo->block);
248 
249         obj->base.size = size;
250         obj->base.dev = &file->dev;
251         obj->vaddr = sim_state.mem + sim_bo->block->ofs;
252         obj->paddr = simpenrose_hw_addr(obj->vaddr);
253 
254         *(uint32_t *)(obj->vaddr + size) = BO_SENTINEL;
255 
256         /* A handle of 0 is used for vc4_gem.c internal allocations that
257          * don't need to go in the lookup table.
258          */
259         if (handle != 0) {
260                 simple_mtx_lock(&sim_state.mutex);
261                 _mesa_hash_table_insert(file->bo_map, int_to_key(handle), bo);
262                 simple_mtx_unlock(&sim_state.mutex);
263 
264                 /* Map the GEM buffer for copy in/out to the simulator. */
265                 uint64_t mmap_offset;
266                 int ret = vc4_gem_mmap(fd, handle, &mmap_offset);
267 
268                 if (ret) {
269                         fprintf(stderr, "Failed to get MMAP offset: %d\n",
270                                 errno);
271                         abort();
272                 }
273                 sim_bo->gem_vaddr = mmap(NULL, obj->base.size,
274                                          PROT_READ | PROT_WRITE, MAP_SHARED,
275                                          fd, mmap_offset);
276                 if (sim_bo->gem_vaddr == MAP_FAILED) {
277                         fprintf(stderr, "mmap of bo %d (offset 0x%016llx, size %d) failed\n",
278                                 handle, (long long)mmap_offset, (int)obj->base.size);
279                         abort();
280                 }
281         }
282 
283         return sim_bo;
284 }
285 
286 static void
vc4_free_simulator_bo(struct vc4_simulator_bo * sim_bo)287 vc4_free_simulator_bo(struct vc4_simulator_bo *sim_bo)
288 {
289         struct vc4_simulator_file *sim_file = sim_bo->file;
290         struct drm_vc4_bo *bo = &sim_bo->base;
291         struct drm_gem_cma_object *obj = &bo->base;
292 
293         if (bo->validated_shader) {
294                 free(bo->validated_shader->texture_samples);
295                 free(bo->validated_shader);
296         }
297 
298         if (sim_bo->gem_vaddr)
299                 munmap(sim_bo->gem_vaddr, obj->base.size);
300 
301         simple_mtx_lock(&sim_state.mutex);
302         u_mmFreeMem(sim_bo->block);
303         if (sim_bo->handle) {
304                 _mesa_hash_table_remove_key(sim_file->bo_map,
305                                             int_to_key(sim_bo->handle));
306         }
307         simple_mtx_unlock(&sim_state.mutex);
308         ralloc_free(sim_bo);
309 }
310 
311 static struct vc4_simulator_bo *
vc4_get_simulator_bo(struct vc4_simulator_file * file,int gem_handle)312 vc4_get_simulator_bo(struct vc4_simulator_file *file, int gem_handle)
313 {
314         simple_mtx_lock(&sim_state.mutex);
315         struct hash_entry *entry =
316                 _mesa_hash_table_search(file->bo_map, int_to_key(gem_handle));
317         simple_mtx_unlock(&sim_state.mutex);
318 
319         return entry ? entry->data : NULL;
320 }
321 
322 struct drm_gem_cma_object *
drm_gem_cma_create(struct drm_device * dev,size_t size)323 drm_gem_cma_create(struct drm_device *dev, size_t size)
324 {
325         struct vc4_screen *screen = dev->screen;
326         struct vc4_simulator_bo *sim_bo = vc4_create_simulator_bo(screen->fd,
327                                                                   0, size);
328         return &sim_bo->base.base;
329 }
330 
331 static int
vc4_simulator_pin_bos(struct vc4_simulator_file * file,struct vc4_exec_info * exec)332 vc4_simulator_pin_bos(struct vc4_simulator_file *file,
333                       struct vc4_exec_info *exec)
334 {
335         struct drm_vc4_submit_cl *args = exec->args;
336         uint32_t *bo_handles = (uint32_t *)(uintptr_t)args->bo_handles;
337 
338         exec->bo_count = args->bo_handle_count;
339         exec->bo = calloc(exec->bo_count, sizeof(void *));
340         for (int i = 0; i < exec->bo_count; i++) {
341                 struct vc4_simulator_bo *sim_bo =
342                         vc4_get_simulator_bo(file, bo_handles[i]);
343                 struct drm_vc4_bo *drm_bo = &sim_bo->base;
344                 struct drm_gem_cma_object *obj = &drm_bo->base;
345 
346                 memcpy(obj->vaddr, sim_bo->gem_vaddr, obj->base.size);
347 
348                 exec->bo[i] = obj;
349         }
350         return 0;
351 }
352 
353 static int
vc4_simulator_unpin_bos(struct vc4_exec_info * exec)354 vc4_simulator_unpin_bos(struct vc4_exec_info *exec)
355 {
356         for (int i = 0; i < exec->bo_count; i++) {
357                 struct drm_gem_cma_object *obj = exec->bo[i];
358                 struct drm_vc4_bo *drm_bo = to_vc4_bo(&obj->base);
359                 struct vc4_simulator_bo *sim_bo =
360                         (struct vc4_simulator_bo *)drm_bo;
361 
362                 assert(*(uint32_t *)(obj->vaddr +
363                                      obj->base.size) == BO_SENTINEL);
364                 if (sim_bo->gem_vaddr)
365                         memcpy(sim_bo->gem_vaddr, obj->vaddr, obj->base.size);
366         }
367 
368         free(exec->bo);
369 
370         return 0;
371 }
372 
373 static void
vc4_dump_to_file(struct vc4_exec_info * exec)374 vc4_dump_to_file(struct vc4_exec_info *exec)
375 {
376         static int dumpno = 0;
377         struct drm_vc4_get_hang_state *state;
378         struct drm_vc4_get_hang_state_bo *bo_state;
379         unsigned int dump_version = 0;
380 
381         if (!VC4_DBG(DUMP))
382                 return;
383 
384         state = calloc(1, sizeof(*state));
385 
386         int unref_count = 0;
387         list_for_each_entry_safe(struct drm_vc4_bo, bo, &exec->unref_list,
388                                  unref_head) {
389                 unref_count++;
390         }
391 
392         /* Add one more for the overflow area that isn't wrapped in a BO. */
393         state->bo_count = exec->bo_count + unref_count + 1;
394         bo_state = calloc(state->bo_count, sizeof(*bo_state));
395 
396         char *filename = NULL;
397         asprintf(&filename, "vc4-dri-%d.dump", dumpno++);
398         FILE *f = fopen(filename, "w+");
399         if (!f) {
400                 fprintf(stderr, "Couldn't open %s: %s", filename,
401                         strerror(errno));
402                 return;
403         }
404 
405         fwrite(&dump_version, sizeof(dump_version), 1, f);
406 
407         state->ct0ca = exec->ct0ca;
408         state->ct0ea = exec->ct0ea;
409         state->ct1ca = exec->ct1ca;
410         state->ct1ea = exec->ct1ea;
411         state->start_bin = exec->ct0ca;
412         state->start_render = exec->ct1ca;
413         fwrite(state, sizeof(*state), 1, f);
414 
415         int i;
416         for (i = 0; i < exec->bo_count; i++) {
417                 struct drm_gem_cma_object *cma_bo = exec->bo[i];
418                 bo_state[i].handle = i; /* Not used by the parser. */
419                 bo_state[i].paddr = cma_bo->paddr;
420                 bo_state[i].size = cma_bo->base.size;
421         }
422 
423         list_for_each_entry_safe(struct drm_vc4_bo, bo, &exec->unref_list,
424                                  unref_head) {
425                 struct drm_gem_cma_object *cma_bo = &bo->base;
426                 bo_state[i].handle = 0;
427                 bo_state[i].paddr = cma_bo->paddr;
428                 bo_state[i].size = cma_bo->base.size;
429                 i++;
430         }
431 
432         /* Add the static overflow memory area. */
433         bo_state[i].handle = exec->bo_count;
434         bo_state[i].paddr = sim_state.overflow->ofs;
435         bo_state[i].size = sim_state.overflow->size;
436         i++;
437 
438         fwrite(bo_state, sizeof(*bo_state), state->bo_count, f);
439 
440         for (int i = 0; i < exec->bo_count; i++) {
441                 struct drm_gem_cma_object *cma_bo = exec->bo[i];
442                 fwrite(cma_bo->vaddr, cma_bo->base.size, 1, f);
443         }
444 
445         list_for_each_entry_safe(struct drm_vc4_bo, bo, &exec->unref_list,
446                                  unref_head) {
447                 struct drm_gem_cma_object *cma_bo = &bo->base;
448                 fwrite(cma_bo->vaddr, cma_bo->base.size, 1, f);
449         }
450 
451         void *overflow = calloc(1, sim_state.overflow->size);
452         fwrite(overflow, 1, sim_state.overflow->size, f);
453         free(overflow);
454 
455         free(state);
456         free(bo_state);
457         fclose(f);
458 }
459 
460 static int
vc4_simulator_submit_cl_ioctl(int fd,struct drm_vc4_submit_cl * args)461 vc4_simulator_submit_cl_ioctl(int fd, struct drm_vc4_submit_cl *args)
462 {
463         struct vc4_simulator_file *file = vc4_get_simulator_file_for_fd(fd);
464         struct vc4_exec_info exec;
465         struct drm_device *dev = &file->dev;
466         int ret;
467 
468         memset(&exec, 0, sizeof(exec));
469         list_inithead(&exec.unref_list);
470 
471         exec.args = args;
472 
473         ret = vc4_simulator_pin_bos(file, &exec);
474         if (ret)
475                 return ret;
476 
477         ret = vc4_cl_validate(dev, &exec);
478         if (ret)
479                 return ret;
480 
481         if (VC4_DBG(CL)) {
482                 fprintf(stderr, "RCL:\n");
483                 vc4_dump_cl(sim_state.mem + exec.ct1ca,
484                             exec.ct1ea - exec.ct1ca, true);
485         }
486 
487         vc4_dump_to_file(&exec);
488 
489         if (exec.ct0ca != exec.ct0ea) {
490                 int bfc = simpenrose_do_binning(exec.ct0ca, exec.ct0ea);
491                 if (bfc != 1) {
492                         fprintf(stderr, "Binning returned %d flushes, should be 1.\n",
493                                 bfc);
494                         fprintf(stderr, "Relocated binning command list:\n");
495                         vc4_dump_cl(sim_state.mem + exec.ct0ca,
496                                     exec.ct0ea - exec.ct0ca, false);
497                         abort();
498                 }
499         }
500         int rfc = simpenrose_do_rendering(exec.ct1ca, exec.ct1ea);
501         if (rfc != 1) {
502                 fprintf(stderr, "Rendering returned %d frames, should be 1.\n",
503                         rfc);
504                 fprintf(stderr, "Relocated render command list:\n");
505                 vc4_dump_cl(sim_state.mem + exec.ct1ca,
506                             exec.ct1ea - exec.ct1ca, true);
507                 abort();
508         }
509 
510         ret = vc4_simulator_unpin_bos(&exec);
511         if (ret)
512                 return ret;
513 
514         list_for_each_entry_safe(struct drm_vc4_bo, bo, &exec.unref_list,
515                                  unref_head) {
516                 struct vc4_simulator_bo *sim_bo = (struct vc4_simulator_bo *)bo;
517                 ASSERTED struct drm_gem_cma_object *obj = &sim_bo->base.base;
518 		list_del(&bo->unref_head);
519                 assert(*(uint32_t *)(obj->vaddr + obj->base.size) ==
520                        BO_SENTINEL);
521                 vc4_free_simulator_bo(sim_bo);
522         }
523 
524         return 0;
525 }
526 
527 /**
528  * Do fixups after a BO has been opened from a handle.
529  *
530  * This could be done at DRM_IOCTL_GEM_OPEN/DRM_IOCTL_GEM_PRIME_FD_TO_HANDLE
531  * time, but we're still using drmPrimeFDToHandle() so we have this helper to
532  * be called afterward instead.
533  */
vc4_simulator_open_from_handle(int fd,int handle,uint32_t size)534 void vc4_simulator_open_from_handle(int fd, int handle, uint32_t size)
535 {
536         vc4_create_simulator_bo(fd, handle, size);
537 }
538 
539 /**
540  * Simulated ioctl(fd, DRM_VC4_CREATE_BO) implementation.
541  *
542  * Making a VC4 BO is just a matter of making a corresponding BO on the host.
543  */
544 static int
vc4_simulator_create_bo_ioctl(int fd,struct drm_vc4_create_bo * args)545 vc4_simulator_create_bo_ioctl(int fd, struct drm_vc4_create_bo *args)
546 {
547         int ret = vc4_gem_create(fd, args->size, &(args->handle));
548 
549         vc4_create_simulator_bo(fd, args->handle, args->size);
550 
551         return ret;
552 }
553 
554 /**
555  * Simulated ioctl(fd, DRM_VC4_CREATE_SHADER_BO) implementation.
556  *
557  * In simulation we defer shader validation until exec time.  Just make a host
558  * BO and memcpy the contents in.
559  */
560 static int
vc4_simulator_create_shader_bo_ioctl(int fd,struct drm_vc4_create_shader_bo * args)561 vc4_simulator_create_shader_bo_ioctl(int fd,
562                                      struct drm_vc4_create_shader_bo *args)
563 {
564         int ret = vc4_gem_create(fd, args->size, &(args->handle));
565 
566         if (ret)
567                 return ret;
568 
569         struct vc4_simulator_bo *sim_bo =
570                 vc4_create_simulator_bo(fd, args->handle, args->size);
571         struct drm_vc4_bo *drm_bo = &sim_bo->base;
572         struct drm_gem_cma_object *obj = &drm_bo->base;
573 
574         /* Copy into the simulator's BO for validation. */
575         memcpy(obj->vaddr, (void *)(uintptr_t)args->data, args->size);
576 
577         /* Copy into the GEM BO to prevent the simulator_pin_bos() from
578          * smashing it.
579          */
580         memcpy(sim_bo->gem_vaddr, (void *)(uintptr_t)args->data, args->size);
581 
582         drm_bo->validated_shader = vc4_validate_shader(obj);
583         if (!drm_bo->validated_shader)
584                 return -EINVAL;
585 
586         return 0;
587 }
588 
589 /**
590  * Simulated ioctl(fd, DRM_VC4_MMAP_BO) implementation.
591  *
592  * We just pass this straight through to dumb mmap.
593  */
594 static int
vc4_simulator_mmap_bo_ioctl(int fd,struct drm_vc4_mmap_bo * args)595 vc4_simulator_mmap_bo_ioctl(int fd, struct drm_vc4_mmap_bo *args)
596 {
597         uint64_t mmap_offset;
598         int ret = vc4_gem_mmap(fd, args->handle, &mmap_offset);
599         args->offset = mmap_offset;
600 
601         return ret;
602 }
603 
604 static int
vc4_simulator_gem_close_ioctl(int fd,struct drm_gem_close * args)605 vc4_simulator_gem_close_ioctl(int fd, struct drm_gem_close *args)
606 {
607         /* Free the simulator's internal tracking. */
608         struct vc4_simulator_file *file = vc4_get_simulator_file_for_fd(fd);
609         struct vc4_simulator_bo *sim_bo = vc4_get_simulator_bo(file,
610                                                                args->handle);
611 
612         vc4_free_simulator_bo(sim_bo);
613 
614         /* Pass the call on down. */
615         return drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, args);
616 }
617 
618 static int
vc4_simulator_get_param_ioctl(int fd,struct drm_vc4_get_param * args)619 vc4_simulator_get_param_ioctl(int fd, struct drm_vc4_get_param *args)
620 {
621         switch (args->param) {
622         case DRM_VC4_PARAM_SUPPORTS_BRANCHES:
623         case DRM_VC4_PARAM_SUPPORTS_ETC1:
624         case DRM_VC4_PARAM_SUPPORTS_THREADED_FS:
625         case DRM_VC4_PARAM_SUPPORTS_FIXED_RCL_ORDER:
626                 args->value = true;
627                 return 0;
628 
629         case DRM_VC4_PARAM_SUPPORTS_MADVISE:
630         case DRM_VC4_PARAM_SUPPORTS_PERFMON:
631                 errno = -EINVAL;
632                 return -1;
633 
634         case DRM_VC4_PARAM_V3D_IDENT0:
635                 args->value = 0x02000000;
636                 return 0;
637 
638         case DRM_VC4_PARAM_V3D_IDENT1:
639                 args->value = 0x00000001;
640                 return 0;
641 
642         default:
643                 fprintf(stderr, "Unknown DRM_IOCTL_VC4_GET_PARAM(%lld)\n",
644                         (long long)args->param);
645                 abort();
646         };
647 }
648 
649 int
vc4_simulator_ioctl(int fd,unsigned long request,void * args)650 vc4_simulator_ioctl(int fd, unsigned long request, void *args)
651 {
652         switch (request) {
653         case DRM_IOCTL_VC4_SUBMIT_CL:
654                 return vc4_simulator_submit_cl_ioctl(fd, args);
655         case DRM_IOCTL_VC4_CREATE_BO:
656                 return vc4_simulator_create_bo_ioctl(fd, args);
657         case DRM_IOCTL_VC4_CREATE_SHADER_BO:
658                 return vc4_simulator_create_shader_bo_ioctl(fd, args);
659         case DRM_IOCTL_VC4_MMAP_BO:
660                 return vc4_simulator_mmap_bo_ioctl(fd, args);
661 
662         case DRM_IOCTL_VC4_WAIT_BO:
663         case DRM_IOCTL_VC4_WAIT_SEQNO:
664                 /* We do all of the vc4 rendering synchronously, so we just
665                  * return immediately on the wait ioctls.  This ignores any
666                  * native rendering to the host BO, so it does mean we race on
667                  * front buffer rendering.
668                  */
669                 return 0;
670 
671         case DRM_IOCTL_VC4_LABEL_BO:
672                 /* This is just debug information, nothing to do. */
673                 return 0;
674 
675         case DRM_IOCTL_VC4_GET_TILING:
676         case DRM_IOCTL_VC4_SET_TILING:
677                 /* Disable these for now, since the sharing with i965 requires
678                  * linear buffers.
679                  */
680                 errno = -EINVAL;
681                 return -1;
682 
683         case DRM_IOCTL_VC4_GET_PARAM:
684                 return vc4_simulator_get_param_ioctl(fd, args);
685 
686         case DRM_IOCTL_GEM_CLOSE:
687                 return vc4_simulator_gem_close_ioctl(fd, args);
688 
689         case DRM_IOCTL_GEM_OPEN:
690         case DRM_IOCTL_GEM_FLINK:
691                 return drmIoctl(fd, request, args);
692         default:
693                 fprintf(stderr, "Unknown ioctl 0x%08x\n", (int)request);
694                 abort();
695         }
696 }
697 
698 static void
vc4_simulator_init_global(void)699 vc4_simulator_init_global(void)
700 {
701         simple_mtx_lock(&sim_state.mutex);
702         if (sim_state.refcount++) {
703                 simple_mtx_unlock(&sim_state.mutex);
704                 return;
705         }
706 
707         sim_state.mem_size = 256 * 1024 * 1024;
708         sim_state.mem = calloc(sim_state.mem_size, 1);
709         if (!sim_state.mem)
710                 abort();
711         sim_state.heap = u_mmInit(0, sim_state.mem_size);
712 
713         /* We supply our own memory so that we can have more aperture
714          * available (256MB instead of simpenrose's default 64MB).
715          */
716         simpenrose_init_hardware_supply_mem(sim_state.mem, sim_state.mem_size);
717 
718         /* Carve out low memory for tile allocation overflow.  The kernel
719          * should be automatically handling overflow memory setup on real
720          * hardware, but for simulation we just get one shot to set up enough
721          * overflow memory before execution.  This overflow mem will be used
722          * up over the whole lifetime of simpenrose (not reused on each
723          * flush), so it had better be big.
724          */
725         sim_state.overflow = u_mmAllocMem(sim_state.heap, 32 * 1024 * 1024,
726                                           PAGE_ALIGN2, 0);
727         simpenrose_supply_overflow_mem(sim_state.overflow->ofs,
728                                        sim_state.overflow->size);
729 
730         simple_mtx_unlock(&sim_state.mutex);
731 
732         sim_state.fd_map =
733                 _mesa_hash_table_create(NULL,
734                                         _mesa_hash_pointer,
735                                         _mesa_key_pointer_equal);
736 }
737 
738 void
vc4_simulator_init(struct vc4_screen * screen)739 vc4_simulator_init(struct vc4_screen *screen)
740 {
741         vc4_simulator_init_global();
742 
743         screen->sim_file = rzalloc(screen, struct vc4_simulator_file);
744 
745         screen->sim_file->bo_map =
746                 _mesa_hash_table_create(screen->sim_file,
747                                         _mesa_hash_pointer,
748                                         _mesa_key_pointer_equal);
749 
750         drmVersionPtr version = drmGetVersion(screen->fd);
751         if (version && strncmp(version->name, "i915", version->name_len) == 0)
752                 screen->sim_file->gem_type = GEM_I915;
753         else if (version && strncmp(version->name, "amdgpu", version->name_len) == 0)
754                 screen->sim_file->gem_type = GEM_AMDGPU;
755         else
756                 screen->sim_file->gem_type = GEM_DUMB;
757         drmFreeVersion(version);
758         simple_mtx_lock(&sim_state.mutex);
759         _mesa_hash_table_insert(sim_state.fd_map, int_to_key(screen->fd + 1),
760                                 screen->sim_file);
761         simple_mtx_unlock(&sim_state.mutex);
762 
763         screen->sim_file->dev.screen = screen;
764 }
765 
766 void
vc4_simulator_destroy(struct vc4_screen * screen)767 vc4_simulator_destroy(struct vc4_screen *screen)
768 {
769         simple_mtx_lock(&sim_state.mutex);
770         if (!--sim_state.refcount) {
771                 _mesa_hash_table_destroy(sim_state.fd_map, NULL);
772                 u_mmDestroy(sim_state.heap);
773                 free(sim_state.mem);
774                 /* No memsetting it, because it contains the mutex. */
775         }
776         simple_mtx_unlock(&sim_state.mutex);
777 }
778 
779 #endif /* USE_VC4_SIMULATOR */
780