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 53static 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 107static 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 118static 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 281err_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 286err_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 290err_pvr_srv_heap_finish_vis_test: 291 pvr_srv_heap_finish(srv_ws, &srv_ws->vis_test_heap); 292 293err_pvr_srv_heap_finish_usc: 294 pvr_srv_heap_finish(srv_ws, &srv_ws->usc_heap); 295 296err_pvr_srv_heap_finish_transfer_3d: 297 pvr_srv_heap_finish(srv_ws, &srv_ws->transfer_3d_heap); 298 299err_pvr_srv_heap_finish_pds: 300 pvr_srv_heap_finish(srv_ws, &srv_ws->pds_heap); 301 302err_pvr_srv_heap_finish_general: 303 pvr_srv_heap_finish(srv_ws, &srv_ws->general_heap); 304 305err_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 311static 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 350static 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 364static 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 371static 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 382static uint64_t 383pvr_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 399static inline uint64_t 400pvr_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. */ 406static 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 423static inline uint64_t 424pvr_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 443static inline uint64_t 444pvr_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 479static inline uint64_t 480pvr_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 501static int 502pvr_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 544static 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 561static 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 591static 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 619struct 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 665err_pvr_srv_memctx_finish: 666 pvr_srv_memctx_finish(srv_ws); 667 668err_vk_free_srv_ws: 669 vk_free(alloc, srv_ws); 670 671err_pvr_srv_connection_destroy: 672 pvr_srv_connection_destroy(render_fd); 673 674 return NULL; 675} 676 677struct 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. */ 716void 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