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