stable.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Andrzej Hajda <a.hajda@samsung.com>,
	Inki Dae <inki.dae@samsung.com>, Sasha Levin <sashal@kernel.org>,
	dri-devel@lists.freedesktop.org
Subject: [PATCH AUTOSEL 4.19 41/52] drm/exynos/mixer: fix MIXER shadow registry synchronisation code
Date: Fri, 29 Mar 2019 20:52:48 -0400	[thread overview]
Message-ID: <20190330005301.26868-41-sashal@kernel.org> (raw)
In-Reply-To: <20190330005301.26868-1-sashal@kernel.org>

From: Andrzej Hajda <a.hajda@samsung.com>

[ Upstream commit 6a3b45ada960ac475ec2b4103d43e57943b2b8d3 ]

MIXER on Exynos5 SoCs uses different synchronisation method than Exynos4
to update internal state (shadow registers).
Apparently the driver implements it incorrectly. The rule should be
as follows:
- do not request updating registers until previous request was finished,
  ie. MXR_CFG_LAYER_UPDATE_COUNT must be 0.
- before setting registers synchronisation on VSYNC should be turned off,
  ie. MXR_STATUS_SYNC_ENABLE should be reset,
- after finishing MXR_STATUS_SYNC_ENABLE should be set again.
The patch hopefully implements it correctly.
Below sample kernel log from page fault caused by the bug:

[   25.670038] exynos-sysmmu 14650000.sysmmu: 14450000.mixer: PAGE FAULT occurred at 0x2247b800
[   25.677888] ------------[ cut here ]------------
[   25.682164] kernel BUG at ../drivers/iommu/exynos-iommu.c:450!
[   25.687971] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM
[   25.693778] Modules linked in:
[   25.696816] CPU: 5 PID: 1553 Comm: fb-release_test Not tainted 5.0.0-rc7-01157-g5f86b1566bdd #136
[   25.705646] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree)
[   25.711710] PC is at exynos_sysmmu_irq+0x1c0/0x264
[   25.716470] LR is at lock_is_held_type+0x44/0x64

v2: added missing MXR_CFG_LAYER_UPDATE bit setting in mixer_enable_sync

Reported-by: Marian Mihailescu <mihailescu2m@gmail.com>
Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 drivers/gpu/drm/exynos/exynos_mixer.c | 110 +++++++++++++++-----------
 1 file changed, 66 insertions(+), 44 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index ffbf4a950f69..522d6c46d7b1 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -20,6 +20,7 @@
 #include "regs-vp.h"
 
 #include <linux/kernel.h>
+#include <linux/ktime.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
 #include <linux/i2c.h>
@@ -337,15 +338,62 @@ static void mixer_cfg_vp_blend(struct mixer_context *ctx)
 	mixer_reg_write(ctx, MXR_VIDEO_CFG, val);
 }
 
-static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
+static bool mixer_is_synced(struct mixer_context *ctx)
 {
-	/* block update on vsync */
-	mixer_reg_writemask(ctx, MXR_STATUS, enable ?
-			MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
+	u32 base, shadow;
 
+	if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
+	    ctx->mxr_ver == MXR_VER_128_0_0_184)
+		return !(mixer_reg_read(ctx, MXR_CFG) &
+			 MXR_CFG_LAYER_UPDATE_COUNT_MASK);
+
+	if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags) &&
+	    vp_reg_read(ctx, VP_SHADOW_UPDATE))
+		return false;
+
+	base = mixer_reg_read(ctx, MXR_CFG);
+	shadow = mixer_reg_read(ctx, MXR_CFG_S);
+	if (base != shadow)
+		return false;
+
+	base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(0));
+	shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(0));
+	if (base != shadow)
+		return false;
+
+	base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(1));
+	shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(1));
+	if (base != shadow)
+		return false;
+
+	return true;
+}
+
+static int mixer_wait_for_sync(struct mixer_context *ctx)
+{
+	ktime_t timeout = ktime_add_us(ktime_get(), 100000);
+
+	while (!mixer_is_synced(ctx)) {
+		usleep_range(1000, 2000);
+		if (ktime_compare(ktime_get(), timeout) > 0)
+			return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+static void mixer_disable_sync(struct mixer_context *ctx)
+{
+	mixer_reg_writemask(ctx, MXR_STATUS, 0, MXR_STATUS_SYNC_ENABLE);
+}
+
+static void mixer_enable_sync(struct mixer_context *ctx)
+{
+	if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
+	    ctx->mxr_ver == MXR_VER_128_0_0_184)
+		mixer_reg_writemask(ctx, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
+	mixer_reg_writemask(ctx, MXR_STATUS, ~0, MXR_STATUS_SYNC_ENABLE);
 	if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags))
-		vp_reg_write(ctx, VP_SHADOW_UPDATE, enable ?
-			VP_SHADOW_UPDATE_ENABLE : 0);
+		vp_reg_write(ctx, VP_SHADOW_UPDATE, VP_SHADOW_UPDATE_ENABLE);
 }
 
 static void mixer_cfg_scan(struct mixer_context *ctx, int width, int height)
