Home | History | Annotate | Line # | Download | only in radeon
      1  1.5  riastrad /*	$NetBSD: radeon_vce.c,v 1.5 2021/12/18 23:45:43 riastradh Exp $	*/
      2  1.3  riastrad 
      3  1.1  riastrad /*
      4  1.1  riastrad  * Copyright 2013 Advanced Micro Devices, Inc.
      5  1.1  riastrad  * All Rights Reserved.
      6  1.1  riastrad  *
      7  1.1  riastrad  * Permission is hereby granted, free of charge, to any person obtaining a
      8  1.1  riastrad  * copy of this software and associated documentation files (the
      9  1.1  riastrad  * "Software"), to deal in the Software without restriction, including
     10  1.1  riastrad  * without limitation the rights to use, copy, modify, merge, publish,
     11  1.1  riastrad  * distribute, sub license, and/or sell copies of the Software, and to
     12  1.1  riastrad  * permit persons to whom the Software is furnished to do so, subject to
     13  1.1  riastrad  * the following conditions:
     14  1.1  riastrad  *
     15  1.1  riastrad  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  1.1  riastrad  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  1.1  riastrad  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     18  1.1  riastrad  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
     19  1.1  riastrad  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     20  1.1  riastrad  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     21  1.1  riastrad  * USE OR OTHER DEALINGS IN THE SOFTWARE.
     22  1.1  riastrad  *
     23  1.1  riastrad  * The above copyright notice and this permission notice (including the
     24  1.1  riastrad  * next paragraph) shall be included in all copies or substantial portions
     25  1.1  riastrad  * of the Software.
     26  1.1  riastrad  *
     27  1.1  riastrad  * Authors: Christian Knig <christian.koenig (at) amd.com>
     28  1.1  riastrad  */
     29  1.1  riastrad 
     30  1.3  riastrad #include <sys/cdefs.h>
     31  1.5  riastrad __KERNEL_RCSID(0, "$NetBSD: radeon_vce.c,v 1.5 2021/12/18 23:45:43 riastradh Exp $");
     32  1.3  riastrad 
     33  1.1  riastrad #include <linux/firmware.h>
     34  1.1  riastrad #include <linux/module.h>
     35  1.5  riastrad 
     36  1.1  riastrad #include <drm/drm.h>
     37  1.1  riastrad 
     38  1.1  riastrad #include "radeon.h"
     39  1.1  riastrad #include "radeon_asic.h"
     40  1.1  riastrad #include "sid.h"
     41  1.1  riastrad 
     42  1.1  riastrad /* 1 second timeout */
     43  1.1  riastrad #define VCE_IDLE_TIMEOUT_MS	1000
     44  1.1  riastrad 
     45  1.1  riastrad /* Firmware Names */
     46  1.3  riastrad #define FIRMWARE_TAHITI	"radeon/TAHITI_vce.bin"
     47  1.1  riastrad #define FIRMWARE_BONAIRE	"radeon/BONAIRE_vce.bin"
     48  1.1  riastrad 
     49  1.3  riastrad MODULE_FIRMWARE(FIRMWARE_TAHITI);
     50  1.1  riastrad MODULE_FIRMWARE(FIRMWARE_BONAIRE);
     51  1.1  riastrad 
     52  1.1  riastrad static void radeon_vce_idle_work_handler(struct work_struct *work);
     53  1.1  riastrad 
     54  1.2  riastrad #ifdef __NetBSD__		/* XXX Ugh!  */
     55  1.2  riastrad static bool
     56  1.4  jmcneill scan_2dec_uint(const char **sp, char delim, unsigned int *uintp)
     57  1.2  riastrad {
     58  1.4  jmcneill 	u_int val = 0, n;
     59  1.4  jmcneill 	char c;
     60  1.2  riastrad 
     61  1.4  jmcneill 	for (n = 0; n < 2; n++) {
     62  1.4  jmcneill 		c = *(*sp)++;
     63  1.4  jmcneill 		if (!isdigit((unsigned char)c))
     64  1.4  jmcneill 			return false;
     65  1.4  jmcneill 		if (n != 0)
     66  1.4  jmcneill 			val *= 10;
     67  1.4  jmcneill 		val += (c - '0');
     68  1.4  jmcneill 		if (*(*sp) == delim)
     69  1.4  jmcneill 			break;
     70  1.4  jmcneill 	}
     71  1.4  jmcneill 	if (*(*sp) != delim)
     72  1.2  riastrad 		return false;
     73  1.2  riastrad 
     74  1.4  jmcneill 	(*sp)++;
     75  1.4  jmcneill 	*uintp = val;
     76  1.2  riastrad 	return true;
     77  1.2  riastrad }
     78  1.2  riastrad 
     79  1.2  riastrad static bool
     80  1.4  jmcneill scan_2dec_u8(const char **sp, char delim, uint8_t *u8p)
     81  1.2  riastrad {
     82  1.4  jmcneill 	unsigned int val;
     83  1.2  riastrad 
     84  1.4  jmcneill 	if (!scan_2dec_uint(sp, delim, &val))
     85  1.2  riastrad 		return false;
     86  1.2  riastrad 
     87  1.4  jmcneill 	*u8p = (uint8_t)val;
     88  1.2  riastrad 	return true;
     89  1.2  riastrad }
     90  1.2  riastrad #endif
     91  1.2  riastrad 
     92  1.1  riastrad /**
     93  1.1  riastrad  * radeon_vce_init - allocate memory, load vce firmware
     94  1.1  riastrad  *
     95  1.1  riastrad  * @rdev: radeon_device pointer
     96  1.1  riastrad  *
     97  1.1  riastrad  * First step to get VCE online, allocate memory and load the firmware
     98  1.1  riastrad  */
     99  1.1  riastrad int radeon_vce_init(struct radeon_device *rdev)
    100  1.1  riastrad {
    101  1.1  riastrad 	static const char *fw_version = "[ATI LIB=VCEFW,";
    102  1.1  riastrad 	static const char *fb_version = "[ATI LIB=VCEFWSTATS,";
    103  1.1  riastrad 	unsigned long size;
    104  1.1  riastrad 	const char *fw_name, *c;
    105  1.1  riastrad 	uint8_t start, mid, end;
    106  1.1  riastrad 	int i, r;
    107  1.1  riastrad 
    108  1.1  riastrad 	INIT_DELAYED_WORK(&rdev->vce.idle_work, radeon_vce_idle_work_handler);
    109  1.1  riastrad 
    110  1.1  riastrad 	switch (rdev->family) {
    111  1.3  riastrad 	case CHIP_TAHITI:
    112  1.3  riastrad 	case CHIP_PITCAIRN:
    113  1.3  riastrad 	case CHIP_VERDE:
    114  1.3  riastrad 	case CHIP_OLAND:
    115  1.3  riastrad 	case CHIP_ARUBA:
    116  1.3  riastrad 		fw_name = FIRMWARE_TAHITI;
    117  1.3  riastrad 		break;
    118  1.3  riastrad 
    119  1.1  riastrad 	case CHIP_BONAIRE:
    120  1.1  riastrad 	case CHIP_KAVERI:
    121  1.1  riastrad 	case CHIP_KABINI:
    122  1.3  riastrad 	case CHIP_HAWAII:
    123  1.1  riastrad 	case CHIP_MULLINS:
    124  1.1  riastrad 		fw_name = FIRMWARE_BONAIRE;
    125  1.1  riastrad 		break;
    126  1.1  riastrad 
    127  1.1  riastrad 	default:
    128  1.1  riastrad 		return -EINVAL;
    129  1.1  riastrad 	}
    130  1.1  riastrad 
    131  1.1  riastrad 	r = request_firmware(&rdev->vce_fw, fw_name, rdev->dev);
    132  1.1  riastrad 	if (r) {
    133  1.1  riastrad 		dev_err(rdev->dev, "radeon_vce: Can't load firmware \"%s\"\n",
    134  1.1  riastrad 			fw_name);
    135  1.1  riastrad 		return r;
    136  1.1  riastrad 	}
    137  1.1  riastrad 
    138  1.1  riastrad 	/* search for firmware version */
    139  1.1  riastrad 
    140  1.1  riastrad 	size = rdev->vce_fw->size - strlen(fw_version) - 9;
    141  1.1  riastrad 	c = rdev->vce_fw->data;
    142  1.1  riastrad 	for (;size > 0; --size, ++c)
    143  1.1  riastrad 		if (strncmp(c, fw_version, strlen(fw_version)) == 0)
    144  1.1  riastrad 			break;
    145  1.1  riastrad 
    146  1.1  riastrad 	if (size == 0)
    147  1.1  riastrad 		return -EINVAL;
    148  1.1  riastrad 
    149  1.1  riastrad 	c += strlen(fw_version);
    150  1.2  riastrad #ifdef __NetBSD__
    151  1.2  riastrad 	if (!scan_2dec_u8(&c, '.', &start))
    152  1.2  riastrad 		return -EINVAL;
    153  1.2  riastrad 	if (!scan_2dec_u8(&c, '.', &mid))
    154  1.2  riastrad 		return -EINVAL;
    155  1.2  riastrad 	if (!scan_2dec_u8(&c, ']', &end))
    156  1.2  riastrad 		return -EINVAL;
    157  1.2  riastrad #else
    158  1.1  riastrad 	if (sscanf(c, "%2hhd.%2hhd.%2hhd]", &start, &mid, &end) != 3)
    159  1.1  riastrad 		return -EINVAL;
    160  1.2  riastrad #endif
    161  1.1  riastrad 
    162  1.1  riastrad 	/* search for feedback version */
    163  1.1  riastrad 
    164  1.1  riastrad 	size = rdev->vce_fw->size - strlen(fb_version) - 3;
    165  1.1  riastrad 	c = rdev->vce_fw->data;
    166  1.1  riastrad 	for (;size > 0; --size, ++c)
    167  1.1  riastrad 		if (strncmp(c, fb_version, strlen(fb_version)) == 0)
    168  1.1  riastrad 			break;
    169  1.1  riastrad 
    170  1.1  riastrad 	if (size == 0)
    171  1.1  riastrad 		return -EINVAL;
    172  1.1  riastrad 
    173  1.1  riastrad 	c += strlen(fb_version);
    174  1.2  riastrad #ifdef __NetBSD__
    175  1.2  riastrad 	if (!scan_2dec_uint(&c, ']', &rdev->vce.fb_version))
    176  1.2  riastrad 		return -EINVAL;
    177  1.2  riastrad #else
    178  1.1  riastrad 	if (sscanf(c, "%2u]", &rdev->vce.fb_version) != 1)
    179  1.1  riastrad 		return -EINVAL;
    180  1.2  riastrad #endif
    181  1.1  riastrad 
    182  1.1  riastrad 	DRM_INFO("Found VCE firmware/feedback version %hhd.%hhd.%hhd / %d!\n",
    183  1.1  riastrad 		 start, mid, end, rdev->vce.fb_version);
    184  1.1  riastrad 
    185  1.1  riastrad 	rdev->vce.fw_version = (start << 24) | (mid << 16) | (end << 8);
    186  1.1  riastrad 
    187  1.1  riastrad 	/* we can only work with this fw version for now */
    188  1.3  riastrad 	if ((rdev->vce.fw_version != ((40 << 24) | (2 << 16) | (2 << 8))) &&
    189  1.3  riastrad 	    (rdev->vce.fw_version != ((50 << 24) | (0 << 16) | (1 << 8))) &&
    190  1.3  riastrad 	    (rdev->vce.fw_version != ((50 << 24) | (1 << 16) | (2 << 8))))
    191  1.1  riastrad 		return -EINVAL;
    192  1.1  riastrad 
    193  1.1  riastrad 	/* allocate firmware, stack and heap BO */
    194  1.1  riastrad 
    195  1.3  riastrad 	if (rdev->family < CHIP_BONAIRE)
    196  1.3  riastrad 		size = vce_v1_0_bo_size(rdev);
    197  1.3  riastrad 	else
    198  1.3  riastrad 		size = vce_v2_0_bo_size(rdev);
    199  1.1  riastrad 	r = radeon_bo_create(rdev, size, PAGE_SIZE, true,
    200  1.3  riastrad 			     RADEON_GEM_DOMAIN_VRAM, 0, NULL, NULL,
    201  1.3  riastrad 			     &rdev->vce.vcpu_bo);
    202  1.1  riastrad 	if (r) {
    203  1.1  riastrad 		dev_err(rdev->dev, "(%d) failed to allocate VCE bo\n", r);
    204  1.1  riastrad 		return r;
    205  1.1  riastrad 	}
    206  1.1  riastrad 
    207  1.1  riastrad 	r = radeon_bo_reserve(rdev->vce.vcpu_bo, false);
    208  1.1  riastrad 	if (r) {
    209  1.1  riastrad 		radeon_bo_unref(&rdev->vce.vcpu_bo);
    210  1.1  riastrad 		dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r);
    211  1.1  riastrad 		return r;
    212  1.1  riastrad 	}
    213  1.1  riastrad 
    214  1.1  riastrad 	r = radeon_bo_pin(rdev->vce.vcpu_bo, RADEON_GEM_DOMAIN_VRAM,
    215  1.1  riastrad 			  &rdev->vce.gpu_addr);
    216  1.1  riastrad 	radeon_bo_unreserve(rdev->vce.vcpu_bo);
    217  1.1  riastrad 	if (r) {
    218  1.1  riastrad 		radeon_bo_unref(&rdev->vce.vcpu_bo);
    219  1.1  riastrad 		dev_err(rdev->dev, "(%d) VCE bo pin failed\n", r);
    220  1.1  riastrad 		return r;
    221  1.1  riastrad 	}
    222  1.1  riastrad 
    223  1.1  riastrad 	for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) {
    224  1.1  riastrad 		atomic_set(&rdev->vce.handles[i], 0);
    225  1.1  riastrad 		rdev->vce.filp[i] = NULL;
    226  1.5  riastrad 	}
    227  1.1  riastrad 
    228  1.1  riastrad 	return 0;
    229  1.1  riastrad }
    230  1.1  riastrad 
    231  1.1  riastrad /**
    232  1.1  riastrad  * radeon_vce_fini - free memory
    233  1.1  riastrad  *
    234  1.1  riastrad  * @rdev: radeon_device pointer
    235  1.1  riastrad  *
    236  1.1  riastrad  * Last step on VCE teardown, free firmware memory
    237  1.1  riastrad  */
    238  1.1  riastrad void radeon_vce_fini(struct radeon_device *rdev)
    239  1.1  riastrad {
    240  1.1  riastrad 	if (rdev->vce.vcpu_bo == NULL)
    241  1.1  riastrad 		return;
    242  1.1  riastrad 
    243  1.1  riastrad 	radeon_bo_unref(&rdev->vce.vcpu_bo);
    244  1.1  riastrad 
    245  1.1  riastrad 	release_firmware(rdev->vce_fw);
    246  1.1  riastrad }
    247  1.1  riastrad 
    248  1.1  riastrad /**
    249  1.1  riastrad  * radeon_vce_suspend - unpin VCE fw memory
    250  1.1  riastrad  *
    251  1.1  riastrad  * @rdev: radeon_device pointer
    252  1.1  riastrad  *
    253  1.1  riastrad  */
    254  1.1  riastrad int radeon_vce_suspend(struct radeon_device *rdev)
    255  1.1  riastrad {
    256  1.1  riastrad 	int i;
    257  1.1  riastrad 
    258  1.1  riastrad 	if (rdev->vce.vcpu_bo == NULL)
    259  1.1  riastrad 		return 0;
    260  1.1  riastrad 
    261  1.1  riastrad 	for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i)
    262  1.1  riastrad 		if (atomic_read(&rdev->vce.handles[i]))
    263  1.1  riastrad 			break;
    264  1.1  riastrad 
    265  1.1  riastrad 	if (i == RADEON_MAX_VCE_HANDLES)
    266  1.1  riastrad 		return 0;
    267  1.1  riastrad 
    268  1.1  riastrad 	/* TODO: suspending running encoding sessions isn't supported */
    269  1.1  riastrad 	return -EINVAL;
    270  1.1  riastrad }
    271  1.1  riastrad 
    272  1.1  riastrad /**
    273  1.1  riastrad  * radeon_vce_resume - pin VCE fw memory
    274  1.1  riastrad  *
    275  1.1  riastrad  * @rdev: radeon_device pointer
    276  1.1  riastrad  *
    277  1.1  riastrad  */
    278  1.1  riastrad int radeon_vce_resume(struct radeon_device *rdev)
    279  1.1  riastrad {
    280  1.1  riastrad 	void *cpu_addr;
    281  1.1  riastrad 	int r;
    282  1.1  riastrad 
    283  1.1  riastrad 	if (rdev->vce.vcpu_bo == NULL)
    284  1.1  riastrad 		return -EINVAL;
    285  1.1  riastrad 
    286  1.1  riastrad 	r = radeon_bo_reserve(rdev->vce.vcpu_bo, false);
    287  1.1  riastrad 	if (r) {
    288  1.1  riastrad 		dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r);
    289  1.1  riastrad 		return r;
    290  1.1  riastrad 	}
    291  1.1  riastrad 
    292  1.1  riastrad 	r = radeon_bo_kmap(rdev->vce.vcpu_bo, &cpu_addr);
    293  1.1  riastrad 	if (r) {
    294  1.1  riastrad 		radeon_bo_unreserve(rdev->vce.vcpu_bo);
    295  1.1  riastrad 		dev_err(rdev->dev, "(%d) VCE map failed\n", r);
    296  1.1  riastrad 		return r;
    297  1.1  riastrad 	}
    298  1.1  riastrad 
    299  1.3  riastrad 	memset(cpu_addr, 0, radeon_bo_size(rdev->vce.vcpu_bo));
    300  1.3  riastrad 	if (rdev->family < CHIP_BONAIRE)
    301  1.3  riastrad 		r = vce_v1_0_load_fw(rdev, cpu_addr);
    302  1.3  riastrad 	else
    303  1.3  riastrad 		memcpy(cpu_addr, rdev->vce_fw->data, rdev->vce_fw->size);
    304  1.1  riastrad 
    305  1.1  riastrad 	radeon_bo_kunmap(rdev->vce.vcpu_bo);
    306  1.1  riastrad 
    307  1.1  riastrad 	radeon_bo_unreserve(rdev->vce.vcpu_bo);
    308  1.1  riastrad 
    309  1.3  riastrad 	return r;
    310  1.1  riastrad }
    311  1.1  riastrad 
    312  1.1  riastrad /**
    313  1.1  riastrad  * radeon_vce_idle_work_handler - power off VCE
    314  1.1  riastrad  *
    315  1.1  riastrad  * @work: pointer to work structure
    316  1.1  riastrad  *
    317  1.1  riastrad  * power of VCE when it's not used any more
    318  1.1  riastrad  */
    319  1.1  riastrad static void radeon_vce_idle_work_handler(struct work_struct *work)
    320  1.1  riastrad {
    321  1.1  riastrad 	struct radeon_device *rdev =
    322  1.1  riastrad 		container_of(work, struct radeon_device, vce.idle_work.work);
    323  1.1  riastrad 
    324  1.1  riastrad 	if ((radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE1_INDEX) == 0) &&
    325  1.1  riastrad 	    (radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE2_INDEX) == 0)) {
    326  1.1  riastrad 		if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
    327  1.1  riastrad 			radeon_dpm_enable_vce(rdev, false);
    328  1.1  riastrad 		} else {
    329  1.1  riastrad 			radeon_set_vce_clocks(rdev, 0, 0);
    330  1.1  riastrad 		}
    331  1.1  riastrad 	} else {
    332  1.1  riastrad 		schedule_delayed_work(&rdev->vce.idle_work,
    333  1.1  riastrad 				      msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS));
    334  1.1  riastrad 	}
    335  1.1  riastrad }
    336  1.1  riastrad 
    337  1.1  riastrad /**
    338  1.1  riastrad  * radeon_vce_note_usage - power up VCE
    339  1.1  riastrad  *
    340  1.1  riastrad  * @rdev: radeon_device pointer
    341  1.1  riastrad  *
    342  1.1  riastrad  * Make sure VCE is powerd up when we want to use it
    343  1.1  riastrad  */
    344  1.1  riastrad void radeon_vce_note_usage(struct radeon_device *rdev)
    345  1.1  riastrad {
    346  1.1  riastrad 	bool streams_changed = false;
    347  1.1  riastrad 	bool set_clocks = !cancel_delayed_work_sync(&rdev->vce.idle_work);
    348  1.1  riastrad 	set_clocks &= schedule_delayed_work(&rdev->vce.idle_work,
    349  1.1  riastrad 					    msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS));
    350  1.1  riastrad 
    351  1.1  riastrad 	if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
    352  1.1  riastrad 		/* XXX figure out if the streams changed */
    353  1.1  riastrad 		streams_changed = false;
    354  1.1  riastrad 	}
    355  1.1  riastrad 
    356  1.1  riastrad 	if (set_clocks || streams_changed) {
    357  1.1  riastrad 		if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
    358  1.1  riastrad 			radeon_dpm_enable_vce(rdev, true);
    359  1.1  riastrad 		} else {
    360  1.1  riastrad 			radeon_set_vce_clocks(rdev, 53300, 40000);
    361  1.1  riastrad 		}
    362  1.1  riastrad 	}
    363  1.1  riastrad }
    364  1.1  riastrad 
    365  1.1  riastrad /**
    366  1.1  riastrad  * radeon_vce_free_handles - free still open VCE handles
    367  1.1  riastrad  *
    368  1.1  riastrad  * @rdev: radeon_device pointer
    369  1.1  riastrad  * @filp: drm file pointer
    370  1.1  riastrad  *
    371  1.1  riastrad  * Close all VCE handles still open by this file pointer
    372  1.1  riastrad  */
    373  1.1  riastrad void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp)
    374  1.1  riastrad {
    375  1.1  riastrad 	int i, r;
    376  1.1  riastrad 	for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) {
    377  1.1  riastrad 		uint32_t handle = atomic_read(&rdev->vce.handles[i]);
    378  1.1  riastrad 		if (!handle || rdev->vce.filp[i] != filp)
    379  1.1  riastrad 			continue;
    380  1.1  riastrad 
    381  1.1  riastrad 		radeon_vce_note_usage(rdev);
    382  1.1  riastrad 
    383  1.1  riastrad 		r = radeon_vce_get_destroy_msg(rdev, TN_RING_TYPE_VCE1_INDEX,
    384  1.1  riastrad 					       handle, NULL);
    385  1.1  riastrad 		if (r)
    386  1.1  riastrad 			DRM_ERROR("Error destroying VCE handle (%d)!\n", r);
    387  1.1  riastrad 
    388  1.1  riastrad 		rdev->vce.filp[i] = NULL;
    389  1.1  riastrad 		atomic_set(&rdev->vce.handles[i], 0);
    390  1.1  riastrad 	}
    391  1.1  riastrad }
    392  1.1  riastrad 
    393  1.1  riastrad /**
    394  1.1  riastrad  * radeon_vce_get_create_msg - generate a VCE create msg
    395  1.1  riastrad  *
    396  1.1  riastrad  * @rdev: radeon_device pointer
    397  1.1  riastrad  * @ring: ring we should submit the msg to
    398  1.1  riastrad  * @handle: VCE session handle to use
    399  1.1  riastrad  * @fence: optional fence to return
    400  1.1  riastrad  *
    401  1.1  riastrad  * Open up a stream for HW test
    402  1.1  riastrad  */
    403  1.1  riastrad int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring,
    404  1.1  riastrad 			      uint32_t handle, struct radeon_fence **fence)
    405  1.1  riastrad {
    406  1.1  riastrad 	const unsigned ib_size_dw = 1024;
    407  1.1  riastrad 	struct radeon_ib ib;
    408  1.1  riastrad 	uint64_t dummy;
    409  1.1  riastrad 	int i, r;
    410  1.1  riastrad 
    411  1.1  riastrad 	r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4);
    412  1.1  riastrad 	if (r) {
    413  1.1  riastrad 		DRM_ERROR("radeon: failed to get ib (%d).\n", r);
    414  1.1  riastrad 		return r;
    415  1.1  riastrad 	}
    416  1.1  riastrad 
    417  1.1  riastrad 	dummy = ib.gpu_addr + 1024;
    418  1.1  riastrad 
    419  1.1  riastrad 	/* stitch together an VCE create msg */
    420  1.1  riastrad 	ib.length_dw = 0;
    421  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); /* len */
    422  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); /* session cmd */
    423  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(handle);
    424  1.3  riastrad 
    425  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000030); /* len */
    426  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x01000001); /* create cmd */
    427  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000);
    428  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000042);
    429  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000a);
    430  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001);
    431  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000080);
    432  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000060);
    433  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100);
    434  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100);
    435  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c);
    436  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000);
    437  1.3  riastrad 
    438  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014); /* len */
    439  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005); /* feedback buffer */
    440  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy));
    441  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(dummy);
    442  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001);
    443  1.1  riastrad 
    444  1.1  riastrad 	for (i = ib.length_dw; i < ib_size_dw; ++i)
    445  1.3  riastrad 		ib.ptr[i] = cpu_to_le32(0x0);
    446  1.1  riastrad 
    447  1.3  riastrad 	r = radeon_ib_schedule(rdev, &ib, NULL, false);
    448  1.5  riastrad 	if (r)
    449  1.5  riastrad 		DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
    450  1.5  riastrad 
    451  1.1  riastrad 
    452  1.1  riastrad 	if (fence)
    453  1.1  riastrad 		*fence = radeon_fence_ref(ib.fence);
    454  1.1  riastrad 
    455  1.1  riastrad 	radeon_ib_free(rdev, &ib);
    456  1.1  riastrad 
    457  1.1  riastrad 	return r;
    458  1.1  riastrad }
    459  1.1  riastrad 
    460  1.1  riastrad /**
    461  1.1  riastrad  * radeon_vce_get_destroy_msg - generate a VCE destroy msg
    462  1.1  riastrad  *
    463  1.1  riastrad  * @rdev: radeon_device pointer
    464  1.1  riastrad  * @ring: ring we should submit the msg to
    465  1.1  riastrad  * @handle: VCE session handle to use
    466  1.1  riastrad  * @fence: optional fence to return
    467  1.1  riastrad  *
    468  1.1  riastrad  * Close up a stream for HW test or if userspace failed to do so
    469  1.1  riastrad  */
    470  1.1  riastrad int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring,
    471  1.1  riastrad 			       uint32_t handle, struct radeon_fence **fence)
    472  1.1  riastrad {
    473  1.1  riastrad 	const unsigned ib_size_dw = 1024;
    474  1.1  riastrad 	struct radeon_ib ib;
    475  1.1  riastrad 	uint64_t dummy;
    476  1.1  riastrad 	int i, r;
    477  1.1  riastrad 
    478  1.1  riastrad 	r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4);
    479  1.1  riastrad 	if (r) {
    480  1.1  riastrad 		DRM_ERROR("radeon: failed to get ib (%d).\n", r);
    481  1.1  riastrad 		return r;
    482  1.1  riastrad 	}
    483  1.1  riastrad 
    484  1.1  riastrad 	dummy = ib.gpu_addr + 1024;
    485  1.1  riastrad 
    486  1.1  riastrad 	/* stitch together an VCE destroy msg */
    487  1.1  riastrad 	ib.length_dw = 0;
    488  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); /* len */
    489  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); /* session cmd */
    490  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(handle);
    491  1.3  riastrad 
    492  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014); /* len */
    493  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005); /* feedback buffer */
    494  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy));
    495  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(dummy);
    496  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001);
    497  1.1  riastrad 
    498  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000008); /* len */
    499  1.3  riastrad 	ib.ptr[ib.length_dw++] = cpu_to_le32(0x02000001); /* destroy cmd */
    500  1.1  riastrad 
    501  1.1  riastrad 	for (i = ib.length_dw; i < ib_size_dw; ++i)
    502  1.3  riastrad 		ib.ptr[i] = cpu_to_le32(0x0);
    503  1.1  riastrad 
    504  1.3  riastrad 	r = radeon_ib_schedule(rdev, &ib, NULL, false);
    505  1.1  riastrad 	if (r) {
    506  1.5  riastrad 		DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
    507  1.1  riastrad 	}
    508  1.1  riastrad 
    509  1.1  riastrad 	if (fence)
    510  1.1  riastrad 		*fence = radeon_fence_ref(ib.fence);
    511  1.1  riastrad 
    512  1.1  riastrad 	radeon_ib_free(rdev, &ib);
    513  1.1  riastrad 
    514  1.1  riastrad 	return r;
    515  1.1  riastrad }
    516  1.1  riastrad 
    517  1.1  riastrad /**
    518  1.1  riastrad  * radeon_vce_cs_reloc - command submission relocation
    519  1.1  riastrad  *
    520  1.1  riastrad  * @p: parser context
    521  1.1  riastrad  * @lo: address of lower dword
    522  1.1  riastrad  * @hi: address of higher dword
    523  1.1  riastrad  * @size: size of checker for relocation buffer
    524  1.1  riastrad  *
    525  1.1  riastrad  * Patch relocation inside command stream with real buffer address
    526  1.1  riastrad  */
    527  1.1  riastrad int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi,
    528  1.1  riastrad 			unsigned size)
    529  1.1  riastrad {
    530  1.1  riastrad 	struct radeon_cs_chunk *relocs_chunk;
    531  1.3  riastrad 	struct radeon_bo_list *reloc;
    532  1.1  riastrad 	uint64_t start, end, offset;
    533  1.1  riastrad 	unsigned idx;
    534  1.1  riastrad 
    535  1.3  riastrad 	relocs_chunk = p->chunk_relocs;
    536  1.1  riastrad 	offset = radeon_get_ib_value(p, lo);
    537  1.1  riastrad 	idx = radeon_get_ib_value(p, hi);
    538  1.1  riastrad 
    539  1.1  riastrad 	if (idx >= relocs_chunk->length_dw) {
    540  1.1  riastrad 		DRM_ERROR("Relocs at %d after relocations chunk end %d !\n",
    541  1.1  riastrad 			  idx, relocs_chunk->length_dw);
    542  1.1  riastrad 		return -EINVAL;
    543  1.1  riastrad 	}
    544  1.1  riastrad 
    545  1.3  riastrad 	reloc = &p->relocs[(idx / 4)];
    546  1.1  riastrad 	start = reloc->gpu_offset;
    547  1.1  riastrad 	end = start + radeon_bo_size(reloc->robj);
    548  1.1  riastrad 	start += offset;
    549  1.1  riastrad 
    550  1.1  riastrad 	p->ib.ptr[lo] = start & 0xFFFFFFFF;
    551  1.1  riastrad 	p->ib.ptr[hi] = start >> 32;
    552  1.1  riastrad 
    553  1.1  riastrad 	if (end <= start) {
    554  1.2  riastrad 		DRM_ERROR("invalid reloc offset %"PRIX64"!\n", offset);
    555  1.1  riastrad 		return -EINVAL;
    556  1.1  riastrad 	}
    557  1.1  riastrad 	if ((end - start) < size) {
    558  1.1  riastrad 		DRM_ERROR("buffer to small (%d / %d)!\n",
    559  1.1  riastrad 			(unsigned)(end - start), size);
    560  1.1  riastrad 		return -EINVAL;
    561  1.1  riastrad 	}
    562  1.1  riastrad 
    563  1.1  riastrad 	return 0;
    564  1.1  riastrad }
    565  1.1  riastrad 
    566  1.1  riastrad /**
    567  1.1  riastrad  * radeon_vce_validate_handle - validate stream handle
    568  1.1  riastrad  *
    569  1.1  riastrad  * @p: parser context
    570  1.1  riastrad  * @handle: handle to validate
    571  1.3  riastrad  * @allocated: allocated a new handle?
    572  1.1  riastrad  *
    573  1.1  riastrad  * Validates the handle and return the found session index or -EINVAL
    574  1.1  riastrad  * we we don't have another free session index.
    575  1.1  riastrad  */
    576  1.3  riastrad static int radeon_vce_validate_handle(struct radeon_cs_parser *p,
    577  1.3  riastrad 				      uint32_t handle, bool *allocated)
    578  1.1  riastrad {
    579  1.1  riastrad 	unsigned i;
    580  1.1  riastrad 
    581  1.3  riastrad 	*allocated = false;
    582  1.3  riastrad 
    583  1.1  riastrad 	/* validate the handle */
    584  1.1  riastrad 	for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) {
    585  1.3  riastrad 		if (atomic_read(&p->rdev->vce.handles[i]) == handle) {
    586  1.3  riastrad 			if (p->rdev->vce.filp[i] != p->filp) {
    587  1.3  riastrad 				DRM_ERROR("VCE handle collision detected!\n");
    588  1.3  riastrad 				return -EINVAL;
    589  1.3  riastrad 			}
    590  1.1  riastrad 			return i;
    591  1.3  riastrad 		}
    592  1.1  riastrad 	}
    593  1.1  riastrad 
    594  1.1  riastrad 	/* handle not found try to alloc a new one */
    595  1.1  riastrad 	for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) {
    596  1.1  riastrad 		if (!atomic_cmpxchg(&p->rdev->vce.handles[i], 0, handle)) {
    597  1.1  riastrad 			p->rdev->vce.filp[i] = p->filp;
    598  1.1  riastrad 			p->rdev->vce.img_size[i] = 0;
    599  1.3  riastrad 			*allocated = true;
    600  1.1  riastrad 			return i;
    601  1.1  riastrad 		}
    602  1.1  riastrad 	}
    603  1.1  riastrad 
    604  1.1  riastrad 	DRM_ERROR("No more free VCE handles!\n");
    605  1.1  riastrad 	return -EINVAL;
    606  1.1  riastrad }
    607  1.1  riastrad 
    608  1.1  riastrad /**
    609  1.1  riastrad  * radeon_vce_cs_parse - parse and validate the command stream
    610  1.1  riastrad  *
    611  1.1  riastrad  * @p: parser context
    612  1.1  riastrad  *
    613  1.1  riastrad  */
    614  1.1  riastrad int radeon_vce_cs_parse(struct radeon_cs_parser *p)
    615  1.1  riastrad {
    616  1.1  riastrad 	int session_idx = -1;
    617  1.3  riastrad 	bool destroyed = false, created = false, allocated = false;
    618  1.1  riastrad 	uint32_t tmp, handle = 0;
    619  1.1  riastrad 	uint32_t *size = &tmp;
    620  1.3  riastrad 	int i, r = 0;
    621  1.1  riastrad 
    622  1.3  riastrad 	while (p->idx < p->chunk_ib->length_dw) {
    623  1.1  riastrad 		uint32_t len = radeon_get_ib_value(p, p->idx);
    624  1.1  riastrad 		uint32_t cmd = radeon_get_ib_value(p, p->idx + 1);
    625  1.1  riastrad 
    626  1.1  riastrad 		if ((len < 8) || (len & 3)) {
    627  1.1  riastrad 			DRM_ERROR("invalid VCE command length (%d)!\n", len);
    628  1.3  riastrad 			r = -EINVAL;
    629  1.3  riastrad 			goto out;
    630  1.1  riastrad 		}
    631  1.1  riastrad 
    632  1.1  riastrad 		if (destroyed) {
    633  1.1  riastrad 			DRM_ERROR("No other command allowed after destroy!\n");
    634  1.3  riastrad 			r = -EINVAL;
    635  1.3  riastrad 			goto out;
    636  1.1  riastrad 		}
    637  1.1  riastrad 
    638  1.1  riastrad 		switch (cmd) {
    639  1.1  riastrad 		case 0x00000001: // session
    640  1.1  riastrad 			handle = radeon_get_ib_value(p, p->idx + 2);
    641  1.3  riastrad 			session_idx = radeon_vce_validate_handle(p, handle,
    642  1.3  riastrad 								 &allocated);
    643  1.1  riastrad 			if (session_idx < 0)
    644  1.1  riastrad 				return session_idx;
    645  1.1  riastrad 			size = &p->rdev->vce.img_size[session_idx];
    646  1.1  riastrad 			break;
    647  1.1  riastrad 
    648  1.1  riastrad 		case 0x00000002: // task info
    649  1.1  riastrad 			break;
    650  1.1  riastrad 
    651  1.1  riastrad 		case 0x01000001: // create
    652  1.3  riastrad 			created = true;
    653  1.3  riastrad 			if (!allocated) {
    654  1.3  riastrad 				DRM_ERROR("Handle already in use!\n");
    655  1.3  riastrad 				r = -EINVAL;
    656  1.3  riastrad 				goto out;
    657  1.3  riastrad 			}
    658  1.3  riastrad 
    659  1.1  riastrad 			*size = radeon_get_ib_value(p, p->idx + 8) *
    660  1.1  riastrad 				radeon_get_ib_value(p, p->idx + 10) *
    661  1.1  riastrad 				8 * 3 / 2;
    662  1.1  riastrad 			break;
    663  1.1  riastrad 
    664  1.1  riastrad 		case 0x04000001: // config extension
    665  1.1  riastrad 		case 0x04000002: // pic control
    666  1.1  riastrad 		case 0x04000005: // rate control
    667  1.1  riastrad 		case 0x04000007: // motion estimation
    668  1.1  riastrad 		case 0x04000008: // rdo
    669  1.3  riastrad 		case 0x04000009: // vui
    670  1.1  riastrad 			break;
    671  1.1  riastrad 
    672  1.1  riastrad 		case 0x03000001: // encode
    673  1.1  riastrad 			r = radeon_vce_cs_reloc(p, p->idx + 10, p->idx + 9,
    674  1.1  riastrad 						*size);
    675  1.1  riastrad 			if (r)
    676  1.3  riastrad 				goto out;
    677  1.1  riastrad 
    678  1.1  riastrad 			r = radeon_vce_cs_reloc(p, p->idx + 12, p->idx + 11,
    679  1.1  riastrad 						*size / 3);
    680  1.1  riastrad 			if (r)
    681  1.3  riastrad 				goto out;
    682  1.1  riastrad 			break;
    683  1.1  riastrad 
    684  1.1  riastrad 		case 0x02000001: // destroy
    685  1.1  riastrad 			destroyed = true;
    686  1.1  riastrad 			break;
    687  1.1  riastrad 
    688  1.1  riastrad 		case 0x05000001: // context buffer
    689  1.1  riastrad 			r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2,
    690  1.1  riastrad 						*size * 2);
    691  1.1  riastrad 			if (r)
    692  1.3  riastrad 				goto out;
    693  1.1  riastrad 			break;
    694  1.1  riastrad 
    695  1.1  riastrad 		case 0x05000004: // video bitstream buffer
    696  1.1  riastrad 			tmp = radeon_get_ib_value(p, p->idx + 4);
    697  1.1  riastrad 			r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2,
    698  1.1  riastrad 						tmp);
    699  1.1  riastrad 			if (r)
    700  1.3  riastrad 				goto out;
    701  1.1  riastrad 			break;
    702  1.1  riastrad 
    703  1.1  riastrad 		case 0x05000005: // feedback buffer
    704  1.1  riastrad 			r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2,
    705  1.1  riastrad 						4096);
    706  1.1  riastrad 			if (r)
    707  1.3  riastrad 				goto out;
    708  1.1  riastrad 			break;
    709  1.1  riastrad 
    710  1.1  riastrad 		default:
    711  1.1  riastrad 			DRM_ERROR("invalid VCE command (0x%x)!\n", cmd);
    712  1.3  riastrad 			r = -EINVAL;
    713  1.3  riastrad 			goto out;
    714  1.1  riastrad 		}
    715  1.1  riastrad 
    716  1.1  riastrad 		if (session_idx == -1) {
    717  1.1  riastrad 			DRM_ERROR("no session command at start of IB\n");
    718  1.3  riastrad 			r = -EINVAL;
    719  1.3  riastrad 			goto out;
    720  1.1  riastrad 		}
    721  1.1  riastrad 
    722  1.1  riastrad 		p->idx += len / 4;
    723  1.1  riastrad 	}
    724  1.1  riastrad 
    725  1.3  riastrad 	if (allocated && !created) {
    726  1.3  riastrad 		DRM_ERROR("New session without create command!\n");
    727  1.3  riastrad 		r = -ENOENT;
    728  1.3  riastrad 	}
    729  1.3  riastrad 
    730  1.3  riastrad out:
    731  1.3  riastrad 	if ((!r && destroyed) || (r && allocated)) {
    732  1.3  riastrad 		/*
    733  1.3  riastrad 		 * IB contains a destroy msg or we have allocated an
    734  1.3  riastrad 		 * handle and got an error, anyway free the handle
    735  1.3  riastrad 		 */
    736  1.1  riastrad 		for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i)
    737  1.1  riastrad 			atomic_cmpxchg(&p->rdev->vce.handles[i], handle, 0);
    738  1.1  riastrad 	}
    739  1.1  riastrad 
    740  1.3  riastrad 	return r;
    741  1.1  riastrad }
    742  1.1  riastrad 
    743  1.1  riastrad /**
    744  1.1  riastrad  * radeon_vce_semaphore_emit - emit a semaphore command
    745  1.1  riastrad  *
    746  1.1  riastrad  * @rdev: radeon_device pointer
    747  1.1  riastrad  * @ring: engine to use
    748  1.1  riastrad  * @semaphore: address of semaphore
    749  1.1  riastrad  * @emit_wait: true=emit wait, false=emit signal
    750  1.1  riastrad  *
    751  1.1  riastrad  */
    752  1.1  riastrad bool radeon_vce_semaphore_emit(struct radeon_device *rdev,
    753  1.1  riastrad 			       struct radeon_ring *ring,
    754  1.1  riastrad 			       struct radeon_semaphore *semaphore,
    755  1.1  riastrad 			       bool emit_wait)
    756  1.1  riastrad {
    757  1.1  riastrad 	uint64_t addr = semaphore->gpu_addr;
    758  1.1  riastrad 
    759  1.3  riastrad 	radeon_ring_write(ring, cpu_to_le32(VCE_CMD_SEMAPHORE));
    760  1.3  riastrad 	radeon_ring_write(ring, cpu_to_le32((addr >> 3) & 0x000FFFFF));
    761  1.3  riastrad 	radeon_ring_write(ring, cpu_to_le32((addr >> 23) & 0x000FFFFF));
    762  1.3  riastrad 	radeon_ring_write(ring, cpu_to_le32(0x01003000 | (emit_wait ? 1 : 0)));
    763  1.1  riastrad 	if (!emit_wait)
    764  1.3  riastrad 		radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END));
    765  1.1  riastrad 
    766  1.1  riastrad 	return true;
    767  1.1  riastrad }
    768  1.1  riastrad 
    769  1.1  riastrad /**
    770  1.1  riastrad  * radeon_vce_ib_execute - execute indirect buffer
    771  1.1  riastrad  *
    772  1.1  riastrad  * @rdev: radeon_device pointer
    773  1.1  riastrad  * @ib: the IB to execute
    774  1.1  riastrad  *
    775  1.1  riastrad  */
    776  1.1  riastrad void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
    777  1.1  riastrad {
    778  1.1  riastrad 	struct radeon_ring *ring = &rdev->ring[ib->ring];
    779  1.3  riastrad 	radeon_ring_write(ring, cpu_to_le32(VCE_CMD_IB));
    780  1.3  riastrad 	radeon_ring_write(ring, cpu_to_le32(ib->gpu_addr));
    781  1.3  riastrad 	radeon_ring_write(ring, cpu_to_le32(upper_32_bits(ib->gpu_addr)));
    782  1.3  riastrad 	radeon_ring_write(ring, cpu_to_le32(ib->length_dw));
    783  1.1  riastrad }
    784  1.1  riastrad 
    785  1.1  riastrad /**
    786  1.1  riastrad  * radeon_vce_fence_emit - add a fence command to the ring
    787  1.1  riastrad  *
    788  1.1  riastrad  * @rdev: radeon_device pointer
    789  1.1  riastrad  * @fence: the fence
    790  1.1  riastrad  *
    791  1.1  riastrad  */
    792  1.1  riastrad void radeon_vce_fence_emit(struct radeon_device *rdev,
    793  1.1  riastrad 			   struct radeon_fence *fence)
    794  1.1  riastrad {
    795  1.1  riastrad 	struct radeon_ring *ring = &rdev->ring[fence->ring];
    796  1.1  riastrad 	uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr;
    797  1.1  riastrad 
    798  1.3  riastrad 	radeon_ring_write(ring, cpu_to_le32(VCE_CMD_FENCE));
    799  1.3  riastrad 	radeon_ring_write(ring, cpu_to_le32(addr));
    800  1.3  riastrad 	radeon_ring_write(ring, cpu_to_le32(upper_32_bits(addr)));
    801  1.3  riastrad 	radeon_ring_write(ring, cpu_to_le32(fence->seq));
    802  1.3  riastrad 	radeon_ring_write(ring, cpu_to_le32(VCE_CMD_TRAP));
    803  1.3  riastrad 	radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END));
    804  1.1  riastrad }
    805  1.1  riastrad 
    806  1.1  riastrad /**
    807  1.1  riastrad  * radeon_vce_ring_test - test if VCE ring is working
    808  1.1  riastrad  *
    809  1.1  riastrad  * @rdev: radeon_device pointer
    810  1.1  riastrad  * @ring: the engine to test on
    811  1.1  riastrad  *
    812  1.1  riastrad  */
    813  1.1  riastrad int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
    814  1.1  riastrad {
    815  1.1  riastrad 	uint32_t rptr = vce_v1_0_get_rptr(rdev, ring);
    816  1.1  riastrad 	unsigned i;
    817  1.1  riastrad 	int r;
    818  1.1  riastrad 
    819  1.1  riastrad 	r = radeon_ring_lock(rdev, ring, 16);
    820  1.1  riastrad 	if (r) {
    821  1.1  riastrad 		DRM_ERROR("radeon: vce failed to lock ring %d (%d).\n",
    822  1.1  riastrad 			  ring->idx, r);
    823  1.1  riastrad 		return r;
    824  1.1  riastrad 	}
    825  1.3  riastrad 	radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END));
    826  1.3  riastrad 	radeon_ring_unlock_commit(rdev, ring, false);
    827  1.1  riastrad 
    828  1.1  riastrad 	for (i = 0; i < rdev->usec_timeout; i++) {
    829  1.5  riastrad 		if (vce_v1_0_get_rptr(rdev, ring) != rptr)
    830  1.5  riastrad 			break;
    831  1.5  riastrad 		udelay(1);
    832  1.1  riastrad 	}
    833  1.1  riastrad 
    834  1.1  riastrad 	if (i < rdev->usec_timeout) {
    835  1.5  riastrad 		DRM_INFO("ring test on %d succeeded in %d usecs\n",
    836  1.5  riastrad 			 ring->idx, i);
    837  1.1  riastrad 	} else {
    838  1.5  riastrad 		DRM_ERROR("radeon: ring %d test failed\n",
    839  1.5  riastrad 			 ring->idx);
    840  1.5  riastrad 		r = -ETIMEDOUT;
    841  1.1  riastrad 	}
    842  1.1  riastrad 
    843  1.1  riastrad 	return r;
    844  1.1  riastrad }
    845  1.1  riastrad 
    846  1.1  riastrad /**
    847  1.1  riastrad  * radeon_vce_ib_test - test if VCE IBs are working
    848  1.1  riastrad  *
    849  1.1  riastrad  * @rdev: radeon_device pointer
    850  1.1  riastrad  * @ring: the engine to test on
    851  1.1  riastrad  *
    852  1.1  riastrad  */
    853  1.1  riastrad int radeon_vce_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
    854  1.1  riastrad {
    855  1.1  riastrad 	struct radeon_fence *fence = NULL;
    856  1.1  riastrad 	int r;
    857  1.1  riastrad 
    858  1.1  riastrad 	r = radeon_vce_get_create_msg(rdev, ring->idx, 1, NULL);
    859  1.1  riastrad 	if (r) {
    860  1.1  riastrad 		DRM_ERROR("radeon: failed to get create msg (%d).\n", r);
    861  1.1  riastrad 		goto error;
    862  1.1  riastrad 	}
    863  1.1  riastrad 
    864  1.1  riastrad 	r = radeon_vce_get_destroy_msg(rdev, ring->idx, 1, &fence);
    865  1.1  riastrad 	if (r) {
    866  1.1  riastrad 		DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r);
    867  1.1  riastrad 		goto error;
    868  1.1  riastrad 	}
    869  1.1  riastrad 
    870  1.5  riastrad 	r = radeon_fence_wait_timeout(fence, false, usecs_to_jiffies(
    871  1.5  riastrad 		RADEON_USEC_IB_TEST_TIMEOUT));
    872  1.5  riastrad 	if (r < 0) {
    873  1.1  riastrad 		DRM_ERROR("radeon: fence wait failed (%d).\n", r);
    874  1.5  riastrad 	} else if (r == 0) {
    875  1.5  riastrad 		DRM_ERROR("radeon: fence wait timed out.\n");
    876  1.5  riastrad 		r = -ETIMEDOUT;
    877  1.1  riastrad 	} else {
    878  1.5  riastrad 		DRM_INFO("ib test on ring %d succeeded\n", ring->idx);
    879  1.5  riastrad 		r = 0;
    880  1.1  riastrad 	}
    881  1.1  riastrad error:
    882  1.1  riastrad 	radeon_fence_unref(&fence);
    883  1.1  riastrad 	return r;
    884  1.1  riastrad }
    885