From: Rob Clark Date: Mon, 5 Mar 2012 16:48:33 +0000 (-0600) Subject: staging: drm/omap: call omap_gem_roll() in non-atomic ctx X-Git-Tag: v3.4~473^2~63 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9b55b95a8eca1a6bb2d7674e4af1fed003462677;p=platform%2Fkernel%2Flinux-amlogic.git staging: drm/omap: call omap_gem_roll() in non-atomic ctx If fbcon calls us from atomic context, push the work off to the workqueue to avoid calling into the gem/dmm code in an atomic context. Signed-off-by: Rob Clark Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/staging/omapdrm/omap_fbdev.c b/drivers/staging/omapdrm/omap_fbdev.c index 96940bb..11acd4c 100644 --- a/drivers/staging/omapdrm/omap_fbdev.c +++ b/drivers/staging/omapdrm/omap_fbdev.c @@ -37,6 +37,9 @@ struct omap_fbdev { struct drm_framebuffer *fb; struct drm_gem_object *bo; bool ywrap_enabled; + + /* for deferred dmm roll when getting called in atomic ctx */ + struct work_struct work; }; static void omap_fbdev_flush(struct fb_info *fbi, int x, int y, int w, int h); @@ -75,12 +78,22 @@ static void omap_fbdev_imageblit(struct fb_info *fbi, image->width, image->height); } +static void pan_worker(struct work_struct *work) +{ + struct omap_fbdev *fbdev = container_of(work, struct omap_fbdev, work); + struct fb_info *fbi = fbdev->base.fbdev; + int npages; + + /* DMM roll shifts in 4K pages: */ + npages = fbi->fix.line_length >> PAGE_SHIFT; + omap_gem_roll(fbdev->bo, fbi->var.yoffset * npages); +} + static int omap_fbdev_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi) { struct drm_fb_helper *helper = get_fb(fbi); struct omap_fbdev *fbdev = to_omap_fbdev(helper); - int npages; if (!helper) goto fallback; @@ -88,9 +101,12 @@ static int omap_fbdev_pan_display(struct fb_var_screeninfo *var, if (!fbdev->ywrap_enabled) goto fallback; - /* DMM roll shifts in 4K pages: */ - npages = fbi->fix.line_length >> PAGE_SHIFT; - omap_gem_roll(fbdev->bo, var->yoffset * npages); + if (drm_can_sleep()) { + pan_worker(&fbdev->work); + } else { + struct omap_drm_private *priv = helper->dev->dev_private; + queue_work(priv->wq, &fbdev->work); + } return 0; @@ -336,6 +352,8 @@ struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev) goto fail; } + INIT_WORK(&fbdev->work, pan_worker); + helper = &fbdev->base; helper->funcs = &omap_fb_helper_funcs; diff --git a/drivers/staging/omapdrm/omap_gem.c b/drivers/staging/omapdrm/omap_gem.c index b7d6f88..bd35520 100644 --- a/drivers/staging/omapdrm/omap_gem.c +++ b/drivers/staging/omapdrm/omap_gem.c @@ -566,6 +566,8 @@ fail: /* Set scrolling position. This allows us to implement fast scrolling * for console. + * + * Call only from non-atomic contexts. */ int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll) { @@ -580,18 +582,6 @@ int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll) omap_obj->roll = roll; - if (in_atomic() || mutex_is_locked(&obj->dev->struct_mutex)) { - /* this can get called from fbcon in atomic context.. so - * just ignore it and wait for next time called from - * interruptible context to update the PAT.. the result - * may be that user sees wrap-around instead of scrolling - * momentarily on the screen. If we wanted to be fancier - * we could perhaps schedule some workqueue work at this - * point. - */ - return 0; - } - mutex_lock(&obj->dev->struct_mutex); /* if we aren't mapped yet, we don't need to do anything */