@@ -482,7 +530,6 @@ static void vp_video_buffer(struct mixer_context *ctx,
 
 	spin_lock_irqsave(&ctx->reg_slock, flags);
 
-	vp_reg_write(ctx, VP_SHADOW_UPDATE, 1);
 	/* interlace or progressive scan mode */
 	val = (test_bit(MXR_BIT_INTERLACE, &ctx->flags) ? ~0 : 0);
 	vp_reg_writemask(ctx, VP_MODE, val, VP_MODE_LINE_SKIP);
@@ -537,11 +584,6 @@ static void vp_video_buffer(struct mixer_context *ctx,
 	vp_regs_dump(ctx);
 }
 
-static void mixer_layer_update(struct mixer_context *ctx)
-{
-	mixer_reg_writemask(ctx, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
-}
-
 static void mixer_graph_buffer(struct mixer_context *ctx,
 			       struct exynos_drm_plane *plane)
 {
@@ -618,11 +660,6 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
 	mixer_cfg_layer(ctx, win, priority, true);
 	mixer_cfg_gfx_blend(ctx, win, fb->format->has_alpha);
 
-	/* layer update mandatory for mixer 16.0.33.0 */
-	if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
-		ctx->mxr_ver == MXR_VER_128_0_0_184)
-		mixer_layer_update(ctx);
-
 	spin_unlock_irqrestore(&ctx->reg_slock, flags);
 
 	mixer_regs_dump(ctx);
@@ -687,7 +724,7 @@ static void mixer_win_reset(struct mixer_context *ctx)
 static irqreturn_t mixer_irq_handler(int irq, void *arg)
 {
 	struct mixer_context *ctx = arg;
-	u32 val, base, shadow;
+	u32 val;
 
 	spin_lock(&ctx->reg_slock);
 
@@ -701,26 +738,9 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
 		val &= ~MXR_INT_STATUS_VSYNC;
 
 		/* interlace scan need to check shadow register */
-		if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) {
-			if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags) &&
-			    vp_reg_read(ctx, VP_SHADOW_UPDATE))
-				goto out;
-
-			base = mixer_reg_read(ctx, MXR_CFG);
-			shadow = mixer_reg_read(ctx, MXR_CFG_S);
-			if (base != shadow)
-				goto out;
-
-			base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(0));
-			shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(0));
-			if (base != shadow)
-				goto out;
-
-			base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(1));
-			shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(1));
-			if (base != shadow)
-				goto out;
-		}
+		if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)
+		    && !mixer_is_synced(ctx))
+			goto out;
 
 		drm_crtc_handle_vblank(&ctx->crtc->base);
 	}
@@ -895,12 +915,14 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
 
 static void mixer_atomic_begin(struct exynos_drm_crtc *crtc)
 {
-	struct mixer_context *mixer_ctx = crtc->ctx;
+	struct mixer_context *ctx = crtc->ctx;
 
-	if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
+	if (!test_bit(MXR_BIT_POWERED, &ctx->flags))
 		return;
 
-	mixer_vsync_set_update(mixer_ctx, false);
+	if (mixer_wait_for_sync(ctx))
+		dev_err(ctx->dev, "timeout waiting for VSYNC\n");
+	mixer_disable_sync(ctx);
 }
 
 static void mixer_update_plane(struct exynos_drm_crtc *crtc,
@@ -942,7 +964,7 @@ static void mixer_atomic_flush(struct exynos_drm_crtc *crtc)
 	if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags))
 		return;
 
-	mixer_vsync_set_update(mixer_ctx, true);
+	mixer_enable_sync(mixer_ctx);
 	exynos_crtc_handle_event(crtc);
 }
 
@@ -957,7 +979,7 @@ static void mixer_enable(struct exynos_drm_crtc *crtc)
 
 	exynos_drm_pipe_clk_enable(crtc, true);
 
