From 3ed605bc8a0a688d8750a1e2eff39c854418c5cf Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 26 Apr 2016 12:32:27 -0300 Subject: kernel.h: add u64_to_user_ptr() This function had copies in 3 different files. Unify them in kernel.h. Cc: Joe Perches Cc: Andrew Morton Cc: David Airlie Cc: Daniel Vetter Cc: Rob Clark Signed-off-by: Gustavo Padovan Acked-by: Daniel Vetter [drm/i915/] Acked-by: Rob Clark [drm/msm/] Acked-by: Lucas Stach [drm/etinav/] Acked-by: Maarten Lankhorst Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/msm/msm_gem_submit.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/msm/msm_gem_submit.c') diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 43d2181231c0..23d25283616c 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -28,11 +28,6 @@ #define BO_LOCKED 0x4000 #define BO_PINNED 0x2000 -static inline void __user *to_user_ptr(u64 address) -{ - return (void __user *)(uintptr_t)address; -} - static struct msm_gem_submit *submit_create(struct drm_device *dev, struct msm_gpu *gpu, int nr) { @@ -68,7 +63,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit, struct drm_gem_object *obj; struct msm_gem_object *msm_obj; void __user *userptr = - to_user_ptr(args->bos + (i * sizeof(submit_bo))); + u64_to_user_ptr(args->bos + (i * sizeof(submit_bo))); ret = copy_from_user(&submit_bo, userptr, sizeof(submit_bo)); if (ret) { @@ -257,7 +252,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob for (i = 0; i < nr_relocs; i++) { struct drm_msm_gem_submit_reloc submit_reloc; void __user *userptr = - to_user_ptr(relocs + (i * sizeof(submit_reloc))); + u64_to_user_ptr(relocs + (i * sizeof(submit_reloc))); uint32_t iova, off; bool valid; @@ -356,7 +351,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, for (i = 0; i < args->nr_cmds; i++) { struct drm_msm_gem_submit_cmd submit_cmd; void __user *userptr = - to_user_ptr(args->cmds + (i * sizeof(submit_cmd))); + u64_to_user_ptr(args->cmds + (i * sizeof(submit_cmd))); struct msm_gem_object *msm_obj; uint32_t iova; -- cgit From 340faef2418989b2573b82e6c708ef9e24ca439b Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 14 Mar 2016 13:56:37 -0400 Subject: drm/msm: split locking and pinning BO's Split up locking and pinning buffers in the submit path. This is needed because we'll want to insert fencing in between the two steps. This makes things end up looking more similar to etnaviv submit code (which was originally modelled on the msm code but has already added 'struct fence' support). Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gem.h | 2 +- drivers/gpu/drm/msm/msm_gem_submit.c | 69 ++++++++++++++++++++---------------- 2 files changed, 40 insertions(+), 31 deletions(-) (limited to 'drivers/gpu/drm/msm/msm_gem_submit.c') diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 6fc59bfeedeb..b8904517117d 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -100,7 +100,7 @@ struct msm_gem_submit { struct list_head bo_list; struct ww_acquire_ctx ticket; uint32_t fence; - bool valid; + bool valid; /* true if no cmdstream patching needed */ unsigned int nr_cmds; unsigned int nr_bos; struct { diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 43d2181231c0..b231544b3f52 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -24,7 +24,7 @@ */ /* make sure these don't conflict w/ MSM_SUBMIT_BO_x */ -#define BO_VALID 0x8000 +#define BO_VALID 0x8000 /* is current addr in cmdstream correct/valid? */ #define BO_LOCKED 0x4000 #define BO_PINNED 0x2000 @@ -136,16 +136,13 @@ static void submit_unlock_unpin_bo(struct msm_gem_submit *submit, int i) } /* This is where we make sure all the bo's are reserved and pin'd: */ -static int submit_validate_objects(struct msm_gem_submit *submit) +static int submit_lock_objects(struct msm_gem_submit *submit) { int contended, slow_locked = -1, i, ret = 0; retry: - submit->valid = true; - for (i = 0; i < submit->nr_bos; i++) { struct msm_gem_object *msm_obj = submit->bos[i].obj; - uint32_t iova; if (slow_locked == i) slow_locked = -1; @@ -159,30 +156,6 @@ retry: goto fail; submit->bos[i].flags |= BO_LOCKED; } - - - /* if locking succeeded, pin bo: */ - ret = msm_gem_get_iova_locked(&msm_obj->base, - submit->gpu->id, &iova); - - /* this would break the logic in the fail path.. there is no - * reason for this to happen, but just to be on the safe side - * let's notice if this starts happening in the future: - */ - WARN_ON(ret == -EDEADLK); - - if (ret) - goto fail; - - submit->bos[i].flags |= BO_PINNED; - - if (iova == submit->bos[i].iova) { - submit->bos[i].flags |= BO_VALID; - } else { - submit->bos[i].iova = iova; - submit->bos[i].flags &= ~BO_VALID; - submit->valid = false; - } } ww_acquire_done(&submit->ticket); @@ -211,6 +184,38 @@ fail: return ret; } +static int submit_pin_objects(struct msm_gem_submit *submit) +{ + int i, ret = 0; + + submit->valid = true; + + for (i = 0; i < submit->nr_bos; i++) { + struct msm_gem_object *msm_obj = submit->bos[i].obj; + uint32_t iova; + + /* if locking succeeded, pin bo: */ + ret = msm_gem_get_iova_locked(&msm_obj->base, + submit->gpu->id, &iova); + + if (ret) + break; + + submit->bos[i].flags |= BO_PINNED; + + if (iova == submit->bos[i].iova) { + submit->bos[i].flags |= BO_VALID; + } else { + submit->bos[i].iova = iova; + /* iova changed, so address in cmdstream is not valid: */ + submit->bos[i].flags &= ~BO_VALID; + submit->valid = false; + } + } + + return ret; +} + static int submit_bo(struct msm_gem_submit *submit, uint32_t idx, struct msm_gem_object **obj, uint32_t *iova, bool *valid) { @@ -349,7 +354,11 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, if (ret) goto out; - ret = submit_validate_objects(submit); + ret = submit_lock_objects(submit); + if (ret) + goto out; + + ret = submit_pin_objects(submit); if (ret) goto out; -- cgit From b6295f9a38fc3f7d59ec0caa45aa803461c6cea5 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 15 Mar 2016 18:26:28 -0400 Subject: drm/msm: 'struct fence' conversion Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 4 +- drivers/gpu/drm/msm/msm_atomic.c | 42 ++++++----- drivers/gpu/drm/msm/msm_drv.h | 5 +- drivers/gpu/drm/msm/msm_fence.c | 71 +++++++++++++++++- drivers/gpu/drm/msm/msm_fence.h | 4 ++ drivers/gpu/drm/msm/msm_gem.c | 124 ++++++++++++++++++++++++-------- drivers/gpu/drm/msm/msm_gem.h | 16 +---- drivers/gpu/drm/msm/msm_gem_submit.c | 22 +++++- drivers/gpu/drm/msm/msm_gpu.c | 27 ++++--- drivers/gpu/drm/msm/msm_rd.c | 2 +- 10 files changed, 233 insertions(+), 84 deletions(-) (limited to 'drivers/gpu/drm/msm/msm_gem_submit.c') diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 9aab871f4def..95aed377b933 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -168,7 +168,7 @@ int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, OUT_PKT2(ring); OUT_PKT0(ring, REG_AXXX_CP_SCRATCH_REG2, 1); - OUT_RING(ring, submit->fence); + OUT_RING(ring, submit->fence->seqno); if (adreno_is_a3xx(adreno_gpu) || adreno_is_a4xx(adreno_gpu)) { /* Flush HLSQ lazy updates to make sure there is nothing @@ -185,7 +185,7 @@ int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, OUT_PKT3(ring, CP_EVENT_WRITE, 3); OUT_RING(ring, CACHE_FLUSH_TS); OUT_RING(ring, rbmemptr(adreno_gpu, fence)); - OUT_RING(ring, submit->fence); + OUT_RING(ring, submit->fence->seqno); /* we could maybe be clever and only CP_COND_EXEC the interrupt: */ OUT_PKT3(ring, CP_INTERRUPT, 1); diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 6ac7192d0ad6..e3892c263f27 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -107,27 +107,6 @@ static void msm_atomic_wait_for_commit_done(struct drm_device *dev, } } -static void wait_fences(struct msm_commit *c, bool async) -{ - int nplanes = c->dev->mode_config.num_total_plane; - ktime_t timeout = ktime_add_ms(ktime_get(), 1000); - int i; - - for (i = 0; i < nplanes; i++) { - struct drm_plane *plane = c->state->planes[i]; - struct drm_plane_state *new_state = c->state->plane_states[i]; - - if (!plane) - continue; - - if ((plane->state->fb != new_state->fb) && new_state->fb) { - struct drm_gem_object *obj = - msm_framebuffer_bo(new_state->fb, 0); - msm_gem_cpu_sync(obj, MSM_PREP_READ, &timeout); - } - } -} - /* The (potentially) asynchronous part of the commit. At this point * nothing can fail short of armageddon. */ @@ -138,7 +117,7 @@ static void complete_commit(struct msm_commit *c, bool async) struct msm_drm_private *priv = dev->dev_private; struct msm_kms *kms = priv->kms; - wait_fences(c, async); + drm_atomic_helper_wait_for_fences(dev, state); kms->funcs->prepare_commit(kms, state); @@ -213,6 +192,7 @@ int msm_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool nonblock) { struct msm_drm_private *priv = dev->dev_private; + int nplanes = dev->mode_config.num_total_plane; int ncrtcs = dev->mode_config.num_crtc; struct msm_commit *c; int i, ret; @@ -237,6 +217,24 @@ int msm_atomic_commit(struct drm_device *dev, c->crtc_mask |= (1 << drm_crtc_index(crtc)); } + /* + * Figure out what fence to wait for: + */ + for (i = 0; i < nplanes; i++) { + struct drm_plane *plane = state->planes[i]; + struct drm_plane_state *new_state = state->plane_states[i]; + + if (!plane) + continue; + + if ((plane->state->fb != new_state->fb) && new_state->fb) { + struct drm_gem_object *obj = msm_framebuffer_bo(new_state->fb, 0); + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + new_state->fence = reservation_object_get_excl_rcu(msm_obj->resv); + } + } + /* * Wait for pending updates on any of the same crtc's and then * mark our set of crtc's as busy: diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 7124c7f262ec..4114a40e4a09 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -190,10 +190,11 @@ int msm_gem_prime_pin(struct drm_gem_object *obj); void msm_gem_prime_unpin(struct drm_gem_object *obj); void *msm_gem_vaddr_locked(struct drm_gem_object *obj); void *msm_gem_vaddr(struct drm_gem_object *obj); +int msm_gem_sync_object(struct drm_gem_object *obj, + struct msm_fence_context *fctx, bool exclusive); void msm_gem_move_to_active(struct drm_gem_object *obj, - struct msm_gpu *gpu, bool write, uint32_t fence); + struct msm_gpu *gpu, bool exclusive, struct fence *fence); void msm_gem_move_to_inactive(struct drm_gem_object *obj); -int msm_gem_cpu_sync(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout); int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout); int msm_gem_cpu_fini(struct drm_gem_object *obj); void msm_gem_free_object(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/msm/msm_fence.c b/drivers/gpu/drm/msm/msm_fence.c index 088610ca80ca..a9b9b1c95a2e 100644 --- a/drivers/gpu/drm/msm/msm_fence.c +++ b/drivers/gpu/drm/msm/msm_fence.c @@ -32,7 +32,9 @@ msm_fence_context_alloc(struct drm_device *dev, const char *name) fctx->dev = dev; fctx->name = name; + fctx->context = fence_context_alloc(1); init_waitqueue_head(&fctx->event); + spin_lock_init(&fctx->spinlock); return fctx; } @@ -47,6 +49,7 @@ static inline bool fence_completed(struct msm_fence_context *fctx, uint32_t fenc return (int32_t)(fctx->completed_fence - fence) >= 0; } +/* legacy path for WAIT_FENCE ioctl: */ int msm_wait_fence(struct msm_fence_context *fctx, uint32_t fence, ktime_t *timeout, bool interruptible) { @@ -88,9 +91,73 @@ int msm_wait_fence(struct msm_fence_context *fctx, uint32_t fence, /* called from workqueue */ void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence) { - mutex_lock(&fctx->dev->struct_mutex); + spin_lock(&fctx->spinlock); fctx->completed_fence = max(fence, fctx->completed_fence); - mutex_unlock(&fctx->dev->struct_mutex); + spin_unlock(&fctx->spinlock); wake_up_all(&fctx->event); } + +struct msm_fence { + struct msm_fence_context *fctx; + struct fence base; +}; + +static inline struct msm_fence *to_msm_fence(struct fence *fence) +{ + return container_of(fence, struct msm_fence, base); +} + +static const char *msm_fence_get_driver_name(struct fence *fence) +{ + return "msm"; +} + +static const char *msm_fence_get_timeline_name(struct fence *fence) +{ + struct msm_fence *f = to_msm_fence(fence); + return f->fctx->name; +} + +static bool msm_fence_enable_signaling(struct fence *fence) +{ + return true; +} + +static bool msm_fence_signaled(struct fence *fence) +{ + struct msm_fence *f = to_msm_fence(fence); + return fence_completed(f->fctx, f->base.seqno); +} + +static void msm_fence_release(struct fence *fence) +{ + struct msm_fence *f = to_msm_fence(fence); + kfree_rcu(f, base.rcu); +} + +static const struct fence_ops msm_fence_ops = { + .get_driver_name = msm_fence_get_driver_name, + .get_timeline_name = msm_fence_get_timeline_name, + .enable_signaling = msm_fence_enable_signaling, + .signaled = msm_fence_signaled, + .wait = fence_default_wait, + .release = msm_fence_release, +}; + +struct fence * +msm_fence_alloc(struct msm_fence_context *fctx) +{ + struct msm_fence *f; + + f = kzalloc(sizeof(*f), GFP_KERNEL); + if (!f) + return ERR_PTR(-ENOMEM); + + f->fctx = fctx; + + fence_init(&f->base, &msm_fence_ops, &fctx->spinlock, + fctx->context, ++fctx->last_fence); + + return &f->base; +} diff --git a/drivers/gpu/drm/msm/msm_fence.h b/drivers/gpu/drm/msm/msm_fence.h index 2820781d974a..ceb5b3d314b4 100644 --- a/drivers/gpu/drm/msm/msm_fence.h +++ b/drivers/gpu/drm/msm/msm_fence.h @@ -23,10 +23,12 @@ struct msm_fence_context { struct drm_device *dev; const char *name; + unsigned context; /* last_fence == completed_fence --> no pending work */ uint32_t last_fence; /* last assigned fence */ uint32_t completed_fence; /* last completed fence */ wait_queue_head_t event; + spinlock_t spinlock; }; struct msm_fence_context * msm_fence_context_alloc(struct drm_device *dev, @@ -39,4 +41,6 @@ int msm_queue_fence_cb(struct msm_fence_context *fctx, struct msm_fence_cb *cb, uint32_t fence); void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence); +struct fence * msm_fence_alloc(struct msm_fence_context *fctx); + #endif diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 9080ed13998a..9bbe1c5e7151 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -411,15 +411,62 @@ void *msm_gem_vaddr(struct drm_gem_object *obj) return ret; } +/* must be called before _move_to_active().. */ +int msm_gem_sync_object(struct drm_gem_object *obj, + struct msm_fence_context *fctx, bool exclusive) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct reservation_object_list *fobj; + struct fence *fence; + int i, ret; + + if (!exclusive) { + /* NOTE: _reserve_shared() must happen before _add_shared_fence(), + * which makes this a slightly strange place to call it. OTOH this + * is a convenient can-fail point to hook it in. (And similar to + * how etnaviv and nouveau handle this.) + */ + ret = reservation_object_reserve_shared(msm_obj->resv); + if (ret) + return ret; + } + + fobj = reservation_object_get_list(msm_obj->resv); + if (!fobj || (fobj->shared_count == 0)) { + fence = reservation_object_get_excl(msm_obj->resv); + /* don't need to wait on our own fences, since ring is fifo */ + if (fence && (fence->context != fctx->context)) { + ret = fence_wait(fence, true); + if (ret) + return ret; + } + } + + if (!exclusive || !fobj) + return 0; + + for (i = 0; i < fobj->shared_count; i++) { + fence = rcu_dereference_protected(fobj->shared[i], + reservation_object_held(msm_obj->resv)); + if (fence->context != fctx->context) { + ret = fence_wait(fence, true); + if (ret) + return ret; + } + } + + return 0; +} + void msm_gem_move_to_active(struct drm_gem_object *obj, - struct msm_gpu *gpu, bool write, uint32_t fence) + struct msm_gpu *gpu, bool exclusive, struct fence *fence) { struct msm_gem_object *msm_obj = to_msm_bo(obj); msm_obj->gpu = gpu; - if (write) - msm_obj->write_fence = fence; + if (exclusive) + reservation_object_add_excl_fence(msm_obj->resv, fence); else - msm_obj->read_fence = fence; + reservation_object_add_shared_fence(msm_obj->resv, fence); list_del_init(&msm_obj->mm_list); list_add_tail(&msm_obj->mm_list, &gpu->active_list); } @@ -433,39 +480,30 @@ void msm_gem_move_to_inactive(struct drm_gem_object *obj) WARN_ON(!mutex_is_locked(&dev->struct_mutex)); msm_obj->gpu = NULL; - msm_obj->read_fence = 0; - msm_obj->write_fence = 0; list_del_init(&msm_obj->mm_list); list_add_tail(&msm_obj->mm_list, &priv->inactive_list); } -int msm_gem_cpu_sync(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout) +int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout) { - struct drm_device *dev = obj->dev; - struct msm_drm_private *priv = dev->dev_private; struct msm_gem_object *msm_obj = to_msm_bo(obj); - int ret = 0; - - if (is_active(msm_obj)) { - uint32_t fence = msm_gem_fence(msm_obj, op); + bool write = !!(op & MSM_PREP_WRITE); - if (op & MSM_PREP_NOSYNC) - timeout = NULL; + if (op & MSM_PREP_NOSYNC) { + if (!reservation_object_test_signaled_rcu(msm_obj->resv, write)) + return -EBUSY; + } else { + int ret; - if (priv->gpu) - ret = msm_wait_fence(priv->gpu->fctx, fence, timeout, true); + ret = reservation_object_wait_timeout_rcu(msm_obj->resv, write, + true, timeout_to_jiffies(timeout)); + if (ret <= 0) + return ret == 0 ? -ETIMEDOUT : ret; } - return ret; -} - -int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout) -{ - int ret = msm_gem_cpu_sync(obj, op, timeout); - /* TODO cache maintenance */ - return ret; + return 0; } int msm_gem_cpu_fini(struct drm_gem_object *obj) @@ -475,18 +513,46 @@ int msm_gem_cpu_fini(struct drm_gem_object *obj) } #ifdef CONFIG_DEBUG_FS +static void describe_fence(struct fence *fence, const char *type, + struct seq_file *m) +{ + if (!fence_is_signaled(fence)) + seq_printf(m, "\t%9s: %s %s seq %u\n", type, + fence->ops->get_driver_name(fence), + fence->ops->get_timeline_name(fence), + fence->seqno); +} + void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m) { - struct drm_device *dev = obj->dev; struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct reservation_object *robj = msm_obj->resv; + struct reservation_object_list *fobj; + struct fence *fence; uint64_t off = drm_vma_node_start(&obj->vma_node); - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %p %zu\n", + WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); + + seq_printf(m, "%08x: %c %2d (%2d) %08llx %p %zu\n", msm_obj->flags, is_active(msm_obj) ? 'A' : 'I', - msm_obj->read_fence, msm_obj->write_fence, obj->name, obj->refcount.refcount.counter, off, msm_obj->vaddr, obj->size); + + rcu_read_lock(); + fobj = rcu_dereference(robj->fence); + if (fobj) { + unsigned int i, shared_count = fobj->shared_count; + + for (i = 0; i < shared_count; i++) { + fence = rcu_dereference(fobj->shared[i]); + describe_fence(fence, "Shared", m); + } + } + + fence = rcu_dereference(robj->fence_excl); + if (fence) + describe_fence(fence, "Exclusive", m); + rcu_read_unlock(); } void msm_gem_describe_objects(struct list_head *list, struct seq_file *m) diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index b8904517117d..2771d155587a 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -39,7 +39,6 @@ struct msm_gem_object { */ struct list_head mm_list; struct msm_gpu *gpu; /* non-null if active */ - uint32_t read_fence, write_fence; /* Transiently in the process of submit ioctl, objects associated * with the submit are on submit->bo_list.. this only lasts for @@ -73,19 +72,6 @@ static inline bool is_active(struct msm_gem_object *msm_obj) return msm_obj->gpu != NULL; } -static inline uint32_t msm_gem_fence(struct msm_gem_object *msm_obj, - uint32_t op) -{ - uint32_t fence = 0; - - if (op & MSM_PREP_READ) - fence = msm_obj->write_fence; - if (op & MSM_PREP_WRITE) - fence = max(fence, msm_obj->read_fence); - - return fence; -} - #define MAX_CMDS 4 /* Created per submit-ioctl, to track bo's and cmdstream bufs, etc, @@ -99,7 +85,7 @@ struct msm_gem_submit { struct list_head node; /* node in gpu submit_list */ struct list_head bo_list; struct ww_acquire_ctx ticket; - uint32_t fence; + struct fence *fence; bool valid; /* true if no cmdstream patching needed */ unsigned int nr_cmds; unsigned int nr_bos; diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index b231544b3f52..2661a7cb23c8 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -184,6 +184,22 @@ fail: return ret; } +static int submit_fence_sync(struct msm_gem_submit *submit) +{ + int i, ret = 0; + + for (i = 0; i < submit->nr_bos; i++) { + struct msm_gem_object *msm_obj = submit->bos[i].obj; + bool write = submit->bos[i].flags & MSM_SUBMIT_BO_WRITE; + + ret = msm_gem_sync_object(&msm_obj->base, submit->gpu->fctx, write); + if (ret) + break; + } + + return ret; +} + static int submit_pin_objects(struct msm_gem_submit *submit) { int i, ret = 0; @@ -358,6 +374,10 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, if (ret) goto out; + ret = submit_fence_sync(submit); + if (ret) + goto out; + ret = submit_pin_objects(submit); if (ret) goto out; @@ -424,7 +444,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, ret = msm_gpu_submit(gpu, submit, ctx); - args->fence = submit->fence; + args->fence = submit->fence->seqno; out: submit_cleanup(submit, !!ret); diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 8f0b29548cfc..f94d01099e19 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -266,22 +266,24 @@ static void inactive_start(struct msm_gpu *gpu) * Hangcheck detection for locked gpu: */ -static void retire_submits(struct msm_gpu *gpu, uint32_t fence); +static void retire_submits(struct msm_gpu *gpu); static void recover_worker(struct work_struct *work) { struct msm_gpu *gpu = container_of(work, struct msm_gpu, recover_work); struct drm_device *dev = gpu->dev; + uint32_t fence = gpu->funcs->last_fence(gpu); dev_err(dev->dev, "%s: hangcheck recover!\n", gpu->name); + msm_update_fence(gpu->fctx, fence + 1); + mutex_lock(&dev->struct_mutex); if (msm_gpu_active(gpu)) { struct msm_gem_submit *submit; - uint32_t fence = gpu->funcs->last_fence(gpu); /* retire completed submits, plus the one that hung: */ - retire_submits(gpu, fence + 1); + retire_submits(gpu); inactive_cancel(gpu); gpu->funcs->recover(gpu); @@ -444,11 +446,12 @@ static void retire_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) drm_gem_object_unreference(&msm_obj->base); } + fence_put(submit->fence); list_del(&submit->node); kfree(submit); } -static void retire_submits(struct msm_gpu *gpu, uint32_t fence) +static void retire_submits(struct msm_gpu *gpu) { struct drm_device *dev = gpu->dev; @@ -460,7 +463,7 @@ static void retire_submits(struct msm_gpu *gpu, uint32_t fence) submit = list_first_entry(&gpu->submit_list, struct msm_gem_submit, node); - if (submit->fence <= fence) { + if (fence_is_signaled(submit->fence)) { retire_submit(gpu, submit); } else { break; @@ -477,7 +480,7 @@ static void retire_worker(struct work_struct *work) msm_update_fence(gpu->fctx, fence); mutex_lock(&dev->struct_mutex); - retire_submits(gpu, fence); + retire_submits(gpu); mutex_unlock(&dev->struct_mutex); if (!msm_gpu_active(gpu)) @@ -502,7 +505,12 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - submit->fence = ++gpu->fctx->last_fence; + submit->fence = msm_fence_alloc(gpu->fctx); + if (IS_ERR(submit->fence)) { + ret = PTR_ERR(submit->fence); + submit->fence = NULL; + return ret; + } inactive_cancel(gpu); @@ -526,11 +534,10 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, msm_gem_get_iova_locked(&msm_obj->base, submit->gpu->id, &iova); - if (submit->bos[i].flags & MSM_SUBMIT_BO_READ) - msm_gem_move_to_active(&msm_obj->base, gpu, false, submit->fence); - if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE) msm_gem_move_to_active(&msm_obj->base, gpu, true, submit->fence); + else if (submit->bos[i].flags & MSM_SUBMIT_BO_READ) + msm_gem_move_to_active(&msm_obj->base, gpu, false, submit->fence); } ret = gpu->funcs->submit(gpu, submit, ctx); diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c index 9a78c48817c6..b48f73ac6389 100644 --- a/drivers/gpu/drm/msm/msm_rd.c +++ b/drivers/gpu/drm/msm/msm_rd.c @@ -296,7 +296,7 @@ void msm_rd_dump_submit(struct msm_gem_submit *submit) n = snprintf(msg, sizeof(msg), "%.*s/%d: fence=%u", TASK_COMM_LEN, current->comm, task_pid_nr(current), - submit->fence); + submit->fence->seqno); rd_write_section(rd, RD_CMD, msg, ALIGN(n, 4)); -- cgit From 6860b56c4b84bf9dba479c3f881d45a0b09a879c Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 3 May 2016 09:49:40 -0400 Subject: drm/msm: de-indent submit_create() Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gem_submit.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers/gpu/drm/msm/msm_gem_submit.c') diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 2661a7cb23c8..96c595c9ab93 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -40,17 +40,18 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, int sz = sizeof(*submit) + (nr * sizeof(submit->bos[0])); submit = kmalloc(sz, GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); - if (submit) { - submit->dev = dev; - submit->gpu = gpu; + if (!submit) + return NULL; - /* initially, until copy_from_user() and bo lookup succeeds: */ - submit->nr_bos = 0; - submit->nr_cmds = 0; + submit->dev = dev; + submit->gpu = gpu; - INIT_LIST_HEAD(&submit->bo_list); - ww_acquire_init(&submit->ticket, &reservation_ww_class); - } + /* initially, until copy_from_user() and bo lookup succeeds: */ + submit->nr_bos = 0; + submit->nr_cmds = 0; + + INIT_LIST_HEAD(&submit->bo_list); + ww_acquire_init(&submit->ticket, &reservation_ww_class); return submit; } -- cgit From 40e6815bba6e34e5560e8855b43cd3eb17b24b09 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 3 May 2016 09:50:26 -0400 Subject: drm/msm: fix leak in failed submit path Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_drv.h | 1 + drivers/gpu/drm/msm/msm_gem_submit.c | 13 +++++++++++-- drivers/gpu/drm/msm/msm_gpu.c | 4 +--- 3 files changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/msm/msm_gem_submit.c') diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 4114a40e4a09..5b2963f32291 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -161,6 +161,7 @@ int msm_atomic_commit(struct drm_device *dev, int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu); +void msm_gem_submit_free(struct msm_gem_submit *submit); int msm_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_file *file); diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 96c595c9ab93..711a658cf1ea 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -56,6 +56,13 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, return submit; } +void msm_gem_submit_free(struct msm_gem_submit *submit) +{ + fence_put(submit->fence); + list_del(&submit->node); + kfree(submit); +} + static int submit_lookup_objects(struct msm_gem_submit *submit, struct drm_msm_gem_submit *args, struct drm_file *file) { @@ -324,7 +331,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob return 0; } -static void submit_cleanup(struct msm_gem_submit *submit, bool fail) +static void submit_cleanup(struct msm_gem_submit *submit) { unsigned i; @@ -448,7 +455,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, args->fence = submit->fence->seqno; out: - submit_cleanup(submit, !!ret); + submit_cleanup(submit); + if (ret) + msm_gem_submit_free(submit); mutex_unlock(&dev->struct_mutex); return ret; } diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 4c4f4b5abe2c..5aed93a87e4c 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -446,9 +446,7 @@ static void retire_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) drm_gem_object_unreference(&msm_obj->base); } - fence_put(submit->fence); - list_del(&submit->node); - kfree(submit); + msm_gem_submit_free(submit); } static void retire_submits(struct msm_gpu *gpu) -- cgit From 4816b6267cf078f40158ff2e6bf9d0223f0c1cf6 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 3 May 2016 10:10:15 -0400 Subject: drm/msm: print offender task name on hangcheck recovery Track the pid per submit, so we can print the name of the task which submitted the batch that caused the gpu to hang. Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gem.h | 1 + drivers/gpu/drm/msm/msm_gem_submit.c | 2 ++ drivers/gpu/drm/msm/msm_gpu.c | 23 +++++++++++++++++++---- 3 files changed, 22 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/msm/msm_gem_submit.c') diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 2771d155587a..9facd4b6ffd9 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -86,6 +86,7 @@ struct msm_gem_submit { struct list_head bo_list; struct ww_acquire_ctx ticket; struct fence *fence; + struct pid *pid; /* submitting process */ bool valid; /* true if no cmdstream patching needed */ unsigned int nr_cmds; unsigned int nr_bos; diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 711a658cf1ea..a9a001150b9e 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -45,6 +45,7 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, submit->dev = dev; submit->gpu = gpu; + submit->pid = get_pid(task_pid(current)); /* initially, until copy_from_user() and bo lookup succeeds: */ submit->nr_bos = 0; @@ -60,6 +61,7 @@ void msm_gem_submit_free(struct msm_gem_submit *submit) { fence_put(submit->fence); list_del(&submit->node); + put_pid(submit->pid); kfree(submit); } diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 5aed93a87e4c..36ed53e661fe 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -272,16 +272,30 @@ static void recover_worker(struct work_struct *work) { struct msm_gpu *gpu = container_of(work, struct msm_gpu, recover_work); struct drm_device *dev = gpu->dev; + struct msm_gem_submit *submit; uint32_t fence = gpu->funcs->last_fence(gpu); - dev_err(dev->dev, "%s: hangcheck recover!\n", gpu->name); - msm_update_fence(gpu->fctx, fence + 1); mutex_lock(&dev->struct_mutex); - if (msm_gpu_active(gpu)) { - struct msm_gem_submit *submit; + dev_err(dev->dev, "%s: hangcheck recover!\n", gpu->name); + list_for_each_entry(submit, &gpu->submit_list, node) { + if (submit->fence->seqno == (fence + 1)) { + struct task_struct *task; + + rcu_read_lock(); + task = pid_task(submit->pid, PIDTYPE_PID); + if (task) { + dev_err(dev->dev, "%s: offending task: %s\n", + gpu->name, task->comm); + } + rcu_read_unlock(); + break; + } + } + + if (msm_gpu_active(gpu)) { /* retire completed submits, plus the one that hung: */ retire_submits(gpu); @@ -293,6 +307,7 @@ static void recover_worker(struct work_struct *work) gpu->funcs->submit(gpu, submit, NULL); } } + mutex_unlock(&dev->struct_mutex); msm_gpu_retire(gpu); -- cgit