1*d93f7937SChristian König /* 2*d93f7937SChristian König * Copyright 2013 Advanced Micro Devices, Inc. 3*d93f7937SChristian König * All Rights Reserved. 4*d93f7937SChristian König * 5*d93f7937SChristian König * Permission is hereby granted, free of charge, to any person obtaining a 6*d93f7937SChristian König * copy of this software and associated documentation files (the 7*d93f7937SChristian König * "Software"), to deal in the Software without restriction, including 8*d93f7937SChristian König * without limitation the rights to use, copy, modify, merge, publish, 9*d93f7937SChristian König * distribute, sub license, and/or sell copies of the Software, and to 10*d93f7937SChristian König * permit persons to whom the Software is furnished to do so, subject to 11*d93f7937SChristian König * the following conditions: 12*d93f7937SChristian König * 13*d93f7937SChristian König * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14*d93f7937SChristian König * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15*d93f7937SChristian König * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 16*d93f7937SChristian König * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 17*d93f7937SChristian König * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18*d93f7937SChristian König * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 19*d93f7937SChristian König * USE OR OTHER DEALINGS IN THE SOFTWARE. 20*d93f7937SChristian König * 21*d93f7937SChristian König * The above copyright notice and this permission notice (including the 22*d93f7937SChristian König * next paragraph) shall be included in all copies or substantial portions 23*d93f7937SChristian König * of the Software. 24*d93f7937SChristian König * 25*d93f7937SChristian König * Authors: Christian König <christian.koenig@amd.com> 26*d93f7937SChristian König */ 27*d93f7937SChristian König 28*d93f7937SChristian König #include <linux/firmware.h> 29*d93f7937SChristian König #include <linux/module.h> 30*d93f7937SChristian König #include <drm/drmP.h> 31*d93f7937SChristian König #include <drm/drm.h> 32*d93f7937SChristian König 33*d93f7937SChristian König #include "radeon.h" 34*d93f7937SChristian König #include "radeon_asic.h" 35*d93f7937SChristian König #include "sid.h" 36*d93f7937SChristian König 37*d93f7937SChristian König /* Firmware Names */ 38*d93f7937SChristian König #define FIRMWARE_BONAIRE "radeon/BONAIRE_vce.bin" 39*d93f7937SChristian König 40*d93f7937SChristian König MODULE_FIRMWARE(FIRMWARE_BONAIRE); 41*d93f7937SChristian König 42*d93f7937SChristian König /** 43*d93f7937SChristian König * radeon_vce_init - allocate memory, load vce firmware 44*d93f7937SChristian König * 45*d93f7937SChristian König * @rdev: radeon_device pointer 46*d93f7937SChristian König * 47*d93f7937SChristian König * First step to get VCE online, allocate memory and load the firmware 48*d93f7937SChristian König */ 49*d93f7937SChristian König int radeon_vce_init(struct radeon_device *rdev) 50*d93f7937SChristian König { 51*d93f7937SChristian König unsigned long bo_size; 52*d93f7937SChristian König const char *fw_name; 53*d93f7937SChristian König int i, r; 54*d93f7937SChristian König 55*d93f7937SChristian König switch (rdev->family) { 56*d93f7937SChristian König case CHIP_BONAIRE: 57*d93f7937SChristian König case CHIP_KAVERI: 58*d93f7937SChristian König case CHIP_KABINI: 59*d93f7937SChristian König fw_name = FIRMWARE_BONAIRE; 60*d93f7937SChristian König break; 61*d93f7937SChristian König 62*d93f7937SChristian König default: 63*d93f7937SChristian König return -EINVAL; 64*d93f7937SChristian König } 65*d93f7937SChristian König 66*d93f7937SChristian König r = request_firmware(&rdev->vce_fw, fw_name, rdev->dev); 67*d93f7937SChristian König if (r) { 68*d93f7937SChristian König dev_err(rdev->dev, "radeon_vce: Can't load firmware \"%s\"\n", 69*d93f7937SChristian König fw_name); 70*d93f7937SChristian König return r; 71*d93f7937SChristian König } 72*d93f7937SChristian König 73*d93f7937SChristian König bo_size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->size) + 74*d93f7937SChristian König RADEON_VCE_STACK_SIZE + RADEON_VCE_HEAP_SIZE; 75*d93f7937SChristian König r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true, 76*d93f7937SChristian König RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->vce.vcpu_bo); 77*d93f7937SChristian König if (r) { 78*d93f7937SChristian König dev_err(rdev->dev, "(%d) failed to allocate VCE bo\n", r); 79*d93f7937SChristian König return r; 80*d93f7937SChristian König } 81*d93f7937SChristian König 82*d93f7937SChristian König r = radeon_vce_resume(rdev); 83*d93f7937SChristian König if (r) 84*d93f7937SChristian König return r; 85*d93f7937SChristian König 86*d93f7937SChristian König memset(rdev->vce.cpu_addr, 0, bo_size); 87*d93f7937SChristian König memcpy(rdev->vce.cpu_addr, rdev->vce_fw->data, rdev->vce_fw->size); 88*d93f7937SChristian König 89*d93f7937SChristian König r = radeon_vce_suspend(rdev); 90*d93f7937SChristian König if (r) 91*d93f7937SChristian König return r; 92*d93f7937SChristian König 93*d93f7937SChristian König for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 94*d93f7937SChristian König atomic_set(&rdev->vce.handles[i], 0); 95*d93f7937SChristian König rdev->vce.filp[i] = NULL; 96*d93f7937SChristian König } 97*d93f7937SChristian König 98*d93f7937SChristian König return 0; 99*d93f7937SChristian König } 100*d93f7937SChristian König 101*d93f7937SChristian König /** 102*d93f7937SChristian König * radeon_vce_fini - free memory 103*d93f7937SChristian König * 104*d93f7937SChristian König * @rdev: radeon_device pointer 105*d93f7937SChristian König * 106*d93f7937SChristian König * Last step on VCE teardown, free firmware memory 107*d93f7937SChristian König */ 108*d93f7937SChristian König void radeon_vce_fini(struct radeon_device *rdev) 109*d93f7937SChristian König { 110*d93f7937SChristian König radeon_vce_suspend(rdev); 111*d93f7937SChristian König radeon_bo_unref(&rdev->vce.vcpu_bo); 112*d93f7937SChristian König } 113*d93f7937SChristian König 114*d93f7937SChristian König /** 115*d93f7937SChristian König * radeon_vce_suspend - unpin VCE fw memory 116*d93f7937SChristian König * 117*d93f7937SChristian König * @rdev: radeon_device pointer 118*d93f7937SChristian König * 119*d93f7937SChristian König * TODO: Test VCE suspend/resume 120*d93f7937SChristian König */ 121*d93f7937SChristian König int radeon_vce_suspend(struct radeon_device *rdev) 122*d93f7937SChristian König { 123*d93f7937SChristian König int r; 124*d93f7937SChristian König 125*d93f7937SChristian König if (rdev->vce.vcpu_bo == NULL) 126*d93f7937SChristian König return 0; 127*d93f7937SChristian König 128*d93f7937SChristian König r = radeon_bo_reserve(rdev->vce.vcpu_bo, false); 129*d93f7937SChristian König if (!r) { 130*d93f7937SChristian König radeon_bo_kunmap(rdev->vce.vcpu_bo); 131*d93f7937SChristian König radeon_bo_unpin(rdev->vce.vcpu_bo); 132*d93f7937SChristian König radeon_bo_unreserve(rdev->vce.vcpu_bo); 133*d93f7937SChristian König } 134*d93f7937SChristian König return r; 135*d93f7937SChristian König } 136*d93f7937SChristian König 137*d93f7937SChristian König /** 138*d93f7937SChristian König * radeon_vce_resume - pin VCE fw memory 139*d93f7937SChristian König * 140*d93f7937SChristian König * @rdev: radeon_device pointer 141*d93f7937SChristian König * 142*d93f7937SChristian König * TODO: Test VCE suspend/resume 143*d93f7937SChristian König */ 144*d93f7937SChristian König int radeon_vce_resume(struct radeon_device *rdev) 145*d93f7937SChristian König { 146*d93f7937SChristian König int r; 147*d93f7937SChristian König 148*d93f7937SChristian König if (rdev->vce.vcpu_bo == NULL) 149*d93f7937SChristian König return -EINVAL; 150*d93f7937SChristian König 151*d93f7937SChristian König r = radeon_bo_reserve(rdev->vce.vcpu_bo, false); 152*d93f7937SChristian König if (r) { 153*d93f7937SChristian König radeon_bo_unref(&rdev->vce.vcpu_bo); 154*d93f7937SChristian König dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r); 155*d93f7937SChristian König return r; 156*d93f7937SChristian König } 157*d93f7937SChristian König 158*d93f7937SChristian König r = radeon_bo_pin(rdev->vce.vcpu_bo, RADEON_GEM_DOMAIN_VRAM, 159*d93f7937SChristian König &rdev->vce.gpu_addr); 160*d93f7937SChristian König if (r) { 161*d93f7937SChristian König radeon_bo_unreserve(rdev->vce.vcpu_bo); 162*d93f7937SChristian König radeon_bo_unref(&rdev->vce.vcpu_bo); 163*d93f7937SChristian König dev_err(rdev->dev, "(%d) VCE bo pin failed\n", r); 164*d93f7937SChristian König return r; 165*d93f7937SChristian König } 166*d93f7937SChristian König 167*d93f7937SChristian König r = radeon_bo_kmap(rdev->vce.vcpu_bo, &rdev->vce.cpu_addr); 168*d93f7937SChristian König if (r) { 169*d93f7937SChristian König dev_err(rdev->dev, "(%d) VCE map failed\n", r); 170*d93f7937SChristian König return r; 171*d93f7937SChristian König } 172*d93f7937SChristian König 173*d93f7937SChristian König radeon_bo_unreserve(rdev->vce.vcpu_bo); 174*d93f7937SChristian König 175*d93f7937SChristian König return 0; 176*d93f7937SChristian König } 177*d93f7937SChristian König 178*d93f7937SChristian König /** 179*d93f7937SChristian König * radeon_vce_free_handles - free still open VCE handles 180*d93f7937SChristian König * 181*d93f7937SChristian König * @rdev: radeon_device pointer 182*d93f7937SChristian König * @filp: drm file pointer 183*d93f7937SChristian König * 184*d93f7937SChristian König * Close all VCE handles still open by this file pointer 185*d93f7937SChristian König */ 186*d93f7937SChristian König void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp) 187*d93f7937SChristian König { 188*d93f7937SChristian König int i, r; 189*d93f7937SChristian König for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 190*d93f7937SChristian König uint32_t handle = atomic_read(&rdev->vce.handles[i]); 191*d93f7937SChristian König if (!handle || rdev->vce.filp[i] != filp) 192*d93f7937SChristian König continue; 193*d93f7937SChristian König 194*d93f7937SChristian König r = radeon_vce_get_destroy_msg(rdev, TN_RING_TYPE_VCE1_INDEX, 195*d93f7937SChristian König handle, NULL); 196*d93f7937SChristian König if (r) 197*d93f7937SChristian König DRM_ERROR("Error destroying VCE handle (%d)!\n", r); 198*d93f7937SChristian König 199*d93f7937SChristian König rdev->vce.filp[i] = NULL; 200*d93f7937SChristian König atomic_set(&rdev->vce.handles[i], 0); 201*d93f7937SChristian König } 202*d93f7937SChristian König } 203*d93f7937SChristian König 204*d93f7937SChristian König /** 205*d93f7937SChristian König * radeon_vce_get_create_msg - generate a VCE create msg 206*d93f7937SChristian König * 207*d93f7937SChristian König * @rdev: radeon_device pointer 208*d93f7937SChristian König * @ring: ring we should submit the msg to 209*d93f7937SChristian König * @handle: VCE session handle to use 210*d93f7937SChristian König * @fence: optional fence to return 211*d93f7937SChristian König * 212*d93f7937SChristian König * Open up a stream for HW test 213*d93f7937SChristian König */ 214*d93f7937SChristian König int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring, 215*d93f7937SChristian König uint32_t handle, struct radeon_fence **fence) 216*d93f7937SChristian König { 217*d93f7937SChristian König const unsigned ib_size_dw = 1024; 218*d93f7937SChristian König struct radeon_ib ib; 219*d93f7937SChristian König uint64_t dummy; 220*d93f7937SChristian König int i, r; 221*d93f7937SChristian König 222*d93f7937SChristian König r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4); 223*d93f7937SChristian König if (r) { 224*d93f7937SChristian König DRM_ERROR("radeon: failed to get ib (%d).\n", r); 225*d93f7937SChristian König return r; 226*d93f7937SChristian König } 227*d93f7937SChristian König 228*d93f7937SChristian König dummy = ib.gpu_addr + 1024; 229*d93f7937SChristian König 230*d93f7937SChristian König /* stitch together an VCE create msg */ 231*d93f7937SChristian König ib.length_dw = 0; 232*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x0000000c; /* len */ 233*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */ 234*d93f7937SChristian König ib.ptr[ib.length_dw++] = handle; 235*d93f7937SChristian König 236*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x00000030; /* len */ 237*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x01000001; /* create cmd */ 238*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x00000000; 239*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x00000042; 240*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x0000000a; 241*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x00000001; 242*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x00000080; 243*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x00000060; 244*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x00000100; 245*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x00000100; 246*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x0000000c; 247*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x00000000; 248*d93f7937SChristian König 249*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x00000014; /* len */ 250*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */ 251*d93f7937SChristian König ib.ptr[ib.length_dw++] = upper_32_bits(dummy); 252*d93f7937SChristian König ib.ptr[ib.length_dw++] = dummy; 253*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x00000001; 254*d93f7937SChristian König 255*d93f7937SChristian König for (i = ib.length_dw; i < ib_size_dw; ++i) 256*d93f7937SChristian König ib.ptr[i] = 0x0; 257*d93f7937SChristian König 258*d93f7937SChristian König r = radeon_ib_schedule(rdev, &ib, NULL); 259*d93f7937SChristian König if (r) { 260*d93f7937SChristian König DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); 261*d93f7937SChristian König } 262*d93f7937SChristian König 263*d93f7937SChristian König if (fence) 264*d93f7937SChristian König *fence = radeon_fence_ref(ib.fence); 265*d93f7937SChristian König 266*d93f7937SChristian König radeon_ib_free(rdev, &ib); 267*d93f7937SChristian König 268*d93f7937SChristian König return r; 269*d93f7937SChristian König } 270*d93f7937SChristian König 271*d93f7937SChristian König /** 272*d93f7937SChristian König * radeon_vce_get_destroy_msg - generate a VCE destroy msg 273*d93f7937SChristian König * 274*d93f7937SChristian König * @rdev: radeon_device pointer 275*d93f7937SChristian König * @ring: ring we should submit the msg to 276*d93f7937SChristian König * @handle: VCE session handle to use 277*d93f7937SChristian König * @fence: optional fence to return 278*d93f7937SChristian König * 279*d93f7937SChristian König * Close up a stream for HW test or if userspace failed to do so 280*d93f7937SChristian König */ 281*d93f7937SChristian König int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, 282*d93f7937SChristian König uint32_t handle, struct radeon_fence **fence) 283*d93f7937SChristian König { 284*d93f7937SChristian König const unsigned ib_size_dw = 1024; 285*d93f7937SChristian König struct radeon_ib ib; 286*d93f7937SChristian König uint64_t dummy; 287*d93f7937SChristian König int i, r; 288*d93f7937SChristian König 289*d93f7937SChristian König r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4); 290*d93f7937SChristian König if (r) { 291*d93f7937SChristian König DRM_ERROR("radeon: failed to get ib (%d).\n", r); 292*d93f7937SChristian König return r; 293*d93f7937SChristian König } 294*d93f7937SChristian König 295*d93f7937SChristian König dummy = ib.gpu_addr + 1024; 296*d93f7937SChristian König 297*d93f7937SChristian König /* stitch together an VCE destroy msg */ 298*d93f7937SChristian König ib.length_dw = 0; 299*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x0000000c; /* len */ 300*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */ 301*d93f7937SChristian König ib.ptr[ib.length_dw++] = handle; 302*d93f7937SChristian König 303*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x00000014; /* len */ 304*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */ 305*d93f7937SChristian König ib.ptr[ib.length_dw++] = upper_32_bits(dummy); 306*d93f7937SChristian König ib.ptr[ib.length_dw++] = dummy; 307*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x00000001; 308*d93f7937SChristian König 309*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x00000008; /* len */ 310*d93f7937SChristian König ib.ptr[ib.length_dw++] = 0x02000001; /* destroy cmd */ 311*d93f7937SChristian König 312*d93f7937SChristian König for (i = ib.length_dw; i < ib_size_dw; ++i) 313*d93f7937SChristian König ib.ptr[i] = 0x0; 314*d93f7937SChristian König 315*d93f7937SChristian König r = radeon_ib_schedule(rdev, &ib, NULL); 316*d93f7937SChristian König if (r) { 317*d93f7937SChristian König DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); 318*d93f7937SChristian König } 319*d93f7937SChristian König 320*d93f7937SChristian König if (fence) 321*d93f7937SChristian König *fence = radeon_fence_ref(ib.fence); 322*d93f7937SChristian König 323*d93f7937SChristian König radeon_ib_free(rdev, &ib); 324*d93f7937SChristian König 325*d93f7937SChristian König return r; 326*d93f7937SChristian König } 327*d93f7937SChristian König 328*d93f7937SChristian König /** 329*d93f7937SChristian König * radeon_vce_cs_reloc - command submission relocation 330*d93f7937SChristian König * 331*d93f7937SChristian König * @p: parser context 332*d93f7937SChristian König * @lo: address of lower dword 333*d93f7937SChristian König * @hi: address of higher dword 334*d93f7937SChristian König * 335*d93f7937SChristian König * Patch relocation inside command stream with real buffer address 336*d93f7937SChristian König */ 337*d93f7937SChristian König int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi) 338*d93f7937SChristian König { 339*d93f7937SChristian König struct radeon_cs_chunk *relocs_chunk; 340*d93f7937SChristian König uint64_t offset; 341*d93f7937SChristian König unsigned idx; 342*d93f7937SChristian König 343*d93f7937SChristian König relocs_chunk = &p->chunks[p->chunk_relocs_idx]; 344*d93f7937SChristian König offset = radeon_get_ib_value(p, lo); 345*d93f7937SChristian König idx = radeon_get_ib_value(p, hi); 346*d93f7937SChristian König 347*d93f7937SChristian König if (idx >= relocs_chunk->length_dw) { 348*d93f7937SChristian König DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", 349*d93f7937SChristian König idx, relocs_chunk->length_dw); 350*d93f7937SChristian König return -EINVAL; 351*d93f7937SChristian König } 352*d93f7937SChristian König 353*d93f7937SChristian König offset += p->relocs_ptr[(idx / 4)]->lobj.gpu_offset; 354*d93f7937SChristian König 355*d93f7937SChristian König p->ib.ptr[lo] = offset & 0xFFFFFFFF; 356*d93f7937SChristian König p->ib.ptr[hi] = offset >> 32; 357*d93f7937SChristian König 358*d93f7937SChristian König return 0; 359*d93f7937SChristian König } 360*d93f7937SChristian König 361*d93f7937SChristian König /** 362*d93f7937SChristian König * radeon_vce_cs_parse - parse and validate the command stream 363*d93f7937SChristian König * 364*d93f7937SChristian König * @p: parser context 365*d93f7937SChristian König * 366*d93f7937SChristian König */ 367*d93f7937SChristian König int radeon_vce_cs_parse(struct radeon_cs_parser *p) 368*d93f7937SChristian König { 369*d93f7937SChristian König uint32_t handle = 0; 370*d93f7937SChristian König bool destroy = false; 371*d93f7937SChristian König int i, r; 372*d93f7937SChristian König 373*d93f7937SChristian König while (p->idx < p->chunks[p->chunk_ib_idx].length_dw) { 374*d93f7937SChristian König uint32_t len = radeon_get_ib_value(p, p->idx); 375*d93f7937SChristian König uint32_t cmd = radeon_get_ib_value(p, p->idx + 1); 376*d93f7937SChristian König 377*d93f7937SChristian König if ((len < 8) || (len & 3)) { 378*d93f7937SChristian König DRM_ERROR("invalid VCE command length (%d)!\n", len); 379*d93f7937SChristian König return -EINVAL; 380*d93f7937SChristian König } 381*d93f7937SChristian König 382*d93f7937SChristian König switch (cmd) { 383*d93f7937SChristian König case 0x00000001: // session 384*d93f7937SChristian König handle = radeon_get_ib_value(p, p->idx + 2); 385*d93f7937SChristian König break; 386*d93f7937SChristian König 387*d93f7937SChristian König case 0x00000002: // task info 388*d93f7937SChristian König case 0x01000001: // create 389*d93f7937SChristian König case 0x04000001: // config extension 390*d93f7937SChristian König case 0x04000002: // pic control 391*d93f7937SChristian König case 0x04000005: // rate control 392*d93f7937SChristian König case 0x04000007: // motion estimation 393*d93f7937SChristian König case 0x04000008: // rdo 394*d93f7937SChristian König break; 395*d93f7937SChristian König 396*d93f7937SChristian König case 0x03000001: // encode 397*d93f7937SChristian König r = radeon_vce_cs_reloc(p, p->idx + 10, p->idx + 9); 398*d93f7937SChristian König if (r) 399*d93f7937SChristian König return r; 400*d93f7937SChristian König 401*d93f7937SChristian König r = radeon_vce_cs_reloc(p, p->idx + 12, p->idx + 11); 402*d93f7937SChristian König if (r) 403*d93f7937SChristian König return r; 404*d93f7937SChristian König break; 405*d93f7937SChristian König 406*d93f7937SChristian König case 0x02000001: // destroy 407*d93f7937SChristian König destroy = true; 408*d93f7937SChristian König break; 409*d93f7937SChristian König 410*d93f7937SChristian König case 0x05000001: // context buffer 411*d93f7937SChristian König case 0x05000004: // video bitstream buffer 412*d93f7937SChristian König case 0x05000005: // feedback buffer 413*d93f7937SChristian König r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2); 414*d93f7937SChristian König if (r) 415*d93f7937SChristian König return r; 416*d93f7937SChristian König break; 417*d93f7937SChristian König 418*d93f7937SChristian König default: 419*d93f7937SChristian König DRM_ERROR("invalid VCE command (0x%x)!\n", cmd); 420*d93f7937SChristian König return -EINVAL; 421*d93f7937SChristian König } 422*d93f7937SChristian König 423*d93f7937SChristian König p->idx += len / 4; 424*d93f7937SChristian König } 425*d93f7937SChristian König 426*d93f7937SChristian König if (destroy) { 427*d93f7937SChristian König /* IB contains a destroy msg, free the handle */ 428*d93f7937SChristian König for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) 429*d93f7937SChristian König atomic_cmpxchg(&p->rdev->vce.handles[i], handle, 0); 430*d93f7937SChristian König 431*d93f7937SChristian König return 0; 432*d93f7937SChristian König } 433*d93f7937SChristian König 434*d93f7937SChristian König /* create or encode, validate the handle */ 435*d93f7937SChristian König for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 436*d93f7937SChristian König if (atomic_read(&p->rdev->vce.handles[i]) == handle) 437*d93f7937SChristian König return 0; 438*d93f7937SChristian König } 439*d93f7937SChristian König 440*d93f7937SChristian König /* handle not found try to alloc a new one */ 441*d93f7937SChristian König for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 442*d93f7937SChristian König if (!atomic_cmpxchg(&p->rdev->vce.handles[i], 0, handle)) { 443*d93f7937SChristian König p->rdev->vce.filp[i] = p->filp; 444*d93f7937SChristian König return 0; 445*d93f7937SChristian König } 446*d93f7937SChristian König } 447*d93f7937SChristian König 448*d93f7937SChristian König DRM_ERROR("No more free VCE handles!\n"); 449*d93f7937SChristian König return -EINVAL; 450*d93f7937SChristian König } 451*d93f7937SChristian König 452*d93f7937SChristian König /** 453*d93f7937SChristian König * radeon_vce_semaphore_emit - emit a semaphore command 454*d93f7937SChristian König * 455*d93f7937SChristian König * @rdev: radeon_device pointer 456*d93f7937SChristian König * @ring: engine to use 457*d93f7937SChristian König * @semaphore: address of semaphore 458*d93f7937SChristian König * @emit_wait: true=emit wait, false=emit signal 459*d93f7937SChristian König * 460*d93f7937SChristian König */ 461*d93f7937SChristian König bool radeon_vce_semaphore_emit(struct radeon_device *rdev, 462*d93f7937SChristian König struct radeon_ring *ring, 463*d93f7937SChristian König struct radeon_semaphore *semaphore, 464*d93f7937SChristian König bool emit_wait) 465*d93f7937SChristian König { 466*d93f7937SChristian König uint64_t addr = semaphore->gpu_addr; 467*d93f7937SChristian König 468*d93f7937SChristian König radeon_ring_write(ring, VCE_CMD_SEMAPHORE); 469*d93f7937SChristian König radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); 470*d93f7937SChristian König radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); 471*d93f7937SChristian König radeon_ring_write(ring, 0x01003000 | (emit_wait ? 1 : 0)); 472*d93f7937SChristian König if (!emit_wait) 473*d93f7937SChristian König radeon_ring_write(ring, VCE_CMD_END); 474*d93f7937SChristian König 475*d93f7937SChristian König return true; 476*d93f7937SChristian König } 477*d93f7937SChristian König 478*d93f7937SChristian König /** 479*d93f7937SChristian König * radeon_vce_ib_execute - execute indirect buffer 480*d93f7937SChristian König * 481*d93f7937SChristian König * @rdev: radeon_device pointer 482*d93f7937SChristian König * @ib: the IB to execute 483*d93f7937SChristian König * 484*d93f7937SChristian König */ 485*d93f7937SChristian König void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) 486*d93f7937SChristian König { 487*d93f7937SChristian König struct radeon_ring *ring = &rdev->ring[ib->ring]; 488*d93f7937SChristian König radeon_ring_write(ring, VCE_CMD_IB); 489*d93f7937SChristian König radeon_ring_write(ring, ib->gpu_addr); 490*d93f7937SChristian König radeon_ring_write(ring, upper_32_bits(ib->gpu_addr)); 491*d93f7937SChristian König radeon_ring_write(ring, ib->length_dw); 492*d93f7937SChristian König } 493*d93f7937SChristian König 494*d93f7937SChristian König /** 495*d93f7937SChristian König * radeon_vce_fence_emit - add a fence command to the ring 496*d93f7937SChristian König * 497*d93f7937SChristian König * @rdev: radeon_device pointer 498*d93f7937SChristian König * @fence: the fence 499*d93f7937SChristian König * 500*d93f7937SChristian König */ 501*d93f7937SChristian König void radeon_vce_fence_emit(struct radeon_device *rdev, 502*d93f7937SChristian König struct radeon_fence *fence) 503*d93f7937SChristian König { 504*d93f7937SChristian König struct radeon_ring *ring = &rdev->ring[fence->ring]; 505*d93f7937SChristian König uint32_t addr = rdev->fence_drv[fence->ring].gpu_addr; 506*d93f7937SChristian König 507*d93f7937SChristian König radeon_ring_write(ring, VCE_CMD_FENCE); 508*d93f7937SChristian König radeon_ring_write(ring, addr); 509*d93f7937SChristian König radeon_ring_write(ring, upper_32_bits(addr)); 510*d93f7937SChristian König radeon_ring_write(ring, fence->seq); 511*d93f7937SChristian König radeon_ring_write(ring, VCE_CMD_TRAP); 512*d93f7937SChristian König radeon_ring_write(ring, VCE_CMD_END); 513*d93f7937SChristian König } 514*d93f7937SChristian König 515*d93f7937SChristian König /** 516*d93f7937SChristian König * radeon_vce_ring_test - test if VCE ring is working 517*d93f7937SChristian König * 518*d93f7937SChristian König * @rdev: radeon_device pointer 519*d93f7937SChristian König * @ring: the engine to test on 520*d93f7937SChristian König * 521*d93f7937SChristian König */ 522*d93f7937SChristian König int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) 523*d93f7937SChristian König { 524*d93f7937SChristian König uint32_t rptr = vce_v1_0_get_rptr(rdev, ring); 525*d93f7937SChristian König unsigned i; 526*d93f7937SChristian König int r; 527*d93f7937SChristian König 528*d93f7937SChristian König r = radeon_ring_lock(rdev, ring, 16); 529*d93f7937SChristian König if (r) { 530*d93f7937SChristian König DRM_ERROR("radeon: vce failed to lock ring %d (%d).\n", 531*d93f7937SChristian König ring->idx, r); 532*d93f7937SChristian König return r; 533*d93f7937SChristian König } 534*d93f7937SChristian König radeon_ring_write(ring, VCE_CMD_END); 535*d93f7937SChristian König radeon_ring_unlock_commit(rdev, ring); 536*d93f7937SChristian König 537*d93f7937SChristian König for (i = 0; i < rdev->usec_timeout; i++) { 538*d93f7937SChristian König if (vce_v1_0_get_rptr(rdev, ring) != rptr) 539*d93f7937SChristian König break; 540*d93f7937SChristian König DRM_UDELAY(1); 541*d93f7937SChristian König } 542*d93f7937SChristian König 543*d93f7937SChristian König if (i < rdev->usec_timeout) { 544*d93f7937SChristian König DRM_INFO("ring test on %d succeeded in %d usecs\n", 545*d93f7937SChristian König ring->idx, i); 546*d93f7937SChristian König } else { 547*d93f7937SChristian König DRM_ERROR("radeon: ring %d test failed\n", 548*d93f7937SChristian König ring->idx); 549*d93f7937SChristian König r = -ETIMEDOUT; 550*d93f7937SChristian König } 551*d93f7937SChristian König 552*d93f7937SChristian König return r; 553*d93f7937SChristian König } 554*d93f7937SChristian König 555*d93f7937SChristian König /** 556*d93f7937SChristian König * radeon_vce_ib_test - test if VCE IBs are working 557*d93f7937SChristian König * 558*d93f7937SChristian König * @rdev: radeon_device pointer 559*d93f7937SChristian König * @ring: the engine to test on 560*d93f7937SChristian König * 561*d93f7937SChristian König */ 562*d93f7937SChristian König int radeon_vce_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) 563*d93f7937SChristian König { 564*d93f7937SChristian König struct radeon_fence *fence = NULL; 565*d93f7937SChristian König int r; 566*d93f7937SChristian König 567*d93f7937SChristian König r = radeon_vce_get_create_msg(rdev, ring->idx, 1, NULL); 568*d93f7937SChristian König if (r) { 569*d93f7937SChristian König DRM_ERROR("radeon: failed to get create msg (%d).\n", r); 570*d93f7937SChristian König goto error; 571*d93f7937SChristian König } 572*d93f7937SChristian König 573*d93f7937SChristian König r = radeon_vce_get_destroy_msg(rdev, ring->idx, 1, &fence); 574*d93f7937SChristian König if (r) { 575*d93f7937SChristian König DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r); 576*d93f7937SChristian König goto error; 577*d93f7937SChristian König } 578*d93f7937SChristian König 579*d93f7937SChristian König r = radeon_fence_wait(fence, false); 580*d93f7937SChristian König if (r) { 581*d93f7937SChristian König DRM_ERROR("radeon: fence wait failed (%d).\n", r); 582*d93f7937SChristian König } else { 583*d93f7937SChristian König DRM_INFO("ib test on ring %d succeeded\n", ring->idx); 584*d93f7937SChristian König } 585*d93f7937SChristian König error: 586*d93f7937SChristian König radeon_fence_unref(&fence); 587*d93f7937SChristian König return r; 588*d93f7937SChristian König } 589