Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 99771a53 authored by Prabhanjan Kandula's avatar Prabhanjan Kandula Committed by Gerrit - the friendly Code Review server
Browse files

drm/msm/sde: propagate frame error through fence



DMA fence driver supports error status indication to
fence reader. Populate the frame status for sde fences
so that client can consume or discard the buffer.

Change-Id: I9b10f4ff3c97aa2c018a5f0b7f40089590aac3ae
Signed-off-by: default avatarPrabhanjan Kandula <pkandula@codeaurora.org>
parent 9956996a
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -1219,7 +1219,7 @@ void sde_connector_prepare_fence(struct drm_connector *connector)
}

void sde_connector_complete_commit(struct drm_connector *connector,
		ktime_t ts)
		ktime_t ts, enum sde_fence_event fence_event)
{
	if (!connector) {
		SDE_ERROR("invalid connector\n");
@@ -1227,7 +1227,8 @@ void sde_connector_complete_commit(struct drm_connector *connector,
	}

	/* signal connector's retire fence */
	sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, false);
	sde_fence_signal(&to_sde_connector(connector)->retire_fence,
			ts, fence_event);
}

void sde_connector_commit_reset(struct drm_connector *connector, ktime_t ts)
@@ -1238,7 +1239,8 @@ void sde_connector_commit_reset(struct drm_connector *connector, ktime_t ts)
	}

	/* signal connector's retire fence */
	sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, true);
	sde_fence_signal(&to_sde_connector(connector)->retire_fence,
			ts, SDE_FENCE_RESET_TIMELINE);
}

static void sde_connector_update_hdr_props(struct drm_connector *connector)
+3 −1
Original line number Diff line number Diff line
@@ -632,8 +632,10 @@ void sde_connector_prepare_fence(struct drm_connector *connector);
 * sde_connector_complete_commit - signal completion of current commit
 * @connector: Pointer to drm connector object
 * @ts: timestamp to be updated in the fence signalling
 * @fence_event: enum value to indicate nature of fence event
 */
void sde_connector_complete_commit(struct drm_connector *connector, ktime_t ts);
void sde_connector_complete_commit(struct drm_connector *connector,
		ktime_t ts, enum sde_fence_event fence_event);

/**
 * sde_connector_commit_reset - reset the completion signal
+12 −6
Original line number Diff line number Diff line
@@ -2258,7 +2258,8 @@ static void sde_crtc_vblank_cb(void *data)
	SDE_EVT32_VERBOSE(DRMID(crtc));
}

static void _sde_crtc_retire_event(struct drm_crtc *crtc, ktime_t ts)
static void _sde_crtc_retire_event(struct drm_crtc *crtc, ktime_t ts,
		bool is_error)
{
	struct sde_crtc_retire_event *retire_event;
	struct sde_crtc *sde_crtc;
@@ -2288,8 +2289,8 @@ static void _sde_crtc_retire_event(struct drm_crtc *crtc, ktime_t ts)
	SDE_ATRACE_BEGIN("signal_retire_fence");
	for (i = 0; (i < retire_event->num_connectors) &&
					retire_event->connectors[i]; ++i)
		sde_connector_complete_commit(
					retire_event->connectors[i], ts);
		sde_connector_complete_commit(retire_event->connectors[i],
					ts, is_error);
	SDE_ATRACE_END("signal_retire_fence");
}

@@ -2357,13 +2358,17 @@ static void sde_crtc_frame_event_work(struct kthread_work *work)

	if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE) {
		SDE_ATRACE_BEGIN("signal_release_fence");
		sde_fence_signal(&sde_crtc->output_fence, fevent->ts, false);
		sde_fence_signal(&sde_crtc->output_fence, fevent->ts,
				(fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR)
				? SDE_FENCE_SIGNAL_ERROR : SDE_FENCE_SIGNAL);
		SDE_ATRACE_END("signal_release_fence");
	}

	if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE)
		/* this api should be called without spin_lock */
		_sde_crtc_retire_event(crtc, fevent->ts);
		_sde_crtc_retire_event(crtc, fevent->ts,
				(fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR)
				? SDE_FENCE_SIGNAL_ERROR : SDE_FENCE_SIGNAL);

	if (fevent->event & SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)
		SDE_ERROR("crtc%d ts:%lld received panel dead event\n",
@@ -4198,7 +4203,8 @@ static void sde_crtc_disable(struct drm_crtc *crtc)
	 * reset the fence timeline if crtc will not be enabled for this commit
	 */
	if (!crtc->state->active || !crtc->state->enable) {
		sde_fence_signal(&sde_crtc->output_fence, ktime_get(), true);
		sde_fence_signal(&sde_crtc->output_fence,
				ktime_get(), SDE_FENCE_RESET_TIMELINE);
		for (i = 0; i < cstate->num_connectors; ++i)
			sde_connector_commit_reset(cstate->connectors[i],
					ktime_get());
+9 −7
Original line number Diff line number Diff line
@@ -279,7 +279,8 @@ void sde_fence_prepare(struct sde_fence_context *ctx)
	}
}

