diff options
author | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-05-11 08:08:50 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-05-11 08:08:50 -0300 |
commit | 4c0a65aec3784017aeeb1933c465f901568e98ee (patch) | |
tree | 7a986c1cf1bc2d05870822611ccdd6ef93b65bc7 /drivers/gpu/drm/radeon/radeon_uvd.c | |
parent | c3f22501b52de17c6087b6fe6f2236e4183ac07c (diff) | |
parent | 030bbdbf4c833bc69f502eae58498bc5572db736 (diff) | |
download | blackbird-obmc-linux-4c0a65aec3784017aeeb1933c465f901568e98ee.tar.gz blackbird-obmc-linux-4c0a65aec3784017aeeb1933c465f901568e98ee.zip |
Merge tag 'v4.1-rc3' into patchwork
Linux 4.1-rc3
* tag 'v4.1-rc3': (381 commits)
Linux 4.1-rc3
drm: Zero out invalid vblank timestamp in drm_update_vblank_count.
m32r: make flush_cpumask non-volatile.
mnt: Fix fs_fully_visible to verify the root directory is visible
path_openat(): fix double fput()
namei: d_is_negative() should be checked before ->d_seq validation
ARM: dts: Add keep-power-in-suspend to WiFi SDIO node for exynos5250-snow
ARM: dts: Fix typo in trip point temperature for exynos5420/5440
ARM: dts: add 'rtc_src' clock to rtc node for exynos4412-odroid boards
ARM: dts: Make DP a consumer of DISP1 power domain on Exynos5420
MAINTAINERS: add Conexant Digicolor machines entry
MAINTAINERS: socfpga: update the git repo for SoCFPGA
drm/tegra: Don't use vblank_disable_immediate on incapable driver.
mmc: dw_mmc: dw_mci_get_cd check MMC_CAP_NONREMOVABLE
mmc: dw_mmc: init desc in dw_mci_idmac_init
ARM: multi_v7_defconfig: Select more FSL SoCs
MAINTAINERS: replace an AT91 maintainer
drivers: CCI: fix used_mask init in validate_group()
drm/radeon: stop trying to suspend UVD sessions
drm/radeon: more strictly validate the UVD codec
...
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_uvd.c')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_uvd.c | 144 |
1 files changed, 93 insertions, 51 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index c10b2aec6450..6edcb5485092 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -204,28 +204,32 @@ void radeon_uvd_fini(struct radeon_device *rdev) int radeon_uvd_suspend(struct radeon_device *rdev) { - unsigned size; - void *ptr; - int i; + int i, r; if (rdev->uvd.vcpu_bo == NULL) return 0; - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) - if (atomic_read(&rdev->uvd.handles[i])) - break; + for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { + uint32_t handle = atomic_read(&rdev->uvd.handles[i]); + if (handle != 0) { + struct radeon_fence *fence; - if (i == RADEON_MAX_UVD_HANDLES) - return 0; + radeon_uvd_note_usage(rdev); - size = radeon_bo_size(rdev->uvd.vcpu_bo); - size -= rdev->uvd_fw->size; + r = radeon_uvd_get_destroy_msg(rdev, + R600_RING_TYPE_UVD_INDEX, handle, &fence); + if (r) { + DRM_ERROR("Error destroying UVD (%d)!\n", r); + continue; + } - ptr = rdev->uvd.cpu_addr; - ptr += rdev->uvd_fw->size; + radeon_fence_wait(fence, false); + radeon_fence_unref(&fence); - rdev->uvd.saved_bo = kmalloc(size, GFP_KERNEL); - memcpy(rdev->uvd.saved_bo, ptr, size); + rdev->uvd.filp[i] = NULL; + atomic_set(&rdev->uvd.handles[i], 0); + } + } return 0; } @@ -246,12 +250,7 @@ int radeon_uvd_resume(struct radeon_device *rdev) ptr = rdev->uvd.cpu_addr; ptr += rdev->uvd_fw->size; - if (rdev->uvd.saved_bo != NULL) { - memcpy(ptr, rdev->uvd.saved_bo, size); - kfree(rdev->uvd.saved_bo); - rdev->uvd.saved_bo = NULL; - } else - memset(ptr, 0, size); + memset(ptr, 0, size); return 0; } @@ -396,6 +395,29 @@ static int radeon_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[]) return 0; } +static int radeon_uvd_validate_codec(struct radeon_cs_parser *p, + unsigned stream_type) +{ + switch (stream_type) { + case 0: /* H264 */ + case 1: /* VC1 */ + /* always supported */ + return 0; + + case 3: /* MPEG2 */ + case 4: /* MPEG4 */ + /* only since UVD 3 */ + if (p->rdev->family >= CHIP_PALM) + return 0; + + /* fall through */ + default: + DRM_ERROR("UVD codec not supported by hardware %d!\n", + stream_type); + return -EINVAL; + } +} + static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, unsigned offset, unsigned buf_sizes[]) { @@ -436,50 +458,70 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, return -EINVAL; } - if (msg_type == 1) { - /* it's a decode msg, calc buffer sizes */ - r = radeon_uvd_cs_msg_decode(msg, buf_sizes); - /* calc image size (width * height) */ - img_size = msg[6] * msg[7]; + switch (msg_type) { + case 0: + /* it's a create msg, calc image size (width * height) */ + img_size = msg[7] * msg[8]; + + r = radeon_uvd_validate_codec(p, msg[4]); radeon_bo_kunmap(bo); if (r) return r; - } else if (msg_type == 2) { + /* try to alloc a new handle */ + for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { + if (atomic_read(&p->rdev->uvd.handles[i]) == handle) { + DRM_ERROR("Handle 0x%x already in use!\n", handle); + return -EINVAL; + } + + if (!atomic_cmpxchg(&p->rdev->uvd.handles[i], 0, handle)) { + p->rdev->uvd.filp[i] = p->filp; + p->rdev->uvd.img_size[i] = img_size; + return 0; + } + } + + DRM_ERROR("No more free UVD handles!\n"); + return -EINVAL; + + case 1: + /* it's a decode msg, validate codec and calc buffer sizes */ + r = radeon_uvd_validate_codec(p, msg[4]); + if (!r) + r = radeon_uvd_cs_msg_decode(msg, buf_sizes); + radeon_bo_kunmap(bo); + if (r) + return r; + + /* validate the handle */ + for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { + if (atomic_read(&p->rdev->uvd.handles[i]) == handle) { + if (p->rdev->uvd.filp[i] != p->filp) { + DRM_ERROR("UVD handle collision detected!\n"); + return -EINVAL; + } + return 0; + } + } + + DRM_ERROR("Invalid UVD handle 0x%x!\n", handle); + return -ENOENT; + + case 2: /* it's a destroy msg, free the handle */ for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) atomic_cmpxchg(&p->rdev->uvd.handles[i], handle, 0); radeon_bo_kunmap(bo); return 0; - } else { - /* it's a create msg, calc image size (width * height) */ - img_size = msg[7] * msg[8]; - radeon_bo_kunmap(bo); - if (msg_type != 0) { - DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type); - return -EINVAL; - } - - /* it's a create msg, no special handling needed */ - } - - /* create or decode, validate the handle */ - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { - if (atomic_read(&p->rdev->uvd.handles[i]) == handle) - return 0; - } + default: - /* handle not found try to alloc a new one */ - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { - if (!atomic_cmpxchg(&p->rdev->uvd.handles[i], 0, handle)) { - p->rdev->uvd.filp[i] = p->filp; - p->rdev->uvd.img_size[i] = img_size; - return 0; - } + DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type); + return -EINVAL; } - DRM_ERROR("No more free UVD handles!\n"); + BUG(); return -EINVAL; } |