diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index fc7ad9b0e0..5540f50a00 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -1204,7 +1204,8 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, struct sde_connector *c_conn; struct sde_connector_state *c_state; int idx, rc; - uint64_t fence_fd; + uint64_t fence_user_fd; + uint64_t __user prev_user_fd; if (!connector || !state || !property) { SDE_ERROR("invalid argument(s), conn %pK, state %pK, prp %pK\n", @@ -1247,23 +1248,42 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, if (!val) goto end; - /* - * update the the offset to a timeline for commit completion - */ - rc = sde_fence_create(c_conn->retire_fence, &fence_fd, 1); + rc = copy_from_user(&prev_user_fd, (void __user *)val, + sizeof(uint64_t)); if (rc) { - SDE_ERROR("fence create failed rc:%d\n", rc); + SDE_ERROR("copy from user failed rc:%d\n", rc); + rc = -EFAULT; goto end; } - rc = copy_to_user((uint64_t __user *)(uintptr_t)val, &fence_fd, - sizeof(uint64_t)); - if (rc) { - SDE_ERROR("copy to user failed rc:%d\n", rc); - /* fence will be released with timeline update */ - put_unused_fd(fence_fd); - rc = -EFAULT; - goto end; + /* + * client is expected to reset the property to -1 before + * requesting for the retire fence + */ + if (prev_user_fd == -1) { + /* + * update the offset to a timeline for + * commit completion + */ + rc = sde_fence_create(c_conn->retire_fence, + &fence_user_fd, 1); + if (rc) { + SDE_ERROR("fence create failed rc:%d\n", rc); + goto end; + } + + rc = copy_to_user((uint64_t __user *)(uintptr_t)val, + &fence_user_fd, sizeof(uint64_t)); + if (rc) { + SDE_ERROR("copy to user failed rc:%d\n", rc); + /* + * fence will be released with timeline + * update + */ + put_unused_fd(fence_user_fd); + rc = -EFAULT; + goto end; + } } break; case CONNECTOR_PROP_ROI_V1: diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 1eb6ac9dcb..7cfc3900c0 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -5025,7 +5025,8 @@ static int sde_crtc_atomic_set_property(struct drm_crtc *crtc, struct sde_crtc *sde_crtc; struct sde_crtc_state *cstate; int idx, ret; - uint64_t fence_fd; + uint64_t fence_user_fd; + uint64_t __user prev_user_fd; if (!crtc || !state || !property) { SDE_ERROR("invalid argument(s)\n"); @@ -5085,19 +5086,34 @@ static int sde_crtc_atomic_set_property(struct drm_crtc *crtc, if (!val) goto exit; - ret = _sde_crtc_get_output_fence(crtc, state, &fence_fd); + ret = copy_from_user(&prev_user_fd, (void __user *)val, + sizeof(uint64_t)); if (ret) { - SDE_ERROR("fence create failed rc:%d\n", ret); + SDE_ERROR("copy from user failed rc:%d\n", ret); + ret = -EFAULT; goto exit; } - ret = copy_to_user((uint64_t __user *)(uintptr_t)val, &fence_fd, - sizeof(uint64_t)); - if (ret) { - SDE_ERROR("copy to user failed rc:%d\n", ret); - put_unused_fd(fence_fd); - ret = -EFAULT; - goto exit; + /* + * client is expected to reset the property to -1 before + * requesting for the release fence + */ + if (prev_user_fd == -1) { + ret = _sde_crtc_get_output_fence(crtc, state, + &fence_user_fd); + if (ret) { + SDE_ERROR("fence create failed rc:%d\n", ret); + goto exit; + } + + ret = copy_to_user((uint64_t __user *)(uintptr_t)val, + &fence_user_fd, sizeof(uint64_t)); + if (ret) { + SDE_ERROR("copy to user failed rc:%d\n", ret); + put_unused_fd(fence_user_fd); + ret = -EFAULT; + goto exit; + } } break; default: diff --git a/msm/sde/sde_fence.c b/msm/sde/sde_fence.c index dc9cc7731c..6c41e3b6fb 100644 --- a/msm/sde/sde_fence.c +++ b/msm/sde/sde_fence.c @@ -325,9 +325,8 @@ int sde_fence_create(struct sde_fence_context *ctx, uint64_t *val, uint32_t offset) { uint32_t trigger_value; - int fd = -1, rc = -EINVAL; + int fd, rc = -EINVAL; unsigned long flags; - struct sde_fence *fc; if (!ctx || !val) { SDE_ERROR("invalid argument(s), fence %d, pval %d\n", @@ -347,22 +346,10 @@ int sde_fence_create(struct sde_fence_context *ctx, uint64_t *val, trigger_value = ctx->commit_count + offset; spin_unlock_irqrestore(&ctx->lock, flags); - spin_lock(&ctx->list_lock); - list_for_each_entry(fc, &ctx->fence_list_head, fence_list) { - if (trigger_value == fc->base.seqno) { - fd = fc->fd; - *val = fd; - break; - } - } - spin_unlock(&ctx->list_lock); - - if (fd < 0) { - fd = _sde_fence_create_fd(ctx, trigger_value); - *val = fd; - SDE_DEBUG("fd:%d trigger:%d commit:%d offset:%d\n", - fd, trigger_value, ctx->commit_count, offset); - } + fd = _sde_fence_create_fd(ctx, trigger_value); + *val = fd; + SDE_DEBUG("fd:%d trigger:%d commit:%d offset:%d\n", + fd, trigger_value, ctx->commit_count, offset); SDE_EVT32(ctx->drm_id, trigger_value, fd); rc = (fd >= 0) ? 0 : fd; diff --git a/msm/sde/sde_plane.c b/msm/sde/sde_plane.c index d60a3ff700..793c1160c6 100644 --- a/msm/sde/sde_plane.c +++ b/msm/sde/sde_plane.c @@ -765,8 +765,9 @@ int sde_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms) switch (rc) { case 0: - SDE_ERROR_PLANE(psde, "%ums timeout on %08X\n", - wait_ms, prefix); + SDE_ERROR_PLANE(psde, "%ums timeout on %08X fd %d\n", + wait_ms, prefix, sde_plane_get_property(pstate, + PLANE_PROP_INPUT_FENCE)); psde->is_error = true; sde_kms_timeline_status(plane->dev); ret = -ETIMEDOUT;