-	mixer_vsync_set_update(ctx, false);
+	mixer_disable_sync(ctx);
 
 	mixer_reg_writemask(ctx, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
 
@@ -970,7 +992,7 @@ static void mixer_enable(struct exynos_drm_crtc *crtc)
 
 	mixer_commit(ctx);
 
-	mixer_vsync_set_update(ctx, true);
+	mixer_enable_sync(ctx);
 
 	set_bit(MXR_BIT_POWERED, &ctx->flags);
 }
-- 
2.19.1


  parent reply	other threads:[~2019-03-30  1:05 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-30  0:52 [PATCH AUTOSEL 4.19 01/52] ARC: u-boot args: check that magic number is correct Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 02/52] arc: hsdk_defconfig: Enable CONFIG_BLK_DEV_RAM Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 03/52] inotify: Fix fsnotify_mark refcount leak in inotify_update_existing_watch() Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 04/52] perf/core: Restore mmap record type correctly Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 05/52] perf data: Don't store auxtrace index for directory data file Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 06/52] ext4: avoid panic during forced reboot Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 07/52] ext4: add missing brelse() in add_new_gdb_meta_bg() Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 08/52] ext4: report real fs size after failed resize Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 09/52] ALSA: echoaudio: add a check for ioremap_nocache Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 10/52] ALSA: sb8: add a check for request_region Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 11/52] auxdisplay: hd44780: Fix memory leak on ->remove() Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 12/52] drm/udl: use drm_gem_object_put_unlocked Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 13/52] IB/mlx4: Fix race condition between catas error reset and aliasguid flows Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 14/52] i40iw: Avoid panic when handling the inetdev event Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 15/52] mmc: davinci: remove extraneous __init annotation Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 16/52] ALSA: opl3: fix mismatch between snd_opl3_drum_switch definition and declaration Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 17/52] thermal/intel_powerclamp: fix __percpu declaration of worker_data Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 18/52] thermal: samsung: Fix incorrect check after code merge Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 19/52] thermal: bcm2835: Fix crash in bcm2835_thermal_debugfs Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 20/52] thermal/int340x_thermal: Add additional UUIDs Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 21/52] thermal/int340x_thermal: fix mode setting Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 22/52] thermal/intel_powerclamp: fix truncated kthread name Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 23/52] scsi: iscsi: flush running unbind operations when removing a session Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 24/52] sched/cpufreq: Fix 32-bit math overflow Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 25/52] sched/core: Fix buffer overflow in cgroup2 property cpu.max Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 26/52] x86/mm: Don't leak kernel addresses Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 27/52] tools/power turbostat: return the exit status of a command Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 28/52] perf list: Don't forget to drop the reference to the allocated thread_map Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 29/52] perf config: Fix an error in the config template documentation Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 30/52] perf config: Fix a memory leak in collect_config() Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 31/52] perf build-id: Fix memory leak in print_sdt_events() Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 32/52] perf top: Fix error handling in cmd_top() Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 33/52] perf hist: Add missing map__put() in error case Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 34/52] perf evsel: Free evsel->counts in perf_evsel__exit() Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 35/52] perf tests: Fix a memory leak of cpu_map object in the openat_syscall_event_on_all_cpus test Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 36/52] perf tests: Fix memory leak by expr__find_other() in test__expr() Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 37/52] perf tests: Fix a memory leak in test__perf_evsel__tp_sched_test() Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 38/52] ACPI / utils: Drop reference in test for device presence Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 39/52] PM / Domains: Avoid a potential deadlock Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 40/52] blk-iolatency: #include "blk.h" Sasha Levin
2019-03-30  0:52 ` Sasha Levin [this message]
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 42/52] irqchip/stm32: Don't clear rising/falling config registers at init Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 43/52] irqchip/mbigen: Don't clear eventid when freeing an MSI Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 44/52] x86/hpet: Prevent potential NULL pointer dereference Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 45/52] x86/hyperv: " Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 46/52] x86/cpu/cyrix: Use correct macros for Cyrix calls on Geode processors Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 47/52] drm/nouveau/debugfs: Fix check of pm_runtime_get_sync failure Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 48/52] iommu/vt-d: Check capability before disabling protected memory Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 49/52] x86/hw_breakpoints: Make default case in hw_breakpoint_arch_parse() return an error Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 50/52] fix incorrect error code mapping for OBJECTID_NOT_FOUND Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 51/52] x86/gart: Exclude GART aperture from kcore Sasha Levin
2019-03-30  0:52 ` [PATCH AUTOSEL 4.19 52/52] ext4: prohibit fstrim in norecovery mode Sasha Levin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190330005301.26868-41-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=a.hajda@samsung.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=inki.dae@samsung.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).