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