xref: /aosp_15_r20/external/mesa3d/src/imagination/vulkan/winsys/pvrsrvkm/pvr_srv.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2022 Imagination Technologies Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * 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 THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 
24 #include <assert.h>
25 #include <stdbool.h>
26 #include <stdint.h>
27 #include <xf86drm.h>
28 
29 #include "hwdef/rogue_hw_utils.h"
30 #include "pvr_csb.h"
31 #include "pvr_device_info.h"
32 #include "pvr_private.h"
33 #include "pvr_srv.h"
34 #include "pvr_srv_bo.h"
35 #include "pvr_srv_bridge.h"
36 #include "pvr_srv_job_common.h"
37 #include "pvr_srv_job_compute.h"
38 #include "pvr_srv_job_render.h"
39 #include "pvr_srv_job_transfer.h"
40 #include "pvr_srv_public.h"
41 #include "pvr_srv_sync.h"
42 #include "pvr_srv_sync_prim.h"
43 #include "pvr_srv_job_null.h"
44 #include "pvr_types.h"
45 #include "pvr_winsys.h"
46 #include "pvr_winsys_helper.h"
47 #include "util/log.h"
48 #include "util/macros.h"
49 #include "util/os_misc.h"
50 #include "util/u_atomic.h"
51 #include "vk_log.h"
52 #include "vk_sync.h"
53 #include "vk_sync_timeline.h"
54 
55 /* carveout_size can be 0 when no carveout is needed. carveout_address must
56  * be 0 if carveout_size is 0.
57  */
pvr_winsys_heap_init(struct pvr_winsys * const ws,pvr_dev_addr_t base_address,uint64_t size,pvr_dev_addr_t carveout_address,uint64_t carveout_size,uint32_t log2_page_size,const struct pvr_winsys_static_data_offsets * const static_data_offsets,struct pvr_winsys_heap * const heap)58 static VkResult pvr_winsys_heap_init(
59    struct pvr_winsys *const ws,
60    pvr_dev_addr_t base_address,
61    uint64_t size,
62    pvr_dev_addr_t carveout_address,
63    uint64_t carveout_size,
64    uint32_t log2_page_size,
65    const struct pvr_winsys_static_data_offsets *const static_data_offsets,
66    struct pvr_winsys_heap *const heap)
67 {
68    const bool carveout_area_bottom_of_heap = carveout_address.addr ==
69                                              base_address.addr;
70    const pvr_dev_addr_t vma_heap_begin_addr =
71       carveout_area_bottom_of_heap
72          ? PVR_DEV_ADDR_OFFSET(base_address, carveout_size)
73          : base_address;
74    const uint64_t vma_heap_size = size - carveout_size;
75 
76    assert(base_address.addr);
77    assert(carveout_size <= size);
78 
79    /* As per the static_data_carveout_base powervr-km uapi documentation the
80     * carveout region can only be at the beginning of the heap or at the end.
81     * carveout_address is 0 if there is no carveout region.
82     * pvrsrv-km doesn't explicitly provide this info and it's assumed that it's
83     * always at the beginning.
84     */
85    assert(carveout_area_bottom_of_heap ||
86           carveout_address.addr + carveout_size == base_address.addr + size ||
87           (!carveout_address.addr && !carveout_size));
88 
89    heap->ws = ws;
90    heap->base_addr = base_address;
91    heap->static_data_carveout_addr = carveout_address;
92 
93    heap->size = size;
94    heap->static_data_carveout_size = carveout_size;
95 
96    heap->page_size = 1 << log2_page_size;
97    heap->log2_page_size = log2_page_size;
98 
99    util_vma_heap_init(&heap->vma_heap, vma_heap_begin_addr.addr, vma_heap_size);
100 
101    heap->vma_heap.alloc_high = false;
102 
103    /* It's expected that the heap destroy function to be the last thing that's
104     * called, so we start the ref_count at 0.
105     */
106    p_atomic_set(&heap->ref_count, 0);
107 
108    if (pthread_mutex_init(&heap->lock, NULL))
109       return vk_error(NULL, VK_ERROR_INITIALIZATION_FAILED);
110 
111    heap->static_data_offsets = *static_data_offsets;
112 
113    return VK_SUCCESS;
114 }
115 
116 /**
117  * Maximum PB free list size supported by RGX and Services.
118  *
119  * Maximum PB free list size must ensure that no PM address space can be fully
120  * used, because if the full address space was used it would wrap and corrupt
121  * itself. Since there are two freelists (local is always minimum sized) this
122  * can be described as following three conditions being met:
123  *
124  *  Minimum PB + Maximum PB < ALIST PM address space size (16GB)
125  *  Minimum PB + Maximum PB < TE PM address space size (16GB) / NUM_TE_PIPES
126  *  Minimum PB + Maximum PB < VCE PM address space size (16GB) / NUM_VCE_PIPES
127  *
128  * Since the max of NUM_TE_PIPES and NUM_VCE_PIPES is 4, we have a hard limit
129  * of 4GB minus the Minimum PB. For convenience we take the smaller power-of-2
130  * value of 2GB. This is far more than any normal application would request
131  * or use.
132  */
133 #define PVR_SRV_FREE_LIST_MAX_SIZE (2ULL * 1024ULL * 1024ULL * 1024ULL)
134 
pvr_srv_heap_init(struct pvr_srv_winsys * srv_ws,struct pvr_srv_winsys_heap * srv_heap,uint32_t heap_idx,const struct pvr_winsys_static_data_offsets * const static_data_offsets)135 static VkResult pvr_srv_heap_init(
136    struct pvr_srv_winsys *srv_ws,
137    struct pvr_srv_winsys_heap *srv_heap,
138    uint32_t heap_idx,
139    const struct pvr_winsys_static_data_offsets *const static_data_offsets)
140 {
141    pvr_dev_addr_t base_address;
142    uint32_t log2_page_size;
143    uint64_t carveout_size;
144    VkResult result;
145    uint64_t size;
146 
147    result = pvr_srv_get_heap_details(srv_ws->base.render_fd,
148                                      heap_idx,
149                                      0,
150                                      NULL,
151                                      &base_address,
152                                      &size,
153                                      &carveout_size,
154                                      &log2_page_size);
155    if (result != VK_SUCCESS)
156       return result;
157 
158    result = pvr_winsys_heap_init(&srv_ws->base,
159                                  base_address,
160                                  size,
161                                  base_address,
162                                  carveout_size,
163                                  log2_page_size,
164                                  static_data_offsets,
165                                  &srv_heap->base);
166    if (result != VK_SUCCESS)
167       return result;
168 
169    assert(srv_heap->base.page_size == srv_ws->base.page_size);
170    assert(srv_heap->base.log2_page_size == srv_ws->base.log2_page_size);
171    assert(srv_heap->base.static_data_carveout_size %
172              PVR_SRV_CARVEOUT_SIZE_GRANULARITY ==
173           0);
174 
175    /* Create server-side counterpart of Device Memory heap */
176    result = pvr_srv_int_heap_create(srv_ws->base.render_fd,
177                                     srv_heap->base.base_addr,
178                                     srv_heap->base.size,
179                                     srv_heap->base.log2_page_size,
180                                     srv_ws->server_memctx,
181                                     &srv_heap->server_heap);
182    if (result != VK_SUCCESS) {
183       pvr_winsys_helper_winsys_heap_finish(&srv_heap->base);
184       return result;
185    }
186 
187    return VK_SUCCESS;
188 }
189 
pvr_srv_heap_finish(struct pvr_srv_winsys * srv_ws,struct pvr_srv_winsys_heap * srv_heap)190 static bool pvr_srv_heap_finish(struct pvr_srv_winsys *srv_ws,
191                                 struct pvr_srv_winsys_heap *srv_heap)
192 {
193    if (!pvr_winsys_helper_winsys_heap_finish(&srv_heap->base))
194       return false;
195 
196    pvr_srv_int_heap_destroy(srv_ws->base.render_fd, srv_heap->server_heap);
197 
198    return true;
199 }
200 
pvr_srv_memctx_init(struct pvr_srv_winsys * srv_ws)201 static VkResult pvr_srv_memctx_init(struct pvr_srv_winsys *srv_ws)
202 {
203    const struct pvr_winsys_static_data_offsets
204       general_heap_static_data_offsets = {
205          .yuv_csc = FWIF_GENERAL_HEAP_YUV_CSC_OFFSET_BYTES,
206       };
207    const struct pvr_winsys_static_data_offsets pds_heap_static_data_offsets = {
208       .eot = FWIF_PDS_HEAP_EOT_OFFSET_BYTES,
209       .vdm_sync = FWIF_PDS_HEAP_VDM_SYNC_OFFSET_BYTES,
210    };
211    const struct pvr_winsys_static_data_offsets usc_heap_static_data_offsets = {
212       .vdm_sync = FWIF_USC_HEAP_VDM_SYNC_OFFSET_BYTES,
213    };
214    const struct pvr_winsys_static_data_offsets no_static_data_offsets = { 0 };
215 
216    char heap_name[PVR_SRV_DEVMEM_HEAPNAME_MAXLENGTH];
217    int transfer_3d_heap_idx = -1;
218    int vis_test_heap_idx = -1;
219    int general_heap_idx = -1;
220    int rgn_hdr_heap_idx = -1;
221    int pds_heap_idx = -1;
222    int usc_heap_idx = -1;
223    uint32_t heap_count;
224    VkResult result;
225 
226    result = pvr_srv_int_ctx_create(srv_ws->base.render_fd,
227                                    &srv_ws->server_memctx,
228                                    &srv_ws->server_memctx_data);
229    if (result != VK_SUCCESS)
230       return result;
231 
232    os_get_page_size(&srv_ws->base.page_size);
233    srv_ws->base.log2_page_size = util_logbase2(srv_ws->base.page_size);
234 
235    result = pvr_srv_get_heap_count(srv_ws->base.render_fd, &heap_count);
236    if (result != VK_SUCCESS)
237       goto err_pvr_srv_int_ctx_destroy;
238 
239    assert(heap_count > 0);
240 
241    for (uint32_t i = 0; i < heap_count; i++) {
242       result = pvr_srv_get_heap_details(srv_ws->base.render_fd,
243                                         i,
244                                         sizeof(heap_name),
245                                         heap_name,
246                                         NULL,
247                                         NULL,
248                                         NULL,
249                                         NULL);
250       if (result != VK_SUCCESS)
251          goto err_pvr_srv_int_ctx_destroy;
252 
253       if (general_heap_idx == -1 &&
254           strncmp(heap_name,
255                   PVR_SRV_GENERAL_HEAP_IDENT,
256                   sizeof(PVR_SRV_GENERAL_HEAP_IDENT)) == 0) {
257          general_heap_idx = i;
258       } else if (pds_heap_idx == -1 &&
259                  strncmp(heap_name,
260                          PVR_SRV_PDSCODEDATA_HEAP_IDENT,
261                          sizeof(PVR_SRV_PDSCODEDATA_HEAP_IDENT)) == 0) {
262          pds_heap_idx = i;
263       } else if (rgn_hdr_heap_idx == -1 &&
264                  strncmp(heap_name,
265                          PVR_SRV_RGNHDR_BRN_63142_HEAP_IDENT,
266                          sizeof(PVR_SRV_RGNHDR_BRN_63142_HEAP_IDENT)) == 0) {
267          rgn_hdr_heap_idx = i;
268       } else if (transfer_3d_heap_idx == -1 &&
269                  strncmp(heap_name,
270                          PVR_SRV_TRANSFER_3D_HEAP_IDENT,
271                          sizeof(PVR_SRV_TRANSFER_3D_HEAP_IDENT)) == 0) {
272          transfer_3d_heap_idx = i;
273       } else if (usc_heap_idx == -1 &&
274                  strncmp(heap_name,
275                          PVR_SRV_USCCODE_HEAP_IDENT,
276                          sizeof(PVR_SRV_USCCODE_HEAP_IDENT)) == 0) {
277          usc_heap_idx = i;
278       } else if (vis_test_heap_idx == -1 &&
279                  strncmp(heap_name,
280                          PVR_SRV_VISIBILITY_TEST_HEAP_IDENT,
281                          sizeof(PVR_SRV_VISIBILITY_TEST_HEAP_IDENT)) == 0) {
282          vis_test_heap_idx = i;
283       }
284    }
285 
286    /* Check for and initialise required heaps. */
287    if (general_heap_idx == -1 || pds_heap_idx == -1 ||
288        transfer_3d_heap_idx == -1 || usc_heap_idx == -1 ||
289        vis_test_heap_idx == -1) {
290       result = vk_error(NULL, VK_ERROR_INITIALIZATION_FAILED);
291       goto err_pvr_srv_int_ctx_destroy;
292    }
293 
294    result = pvr_srv_heap_init(srv_ws,
295                               &srv_ws->general_heap,
296                               general_heap_idx,
297                               &general_heap_static_data_offsets);
298    if (result != VK_SUCCESS)
299       goto err_pvr_srv_int_ctx_destroy;
300 
301    result = pvr_srv_heap_init(srv_ws,
302                               &srv_ws->pds_heap,
303                               pds_heap_idx,
304                               &pds_heap_static_data_offsets);
305    if (result != VK_SUCCESS)
306       goto err_pvr_srv_heap_finish_general;
307 
308    result = pvr_srv_heap_init(srv_ws,
309                               &srv_ws->transfer_3d_heap,
310                               transfer_3d_heap_idx,
311                               &no_static_data_offsets);
312    if (result != VK_SUCCESS)
313       goto err_pvr_srv_heap_finish_pds;
314 
315    result = pvr_srv_heap_init(srv_ws,
316                               &srv_ws->usc_heap,
317                               usc_heap_idx,
318                               &usc_heap_static_data_offsets);
319    if (result != VK_SUCCESS)
320       goto err_pvr_srv_heap_finish_transfer_3d;
321 
322    result = pvr_srv_heap_init(srv_ws,
323                               &srv_ws->vis_test_heap,
324                               vis_test_heap_idx,
325                               &no_static_data_offsets);
326    if (result != VK_SUCCESS)
327       goto err_pvr_srv_heap_finish_usc;
328 
329    /* Check for and set up optional heaps. */
330    if (rgn_hdr_heap_idx != -1) {
331       result = pvr_srv_heap_init(srv_ws,
332                                  &srv_ws->rgn_hdr_heap,
333                                  rgn_hdr_heap_idx,
334                                  &no_static_data_offsets);
335       if (result != VK_SUCCESS)
336          goto err_pvr_srv_heap_finish_vis_test;
337 
338       srv_ws->rgn_hdr_heap_present = true;
339    } else {
340       srv_ws->rgn_hdr_heap_present = false;
341    }
342 
343    result =
344       pvr_winsys_helper_allocate_static_memory(&srv_ws->base,
345                                                pvr_srv_heap_alloc_carveout,
346                                                &srv_ws->general_heap.base,
347                                                &srv_ws->pds_heap.base,
348                                                &srv_ws->usc_heap.base,
349                                                &srv_ws->general_vma,
350                                                &srv_ws->pds_vma,
351                                                &srv_ws->usc_vma);
352    if (result != VK_SUCCESS)
353       goto err_pvr_srv_heap_finish_rgn_hdr;
354 
355    result = pvr_winsys_helper_fill_static_memory(&srv_ws->base,
356                                                  srv_ws->general_vma,
357                                                  srv_ws->pds_vma,
358                                                  srv_ws->usc_vma);
359    if (result != VK_SUCCESS)
360       goto err_pvr_srv_free_static_memory;
361 
362    return VK_SUCCESS;
363 
364 err_pvr_srv_free_static_memory:
365    pvr_winsys_helper_free_static_memory(srv_ws->general_vma,
366                                         srv_ws->pds_vma,
367                                         srv_ws->usc_vma);
368 
369 err_pvr_srv_heap_finish_rgn_hdr:
370    if (srv_ws->rgn_hdr_heap_present)
371       pvr_srv_heap_finish(srv_ws, &srv_ws->rgn_hdr_heap);
372 
373 err_pvr_srv_heap_finish_vis_test:
374    pvr_srv_heap_finish(srv_ws, &srv_ws->vis_test_heap);
375 
376 err_pvr_srv_heap_finish_usc:
377    pvr_srv_heap_finish(srv_ws, &srv_ws->usc_heap);
378 
379 err_pvr_srv_heap_finish_transfer_3d:
380    pvr_srv_heap_finish(srv_ws, &srv_ws->transfer_3d_heap);
381 
382 err_pvr_srv_heap_finish_pds:
383    pvr_srv_heap_finish(srv_ws, &srv_ws->pds_heap);
384 
385 err_pvr_srv_heap_finish_general:
386    pvr_srv_heap_finish(srv_ws, &srv_ws->general_heap);
387 
388 err_pvr_srv_int_ctx_destroy:
389    pvr_srv_int_ctx_destroy(srv_ws->base.render_fd, srv_ws->server_memctx);
390 
391    return result;
392 }
393 
pvr_srv_memctx_finish(struct pvr_srv_winsys * srv_ws)394 static void pvr_srv_memctx_finish(struct pvr_srv_winsys *srv_ws)
395 {
396    pvr_winsys_helper_free_static_memory(srv_ws->general_vma,
397                                         srv_ws->pds_vma,
398                                         srv_ws->usc_vma);
399 
400    if (srv_ws->rgn_hdr_heap_present) {
401       if (!pvr_srv_heap_finish(srv_ws, &srv_ws->rgn_hdr_heap)) {
402          vk_errorf(NULL,
403                    VK_ERROR_UNKNOWN,
404                    "Region header heap in use, can not deinit");
405       }
406    }
407 
408    if (!pvr_srv_heap_finish(srv_ws, &srv_ws->vis_test_heap)) {
409       vk_errorf(NULL,
410                 VK_ERROR_UNKNOWN,
411                 "Visibility test heap in use, can not deinit");
412    }
413 
414    if (!pvr_srv_heap_finish(srv_ws, &srv_ws->usc_heap))
415       vk_errorf(NULL, VK_ERROR_UNKNOWN, "USC heap in use, can not deinit");
416 
417    if (!pvr_srv_heap_finish(srv_ws, &srv_ws->transfer_3d_heap)) {
418       vk_errorf(NULL,
419                 VK_ERROR_UNKNOWN,
420                 "Transfer 3D heap in use, can not deinit");
421    }
422 
423    if (!pvr_srv_heap_finish(srv_ws, &srv_ws->pds_heap))
424       vk_errorf(NULL, VK_ERROR_UNKNOWN, "PDS heap in use, can not deinit");
425 
426    if (!pvr_srv_heap_finish(srv_ws, &srv_ws->general_heap)) {
427       vk_errorf(NULL, VK_ERROR_UNKNOWN, "General heap in use, can not deinit");
428    }
429 
430    pvr_srv_int_ctx_destroy(srv_ws->base.render_fd, srv_ws->server_memctx);
431 }
432 
pvr_srv_winsys_destroy(struct pvr_winsys * ws)433 static void pvr_srv_winsys_destroy(struct pvr_winsys *ws)
434 {
435    struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ws);
436    int fd = ws->render_fd;
437 
438    if (srv_ws->presignaled_sync) {
439       vk_sync_destroy(&srv_ws->presignaled_sync_device->vk,
440                       &srv_ws->presignaled_sync->base);
441    }
442 
443    pvr_srv_sync_prim_block_finish(srv_ws);
444    pvr_srv_memctx_finish(srv_ws);
445    vk_free(ws->alloc, srv_ws);
446    pvr_srv_connection_destroy(fd);
447 }
448 
449 static uint64_t
pvr_srv_get_min_free_list_size(const struct pvr_device_info * dev_info)450 pvr_srv_get_min_free_list_size(const struct pvr_device_info *dev_info)
451 {
452    uint64_t min_num_pages;
453 
454    if (PVR_HAS_FEATURE(dev_info, roguexe)) {
455       if (PVR_HAS_QUIRK(dev_info, 66011))
456          min_num_pages = 40U;
457       else
458          min_num_pages = 25U;
459    } else {
460       min_num_pages = 50U;
461    }
462 
463    return min_num_pages << ROGUE_BIF_PM_PHYSICAL_PAGE_SHIFT;
464 }
465 
466 static inline uint64_t
pvr_srv_get_num_phantoms(const struct pvr_device_info * dev_info)467 pvr_srv_get_num_phantoms(const struct pvr_device_info *dev_info)
468 {
469    return DIV_ROUND_UP(PVR_GET_FEATURE_VALUE(dev_info, num_clusters, 1U), 4U);
470 }
471 
472 /* Return the total reserved size of partition in dwords. */
pvr_srv_get_total_reserved_partition_size(const struct pvr_device_info * dev_info)473 static inline uint64_t pvr_srv_get_total_reserved_partition_size(
474    const struct pvr_device_info *dev_info)
475 {
476    uint32_t tile_size_x = PVR_GET_FEATURE_VALUE(dev_info, tile_size_x, 0);
477    uint32_t tile_size_y = PVR_GET_FEATURE_VALUE(dev_info, tile_size_y, 0);
478    uint32_t max_partitions = PVR_GET_FEATURE_VALUE(dev_info, max_partitions, 0);
479 
480    if (tile_size_x == 16 && tile_size_y == 16) {
481       return tile_size_x * tile_size_y * max_partitions *
482              PVR_GET_FEATURE_VALUE(dev_info,
483                                    usc_min_output_registers_per_pix,
484                                    0);
485    }
486 
487    return (uint64_t)max_partitions * 1024U;
488 }
489 
490 static inline uint64_t
pvr_srv_get_reserved_shared_size(const struct pvr_device_info * dev_info)491 pvr_srv_get_reserved_shared_size(const struct pvr_device_info *dev_info)
492 {
493    uint32_t common_store_size_in_dwords =
494       PVR_GET_FEATURE_VALUE(dev_info,
495                             common_store_size_in_dwords,
496                             512U * 4U * 4U);
497    uint32_t reserved_shared_size =
498       common_store_size_in_dwords - (256U * 4U) -
499       pvr_srv_get_total_reserved_partition_size(dev_info);
500 
501    if (PVR_HAS_QUIRK(dev_info, 44079)) {
502       uint32_t common_store_split_point = (768U * 4U * 4U);
503 
504       return MIN2(common_store_split_point - (256U * 4U), reserved_shared_size);
505    }
506 
507    return reserved_shared_size;
508 }
509 
510 static inline uint64_t
pvr_srv_get_max_coeffs(const struct pvr_device_info * dev_info)511 pvr_srv_get_max_coeffs(const struct pvr_device_info *dev_info)
512 {
513    uint32_t max_coeff_additional_portion = ROGUE_MAX_VERTEX_SHARED_REGISTERS;
514    uint32_t pending_allocation_shared_regs = 2U * 1024U;
515    uint32_t pending_allocation_coeff_regs = 0U;
516    uint32_t num_phantoms = pvr_srv_get_num_phantoms(dev_info);
517    uint32_t tiles_in_flight =
518       PVR_GET_FEATURE_VALUE(dev_info, isp_max_tiles_in_flight, 0);
519    uint32_t max_coeff_pixel_portion =
520       DIV_ROUND_UP(tiles_in_flight, num_phantoms);
521 
522    max_coeff_pixel_portion *= ROGUE_MAX_PIXEL_SHARED_REGISTERS;
523 
524    /* Compute tasks on cores with BRN48492 and without compute overlap may lock
525     * up without two additional lines of coeffs.
526     */
527    if (PVR_HAS_QUIRK(dev_info, 48492) &&
528        !PVR_HAS_FEATURE(dev_info, compute_overlap)) {
529       pending_allocation_coeff_regs = 2U * 1024U;
530    }
531 
532    if (PVR_HAS_ERN(dev_info, 38748))
533       pending_allocation_shared_regs = 0U;
534 
535    if (PVR_HAS_ERN(dev_info, 38020)) {
536       max_coeff_additional_portion +=
537          rogue_max_compute_shared_registers(dev_info);
538    }
539 
540    return pvr_srv_get_reserved_shared_size(dev_info) +
541           pending_allocation_coeff_regs -
542           (max_coeff_pixel_portion + max_coeff_additional_portion +
543            pending_allocation_shared_regs);
544 }
545 
546 static inline uint64_t
pvr_srv_get_cdm_max_local_mem_size_regs(const struct pvr_device_info * dev_info)547 pvr_srv_get_cdm_max_local_mem_size_regs(const struct pvr_device_info *dev_info)
548 {
549    uint32_t available_coeffs_in_dwords = pvr_srv_get_max_coeffs(dev_info);
550 
551    if (PVR_HAS_QUIRK(dev_info, 48492) && PVR_HAS_FEATURE(dev_info, roguexe) &&
552        !PVR_HAS_FEATURE(dev_info, compute_overlap)) {
553       /* Driver must not use the 2 reserved lines. */
554       available_coeffs_in_dwords -= ROGUE_CSRM_LINE_SIZE_IN_DWORDS * 2;
555    }
556 
557    /* The maximum amount of local memory available to a kernel is the minimum
558     * of the total number of coefficient registers available and the max common
559     * store allocation size which can be made by the CDM.
560     *
561     * If any coeff lines are reserved for tessellation or pixel then we need to
562     * subtract those too.
563     */
564    return MIN2(available_coeffs_in_dwords,
565                ROGUE_MAX_PER_KERNEL_LOCAL_MEM_SIZE_REGS);
566 }
567 
568 static VkResult
pvr_srv_winsys_device_info_init(struct pvr_winsys * ws,struct pvr_device_info * dev_info,struct pvr_device_runtime_info * runtime_info)569 pvr_srv_winsys_device_info_init(struct pvr_winsys *ws,
570                                 struct pvr_device_info *dev_info,
571                                 struct pvr_device_runtime_info *runtime_info)
572 {
573    struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ws);
574    VkResult result;
575    int ret;
576 
577    ret = pvr_device_info_init(dev_info, srv_ws->bvnc);
578    if (ret) {
579       return vk_errorf(NULL,
580                        VK_ERROR_INCOMPATIBLE_DRIVER,
581                        "Unsupported BVNC: %u.%u.%u.%u\n",
582                        PVR_BVNC_UNPACK_B(srv_ws->bvnc),
583                        PVR_BVNC_UNPACK_V(srv_ws->bvnc),
584                        PVR_BVNC_UNPACK_N(srv_ws->bvnc),
585                        PVR_BVNC_UNPACK_C(srv_ws->bvnc));
586    }
587 
588    runtime_info->min_free_list_size = pvr_srv_get_min_free_list_size(dev_info);
589    runtime_info->max_free_list_size = PVR_SRV_FREE_LIST_MAX_SIZE;
590    runtime_info->reserved_shared_size =
591       pvr_srv_get_reserved_shared_size(dev_info);
592    runtime_info->total_reserved_partition_size =
593       pvr_srv_get_total_reserved_partition_size(dev_info);
594    runtime_info->num_phantoms = pvr_srv_get_num_phantoms(dev_info);
595    runtime_info->max_coeffs = pvr_srv_get_max_coeffs(dev_info);
596    runtime_info->cdm_max_local_mem_size_regs =
597       pvr_srv_get_cdm_max_local_mem_size_regs(dev_info);
598 
599    if (PVR_HAS_FEATURE(dev_info, gpu_multicore_support)) {
600       result = pvr_srv_get_multicore_info(ws->render_fd,
601                                           0,
602                                           NULL,
603                                           &runtime_info->core_count);
604       if (result != VK_SUCCESS)
605          return result;
606    } else {
607       runtime_info->core_count = 1;
608    }
609 
610    return 0;
611 }
612 
pvr_srv_winsys_get_heaps_info(struct pvr_winsys * ws,struct pvr_winsys_heaps * heaps)613 static void pvr_srv_winsys_get_heaps_info(struct pvr_winsys *ws,
614                                           struct pvr_winsys_heaps *heaps)
615 {
616    struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ws);
617 
618    heaps->general_heap = &srv_ws->general_heap.base;
619    heaps->pds_heap = &srv_ws->pds_heap.base;
620    heaps->transfer_frag_heap = &srv_ws->transfer_3d_heap.base;
621    heaps->usc_heap = &srv_ws->usc_heap.base;
622    heaps->vis_test_heap = &srv_ws->vis_test_heap.base;
623 
624    if (srv_ws->rgn_hdr_heap_present)
625       heaps->rgn_hdr_heap = &srv_ws->rgn_hdr_heap.base;
626    else
627       heaps->rgn_hdr_heap = &srv_ws->general_heap.base;
628 }
629 
630 static const struct pvr_winsys_ops srv_winsys_ops = {
631    .destroy = pvr_srv_winsys_destroy,
632    .device_info_init = pvr_srv_winsys_device_info_init,
633    .get_heaps_info = pvr_srv_winsys_get_heaps_info,
634    .buffer_create = pvr_srv_winsys_buffer_create,
635    .buffer_create_from_fd = pvr_srv_winsys_buffer_create_from_fd,
636    .buffer_destroy = pvr_srv_winsys_buffer_destroy,
637    .buffer_get_fd = pvr_srv_winsys_buffer_get_fd,
638    .buffer_map = pvr_srv_winsys_buffer_map,
639    .buffer_unmap = pvr_srv_winsys_buffer_unmap,
640    .heap_alloc = pvr_srv_winsys_heap_alloc,
641    .heap_free = pvr_srv_winsys_heap_free,
642    .vma_map = pvr_srv_winsys_vma_map,
643    .vma_unmap = pvr_srv_winsys_vma_unmap,
644    .free_list_create = pvr_srv_winsys_free_list_create,
645    .free_list_destroy = pvr_srv_winsys_free_list_destroy,
646    .render_target_dataset_create = pvr_srv_render_target_dataset_create,
647    .render_target_dataset_destroy = pvr_srv_render_target_dataset_destroy,
648    .render_ctx_create = pvr_srv_winsys_render_ctx_create,
649    .render_ctx_destroy = pvr_srv_winsys_render_ctx_destroy,
650    .render_submit = pvr_srv_winsys_render_submit,
651    .compute_ctx_create = pvr_srv_winsys_compute_ctx_create,
652    .compute_ctx_destroy = pvr_srv_winsys_compute_ctx_destroy,
653    .compute_submit = pvr_srv_winsys_compute_submit,
654    .transfer_ctx_create = pvr_srv_winsys_transfer_ctx_create,
655    .transfer_ctx_destroy = pvr_srv_winsys_transfer_ctx_destroy,
656    .transfer_submit = pvr_srv_winsys_transfer_submit,
657    .null_job_submit = pvr_srv_winsys_null_job_submit,
658 };
659 
pvr_is_driver_compatible(int render_fd)660 static bool pvr_is_driver_compatible(int render_fd)
661 {
662    drmVersionPtr version;
663 
664    version = drmGetVersion(render_fd);
665    if (!version)
666       return false;
667 
668    assert(strcmp(version->name, "pvr") == 0);
669 
670    /* Only the 1.17 driver is supported for now. */
671    if (version->version_major != PVR_SRV_VERSION_MAJ ||
672        version->version_minor != PVR_SRV_VERSION_MIN) {
673       vk_errorf(NULL,
674                 VK_ERROR_INCOMPATIBLE_DRIVER,
675                 "Unsupported downstream driver version (%u.%u)",
676                 version->version_major,
677                 version->version_minor);
678       drmFreeVersion(version);
679 
680       return false;
681    }
682 
683    drmFreeVersion(version);
684 
685    return true;
686 }
687 
pvr_srv_winsys_create(const int render_fd,const int display_fd,const VkAllocationCallbacks * alloc,struct pvr_winsys ** const ws_out)688 VkResult pvr_srv_winsys_create(const int render_fd,
689                                const int display_fd,
690                                const VkAllocationCallbacks *alloc,
691                                struct pvr_winsys **const ws_out)
692 {
693    struct pvr_srv_winsys *srv_ws;
694    VkResult result;
695    uint64_t bvnc;
696 
697    if (!pvr_is_driver_compatible(render_fd))
698       return VK_ERROR_INCOMPATIBLE_DRIVER;
699 
700    result = pvr_srv_init_module(render_fd, PVR_SRVKM_MODULE_TYPE_SERVICES);
701    if (result != VK_SUCCESS)
702       goto err_out;
703 
704    result = pvr_srv_connection_create(render_fd, &bvnc);
705    if (result != VK_SUCCESS)
706       goto err_out;
707 
708    srv_ws =
709       vk_zalloc(alloc, sizeof(*srv_ws), 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
710    if (!srv_ws) {
711       result = vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
712       goto err_pvr_srv_connection_destroy;
713    }
714 
715    srv_ws->base.ops = &srv_winsys_ops;
716    srv_ws->base.render_fd = render_fd;
717    srv_ws->base.display_fd = display_fd;
718    srv_ws->base.alloc = alloc;
719 
720    srv_ws->bvnc = bvnc;
721 
722    srv_ws->base.syncobj_type = pvr_srv_sync_type;
723    srv_ws->base.sync_types[0] = &srv_ws->base.syncobj_type;
724 
725    srv_ws->base.timeline_syncobj_type =
726       vk_sync_timeline_get_type(srv_ws->base.sync_types[0]);
727    srv_ws->base.sync_types[1] = &srv_ws->base.timeline_syncobj_type.sync;
728    srv_ws->base.sync_types[2] = NULL;
729 
730    /* Threaded submit requires VK_SYNC_FEATURE_WAIT_PENDING which pvrsrv
731     * doesn't support.
732     */
733    srv_ws->base.features.supports_threaded_submit = false;
734 
735    result = pvr_srv_memctx_init(srv_ws);
736    if (result != VK_SUCCESS)
737       goto err_vk_free_srv_ws;
738 
739    result = pvr_srv_sync_prim_block_init(srv_ws);
740    if (result != VK_SUCCESS)
741       goto err_pvr_srv_memctx_finish;
742 
743    *ws_out = &srv_ws->base;
744 
745    return VK_SUCCESS;
746 
747 err_pvr_srv_memctx_finish:
748    pvr_srv_memctx_finish(srv_ws);
749 
750 err_vk_free_srv_ws:
751    vk_free(alloc, srv_ws);
752 
753 err_pvr_srv_connection_destroy:
754    pvr_srv_connection_destroy(render_fd);
755 
756 err_out:
757    return result;
758 }
759 
pvr_srv_create_presignaled_sync(struct pvr_device * device,struct pvr_srv_sync ** out_sync)760 static VkResult pvr_srv_create_presignaled_sync(struct pvr_device *device,
761                                                 struct pvr_srv_sync **out_sync)
762 {
763    struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(device->ws);
764    struct vk_sync *sync;
765 
766    int timeline_fd;
767    int sync_fd;
768 
769    VkResult result;
770 
771    result = pvr_srv_create_timeline(srv_ws->base.render_fd, &timeline_fd);
772    if (result != VK_SUCCESS)
773       return result;
774 
775    result = pvr_srv_set_timeline_sw_only(timeline_fd);
776    if (result != VK_SUCCESS)
777       goto err_close_timeline;
778 
779    result = pvr_srv_create_sw_fence(timeline_fd, &sync_fd, NULL);
780    if (result != VK_SUCCESS)
781       goto err_close_timeline;
782 
783    result = pvr_srv_sw_sync_timeline_increment(timeline_fd, NULL);
784    if (result != VK_SUCCESS)
785       goto err_close_sw_fence;
786 
787    result = vk_sync_create(&device->vk,
788                            &device->pdevice->ws->syncobj_type,
789                            0U,
790                            0UL,
791                            &sync);
792    if (result != VK_SUCCESS)
793       goto err_close_sw_fence;
794 
795    result = vk_sync_import_sync_file(&device->vk, sync, sync_fd);
796    if (result != VK_SUCCESS)
797       goto err_destroy_sync;
798 
799    *out_sync = to_srv_sync(sync);
800    (*out_sync)->signaled = true;
801 
802    close(timeline_fd);
803 
804    return VK_SUCCESS;
805 
806 err_destroy_sync:
807    vk_sync_destroy(&device->vk, sync);
808 
809 err_close_sw_fence:
810    close(sync_fd);
811 
812 err_close_timeline:
813    close(timeline_fd);
814 
815    return result;
816 }
817 
pvr_srv_sync_get_presignaled_sync(struct pvr_device * device,struct pvr_srv_sync ** out_sync)818 VkResult pvr_srv_sync_get_presignaled_sync(struct pvr_device *device,
819                                            struct pvr_srv_sync **out_sync)
820 {
821    struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(device->ws);
822    VkResult result;
823 
824    if (!srv_ws->presignaled_sync) {
825       result =
826          pvr_srv_create_presignaled_sync(device, &srv_ws->presignaled_sync);
827       if (result != VK_SUCCESS)
828          return result;
829 
830       srv_ws->presignaled_sync_device = device;
831    }
832 
833    assert(device == srv_ws->presignaled_sync_device);
834 
835    *out_sync = srv_ws->presignaled_sync;
836 
837    return VK_SUCCESS;
838 }
839