]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - rpmsg/hwspinlock.git/commitdiff
drm/omap: fix race issue when unloading omapdrm
authorTomi Valkeinen <tomi.valkeinen@ti.com>
Wed, 2 Apr 2014 11:31:57 +0000 (14:31 +0300)
committerDan Murphy <DMurphy@ti.com>
Sat, 7 Jun 2014 20:53:59 +0000 (15:53 -0500)
[ Upstream commit e2f8fd74ec1bf15cb2abc1b11f7d9fa09581024e ]

At module unload, omap_fbdev_free() gets called which releases the
framebuffers. However, the framebuffers are still used by crtcs, and
will be released only later at vsync. The driver doesn't wait for this,
and goes on to release the rest of the resources, which often
causes a crash.

This patchs adds a omap_crtc_flush() function which waits until the crtc
has finished with its apply queue and page flips.

The function utilizes a simple polling while-loop, as the performance is
not an issue here.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Reviewed-by: Rob Clark <robdclark@gmail.com>
Signed-off-by: Dan Murphy <DMurphy@ti.com>
drivers/gpu/drm/omapdrm/omap_crtc.c
drivers/gpu/drm/omapdrm/omap_drv.c
drivers/gpu/drm/omapdrm/omap_drv.h

index e7b643c178a6c45e1aab8f8a73c3e71c50cee797..4f624c59a660ae1afe95660d15c99ca5cca889ed 100644 (file)
@@ -620,6 +620,25 @@ static void omap_crtc_post_apply(struct omap_drm_apply *apply)
        /* nothing needed for post-apply */
 }
 
+void omap_crtc_flush(struct drm_crtc *crtc)
+{
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       int loops = 0;
+
+       while (!list_empty(&omap_crtc->pending_applies) ||
+               !list_empty(&omap_crtc->queued_applies) ||
+               omap_crtc->event || omap_crtc->old_fb) {
+
+               if (++loops > 10) {
+                       dev_err(crtc->dev->dev,
+                               "omap_crtc_flush() timeout\n");
+                       break;
+               }
+
+               schedule_timeout_uninterruptible(msecs_to_jiffies(20));
+       }
+}
+
 static const char *channel_names[] = {
                [OMAP_DSS_CHANNEL_LCD] = "lcd",
                [OMAP_DSS_CHANNEL_DIGIT] = "tv",
index df3e66416a305959121d35177027a83c440903c8..21b3c62b361cee06e5db8e02b4a8e2983d4236d8 100644 (file)
@@ -513,12 +513,18 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
 static int dev_unload(struct drm_device *dev)
 {
        struct omap_drm_private *priv = dev->dev_private;
+       int i;
 
        DBG("unload: dev=%p", dev);
 
        drm_kms_helper_poll_fini(dev);
 
        omap_fbdev_free(dev);
+
+       /* flush crtcs so the fbs get released */
+       for (i = 0; i < priv->num_crtcs; i++)
+               omap_crtc_flush(priv->crtcs[i]);
+
        omap_modeset_free(dev);
        omap_gem_deinit(dev);
 
index 428b2981fd685f3e42b3ec4d0a63021a94fdaf15..284b80fc3c54fc4146294656c722fb7af2485b03 100644 (file)
@@ -163,6 +163,7 @@ void omap_crtc_pre_init(void);
 void omap_crtc_pre_uninit(void);
 struct drm_crtc *omap_crtc_init(struct drm_device *dev,
                struct drm_plane *plane, enum omap_channel channel, int id);
+void omap_crtc_flush(struct drm_crtc *crtc);
 
 struct drm_plane *omap_plane_init(struct drm_device *dev,
                int plane_id, bool private_plane);