Re: [PATCH 2/2] drm/amdgpu: add VCE VM session tracking

2016-10-12 Thread Leo Liu



On 10/12/2016 07:05 AM, Christian König wrote:

Andy & Leo could you give that a brief testing?


run `kill -9' over 30 times, no issue.

Patch is:
Reviewed-and-Tested by: Leo Liu 


I currently don't have a setup for encoding/transcoding clips.

Regards,
Christian.

Am 10.10.2016 um 18:45 schrieb Alex Deucher:

On Mon, Oct 10, 2016 at 9:40 AM, Christian König
 wrote:

From: Christian König 

Only compile tested, but should fix the problems with killing
VCE sessions in VM mode.

Signed-off-by: Christian König 

Series is:
Reviewed-by: Alex Deucher 


---
  drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 90 
+

  drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h |  1 +
  drivers/gpu/drm/amd/amdgpu/vce_v3_0.c   |  1 +
  3 files changed, 92 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c

index 05a1ea9..3d6f86c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
@@ -792,6 +792,96 @@ out:
  }

  /**
+ * amdgpu_vce_cs_parse_vm - parse the command stream in VM mode
+ *
+ * @p: parser context
+ *
+ */
+int amdgpu_vce_ring_parse_cs_vm(struct amdgpu_cs_parser *p, 
uint32_t ib_idx)

+{
+   struct amdgpu_ib *ib = &p->job->ibs[ib_idx];
+   int session_idx = -1;
+   uint32_t destroyed = 0;
+   uint32_t created = 0;
+   uint32_t allocated = 0;
+   uint32_t tmp, handle = 0;
+   int i, r = 0, idx = 0;
+
+   while (idx < ib->length_dw) {
+   uint32_t len = amdgpu_get_ib_value(p, ib_idx, idx);
+   uint32_t cmd = amdgpu_get_ib_value(p, ib_idx, idx + 1);
+
+   if ((len < 8) || (len & 3)) {
+   DRM_ERROR("invalid VCE command length 
(%d)!\n", len);

+   r = -EINVAL;
+   goto out;
+   }
+
+   switch (cmd) {
+   case 0x0001: /* session */
+   handle = amdgpu_get_ib_value(p, ib_idx, idx 
+ 2);
+   session_idx = amdgpu_vce_validate_handle(p, 
handle,

+ &allocated);
+   if (session_idx < 0) {
+   r = session_idx;
+   goto out;
+   }
+   break;
+
+   case 0x0101: /* create */
+   created |= 1 << session_idx;
+   if (destroyed & (1 << session_idx)) {
+   destroyed &= ~(1 << session_idx);
+   allocated |= 1 << session_idx;
+
+   } else if (!(allocated & (1 << session_idx))) {
+   DRM_ERROR("Handle already in use!\n");
+   r = -EINVAL;
+   goto out;
+   }
+
+   break;
+
+   case 0x0201: /* destroy */
+   destroyed |= 1 << session_idx;
+   break;
+
+   default:
+   break;
+   }
+
+   if (session_idx == -1) {
+   DRM_ERROR("no session command at start of 
IB\n");

+   r = -EINVAL;
+   goto out;
+   }
+
+   idx += len / 4;
+   }
+
+   if (allocated & ~created) {
+   DRM_ERROR("New session without create command!\n");
+   r = -ENOENT;
+   }
+
+out:
+   if (!r) {
+   /* No error, free all destroyed handle slots */
+   tmp = destroyed;
+   amdgpu_ib_free(p->adev, ib, NULL);
+   } else {
+   /* Error during parsing, free all allocated handle 
slots */

+   tmp = allocated;
+   }
+
+   for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i)
+   if (tmp & (1 << i))
+ atomic_set(&p->adev->vce.handles[i], 0);
+
+   return r;
+}
+
+/**
   * amdgpu_vce_ring_emit_ib - execute indirect buffer
   *
   * @ring: engine to use
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h

index 12729d2..44d49b5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
@@ -34,6 +34,7 @@ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring 
*ring, uint32_t handle,

bool direct, struct fence **fence);
  void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct 
drm_file *filp);
  int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t 
ib_idx);
+int amdgpu_vce_ring_parse_cs_vm(struct amdgpu_cs_parser *p, 
uint32_t ib_idx);
  void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring, struct 
amdgpu_ib *ib,

  unsigned vm_id, bool ctx_switch);
  void amdgpu_vce_ring_emit_fence(struct amdgpu_ring *ring, u64 
addr, u64 seq,
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c 
b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c

i

Re: [PATCH 2/2] drm/amdgpu: add VCE VM session tracking

2016-10-12 Thread Andy Furniss

Christian König wrote:

Andy & Leo could you give that a brief testing?


Seems to be OK for me.



I currently don't have a setup for encoding/transcoding clips.

Regards,
Christian.

Am 10.10.2016 um 18:45 schrieb Alex Deucher:

On Mon, Oct 10, 2016 at 9:40 AM, Christian König
 wrote:

From: Christian König 

Only compile tested, but should fix the problems with killing
VCE sessions in VM mode.

Signed-off-by: Christian König 

Series is:
Reviewed-by: Alex Deucher 


---
  drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 90
+
  drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h |  1 +
  drivers/gpu/drm/amd/amdgpu/vce_v3_0.c   |  1 +
  3 files changed, 92 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
index 05a1ea9..3d6f86c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
@@ -792,6 +792,96 @@ out:
  }

  /**
+ * amdgpu_vce_cs_parse_vm - parse the command stream in VM mode
+ *
+ * @p: parser context
+ *
+ */
+int amdgpu_vce_ring_parse_cs_vm(struct amdgpu_cs_parser *p, uint32_t
ib_idx)
+{
+   struct amdgpu_ib *ib = &p->job->ibs[ib_idx];
+   int session_idx = -1;
+   uint32_t destroyed = 0;
+   uint32_t created = 0;
+   uint32_t allocated = 0;
+   uint32_t tmp, handle = 0;
+   int i, r = 0, idx = 0;
+
+   while (idx < ib->length_dw) {
+   uint32_t len = amdgpu_get_ib_value(p, ib_idx, idx);
+   uint32_t cmd = amdgpu_get_ib_value(p, ib_idx, idx + 1);
+
+   if ((len < 8) || (len & 3)) {
+   DRM_ERROR("invalid VCE command length
(%d)!\n", len);
+   r = -EINVAL;
+   goto out;
+   }
+
+   switch (cmd) {
+   case 0x0001: /* session */
+   handle = amdgpu_get_ib_value(p, ib_idx, idx +
2);
+   session_idx = amdgpu_vce_validate_handle(p,
handle,
+
&allocated);
+   if (session_idx < 0) {
+   r = session_idx;
+   goto out;
+   }
+   break;
+
+   case 0x0101: /* create */
+   created |= 1 << session_idx;
+   if (destroyed & (1 << session_idx)) {
+   destroyed &= ~(1 << session_idx);
+   allocated |= 1 << session_idx;
+
+   } else if (!(allocated & (1 << session_idx))) {
+   DRM_ERROR("Handle already in use!\n");
+   r = -EINVAL;
+   goto out;
+   }
+
+   break;
+
+   case 0x0201: /* destroy */
+   destroyed |= 1 << session_idx;
+   break;
+
+   default:
+   break;
+   }
+
+   if (session_idx == -1) {
+   DRM_ERROR("no session command at start of
IB\n");
+   r = -EINVAL;
+   goto out;
+   }
+
+   idx += len / 4;
+   }
+
+   if (allocated & ~created) {
+   DRM_ERROR("New session without create command!\n");
+   r = -ENOENT;
+   }
+
+out:
+   if (!r) {
+   /* No error, free all destroyed handle slots */
+   tmp = destroyed;
+   amdgpu_ib_free(p->adev, ib, NULL);
+   } else {
+   /* Error during parsing, free all allocated handle
slots */
+   tmp = allocated;
+   }
+
+   for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i)
+   if (tmp & (1 << i))
+   atomic_set(&p->adev->vce.handles[i], 0);
+
+   return r;
+}
+
+/**
   * amdgpu_vce_ring_emit_ib - execute indirect buffer
   *
   * @ring: engine to use
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
index 12729d2..44d49b5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
@@ -34,6 +34,7 @@ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring
*ring, uint32_t handle,
bool direct, struct fence **fence);
  void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct
drm_file *filp);
  int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t
ib_idx);
+int amdgpu_vce_ring_parse_cs_vm(struct amdgpu_cs_parser *p, uint32_t
ib_idx);
  void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring, struct
amdgpu_ib *ib,
  unsigned vm_id, bool ctx_switch);
  void amdgpu_vce_ring_emit_fence(struct amdgpu_ring *ring, u64 addr,
u64 seq,
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
index f7dbd0d..2abf5bd 100644
--- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
+++ b/drivers/gpu

Re: [PATCH 2/2] drm/amdgpu: add VCE VM session tracking

2016-10-12 Thread Christian König

Andy & Leo could you give that a brief testing?

I currently don't have a setup for encoding/transcoding clips.

Regards,
Christian.

Am 10.10.2016 um 18:45 schrieb Alex Deucher:

On Mon, Oct 10, 2016 at 9:40 AM, Christian König
 wrote:

From: Christian König 

Only compile tested, but should fix the problems with killing
VCE sessions in VM mode.

Signed-off-by: Christian König 

Series is:
Reviewed-by: Alex Deucher 


---
  drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 90 +
  drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h |  1 +
  drivers/gpu/drm/amd/amdgpu/vce_v3_0.c   |  1 +
  3 files changed, 92 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
index 05a1ea9..3d6f86c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
@@ -792,6 +792,96 @@ out:
  }

  /**
+ * amdgpu_vce_cs_parse_vm - parse the command stream in VM mode
+ *
+ * @p: parser context
+ *
+ */
+int amdgpu_vce_ring_parse_cs_vm(struct amdgpu_cs_parser *p, uint32_t ib_idx)
+{
+   struct amdgpu_ib *ib = &p->job->ibs[ib_idx];
+   int session_idx = -1;
+   uint32_t destroyed = 0;
+   uint32_t created = 0;
+   uint32_t allocated = 0;
+   uint32_t tmp, handle = 0;
+   int i, r = 0, idx = 0;
+
+   while (idx < ib->length_dw) {
+   uint32_t len = amdgpu_get_ib_value(p, ib_idx, idx);
+   uint32_t cmd = amdgpu_get_ib_value(p, ib_idx, idx + 1);
+
+   if ((len < 8) || (len & 3)) {
+   DRM_ERROR("invalid VCE command length (%d)!\n", len);
+   r = -EINVAL;
+   goto out;
+   }
+
+   switch (cmd) {
+   case 0x0001: /* session */
+   handle = amdgpu_get_ib_value(p, ib_idx, idx + 2);
+   session_idx = amdgpu_vce_validate_handle(p, handle,
+&allocated);
+   if (session_idx < 0) {
+   r = session_idx;
+   goto out;
+   }
+   break;
+
+   case 0x0101: /* create */
+   created |= 1 << session_idx;
+   if (destroyed & (1 << session_idx)) {
+   destroyed &= ~(1 << session_idx);
+   allocated |= 1 << session_idx;
+
+   } else if (!(allocated & (1 << session_idx))) {
+   DRM_ERROR("Handle already in use!\n");
+   r = -EINVAL;
+   goto out;
+   }
+
+   break;
+
+   case 0x0201: /* destroy */
+   destroyed |= 1 << session_idx;
+   break;
+
+   default:
+   break;
+   }
+
+   if (session_idx == -1) {
+   DRM_ERROR("no session command at start of IB\n");
+   r = -EINVAL;
+   goto out;
+   }
+
+   idx += len / 4;
+   }
+
+   if (allocated & ~created) {
+   DRM_ERROR("New session without create command!\n");
+   r = -ENOENT;
+   }
+
+out:
+   if (!r) {
+   /* No error, free all destroyed handle slots */
+   tmp = destroyed;
+   amdgpu_ib_free(p->adev, ib, NULL);
+   } else {
+   /* Error during parsing, free all allocated handle slots */
+   tmp = allocated;
+   }
+
+   for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i)
+   if (tmp & (1 << i))
+   atomic_set(&p->adev->vce.handles[i], 0);
+
+   return r;
+}
+
+/**
   * amdgpu_vce_ring_emit_ib - execute indirect buffer
   *
   * @ring: engine to use
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
index 12729d2..44d49b5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
@@ -34,6 +34,7 @@ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, 
uint32_t handle,
bool direct, struct fence **fence);
  void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file 
*filp);
  int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx);
+int amdgpu_vce_ring_parse_cs_vm(struct amdgpu_cs_parser *p, uint32_t ib_idx);
  void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib,
  unsigned vm_id, bool ctx_switch);
  void amdgpu_vce_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c 
b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
index f7dbd0d..2abf5bd 100644
--- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c

Re: [PATCH 2/2] drm/amdgpu: add VCE VM session tracking

2016-10-10 Thread Alex Deucher
On Mon, Oct 10, 2016 at 9:40 AM, Christian König
 wrote:
> From: Christian König 
>
> Only compile tested, but should fix the problems with killing
> VCE sessions in VM mode.
>
> Signed-off-by: Christian König 

Series is:
Reviewed-by: Alex Deucher 

> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 90 
> +
>  drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h |  1 +
>  drivers/gpu/drm/amd/amdgpu/vce_v3_0.c   |  1 +
>  3 files changed, 92 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
> index 05a1ea9..3d6f86c 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
> @@ -792,6 +792,96 @@ out:
>  }
>
>  /**
> + * amdgpu_vce_cs_parse_vm - parse the command stream in VM mode
> + *
> + * @p: parser context
> + *
> + */
> +int amdgpu_vce_ring_parse_cs_vm(struct amdgpu_cs_parser *p, uint32_t ib_idx)
> +{
> +   struct amdgpu_ib *ib = &p->job->ibs[ib_idx];
> +   int session_idx = -1;
> +   uint32_t destroyed = 0;
> +   uint32_t created = 0;
> +   uint32_t allocated = 0;
> +   uint32_t tmp, handle = 0;
> +   int i, r = 0, idx = 0;
> +
> +   while (idx < ib->length_dw) {
> +   uint32_t len = amdgpu_get_ib_value(p, ib_idx, idx);
> +   uint32_t cmd = amdgpu_get_ib_value(p, ib_idx, idx + 1);
> +
> +   if ((len < 8) || (len & 3)) {
> +   DRM_ERROR("invalid VCE command length (%d)!\n", len);
> +   r = -EINVAL;
> +   goto out;
> +   }
> +
> +   switch (cmd) {
> +   case 0x0001: /* session */
> +   handle = amdgpu_get_ib_value(p, ib_idx, idx + 2);
> +   session_idx = amdgpu_vce_validate_handle(p, handle,
> +&allocated);
> +   if (session_idx < 0) {
> +   r = session_idx;
> +   goto out;
> +   }
> +   break;
> +
> +   case 0x0101: /* create */
> +   created |= 1 << session_idx;
> +   if (destroyed & (1 << session_idx)) {
> +   destroyed &= ~(1 << session_idx);
> +   allocated |= 1 << session_idx;
> +
> +   } else if (!(allocated & (1 << session_idx))) {
> +   DRM_ERROR("Handle already in use!\n");
> +   r = -EINVAL;
> +   goto out;
> +   }
> +
> +   break;
> +
> +   case 0x0201: /* destroy */
> +   destroyed |= 1 << session_idx;
> +   break;
> +
> +   default:
> +   break;
> +   }
> +
> +   if (session_idx == -1) {
> +   DRM_ERROR("no session command at start of IB\n");
> +   r = -EINVAL;
> +   goto out;
> +   }
> +
> +   idx += len / 4;
> +   }
> +
> +   if (allocated & ~created) {
> +   DRM_ERROR("New session without create command!\n");
> +   r = -ENOENT;
> +   }
> +
> +out:
> +   if (!r) {
> +   /* No error, free all destroyed handle slots */
> +   tmp = destroyed;
> +   amdgpu_ib_free(p->adev, ib, NULL);
> +   } else {
> +   /* Error during parsing, free all allocated handle slots */
> +   tmp = allocated;
> +   }
> +
> +   for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i)
> +   if (tmp & (1 << i))
> +   atomic_set(&p->adev->vce.handles[i], 0);
> +
> +   return r;
> +}
> +
> +/**
>   * amdgpu_vce_ring_emit_ib - execute indirect buffer
>   *
>   * @ring: engine to use
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
> index 12729d2..44d49b5 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
> @@ -34,6 +34,7 @@ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, 
> uint32_t handle,
>bool direct, struct fence **fence);
>  void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file 
> *filp);
>  int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx);
> +int amdgpu_vce_ring_parse_cs_vm(struct amdgpu_cs_parser *p, uint32_t ib_idx);
>  void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib,
>  unsigned vm_id, bool ctx_switch);
>  void amdgpu_vce_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
> diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c 
> b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
> index f7d

[PATCH 2/2] drm/amdgpu: add VCE VM session tracking

2016-10-10 Thread Christian König
From: Christian König 

Only compile tested, but should fix the problems with killing
VCE sessions in VM mode.

Signed-off-by: Christian König 
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 90 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h |  1 +
 drivers/gpu/drm/amd/amdgpu/vce_v3_0.c   |  1 +
 3 files changed, 92 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
index 05a1ea9..3d6f86c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
@@ -792,6 +792,96 @@ out:
 }
 
 /**
+ * amdgpu_vce_cs_parse_vm - parse the command stream in VM mode
+ *
+ * @p: parser context
+ *
+ */
+int amdgpu_vce_ring_parse_cs_vm(struct amdgpu_cs_parser *p, uint32_t ib_idx)
+{
+   struct amdgpu_ib *ib = &p->job->ibs[ib_idx];
+   int session_idx = -1;
+   uint32_t destroyed = 0;
+   uint32_t created = 0;
+   uint32_t allocated = 0;
+   uint32_t tmp, handle = 0;
+   int i, r = 0, idx = 0;
+
+   while (idx < ib->length_dw) {
+   uint32_t len = amdgpu_get_ib_value(p, ib_idx, idx);
+   uint32_t cmd = amdgpu_get_ib_value(p, ib_idx, idx + 1);
+
+   if ((len < 8) || (len & 3)) {
+   DRM_ERROR("invalid VCE command length (%d)!\n", len);
+   r = -EINVAL;
+   goto out;
+   }
+
+   switch (cmd) {
+   case 0x0001: /* session */
+   handle = amdgpu_get_ib_value(p, ib_idx, idx + 2);
+   session_idx = amdgpu_vce_validate_handle(p, handle,
+&allocated);
+   if (session_idx < 0) {
+   r = session_idx;
+   goto out;
+   }
+   break;
+
+   case 0x0101: /* create */
+   created |= 1 << session_idx;
+   if (destroyed & (1 << session_idx)) {
+   destroyed &= ~(1 << session_idx);
+   allocated |= 1 << session_idx;
+
+   } else if (!(allocated & (1 << session_idx))) {
+   DRM_ERROR("Handle already in use!\n");
+   r = -EINVAL;
+   goto out;
+   }
+
+   break;
+
+   case 0x0201: /* destroy */
+   destroyed |= 1 << session_idx;
+   break;
+
+   default:
+   break;
+   }
+
+   if (session_idx == -1) {
+   DRM_ERROR("no session command at start of IB\n");
+   r = -EINVAL;
+   goto out;
+   }
+
+   idx += len / 4;
+   }
+
+   if (allocated & ~created) {
+   DRM_ERROR("New session without create command!\n");
+   r = -ENOENT;
+   }
+
+out:
+   if (!r) {
+   /* No error, free all destroyed handle slots */
+   tmp = destroyed;
+   amdgpu_ib_free(p->adev, ib, NULL);
+   } else {
+   /* Error during parsing, free all allocated handle slots */
+   tmp = allocated;
+   }
+
+   for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i)
+   if (tmp & (1 << i))
+   atomic_set(&p->adev->vce.handles[i], 0);
+
+   return r;
+}
+
+/**
  * amdgpu_vce_ring_emit_ib - execute indirect buffer
  *
  * @ring: engine to use
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
index 12729d2..44d49b5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h
@@ -34,6 +34,7 @@ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, 
uint32_t handle,
   bool direct, struct fence **fence);
 void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file 
*filp);
 int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx);
+int amdgpu_vce_ring_parse_cs_vm(struct amdgpu_cs_parser *p, uint32_t ib_idx);
 void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib,
 unsigned vm_id, bool ctx_switch);
 void amdgpu_vce_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c 
b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
index f7dbd0d..2abf5bd 100644
--- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
@@ -854,6 +854,7 @@ static const struct amdgpu_ring_funcs 
vce_v3_0_ring_vm_funcs = {
.get_rptr = vce_v3_0_ring_get_rptr,
.get_wptr = vce_v3_0_ring_get_wptr,
.set_wptr = vce_v3_0_ring_set_wptr,
+   .parse_cs = amdgpu_vce_r