• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_compute.h"
37 #include "pvr_srv_job_render.h"
38 #include "pvr_srv_job_transfer.h"
39 #include "pvr_srv_public.h"
40 #include "pvr_srv_sync.h"
41 #include "pvr_srv_job_null.h"
42 #include "pvr_types.h"
43 #include "pvr_winsys.h"
44 #include "pvr_winsys_helper.h"
45 #include "util/log.h"
46 #include "util/macros.h"
47 #include "util/os_misc.h"
48 #include "vk_log.h"
49 
50 /* Amount of space used to hold sync prim values (in bytes). */
51 #define PVR_SRV_SYNC_PRIM_VALUE_SIZE 4U
52 
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)53 static VkResult pvr_srv_heap_init(
54    struct pvr_srv_winsys *srv_ws,
55    struct pvr_srv_winsys_heap *srv_heap,
56    uint32_t heap_idx,
57    const struct pvr_winsys_static_data_offsets *const static_data_offsets)
58 {
59    pvr_dev_addr_t base_address;
60    uint32_t log2_page_size;
61    uint64_t reserved_size;
62    VkResult result;
63    uint64_t size;
64 
65    result = pvr_srv_get_heap_details(srv_ws->render_fd,
66                                      heap_idx,
67                                      0,
68                                      NULL,
69                                      &base_address,
70                                      &size,
71                                      &reserved_size,
72                                      &log2_page_size);
73    if (result != VK_SUCCESS)
74       return result;
75 
76    result = pvr_winsys_helper_winsys_heap_init(&srv_ws->base,
77                                                base_address,
78                                                size,
79                                                base_address,
80                                                reserved_size,
81                                                log2_page_size,
82                                                static_data_offsets,
83                                                &srv_heap->base);
84    if (result != VK_SUCCESS)
85       return result;
86 
87    assert(srv_heap->base.page_size == srv_ws->base.page_size);
88    assert(srv_heap->base.log2_page_size == srv_ws->base.log2_page_size);
89    assert(srv_heap->base.reserved_size % PVR_SRV_RESERVED_SIZE_GRANULARITY ==
90           0);
91 
92    /* Create server-side counterpart of Device Memory heap */
93    result = pvr_srv_int_heap_create(srv_ws->render_fd,
94                                     srv_heap->base.base_addr,
95                                     srv_heap->base.size,
96                                     srv_heap->base.log2_page_size,
97                                     srv_ws->server_memctx,
98                                     &srv_heap->server_heap);
99    if (result != VK_SUCCESS) {
100       pvr_winsys_helper_winsys_heap_finish(&srv_heap->base);
101       return result;
102    }
103 
104    return VK_SUCCESS;
105 }
106 
pvr_srv_heap_finish(struct pvr_srv_winsys * srv_ws,struct pvr_srv_winsys_heap * srv_heap)107 static bool pvr_srv_heap_finish(struct pvr_srv_winsys *srv_ws,
108                                 struct pvr_srv_winsys_heap *srv_heap)
109 {
110    if (!pvr_winsys_helper_winsys_heap_finish(&srv_heap->base))
111       return false;
112 
113    pvr_srv_int_heap_destroy(srv_ws->render_fd, srv_heap->server_heap);
114 
115    return true;
116 }
117 
pvr_srv_memctx_init(struct pvr_srv_winsys * srv_ws)118 static VkResult pvr_srv_memctx_init(struct pvr_srv_winsys *srv_ws)
119 {
120    const struct pvr_winsys_static_data_offsets
121       general_heap_static_data_offsets = {
122          .yuv_csc = FWIF_GENERAL_HEAP_YUV_CSC_OFFSET_BYTES,
123       };
124    const struct pvr_winsys_static_data_offsets pds_heap_static_data_offsets = {
125       .eot = FWIF_PDS_HEAP_EOT_OFFSET_BYTES,
126       .vdm_sync = FWIF_PDS_HEAP_VDM_SYNC_OFFSET_BYTES,
127    };
128    const struct pvr_winsys_static_data_offsets usc_heap_static_data_offsets = {
129       .vdm_sync = FWIF_USC_HEAP_VDM_SYNC_OFFSET_BYTES,
130    };
131    const struct pvr_winsys_static_data_offsets no_static_data_offsets = { 0 };
132 
133    char heap_name[PVR_SRV_DEVMEM_HEAPNAME_MAXLENGTH];
134    int transfer_3d_heap_idx = -1;
135    int vis_test_heap_idx = -1;
136    int general_heap_idx = -1;
137    int rgn_hdr_heap_idx = -1;
138    int pds_heap_idx = -1;
139    int usc_heap_idx = -1;
140    uint32_t heap_count;
141    VkResult result;
142 
143    result = pvr_srv_int_ctx_create(srv_ws->render_fd,
144                                    &srv_ws->server_memctx,
145                                    &srv_ws->server_memctx_data);
146    if (result != VK_SUCCESS)
147       return result;
148 
149    os_get_page_size(&srv_ws->base.page_size);
150    srv_ws->base.log2_page_size = util_logbase2(srv_ws->base.page_size);
151 
152    result = pvr_srv_get_heap_count(srv_ws->render_fd, &heap_count);
153    if (result != VK_SUCCESS)
154       goto err_pvr_srv_int_ctx_destroy;
155 
156    assert(heap_count > 0);
157 
158    for (uint32_t i = 0; i < heap_count; i++) {
159       result = pvr_srv_get_heap_details(srv_ws->render_fd,
160                                         i,
161                                         sizeof(heap_name),
162                                         heap_name,
163                                         NULL,
164                                         NULL,
165                                         NULL,
166                                         NULL);
167       if (result != VK_SUCCESS)
168          goto err_pvr_srv_int_ctx_destroy;
169 
170       if (general_heap_idx == -1 &&
171           strncmp(heap_name,
172                   PVR_SRV_GENERAL_HEAP_IDENT,
173                   sizeof(PVR_SRV_GENERAL_HEAP_IDENT)) == 0) {
174          general_heap_idx = i;
175       } else if (pds_heap_idx == -1 &&
176                  strncmp(heap_name,
177                          PVR_SRV_PDSCODEDATA_HEAP_IDENT,
178                          sizeof(PVR_SRV_PDSCODEDATA_HEAP_IDENT)) == 0) {
179          pds_heap_idx = i;
180       } else if (rgn_hdr_heap_idx == -1 &&
181                  strncmp(heap_name,
182                          PVR_SRV_RGNHDR_BRN_63142_HEAP_IDENT,
183                          sizeof(PVR_SRV_RGNHDR_BRN_63142_HEAP_IDENT)) == 0) {
184          rgn_hdr_heap_idx = i;
185       } else if (transfer_3d_heap_idx == -1 &&
186                  strncmp(heap_name,
187                          PVR_SRV_TRANSFER_3D_HEAP_IDENT,
188                          sizeof(PVR_SRV_TRANSFER_3D_HEAP_IDENT)) == 0) {
189          transfer_3d_heap_idx = i;
190       } else if (usc_heap_idx == -1 &&
191                  strncmp(heap_name,
192                          PVR_SRV_USCCODE_HEAP_IDENT,
193                          sizeof(PVR_SRV_USCCODE_HEAP_IDENT)) == 0) {
194          usc_heap_idx = i;
195       } else if (vis_test_heap_idx == -1 &&
196                  strncmp(heap_name,
197                          PVR_SRV_VISIBILITY_TEST_HEAP_IDENT,
198                          sizeof(PVR_SRV_VISIBILITY_TEST_HEAP_IDENT)) == 0) {
199          vis_test_heap_idx = i;
200       }
201    }
202 
203    /* Check for and initialise required heaps. */
204    if (general_heap_idx == -1 || pds_heap_idx == -1 ||
205        transfer_3d_heap_idx == -1 || usc_heap_idx == -1 ||
206        vis_test_heap_idx == -1) {
207       result = vk_error(NULL, VK_ERROR_INITIALIZATION_FAILED);
208       goto err_pvr_srv_int_ctx_destroy;
209    }
210 
211    result = pvr_srv_heap_init(srv_ws,
212                               &srv_ws->general_heap,
213                               general_heap_idx,
214                               &general_heap_static_data_offsets);
215    if (result != VK_SUCCESS)
216       goto err_pvr_srv_int_ctx_destroy;
217 
218    result = pvr_srv_heap_init(srv_ws,
219                               &srv_ws->pds_heap,
220                               pds_heap_idx,
221                               &pds_heap_static_data_offsets);
222    if (result != VK_SUCCESS)
223       goto err_pvr_srv_heap_finish_general;
224 
225    result = pvr_srv_heap_init(srv_ws,
226                               &srv_ws->transfer_3d_heap,
227                               transfer_3d_heap_idx,
228                               &no_static_data_offsets);
229    if (result != VK_SUCCESS)
230       goto err_pvr_srv_heap_finish_pds;
231 
232    result = pvr_srv_heap_init(srv_ws,
233                               &srv_ws->usc_heap,
234                               usc_heap_idx,
235                               &usc_heap_static_data_offsets);
236    if (result != VK_SUCCESS)
237       goto err_pvr_srv_heap_finish_transfer_3d;
238 
239    result = pvr_srv_heap_init(srv_ws,
240                               &srv_ws->vis_test_heap,
241                               vis_test_heap_idx,
242                               &no_static_data_offsets);
243    if (result != VK_SUCCESS)
244       goto err_pvr_srv_heap_finish_usc;
245 
246    /* Check for and set up optional heaps. */
247    if (rgn_hdr_heap_idx != -1) {
248       result = pvr_srv_heap_init(srv_ws,
249                                  &srv_ws->rgn_hdr_heap,
250                                  rgn_hdr_heap_idx,
251                                  &no_static_data_offsets);
252       if (result != VK_SUCCESS)
253          goto err_pvr_srv_heap_finish_vis_test;
254 
255       srv_ws->rgn_hdr_heap_present = true;
256    } else {
257       srv_ws->rgn_hdr_heap_present = false;
258    }
259 
260    result =
261       pvr_winsys_helper_allocate_static_memory(&srv_ws->base,
262                                                pvr_srv_heap_alloc_reserved,
263                                                &srv_ws->general_heap.base,
264                                                &srv_ws->pds_heap.base,
265                                                &srv_ws->usc_heap.base,
266                                                &srv_ws->general_vma,
267                                                &srv_ws->pds_vma,
268                                                &srv_ws->usc_vma);
269    if (result != VK_SUCCESS)
270       goto err_pvr_srv_heap_finish_rgn_hdr;
271 
272    result = pvr_winsys_helper_fill_static_memory(&srv_ws->base,
273                                                  srv_ws->general_vma,
274                                                  srv_ws->pds_vma,
275                                                  srv_ws->usc_vma);
276    if (result != VK_SUCCESS)
277       goto err_pvr_srv_free_static_memory;
278 
279    return VK_SUCCESS;
280 
281 err_pvr_srv_free_static_memory:
282    pvr_winsys_helper_free_static_memory(srv_ws->general_vma,
283                                         srv_ws->pds_vma,
284                                         srv_ws->usc_vma);
285 
286 err_pvr_srv_heap_finish_rgn_hdr:
287    if (srv_ws->rgn_hdr_heap_present)
288       pvr_srv_heap_finish(srv_ws, &srv_ws->rgn_hdr_heap);
289 
290 err_pvr_srv_heap_finish_vis_test:
291    pvr_srv_heap_finish(srv_ws, &srv_ws->vis_test_heap);
292 
293 err_pvr_srv_heap_finish_usc:
294    pvr_srv_heap_finish(srv_ws, &srv_ws->usc_heap);
295 
296 err_pvr_srv_heap_finish_transfer_3d:
297    pvr_srv_heap_finish(srv_ws, &srv_ws->transfer_3d_heap);
298 
299 err_pvr_srv_heap_finish_pds:
300    pvr_srv_heap_finish(srv_ws, &srv_ws->pds_heap);
301 
302 err_pvr_srv_heap_finish_general:
303    pvr_srv_heap_finish(srv_ws, &srv_ws->general_heap);
304 
305 err_pvr_srv_int_ctx_destroy:
306    pvr_srv_int_ctx_destroy(srv_ws->render_fd, srv_ws->server_memctx);
307 
308    return result;
309 }
310 
pvr_srv_memctx_finish(struct pvr_srv_winsys * srv_ws)311 static void pvr_srv_memctx_finish(struct pvr_srv_winsys *srv_ws)
312 {
313    pvr_winsys_helper_free_static_memory(srv_ws->general_vma,
314                                         srv_ws->pds_vma,
315                                         srv_ws->usc_vma);
316 
317    if (srv_ws->rgn_hdr_heap_present) {
318       if (!pvr_srv_heap_finish(srv_ws, &srv_ws->rgn_hdr_heap)) {
319          vk_errorf(NULL,
320                    VK_ERROR_UNKNOWN,
321                    "Region header heap in use, can not deinit");
322       }
323    }
324 
325    if (!pvr_srv_heap_finish(srv_ws, &srv_ws->vis_test_heap)) {
326       vk_errorf(NULL,
327                 VK_ERROR_UNKNOWN,
328                 "Visibility test heap in use, can not deinit");
329    }
330 
331    if (!pvr_srv_heap_finish(srv_ws, &srv_ws->usc_heap))
332       vk_errorf(NULL, VK_ERROR_UNKNOWN, "USC heap in use, can not deinit");
333 
334    if (!pvr_srv_heap_finish(srv_ws, &srv_ws->transfer_3d_heap)) {
335       vk_errorf(NULL,
336                 VK_ERROR_UNKNOWN,
337                 "Transfer 3D heap in use, can not deinit");
338    }
339 
340    if (!pvr_srv_heap_finish(srv_ws, &srv_ws->pds_heap))
341       vk_errorf(NULL, VK_ERROR_UNKNOWN, "PDS heap in use, can not deinit");
342 
343    if (!pvr_srv_heap_finish(srv_ws, &srv_ws->general_heap)) {
344       vk_errorf(NULL, VK_ERROR_UNKNOWN, "General heap in use, can not deinit");
345    }
346 
347    pvr_srv_int_ctx_destroy(srv_ws->render_fd, srv_ws->server_memctx);
348 }
349 
pvr_srv_sync_prim_block_init(struct pvr_srv_winsys * srv_ws)350 static VkResult pvr_srv_sync_prim_block_init(struct pvr_srv_winsys *srv_ws)
351 {
352    /* We don't currently make use of this value, but we're required to provide
353     * a valid pointer to pvr_srv_alloc_sync_primitive_block.
354     */
355    void *sync_block_pmr;
356 
357    return pvr_srv_alloc_sync_primitive_block(srv_ws->render_fd,
358                                              &srv_ws->sync_block_handle,
359                                              &sync_block_pmr,
360                                              &srv_ws->sync_block_size,
361                                              &srv_ws->sync_block_fw_addr);
362 }
363 
pvr_srv_sync_prim_block_finish(struct pvr_srv_winsys * srv_ws)364 static void pvr_srv_sync_prim_block_finish(struct pvr_srv_winsys *srv_ws)
365 {
366    pvr_srv_free_sync_primitive_block(srv_ws->render_fd,
367                                      srv_ws->sync_block_handle);
368    srv_ws->sync_block_handle = NULL;
369 }
370 
pvr_srv_winsys_destroy(struct pvr_winsys * ws)371 static void pvr_srv_winsys_destroy(struct pvr_winsys *ws)
372 {
373    struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ws);
374    int fd = srv_ws->render_fd;
375 
376    pvr_srv_sync_prim_block_finish(srv_ws);
377    pvr_srv_memctx_finish(srv_ws);
378    vk_free(srv_ws->alloc, srv_ws);
379    pvr_srv_connection_destroy(fd);
380 }
381 
382 static uint64_t
pvr_srv_get_min_free_list_size(const struct pvr_device_info * dev_info)383 pvr_srv_get_min_free_list_size(const struct pvr_device_info *dev_info)
384 {
385    uint64_t min_num_pages;
386 
387    if (PVR_HAS_FEATURE(dev_info, roguexe)) {
388       if (PVR_HAS_QUIRK(dev_info, 66011))
389          min_num_pages = 40U;
390       else
391          min_num_pages = 25U;
392    } else {
393       min_num_pages = 50U;
394    }
395 
396    return min_num_pages << ROGUE_BIF_PM_PHYSICAL_PAGE_SHIFT;
397 }
398 
399 static inline uint64_t
pvr_srv_get_num_phantoms(const struct pvr_device_info * dev_info)400 pvr_srv_get_num_phantoms(const struct pvr_device_info *dev_info)
401 {
402    return DIV_ROUND_UP(PVR_GET_FEATURE_VALUE(dev_info, num_clusters, 1U), 4U);
403 }
404 
405 /* Return the total reserved size of partition in dwords. */
pvr_srv_get_total_reserved_partition_size(const struct pvr_device_info * dev_info)406 static inline uint64_t pvr_srv_get_total_reserved_partition_size(
407    const struct pvr_device_info *dev_info)
408 {
409    uint32_t tile_size_x = PVR_GET_FEATURE_VALUE(dev_info, tile_size_x, 0);
410    uint32_t tile_size_y = PVR_GET_FEATURE_VALUE(dev_info, tile_size_y, 0);
411    uint32_t max_partitions = PVR_GET_FEATURE_VALUE(dev_info, max_partitions, 0);
412 
413    if (tile_size_x == 16 && tile_size_y == 16) {
414       return tile_size_x * tile_size_y * max_partitions *
415              PVR_GET_FEATURE_VALUE(dev_info,
416                                    usc_min_output_registers_per_pix,
417                                    0);
418    }
419 
420    return max_partitions * 1024U;
421 }
422 
423 static inline uint64_t
pvr_srv_get_reserved_shared_size(const struct pvr_device_info * dev_info)424 pvr_srv_get_reserved_shared_size(const struct pvr_device_info *dev_info)
425 {
426    uint32_t common_store_size_in_dwords =
427       PVR_GET_FEATURE_VALUE(dev_info,
428                             common_store_size_in_dwords,
429                             512U * 4U * 4U);
430    uint32_t reserved_shared_size =
431       common_store_size_in_dwords - (256U * 4U) -
432       pvr_srv_get_total_reserved_partition_size(dev_info);
433 
434    if (PVR_HAS_QUIRK(dev_info, 44079)) {
435       uint32_t common_store_split_point = (768U * 4U * 4U);
436 
437       return MIN2(common_store_split_point - (256U * 4U), reserved_shared_size);
438    }
439 
440    return reserved_shared_size;
441 }
442 
443 static inline uint64_t
pvr_srv_get_max_coeffs(const struct pvr_device_info * dev_info)444 pvr_srv_get_max_coeffs(const struct pvr_device_info *dev_info)
445 {
446    uint32_t max_coeff_additional_portion = ROGUE_MAX_VERTEX_SHARED_REGISTERS;
447    uint32_t pending_allocation_shared_regs = 2U * 1024U;
448    uint32_t pending_allocation_coeff_regs = 0U;
449    uint32_t num_phantoms = pvr_srv_get_num_phantoms(dev_info);
450    uint32_t tiles_in_flight =
451       PVR_GET_FEATURE_VALUE(dev_info, isp_max_tiles_in_flight, 0);
452    uint32_t max_coeff_pixel_portion =
453       DIV_ROUND_UP(tiles_in_flight, num_phantoms);
454 
455    max_coeff_pixel_portion *= ROGUE_MAX_PIXEL_SHARED_REGISTERS;
456 
457    /* Compute tasks on cores with BRN48492 and without compute overlap may lock
458     * up without two additional lines of coeffs.
459     */
460    if (PVR_HAS_QUIRK(dev_info, 48492) &&
461        !PVR_HAS_FEATURE(dev_info, compute_overlap)) {
462       pending_allocation_coeff_regs = 2U * 1024U;
463    }
464 
465    if (PVR_HAS_ERN(dev_info, 38748))
466       pending_allocation_shared_regs = 0U;
467 
468    if (PVR_HAS_ERN(dev_info, 38020)) {
469       max_coeff_additional_portion +=
470          rogue_max_compute_shared_registers(dev_info);
471    }
472 
473    return pvr_srv_get_reserved_shared_size(dev_info) +
474           pending_allocation_coeff_regs -
475           (max_coeff_pixel_portion + max_coeff_additional_portion +
476            pending_allocation_shared_regs);
477 }
478 
479 static inline uint64_t
pvr_srv_get_cdm_max_local_mem_size_regs(const struct pvr_device_info * dev_info)480 pvr_srv_get_cdm_max_local_mem_size_regs(const struct pvr_device_info *dev_info)
481 {
482    uint32_t available_coeffs_in_dwords = pvr_srv_get_max_coeffs(dev_info);
483 
484    if (PVR_HAS_QUIRK(dev_info, 48492) && PVR_HAS_FEATURE(dev_info, roguexe) &&
485        !PVR_HAS_FEATURE(dev_info, compute_overlap)) {
486       /* Driver must not use the 2 reserved lines. */
487       available_coeffs_in_dwords -= ROGUE_CSRM_LINE_SIZE_IN_DWORDS * 2;
488    }
489 
490    /* The maximum amount of local memory available to a kernel is the minimum
491     * of the total number of coefficient registers available and the max common
492     * store allocation size which can be made by the CDM.
493     *
494     * If any coeff lines are reserved for tessellation or pixel then we need to
495     * subtract those too.
496     */
497    return MIN2(available_coeffs_in_dwords,
498                ROGUE_MAX_PER_KERNEL_LOCAL_MEM_SIZE_REGS);
499 }
500 
501 static int
pvr_srv_winsys_device_info_init(struct pvr_winsys * ws,struct pvr_device_info * dev_info,struct pvr_device_runtime_info * runtime_info)502 pvr_srv_winsys_device_info_init(struct pvr_winsys *ws,
503                                 struct pvr_device_info *dev_info,
504                                 struct pvr_device_runtime_info *runtime_info)
505 {
506    struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ws);
507    VkResult result;
508    int ret;
509 
510    ret = pvr_device_info_init(dev_info, srv_ws->bvnc);
511    if (ret) {
512       mesa_logw("Unsupported BVNC: %u.%u.%u.%u\n",
513                 PVR_BVNC_UNPACK_B(srv_ws->bvnc),
514                 PVR_BVNC_UNPACK_V(srv_ws->bvnc),
515                 PVR_BVNC_UNPACK_N(srv_ws->bvnc),
516                 PVR_BVNC_UNPACK_C(srv_ws->bvnc));
517       return ret;
518    }
519 
520    runtime_info->min_free_list_size = pvr_srv_get_min_free_list_size(dev_info);
521    runtime_info->reserved_shared_size =
522       pvr_srv_get_reserved_shared_size(dev_info);
523    runtime_info->total_reserved_partition_size =
524       pvr_srv_get_total_reserved_partition_size(dev_info);
525    runtime_info->num_phantoms = pvr_srv_get_num_phantoms(dev_info);
526    runtime_info->max_coeffs = pvr_srv_get_max_coeffs(dev_info);
527    runtime_info->cdm_max_local_mem_size_regs =
528       pvr_srv_get_cdm_max_local_mem_size_regs(dev_info);
529 
530    if (PVR_HAS_FEATURE(dev_info, gpu_multicore_support)) {
531       result = pvr_srv_get_multicore_info(srv_ws->render_fd,
532                                           0,
533                                           NULL,
534                                           &runtime_info->core_count);
535       if (result != VK_SUCCESS)
536          return -ENODEV;
537    } else {
538       runtime_info->core_count = 1;
539    }
540 
541    return 0;
542 }
543 
pvr_srv_winsys_get_heaps_info(struct pvr_winsys * ws,struct pvr_winsys_heaps * heaps)544 static void pvr_srv_winsys_get_heaps_info(struct pvr_winsys *ws,
545                                           struct pvr_winsys_heaps *heaps)
546 {
547    struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ws);
548 
549    heaps->general_heap = &srv_ws->general_heap.base;
550    heaps->pds_heap = &srv_ws->pds_heap.base;
551    heaps->transfer_3d_heap = &srv_ws->transfer_3d_heap.base;
552    heaps->usc_heap = &srv_ws->usc_heap.base;
553    heaps->vis_test_heap = &srv_ws->vis_test_heap.base;
554 
555    if (srv_ws->rgn_hdr_heap_present)
556       heaps->rgn_hdr_heap = &srv_ws->rgn_hdr_heap.base;
557    else
558       heaps->rgn_hdr_heap = &srv_ws->general_heap.base;
559 }
560 
561 static const struct pvr_winsys_ops srv_winsys_ops = {
562    .destroy = pvr_srv_winsys_destroy,
563    .device_info_init = pvr_srv_winsys_device_info_init,
564    .get_heaps_info = pvr_srv_winsys_get_heaps_info,
565    .buffer_create = pvr_srv_winsys_buffer_create,
566    .buffer_create_from_fd = pvr_srv_winsys_buffer_create_from_fd,
567    .buffer_destroy = pvr_srv_winsys_buffer_destroy,
568    .buffer_get_fd = pvr_srv_winsys_buffer_get_fd,
569    .buffer_map = pvr_srv_winsys_buffer_map,
570    .buffer_unmap = pvr_srv_winsys_buffer_unmap,
571    .heap_alloc = pvr_srv_winsys_heap_alloc,
572    .heap_free = pvr_srv_winsys_heap_free,
573    .vma_map = pvr_srv_winsys_vma_map,
574    .vma_unmap = pvr_srv_winsys_vma_unmap,
575    .free_list_create = pvr_srv_winsys_free_list_create,
576    .free_list_destroy = pvr_srv_winsys_free_list_destroy,
577    .render_target_dataset_create = pvr_srv_render_target_dataset_create,
578    .render_target_dataset_destroy = pvr_srv_render_target_dataset_destroy,
579    .render_ctx_create = pvr_srv_winsys_render_ctx_create,
580    .render_ctx_destroy = pvr_srv_winsys_render_ctx_destroy,
581    .render_submit = pvr_srv_winsys_render_submit,
582    .compute_ctx_create = pvr_srv_winsys_compute_ctx_create,
583    .compute_ctx_destroy = pvr_srv_winsys_compute_ctx_destroy,
584    .compute_submit = pvr_srv_winsys_compute_submit,
585    .transfer_ctx_create = pvr_srv_winsys_transfer_ctx_create,
586    .transfer_ctx_destroy = pvr_srv_winsys_transfer_ctx_destroy,
587    .transfer_submit = pvr_srv_winsys_transfer_submit,
588    .null_job_submit = pvr_srv_winsys_null_job_submit,
589 };
590 
pvr_is_driver_compatible(int render_fd)591 static bool pvr_is_driver_compatible(int render_fd)
592 {
593    drmVersionPtr version;
594 
595    version = drmGetVersion(render_fd);
596    if (!version)
597       return false;
598 
599    assert(strcmp(version->name, "pvr") == 0);
600 
601    /* Only the 1.17 driver is supported for now. */
602    if (version->version_major != PVR_SRV_VERSION_MAJ ||
603        version->version_minor != PVR_SRV_VERSION_MIN) {
604       vk_errorf(NULL,
605                 VK_ERROR_INCOMPATIBLE_DRIVER,
606                 "Unsupported downstream driver version (%u.%u)",
607                 version->version_major,
608                 version->version_minor);
609       drmFreeVersion(version);
610 
611       return false;
612    }
613 
614    drmFreeVersion(version);
615 
616    return true;
617 }
618 
pvr_srv_winsys_create(int master_fd,int render_fd,const VkAllocationCallbacks * alloc)619 struct pvr_winsys *pvr_srv_winsys_create(int master_fd,
620                                          int render_fd,
621                                          const VkAllocationCallbacks *alloc)
622 {
623    struct pvr_srv_winsys *srv_ws;
624    VkResult result;
625    uint64_t bvnc;
626 
627    if (!pvr_is_driver_compatible(render_fd))
628       return NULL;
629 
630    result = pvr_srv_init_module(render_fd, PVR_SRVKM_MODULE_TYPE_SERVICES);
631    if (result != VK_SUCCESS)
632       return NULL;
633 
634    result = pvr_srv_connection_create(render_fd, &bvnc);
635    if (result != VK_SUCCESS)
636       return NULL;
637 
638    srv_ws =
639       vk_zalloc(alloc, sizeof(*srv_ws), 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
640    if (!srv_ws) {
641       vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
642       goto err_pvr_srv_connection_destroy;
643    }
644 
645    srv_ws->base.ops = &srv_winsys_ops;
646    srv_ws->bvnc = bvnc;
647    srv_ws->master_fd = master_fd;
648    srv_ws->render_fd = render_fd;
649    srv_ws->alloc = alloc;
650 
651    srv_ws->base.syncobj_type = pvr_srv_sync_type;
652    srv_ws->base.sync_types[0] = &srv_ws->base.syncobj_type;
653    srv_ws->base.sync_types[1] = NULL;
654 
655    result = pvr_srv_memctx_init(srv_ws);
656    if (result != VK_SUCCESS)
657       goto err_vk_free_srv_ws;
658 
659    result = pvr_srv_sync_prim_block_init(srv_ws);
660    if (result != VK_SUCCESS)
661       goto err_pvr_srv_memctx_finish;
662 
663    return &srv_ws->base;
664 
665 err_pvr_srv_memctx_finish:
666    pvr_srv_memctx_finish(srv_ws);
667 
668 err_vk_free_srv_ws:
669    vk_free(alloc, srv_ws);
670 
671 err_pvr_srv_connection_destroy:
672    pvr_srv_connection_destroy(render_fd);
673 
674    return NULL;
675 }
676 
pvr_srv_sync_prim_alloc(struct pvr_srv_winsys * srv_ws)677 struct pvr_srv_sync_prim *pvr_srv_sync_prim_alloc(struct pvr_srv_winsys *srv_ws)
678 {
679    struct pvr_srv_sync_prim *sync_prim;
680 
681    if (p_atomic_read(&srv_ws->sync_block_offset) == srv_ws->sync_block_size) {
682       vk_error(NULL, VK_ERROR_UNKNOWN);
683       return NULL;
684    }
685 
686    sync_prim = vk_alloc(srv_ws->alloc,
687                         sizeof(*sync_prim),
688                         8,
689                         VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
690    if (!sync_prim) {
691       vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
692       return NULL;
693    }
694 
695    /* p_atomic_add_return() returns the new value rather than the old one, so
696     * we have to subtract PVR_SRV_SYNC_PRIM_VALUE_SIZE to get the old value.
697     */
698    sync_prim->offset = p_atomic_add_return(&srv_ws->sync_block_offset,
699                                            PVR_SRV_SYNC_PRIM_VALUE_SIZE);
700    sync_prim->offset -= PVR_SRV_SYNC_PRIM_VALUE_SIZE;
701    if (sync_prim->offset == srv_ws->sync_block_size) {
702       /* FIXME: need to free offset back to srv_ws->sync_block_offset. */
703       vk_free(srv_ws->alloc, sync_prim);
704 
705       vk_error(NULL, VK_ERROR_UNKNOWN);
706 
707       return NULL;
708    }
709 
710    sync_prim->srv_ws = srv_ws;
711 
712    return sync_prim;
713 }
714 
715 /* FIXME: Add support for freeing offsets back to the sync block. */
pvr_srv_sync_prim_free(struct pvr_srv_sync_prim * sync_prim)716 void pvr_srv_sync_prim_free(struct pvr_srv_sync_prim *sync_prim)
717 {
718    if (sync_prim) {
719       struct pvr_srv_winsys *srv_ws = sync_prim->srv_ws;
720 
721       vk_free(srv_ws->alloc, sync_prim);
722    }
723 }
724