drm/msm/gem: Convert to drm_exec
Replace the ww_mutex locking dance with the drm_exec helper.
v2: Error path fixes, move drm_exec_fini so we only call it once (and
only if we have drm_exec_init()
Signed-off-by: Rob Clark <robdclark@chromium.org>
Patchwork: https://patchwork.freedesktop.org/patch/568342/
This commit is contained in:
@@ -17,6 +17,7 @@ config DRM_MSM
|
||||
select DRM_DP_AUX_BUS
|
||||
select DRM_DISPLAY_DP_HELPER
|
||||
select DRM_DISPLAY_HELPER
|
||||
select DRM_EXEC
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_PANEL
|
||||
select DRM_BRIDGE
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <linux/kref.h>
|
||||
#include <linux/dma-resv.h>
|
||||
#include "drm/drm_exec.h"
|
||||
#include "drm/gpu_scheduler.h"
|
||||
#include "msm_drv.h"
|
||||
|
||||
@@ -258,7 +259,7 @@ struct msm_gem_submit {
|
||||
struct msm_gpu *gpu;
|
||||
struct msm_gem_address_space *aspace;
|
||||
struct list_head node; /* node in ring submit list */
|
||||
struct ww_acquire_ctx ticket;
|
||||
struct drm_exec exec;
|
||||
uint32_t seqno; /* Sequence number of the submit on the ring */
|
||||
|
||||
/* Hw fence, which is created when the scheduler executes the job, and
|
||||
@@ -291,8 +292,6 @@ struct msm_gem_submit {
|
||||
struct drm_msm_gem_submit_reloc *relocs;
|
||||
} *cmd; /* array of size nr_cmds */
|
||||
struct {
|
||||
/* make sure these don't conflict w/ MSM_SUBMIT_BO_x */
|
||||
#define BO_LOCKED 0x4000 /* obj lock is held */
|
||||
uint32_t flags;
|
||||
union {
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
@@ -248,85 +248,30 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void submit_unlock_bo(struct msm_gem_submit *submit, int i)
|
||||
{
|
||||
struct drm_gem_object *obj = submit->bos[i].obj;
|
||||
unsigned cleanup_flags = BO_LOCKED;
|
||||
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_LOCKED)
|
||||
dma_resv_unlock(obj->resv);
|
||||
}
|
||||
|
||||
/* This is where we make sure all the bo's are reserved and pin'd: */
|
||||
static int submit_lock_objects(struct msm_gem_submit *submit)
|
||||
{
|
||||
int contended, slow_locked = -1, i, ret = 0;
|
||||
int ret;
|
||||
|
||||
retry:
|
||||
for (i = 0; i < submit->nr_bos; i++) {
|
||||
struct drm_gem_object *obj = submit->bos[i].obj;
|
||||
drm_exec_init(&submit->exec, DRM_EXEC_INTERRUPTIBLE_WAIT, submit->nr_bos);
|
||||
|
||||
if (slow_locked == i)
|
||||
slow_locked = -1;
|
||||
|
||||
contended = i;
|
||||
|
||||
if (!(submit->bos[i].flags & BO_LOCKED)) {
|
||||
ret = dma_resv_lock_interruptible(obj->resv,
|
||||
&submit->ticket);
|
||||
drm_exec_until_all_locked (&submit->exec) {
|
||||
for (unsigned i = 0; i < submit->nr_bos; i++) {
|
||||
struct drm_gem_object *obj = submit->bos[i].obj;
|
||||
ret = drm_exec_prepare_obj(&submit->exec, obj, 1);
|
||||
drm_exec_retry_on_contention(&submit->exec);
|
||||
if (ret)
|
||||
goto fail;
|
||||
submit->bos[i].flags |= BO_LOCKED;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
ww_acquire_done(&submit->ticket);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (ret == -EALREADY) {
|
||||
SUBMIT_ERROR(submit, "handle %u at index %u already on submit list\n",
|
||||
submit->bos[i].handle, i);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
for (; i >= 0; i--)
|
||||
submit_unlock_bo(submit, i);
|
||||
|
||||
if (slow_locked > 0)
|
||||
submit_unlock_bo(submit, slow_locked);
|
||||
|
||||
if (ret == -EDEADLK) {
|
||||
struct drm_gem_object *obj = submit->bos[contended].obj;
|
||||
/* we lost out in a seqno race, lock and retry.. */
|
||||
ret = dma_resv_lock_slow_interruptible(obj->resv,
|
||||
&submit->ticket);
|
||||
if (!ret) {
|
||||
submit->bos[contended].flags |= BO_LOCKED;
|
||||
slow_locked = contended;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/* Not expecting -EALREADY here, if the bo was already
|
||||
* locked, we should have gotten -EALREADY already from
|
||||
* the dma_resv_lock_interruptable() call.
|
||||
*/
|
||||
WARN_ON_ONCE(ret == -EALREADY);
|
||||
}
|
||||
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int submit_fence_sync(struct msm_gem_submit *submit, bool no_implicit)
|
||||
static int submit_fence_sync(struct msm_gem_submit *submit)
|
||||
{
|
||||
int i, ret = 0;
|
||||
|
||||
@@ -334,22 +279,6 @@ static int submit_fence_sync(struct msm_gem_submit *submit, bool no_implicit)
|
||||
struct drm_gem_object *obj = submit->bos[i].obj;
|
||||
bool write = submit->bos[i].flags & MSM_SUBMIT_BO_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_fences(obj->resv, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* If userspace has determined that explicit fencing is
|
||||
* used, it can disable implicit sync on the entire
|
||||
* submit:
|
||||
*/
|
||||
if (no_implicit)
|
||||
continue;
|
||||
|
||||
/* Otherwise userspace can ask for implicit sync to be
|
||||
* disabled on specific buffers. This is useful for internal
|
||||
* usermode driver managed buffers, suballocation, etc.
|
||||
@@ -529,17 +458,14 @@ out:
|
||||
*/
|
||||
static void submit_cleanup(struct msm_gem_submit *submit, bool error)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (error)
|
||||
if (error) {
|
||||
submit_unpin_objects(submit);
|
||||
|
||||
for (i = 0; i < submit->nr_bos; i++) {
|
||||
struct drm_gem_object *obj = submit->bos[i].obj;
|
||||
submit_unlock_bo(submit, i);
|
||||
if (error)
|
||||
drm_gem_object_put(obj);
|
||||
/* job wasn't enqueued to scheduler, so early retirement: */
|
||||
msm_submit_retire(submit);
|
||||
}
|
||||
|
||||
if (submit->exec.objects)
|
||||
drm_exec_fini(&submit->exec);
|
||||
}
|
||||
|
||||
void msm_submit_retire(struct msm_gem_submit *submit)
|
||||
@@ -733,7 +659,6 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
|
||||
struct msm_submit_post_dep *post_deps = NULL;
|
||||
struct drm_syncobj **syncobjs_to_reset = NULL;
|
||||
int out_fence_fd = -1;
|
||||
bool has_ww_ticket = false;
|
||||
unsigned i;
|
||||
int ret;
|
||||
|
||||
@@ -839,15 +764,15 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
|
||||
goto out;
|
||||
|
||||
/* copy_*_user while holding a ww ticket upsets lockdep */
|
||||
ww_acquire_init(&submit->ticket, &reservation_ww_class);
|
||||
has_ww_ticket = true;
|
||||
ret = submit_lock_objects(submit);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = submit_fence_sync(submit, !!(args->flags & MSM_SUBMIT_NO_IMPLICIT));
|
||||
if (ret)
|
||||
goto out;
|
||||
if (!(args->flags & MSM_SUBMIT_NO_IMPLICIT)) {
|
||||
ret = submit_fence_sync(submit);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = submit_pin_objects(submit);
|
||||
if (ret)
|
||||
@@ -975,8 +900,6 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
|
||||
|
||||
out:
|
||||
submit_cleanup(submit, !!ret);
|
||||
if (has_ww_ticket)
|
||||
ww_acquire_fini(&submit->ticket);
|
||||
out_unlock:
|
||||
mutex_unlock(&queue->lock);
|
||||
out_post_unlock:
|
||||
|
||||
Reference in New Issue
Block a user