drm/amdgpu: fix context switch
authorChristian König <christian.koenig@amd.com>
Mon, 11 May 2015 13:34:59 +0000 (15:34 +0200)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 4 Jun 2015 01:03:34 +0000 (21:03 -0400)
Properly protect the state and also handle submission failures.

Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Jammy Zhou <Jammy.Zhou@amd.com>
Reviewed-by: Monk Liu <monk.liu@amd.com>
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c

index 72d9d9ec5c9f44c354ac0d4d76173617ed496439..003fa2d12bfbf807d714d0b511f04a13e54f8118 100644 (file)
@@ -893,6 +893,7 @@ struct amdgpu_ib {
        struct amdgpu_fence             *fence;
        struct amdgpu_user_fence        *user;
        struct amdgpu_vm                *vm;
+       struct amdgpu_ctx               *ctx;
        struct amdgpu_sync              sync;
        uint32_t                        gds_base, gds_size;
        uint32_t                        gws_base, gws_size;
@@ -943,9 +944,7 @@ struct amdgpu_ring {
        unsigned                wptr_offs;
        unsigned                next_rptr_offs;
        unsigned                fence_offs;
-       struct drm_file         *current_filp;
-       unsigned                current_ctx;
-       bool                    need_ctx_switch;
+       struct amdgpu_ctx       *current_ctx;
        enum amdgpu_ring_type   type;
        char                    name[16];
 };
@@ -1236,7 +1235,7 @@ struct amdgpu_cs_chunk {
 struct amdgpu_cs_parser {
        struct amdgpu_device    *adev;
        struct drm_file         *filp;
-       uint32_t ctx_id;
+       struct amdgpu_ctx       *ctx;
        struct amdgpu_bo_list *bo_list;
        /* chunks */
        unsigned                nchunks;
index de17f845a84b3b6660263d227777c8b04ddbc7ab..ecb30a1a73cc61cdf371bfd73a375baf43469619 100644 (file)
@@ -138,7 +138,11 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data)
        if (!cs->in.num_chunks)
                goto out;
 
-       p->ctx_id = cs->in.ctx_id;
+       p->ctx = amdgpu_ctx_get(fpriv, cs->in.ctx_id);
+       if (!p->ctx) {
+               r = -EINVAL;
+               goto out;
+       }
        p->bo_list = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle);
 
        /* get chunks */
@@ -445,6 +449,8 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bo
                                           &parser->validated);
        }
 
+       if (parser->ctx)
+               amdgpu_ctx_put(parser->ctx);
        if (parser->bo_list)
                amdgpu_bo_list_put(parser->bo_list);
        drm_free_large(parser->vm_bos);
