aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/files/0280-drm-amdgpu-check-VCE-relocation-buffer-range.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/files/0280-drm-amdgpu-check-VCE-relocation-buffer-range.patch')
-rw-r--r--common/recipes-kernel/linux/files/0280-drm-amdgpu-check-VCE-relocation-buffer-range.patch249
1 files changed, 249 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/files/0280-drm-amdgpu-check-VCE-relocation-buffer-range.patch b/common/recipes-kernel/linux/files/0280-drm-amdgpu-check-VCE-relocation-buffer-range.patch
new file mode 100644
index 00000000..195bfcc1
--- /dev/null
+++ b/common/recipes-kernel/linux/files/0280-drm-amdgpu-check-VCE-relocation-buffer-range.patch
@@ -0,0 +1,249 @@
+From f1689ec1b0b1256d0e69653cd4aaeee44aafdf5c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com>
+Date: Thu, 11 Jun 2015 20:56:18 +0200
+Subject: [PATCH 0280/1050] drm/amdgpu: check VCE relocation buffer range
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+port of radeon commit 2fc5703abda201f138faf63bdca743d04dbf4b1a.
+
+Signed-off-by: Christian König <christian.koenig@amd.com>
+Reviewed-by: Leo Liu <leo.liu@amd.com>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 119 ++++++++++++++++++++++++--------
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h | 1 -
+ 3 files changed, 92 insertions(+), 29 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+index 22866d1..963c4ba 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+@@ -1622,6 +1622,7 @@ struct amdgpu_vce {
+ unsigned fb_version;
+ atomic_t handles[AMDGPU_MAX_VCE_HANDLES];
+ struct drm_file *filp[AMDGPU_MAX_VCE_HANDLES];
++ uint32_t img_size[AMDGPU_MAX_VCE_HANDLES];
+ struct delayed_work idle_work;
+ const struct firmware *fw; /* VCE firmware */
+ struct amdgpu_ring ring[AMDGPU_MAX_VCE_RINGS];
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
+index 1127a50..cb1bff7 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
+@@ -464,10 +464,12 @@ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
+ * @p: parser context
+ * @lo: address of lower dword
+ * @hi: address of higher dword
++ * @size: minimum size
+ *
+ * Patch relocation inside command stream with real buffer address
+ */
+-int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int hi)
++static int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx,
++ int lo, int hi, unsigned size)
+ {
+ struct amdgpu_bo_va_mapping *mapping;
+ struct amdgpu_ib *ib = &p->ibs[ib_idx];
+@@ -484,6 +486,13 @@ int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int
+ return -EINVAL;
+ }
+
++ if ((addr + (uint64_t)size) >
++ ((uint64_t)mapping->it.last + 1) * AMDGPU_GPU_PAGE_SIZE) {
++ DRM_ERROR("BO to small for addr 0x%010Lx %d %d\n",
++ addr, lo, hi);
++ return -EINVAL;
++ }
++
+ addr -= ((uint64_t)mapping->it.start) * AMDGPU_GPU_PAGE_SIZE;
+ addr += amdgpu_bo_gpu_offset(bo);
+
+@@ -494,6 +503,39 @@ int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int
+ }
+
+ /**
++ * amdgpu_vce_validate_handle - validate stream handle
++ *
++ * @p: parser context
++ * @handle: handle to validate
++ *
++ * Validates the handle and return the found session index or -EINVAL
++ * we we don't have another free session index.
++ */
++static int amdgpu_vce_validate_handle(struct amdgpu_cs_parser *p,
++ uint32_t handle)
++{
++ unsigned i;
++
++ /* validate the handle */
++ for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
++ if (atomic_read(&p->adev->vce.handles[i]) == handle)
++ return i;
++ }
++
++ /* handle not found try to alloc a new one */
++ for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
++ if (!atomic_cmpxchg(&p->adev->vce.handles[i], 0, handle)) {
++ p->adev->vce.filp[i] = p->filp;
++ p->adev->vce.img_size[i] = 0;
++ return i;
++ }
++ }
++
++ DRM_ERROR("No more free VCE handles!\n");
++ return -EINVAL;
++}
++
++/**
+ * amdgpu_vce_cs_parse - parse and validate the command stream
+ *
+ * @p: parser context
+@@ -501,10 +543,12 @@ int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int
+ */
+ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx)
+ {
+- uint32_t handle = 0;
+- bool destroy = false;
+- int i, r, idx = 0;
+ struct amdgpu_ib *ib = &p->ibs[ib_idx];
++ int session_idx = -1;
++ bool destroyed = false;
++ uint32_t tmp, handle = 0;
++ uint32_t *size = &tmp;
++ int i, r, idx = 0;
+
+ amdgpu_vce_note_usage(p->adev);
+
+@@ -517,13 +561,29 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx)
+ return -EINVAL;
+ }
+
++ if (destroyed) {
++ DRM_ERROR("No other command allowed after destroy!\n");
++ return -EINVAL;
++ }
++
+ switch (cmd) {
+ case 0x00000001: // session
+ handle = amdgpu_get_ib_value(p, ib_idx, idx + 2);
++ session_idx = amdgpu_vce_validate_handle(p, handle);
++ if (session_idx < 0)
++ return session_idx;
++ size = &p->adev->vce.img_size[session_idx];
+ break;
+
+ case 0x00000002: // task info
++ break;
++
+ case 0x01000001: // create
++ *size = amdgpu_get_ib_value(p, ib_idx, idx + 8) *
++ amdgpu_get_ib_value(p, ib_idx, idx + 10) *
++ 8 * 3 / 2;
++ break;
++
+ case 0x04000001: // config extension
+ case 0x04000002: // pic control
+ case 0x04000005: // rate control
+@@ -534,23 +594,39 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx)
+ break;
+
+ case 0x03000001: // encode
+- r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 10, idx + 9);
++ r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 10, idx + 9,
++ *size);
+ if (r)
+ return r;
+
+- r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 12, idx + 11);
++ r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 12, idx + 11,
++ *size / 3);
+ if (r)
+ return r;
+ break;
+
+ case 0x02000001: // destroy
+- destroy = true;
++ destroyed = true;
+ break;
+
+ case 0x05000001: // context buffer
++ r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2,
++ *size * 2);
++ if (r)
++ return r;
++ break;
++
+ case 0x05000004: // video bitstream buffer
++ tmp = amdgpu_get_ib_value(p, ib_idx, idx + 4);
++ r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2,
++ tmp);
++ if (r)
++ return r;
++ break;
++
+ case 0x05000005: // feedback buffer
+- r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2);
++ r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2,
++ 4096);
+ if (r)
+ return r;
+ break;
+@@ -560,34 +636,21 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx)
+ return -EINVAL;
+ }
+
++ if (session_idx == -1) {
++ DRM_ERROR("no session command at start of IB\n");
++ return -EINVAL;
++ }
++
+ idx += len / 4;
+ }
+
+- if (destroy) {
++ if (destroyed) {
+ /* IB contains a destroy msg, free the handle */
+ for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i)
+ atomic_cmpxchg(&p->adev->vce.handles[i], handle, 0);
+-
+- return 0;
+- }
+-
+- /* create or encode, validate the handle */
+- for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
+- if (atomic_read(&p->adev->vce.handles[i]) == handle)
+- return 0;
+- }
+-
+- /* handle not found try to alloc a new one */
+- for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
+- if (!atomic_cmpxchg(&p->adev->vce.handles[i], 0, handle)) {
+- p->adev->vce.filp[i] = p->filp;
+- return 0;
+- }
+ }
+
+- DRM_ERROR("No more free VCE handles!\n");
+-
+- return -EINVAL;
++ return 0;
+ }
+
+ /**
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
+index b6a9d09..7ccdb59 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
+@@ -33,7 +33,6 @@ int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
+ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
+ struct amdgpu_fence **fence);
+ void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp);
+-int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int hi);
+ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx);
+ bool amdgpu_vce_ring_emit_semaphore(struct amdgpu_ring *ring,
+ struct amdgpu_semaphore *semaphore,
+--
+1.9.1
+