Commit e2f8fd74 authored by Tomi Valkeinen's avatar Tomi Valkeinen

drm/omap: fix race issue when unloading omapdrm

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: default avatarTomi Valkeinen <tomi.valkeinen@ti.com>
Reviewed-by: default avatarRob Clark <robdclark@gmail.com>
parent ea7e3a66
...@@ -621,6 +621,25 @@ static void omap_crtc_post_apply(struct omap_drm_apply *apply) ...@@ -621,6 +621,25 @@ static void omap_crtc_post_apply(struct omap_drm_apply *apply)
/* nothing needed for post-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[] = { static const char *channel_names[] = {
[OMAP_DSS_CHANNEL_LCD] = "lcd", [OMAP_DSS_CHANNEL_LCD] = "lcd",
[OMAP_DSS_CHANNEL_DIGIT] = "tv", [OMAP_DSS_CHANNEL_DIGIT] = "tv",
......
...@@ -513,12 +513,18 @@ static int dev_load(struct drm_device *dev, unsigned long flags) ...@@ -513,12 +513,18 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
static int dev_unload(struct drm_device *dev) static int dev_unload(struct drm_device *dev)
{ {
struct omap_drm_private *priv = dev->dev_private; struct omap_drm_private *priv = dev->dev_private;
int i;
DBG("unload: dev=%p", dev); DBG("unload: dev=%p", dev);
drm_kms_helper_poll_fini(dev); drm_kms_helper_poll_fini(dev);
omap_fbdev_free(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_modeset_free(dev);
omap_gem_deinit(dev); omap_gem_deinit(dev);
......
...@@ -163,6 +163,7 @@ void omap_crtc_pre_init(void); ...@@ -163,6 +163,7 @@ void omap_crtc_pre_init(void);
void omap_crtc_pre_uninit(void); void omap_crtc_pre_uninit(void);
struct drm_crtc *omap_crtc_init(struct drm_device *dev, struct drm_crtc *omap_crtc_init(struct drm_device *dev,
struct drm_plane *plane, enum omap_channel channel, int id); 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, struct drm_plane *omap_plane_init(struct drm_device *dev,
int plane_id, bool private_plane); int plane_id, bool private_plane);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment