aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ti.com>2015-02-26 08:20:24 -0500
committerTomi Valkeinen <tomi.valkeinen@ti.com>2015-03-24 07:50:57 -0400
commita36af73f5e825c4c5ae5b11580c24fa7841bd5e2 (patch)
tree2d111dd92f3d22bfbe944fc763d505c9160ed26b
parent3b143fc80c077be54f8f7859d00f2db79250c884 (diff)
drm/omap: fix race with error_irq
omapdrm tries to avoid error floods by unregistering the error irq when an error happens, and then registering the error irq again later. However, the code is racy, as it sometimes tries to unregister the error irq when it's already unregistered, leading to WARN(). Also, the code only registers the error irq again when something is done on that particular output, i.e. if only TV is used to flip the buffers, and LCD is showing a same buffer, an error on LCD will cause the LCD error irq to be unregistered and never registered again. To fix this, let's keep the error irqs always enabled and trust the DRM_ERROR_RATELIMITED to limit the flood. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
-rw-r--r--drivers/gpu/drm/omapdrm/omap_crtc.c21
1 files changed, 13 insertions, 8 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index e91687fe41be..c5c21776131a 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -72,6 +72,8 @@ struct omap_crtc {
72 * XXX maybe fold into apply_work?? 72 * XXX maybe fold into apply_work??
73 */ 73 */
74 struct work_struct page_flip_work; 74 struct work_struct page_flip_work;
75
76 bool ignore_digit_sync_lost;
75}; 77};
76 78
77/* ----------------------------------------------------------------------------- 79/* -----------------------------------------------------------------------------
@@ -157,7 +159,7 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
157 * Digit output produces some sync lost interrupts during the first 159 * Digit output produces some sync lost interrupts during the first
158 * frame when enabling, so we need to ignore those. 160 * frame when enabling, so we need to ignore those.
159 */ 161 */
160 omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); 162 omap_crtc->ignore_digit_sync_lost = true;
161 163
162 framedone_irq = dispc_mgr_get_framedone_irq(channel); 164 framedone_irq = dispc_mgr_get_framedone_irq(channel);
163 vsync_irq = dispc_mgr_get_vsync_irq(channel); 165 vsync_irq = dispc_mgr_get_vsync_irq(channel);
@@ -188,7 +190,9 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
188 omap_crtc->name, enable ? "enable" : "disable"); 190 omap_crtc->name, enable ? "enable" : "disable");
189 } 191 }
190 192
191 omap_irq_register(crtc->dev, &omap_crtc->error_irq); 193 omap_crtc->ignore_digit_sync_lost = false;
194 /* make sure the irq handler sees the value above */
195 mb();
192} 196}
193 197
194 198
@@ -260,10 +264,14 @@ static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
260{ 264{
261 struct omap_crtc *omap_crtc = 265 struct omap_crtc *omap_crtc =
262 container_of(irq, struct omap_crtc, error_irq); 266 container_of(irq, struct omap_crtc, error_irq);
263 struct drm_crtc *crtc = &omap_crtc->base; 267
268 if (omap_crtc->ignore_digit_sync_lost) {
269 irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
270 if (!irqstatus)
271 return;
272 }
273
264 DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus); 274 DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus);
265 /* avoid getting in a flood, unregister the irq until next vblank */
266 __omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
267} 275}
268 276
269static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus) 277static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
@@ -272,9 +280,6 @@ static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
272 container_of(irq, struct omap_crtc, apply_irq); 280 container_of(irq, struct omap_crtc, apply_irq);
273 struct drm_crtc *crtc = &omap_crtc->base; 281 struct drm_crtc *crtc = &omap_crtc->base;
274 282
275 if (!omap_crtc->error_irq.registered)
276 __omap_irq_register(crtc->dev, &omap_crtc->error_irq);
277
278 if (!dispc_mgr_go_busy(omap_crtc->channel)) { 283 if (!dispc_mgr_go_busy(omap_crtc->channel)) {
279 struct omap_drm_private *priv = 284 struct omap_drm_private *priv =
280 crtc->dev->dev_private; 285 crtc->dev->dev_private;