@@ -639,13 +645,7 @@ static int amdgpu_cs_ib_fill(struct amdgpu_device *adev,
                ib->length_dw = chunk_ib->ib_bytes / 4;
 
                ib->flags = chunk_ib->flags;
-
-               if ((ib->ring->current_filp != parser->filp) ||
-                   (ib->ring->current_ctx != parser->ctx_id)) {
-                       ib->ring->need_ctx_switch = true;
-                       ib->ring->current_ctx = parser->ctx_id;
-                       ib->ring->current_filp = parser->filp;
-               }
+               ib->ctx = parser->ctx;
 
                ib_bo = &parser->ib_bos[j];
                ib_bo->robj = aobj;
index 74ed94ee7102fb8e77256e588b7801a1fa9d67ef..560c5fd347be1b72bf1a77838cdf9a2107511c85 100644 (file)
@@ -140,6 +140,7 @@ int amdgpu_ib_schedule(struct amdgpu_device *adev, unsigned num_ibs,
 {
        struct amdgpu_ib *ib = &ibs[0];
        struct amdgpu_ring *ring;
+       struct amdgpu_ctx *ctx, *old_ctx;
        struct amdgpu_vm *vm;
        unsigned i;
        int r = 0;
@@ -148,6 +149,7 @@ int amdgpu_ib_schedule(struct amdgpu_device *adev, unsigned num_ibs,
                return -EINVAL;
 
        ring = ibs->ring;
+       ctx = ibs->ctx;
        vm = ibs->vm;
 
        if (!ring->ready) {
@@ -189,19 +191,23 @@ int amdgpu_ib_schedule(struct amdgpu_device *adev, unsigned num_ibs,
        if (ring->funcs->emit_hdp_flush)
                amdgpu_ring_emit_hdp_flush(ring);
 
+       old_ctx = ring->current_ctx;
        for (i = 0; i < num_ibs; ++i) {
                ib = &ibs[i];
 
-               if (ib->ring != ring) {
+               if (ib->ring != ring || ib->ctx != ctx || ib->vm != vm) {
+                       ring->current_ctx = old_ctx;
                        amdgpu_ring_unlock_undo(ring);
                        return -EINVAL;
                }
                amdgpu_ring_emit_ib(ring, ib);
+               ring->current_ctx = ctx;
        }
 
        r = amdgpu_fence_emit(ring, owner, &ib->fence);
        if (r) {
                dev_err(adev->dev, "failed to emit fence (%d)\n", r);
+               ring->current_ctx = old_ctx;
                amdgpu_ring_unlock_undo(ring);
                return r;
        }
index 855b5272f4b5335c11f5c87f34fbc9d29e2b3721..5315c13a89216a4b18dd4ce27488331ddefe4348 100644 (file)
@@ -2516,19 +2516,20 @@ static bool gfx_v7_0_ring_emit_semaphore(struct amdgpu_ring *ring,
 static void gfx_v7_0_ring_emit_ib(struct amdgpu_ring *ring,
                                  struct amdgpu_ib *ib)
 {
+       bool need_ctx_switch = ring->current_ctx != ib->ctx;
        u32 header, control = 0;
        u32 next_rptr = ring->wptr + 5;
 
        /* drop the CE preamble IB for the same context */
        if ((ring->type == AMDGPU_RING_TYPE_GFX) &&
            (ib->flags & AMDGPU_IB_FLAG_PREAMBLE) &&
-           !ring->need_ctx_switch)
+           !need_ctx_switch)
                return;
 
        if (ring->type == AMDGPU_RING_TYPE_COMPUTE)
                control |= INDIRECT_BUFFER_VALID;
 
-       if (ring->need_ctx_switch && ring->type == AMDGPU_RING_TYPE_GFX)
+       if (need_ctx_switch && ring->type == AMDGPU_RING_TYPE_GFX)
                next_rptr += 2;
 
        next_rptr += 4;
@@ -2539,10 +2540,9 @@ static void gfx_v7_0_ring_emit_ib(struct amdgpu_ring *ring,
        amdgpu_ring_write(ring, next_rptr);
 
        /* insert SWITCH_BUFFER packet before first IB in the ring frame */
-       if (ring->need_ctx_switch && ring->type == AMDGPU_RING_TYPE_GFX) {
+       if (need_ctx_switch && ring->type == AMDGPU_RING_TYPE_GFX) {
                amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
                amdgpu_ring_write(ring, 0);
-               ring->need_ctx_switch = false;
        }
 
        if (ib->flags & AMDGPU_IB_FLAG_CE)
index 63ed3b01cea13654ad38781ca230a7d48d4f3e74..188a7abbddafde981f645c9e00c585eb6ab8d802 100644 (file)
@@ -3645,19 +3645,20 @@ static void gfx_v8_0_ring_emit_hdp_flush(struct amdgpu_ring *ring)
 static void gfx_v8_0_ring_emit_ib(struct amdgpu_ring *ring,
                                  struct amdgpu_ib *ib)
 {
+       bool need_ctx_switch = ring->current_ctx != ib->ctx;
        u32 header, control = 0;
        u32 next_rptr = ring->wptr + 5;
 
        /* drop the CE preamble IB for the same context */
        if ((ring->type == AMDGPU_RING_TYPE_GFX) &&
            (ib->flags & AMDGPU_IB_FLAG_PREAMBLE) &&
-           !ring->need_ctx_switch)
+           !need_ctx_switch)
                return;
 
        if (ring->type == AMDGPU_RING_TYPE_COMPUTE)
                control |= INDIRECT_BUFFER_VALID;
 
-       if (ring->need_ctx_switch && ring->type == AMDGPU_RING_TYPE_GFX)
+       if (need_ctx_switch && ring->type == AMDGPU_RING_TYPE_GFX)
                next_rptr += 2;
 
        next_rptr += 4;
@@ -3668,10 +3669,9 @@ static void gfx_v8_0_ring_emit_ib(struct amdgpu_ring *ring,
        amdgpu_ring_write(ring, next_rptr);
 
        /* insert SWITCH_BUFFER packet before first IB in the ring frame */
-       if (ring->need_ctx_switch && ring->type == AMDGPU_RING_TYPE_GFX) {
+       if (need_ctx_switch && ring->type == AMDGPU_RING_TYPE_GFX) {
                amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
                amdgpu_ring_write(ring, 0);
-               ring->need_ctx_switch = false;
        }
 
        if (ib->flags & AMDGPU_IB_FLAG_CE)