static void _sde_fence_trigger(struct sde_fence_context *ctx, ktime_t ts)
static void _sde_fence_trigger(struct sde_fence_context *ctx,
		ktime_t ts, bool error)
{
	unsigned long flags;
	struct sde_fence *fc, *next;
@@ -301,6 +302,7 @@ static void _sde_fence_trigger(struct sde_fence_context *ctx, ktime_t ts)

	list_for_each_entry_safe(fc, next, &local_list_head, fence_list) {
		spin_lock_irqsave(&ctx->lock, flags);
		fc->base.error = error ? -EBUSY : 0;
		fc->base.timestamp = ts;
		is_signaled = dma_fence_is_signaled_locked(&fc->base);
		spin_unlock_irqrestore(&ctx->lock, flags);
@@ -352,7 +354,7 @@ int sde_fence_create(struct sde_fence_context *ctx, uint64_t *val,

	if (fd >= 0) {
		rc = 0;
		_sde_fence_trigger(ctx, ktime_get());
		_sde_fence_trigger(ctx, ktime_get(), false);
	} else {
		rc = fd;
	}
@@ -361,7 +363,7 @@ int sde_fence_create(struct sde_fence_context *ctx, uint64_t *val,
}

void sde_fence_signal(struct sde_fence_context *ctx, ktime_t ts,
							bool reset_timeline)
		enum sde_fence_event fence_event)
{
	unsigned long flags;

@@ -371,7 +373,7 @@ void sde_fence_signal(struct sde_fence_context *ctx, ktime_t ts,
	}

	spin_lock_irqsave(&ctx->lock, flags);
	if (reset_timeline) {
	if (fence_event == SDE_FENCE_RESET_TIMELINE) {
		if ((int)(ctx->done_count - ctx->commit_count) < 0) {
			SDE_ERROR(
				"timeline reset attempt! done count:%d commit:%d\n",
@@ -379,7 +381,7 @@ void sde_fence_signal(struct sde_fence_context *ctx, ktime_t ts,
			ctx->done_count = ctx->commit_count;
			SDE_EVT32(ctx->drm_id, ctx->done_count,
				ctx->commit_count, ktime_to_us(ts),
				reset_timeline, SDE_EVTLOG_FATAL);
				fence_event, SDE_EVTLOG_FATAL);
		} else {
			spin_unlock_irqrestore(&ctx->lock, flags);
			return;
@@ -392,7 +394,7 @@ void sde_fence_signal(struct sde_fence_context *ctx, ktime_t ts,
		SDE_ERROR("extra signal attempt! done count:%d commit:%d\n",
					ctx->done_count, ctx->commit_count);
		SDE_EVT32(ctx->drm_id, ctx->done_count, ctx->commit_count,
			ktime_to_us(ts), reset_timeline, SDE_EVTLOG_FATAL);
			ktime_to_us(ts), fence_event, SDE_EVTLOG_FATAL);
		spin_unlock_irqrestore(&ctx->lock, flags);
		return;
	}
@@ -401,7 +403,7 @@ void sde_fence_signal(struct sde_fence_context *ctx, ktime_t ts,
	SDE_EVT32(ctx->drm_id, ctx->done_count, ctx->commit_count,
			ktime_to_us(ts));

	_sde_fence_trigger(ctx, ts);
	_sde_fence_trigger(ctx, ts, (fence_event == SDE_FENCE_SIGNAL_ERROR));
}

void sde_fence_timeline_status(struct sde_fence_context *ctx,
+15 −3
Original line number Diff line number Diff line
/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -47,6 +47,18 @@ struct sde_fence_context {
	char name[SDE_FENCE_NAME_SIZE];
};

/**
 * enum sde_fence_event - sde fence event as hint fence operation
 * @SDE_FENCE_SIGNAL: Signal the fence cleanly with current timeline
 * @SDE_FENCE_RESET_TIMELINE: Reset timeline of the fence context
 * @SDE_FENCE_SIGNAL: Signal the fence but indicate error throughfence status
 */
enum sde_fence_event {
	SDE_FENCE_SIGNAL,
	SDE_FENCE_RESET_TIMELINE,
	SDE_FENCE_SIGNAL_ERROR
};

#if IS_ENABLED(CONFIG_SYNC_FILE)
/**
 * sde_sync_get - Query sync fence object from a file handle
@@ -128,10 +140,10 @@ int sde_fence_create(struct sde_fence_context *fence, uint64_t *val,
 * sde_fence_signal - advance fence timeline to signal outstanding fences
 * @fence: Pointer fence container
 * @ts: fence timestamp
 * @reset_timeline: reset the fence timeline to done count equal to commit count
 * @fence_event: fence event to indicate nature of fence signal.
 */
void sde_fence_signal(struct sde_fence_context *fence, ktime_t ts,
		bool reset_timeline);
		enum sde_fence_event fence_event);

/**
 * sde_fence_timeline_status - prints fence timeline status