diff options
Diffstat (limited to 'drivers/gpu/drm/msm/msm_gem_submit.c')
-rw-r--r-- | drivers/gpu/drm/msm/msm_gem_submit.c | 103 |
1 files changed, 71 insertions, 32 deletions
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 6cfa984dee6a..80975229b4de 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -21,12 +21,6 @@ * Cmdstream submission: */ -/* make sure these don't conflict w/ MSM_SUBMIT_BO_x */ -#define BO_VALID 0x8000 /* is current addr in cmdstream correct/valid? */ -#define BO_LOCKED 0x4000 /* obj lock is held */ -#define BO_ACTIVE 0x2000 /* active refcnt is held */ -#define BO_PINNED 0x1000 /* obj is pinned and on active list */ - static struct msm_gem_submit *submit_create(struct drm_device *dev, struct msm_gpu *gpu, struct msm_gpu_submitqueue *queue, uint32_t nr_bos, @@ -231,16 +225,21 @@ static void submit_cleanup_bo(struct msm_gem_submit *submit, int i, struct drm_gem_object *obj = &submit->bos[i].obj->base; unsigned flags = submit->bos[i].flags & cleanup_flags; + /* + * Clear flags bit before dropping lock, so that the msm_job_run() + * path isn't racing with submit_cleanup() (ie. the read/modify/ + * write is protected by the obj lock in all paths) + */ + submit->bos[i].flags &= ~cleanup_flags; + if (flags & BO_PINNED) - msm_gem_unpin_iova_locked(obj, submit->aspace); + msm_gem_unpin_vma_locked(obj, submit->bos[i].vma); if (flags & BO_ACTIVE) msm_gem_active_put(obj); if (flags & BO_LOCKED) dma_resv_unlock(obj->resv); - - submit->bos[i].flags &= ~cleanup_flags; } static void submit_unlock_unpin_bo(struct msm_gem_submit *submit, int i) @@ -320,16 +319,14 @@ static int submit_fence_sync(struct msm_gem_submit *submit, bool no_implicit) struct drm_gem_object *obj = &submit->bos[i].obj->base; bool write = submit->bos[i].flags & MSM_SUBMIT_BO_WRITE; - if (!write) { - /* 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. - */ - ret = dma_resv_reserve_shared(obj->resv, 1); - if (ret) - return ret; - } + /* 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. + */ + ret = dma_resv_reserve_fences(obj->resv, 1); + if (ret) + return ret; /* exclusive fences must be ordered */ if (no_implicit && !write) @@ -365,21 +362,26 @@ static int submit_pin_objects(struct msm_gem_submit *submit) for (i = 0; i < submit->nr_bos; i++) { struct drm_gem_object *obj = &submit->bos[i].obj->base; - uint64_t iova; + struct msm_gem_vma *vma; /* if locking succeeded, pin bo: */ - ret = msm_gem_get_and_pin_iova_locked(obj, - submit->aspace, &iova); + vma = msm_gem_get_vma_locked(obj, submit->aspace); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + break; + } + ret = msm_gem_pin_vma_locked(obj, vma); if (ret) break; submit->bos[i].flags |= BO_PINNED; + submit->bos[i].vma = vma; - if (iova == submit->bos[i].iova) { + if (vma->iova == submit->bos[i].iova) { submit->bos[i].flags |= BO_VALID; } else { - submit->bos[i].iova = iova; + submit->bos[i].iova = vma->iova; /* iova changed, so address in cmdstream is not valid: */ submit->bos[i].flags &= ~BO_VALID; submit->valid = false; @@ -397,9 +399,11 @@ static void submit_attach_object_fences(struct msm_gem_submit *submit) struct drm_gem_object *obj = &submit->bos[i].obj->base; if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE) - dma_resv_add_excl_fence(obj->resv, submit->user_fence); + dma_resv_add_fence(obj->resv, submit->user_fence, + DMA_RESV_USAGE_WRITE); else if (submit->bos[i].flags & MSM_SUBMIT_BO_READ) - dma_resv_add_shared_fence(obj->resv, submit->user_fence); + dma_resv_add_fence(obj->resv, submit->user_fence, + DMA_RESV_USAGE_READ); } } @@ -730,6 +734,11 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, if (args->pad) return -EINVAL; + if (unlikely(!ctx->aspace) && !capable(CAP_SYS_RAWIO)) { + DRM_ERROR_RATELIMITED("IOMMU support or CAP_SYS_RAWIO required!\n"); + return -EPERM; + } + /* for now, we just have 3d pipe.. eventually this would need to * be more clever to dispatch to appropriate gpu module: */ @@ -872,16 +881,46 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, submit->nr_cmds = i; + /* + * If using userspace provided seqno fence, validate that the id + * is available before arming sched job. Since access to fence_idr + * is serialized on the queue lock, the slot should be still avail + * after the job is armed + */ + if ((args->flags & MSM_SUBMIT_FENCE_SN_IN) && + idr_find(&queue->fence_idr, args->fence)) { + ret = -EINVAL; + goto out; + } + drm_sched_job_arm(&submit->base); submit->user_fence = dma_fence_get(&submit->base.s_fence->finished); - /* - * Allocate an id which can be used by WAIT_FENCE ioctl to map back - * to the underlying fence. - */ - submit->fence_id = idr_alloc_cyclic(&queue->fence_idr, - submit->user_fence, 1, INT_MAX, GFP_KERNEL); + if (args->flags & MSM_SUBMIT_FENCE_SN_IN) { + /* + * Userspace has assigned the seqno fence that it wants + * us to use. It is an error to pick a fence sequence + * number that is not available. + */ + submit->fence_id = args->fence; + ret = idr_alloc_u32(&queue->fence_idr, submit->user_fence, + &submit->fence_id, submit->fence_id, + GFP_KERNEL); + /* + * We've already validated that the fence_id slot is valid, + * so if idr_alloc_u32 failed, it is a kernel bug + */ + WARN_ON(ret); + } else { + /* + * Allocate an id which can be used by WAIT_FENCE ioctl to map + * back to the underlying fence. + */ + submit->fence_id = idr_alloc_cyclic(&queue->fence_idr, + submit->user_fence, 1, + INT_MAX, GFP_KERNEL); + } if (submit->fence_id < 0) { ret = submit->fence_id = 0; submit->fence_id = 0; |