17ec681f3Smrg/* 27ec681f3Smrg * Copyright © 2019 Raspberry Pi 37ec681f3Smrg * 47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg * to deal in the Software without restriction, including without limitation 77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg * 117ec681f3Smrg * The above copyright notice and this permission notice (including the next 127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 137ec681f3Smrg * Software. 147ec681f3Smrg * 157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 217ec681f3Smrg * IN THE SOFTWARE. 227ec681f3Smrg */ 237ec681f3Smrg 247ec681f3Smrg#include "v3dv_private.h" 257ec681f3Smrg 267ec681f3Smrg/* We don't expect that the packets we use in this file change across hw 277ec681f3Smrg * versions, so we just explicitly set the V3D_VERSION and include v3dx_pack 287ec681f3Smrg * here 297ec681f3Smrg */ 307ec681f3Smrg#define V3D_VERSION 33 317ec681f3Smrg#include "broadcom/common/v3d_macros.h" 327ec681f3Smrg#include "broadcom/cle/v3dx_pack.h" 337ec681f3Smrg 347ec681f3Smrgvoid 357ec681f3Smrgv3dv_cl_init(struct v3dv_job *job, struct v3dv_cl *cl) 367ec681f3Smrg{ 377ec681f3Smrg cl->base = NULL; 387ec681f3Smrg cl->next = cl->base; 397ec681f3Smrg cl->bo = NULL; 407ec681f3Smrg cl->size = 0; 417ec681f3Smrg cl->job = job; 427ec681f3Smrg list_inithead(&cl->bo_list); 437ec681f3Smrg} 447ec681f3Smrg 457ec681f3Smrgvoid 467ec681f3Smrgv3dv_cl_destroy(struct v3dv_cl *cl) 477ec681f3Smrg{ 487ec681f3Smrg list_for_each_entry_safe(struct v3dv_bo, bo, &cl->bo_list, list_link) { 497ec681f3Smrg assert(cl->job); 507ec681f3Smrg list_del(&bo->list_link); 517ec681f3Smrg v3dv_bo_free(cl->job->device, bo); 527ec681f3Smrg } 537ec681f3Smrg 547ec681f3Smrg /* Leave the CL in a reset state to catch use after destroy instances */ 557ec681f3Smrg v3dv_cl_init(NULL, cl); 567ec681f3Smrg} 577ec681f3Smrg 587ec681f3Smrgstatic bool 597ec681f3Smrgcl_alloc_bo(struct v3dv_cl *cl, uint32_t space, bool use_branch) 607ec681f3Smrg{ 617ec681f3Smrg struct v3dv_bo *bo = v3dv_bo_alloc(cl->job->device, space, "CL", true); 627ec681f3Smrg if (!bo) { 637ec681f3Smrg fprintf(stderr, "failed to allocate memory for command list\n"); 647ec681f3Smrg v3dv_flag_oom(NULL, cl->job); 657ec681f3Smrg return false; 667ec681f3Smrg } 677ec681f3Smrg 687ec681f3Smrg list_addtail(&bo->list_link, &cl->bo_list); 697ec681f3Smrg 707ec681f3Smrg bool ok = v3dv_bo_map(cl->job->device, bo, bo->size); 717ec681f3Smrg if (!ok) { 727ec681f3Smrg fprintf(stderr, "failed to map command list buffer\n"); 737ec681f3Smrg v3dv_flag_oom(NULL, cl->job); 747ec681f3Smrg return false; 757ec681f3Smrg } 767ec681f3Smrg 777ec681f3Smrg /* Chain to the new BO from the old one if requested */ 787ec681f3Smrg if (use_branch && cl->bo) { 797ec681f3Smrg cl_emit(cl, BRANCH, branch) { 807ec681f3Smrg branch.address = v3dv_cl_address(bo, 0); 817ec681f3Smrg } 827ec681f3Smrg } else { 837ec681f3Smrg v3dv_job_add_bo_unchecked(cl->job, bo); 847ec681f3Smrg } 857ec681f3Smrg 867ec681f3Smrg cl->bo = bo; 877ec681f3Smrg cl->base = cl->bo->map; 887ec681f3Smrg cl->size = cl->bo->size; 897ec681f3Smrg cl->next = cl->base; 907ec681f3Smrg 917ec681f3Smrg return true; 927ec681f3Smrg} 937ec681f3Smrg 947ec681f3Smrguint32_t 957ec681f3Smrgv3dv_cl_ensure_space(struct v3dv_cl *cl, uint32_t space, uint32_t alignment) 967ec681f3Smrg{ 977ec681f3Smrg uint32_t offset = align(v3dv_cl_offset(cl), alignment); 987ec681f3Smrg 997ec681f3Smrg if (offset + space <= cl->size) { 1007ec681f3Smrg cl->next = cl->base + offset; 1017ec681f3Smrg return offset; 1027ec681f3Smrg } 1037ec681f3Smrg 1047ec681f3Smrg cl_alloc_bo(cl, space, false); 1057ec681f3Smrg return 0; 1067ec681f3Smrg} 1077ec681f3Smrg 1087ec681f3Smrgvoid 1097ec681f3Smrgv3dv_cl_ensure_space_with_branch(struct v3dv_cl *cl, uint32_t space) 1107ec681f3Smrg{ 1117ec681f3Smrg /* We do not want to emit branches from secondary command lists, instead, 1127ec681f3Smrg * we will branch to them when we execute them in a primary using 1137ec681f3Smrg * 'branch to sub list' commands, expecting each linked secondary to 1147ec681f3Smrg * end with a 'return from sub list' command. 1157ec681f3Smrg */ 1167ec681f3Smrg bool needs_return_from_sub_list = false; 1177ec681f3Smrg if (cl->job->type == V3DV_JOB_TYPE_GPU_CL_SECONDARY) { 1187ec681f3Smrg if (cl->size > 0) { 1197ec681f3Smrg needs_return_from_sub_list = true; 1207ec681f3Smrg space += cl_packet_length(RETURN_FROM_SUB_LIST); 1217ec681f3Smrg } 1227ec681f3Smrg } else { 1237ec681f3Smrg space += cl_packet_length(BRANCH); 1247ec681f3Smrg } 1257ec681f3Smrg 1267ec681f3Smrg if (v3dv_cl_offset(cl) + space <= cl->size) 1277ec681f3Smrg return; 1287ec681f3Smrg 1297ec681f3Smrg if (needs_return_from_sub_list) 1307ec681f3Smrg cl_emit(cl, RETURN_FROM_SUB_LIST, ret); 1317ec681f3Smrg 1327ec681f3Smrg cl_alloc_bo(cl, space, !needs_return_from_sub_list); 1337ec681f3Smrg} 134