Keep track of fbdev users and only restore fbdev in drm_fb_helper_restore_fbdev_mode_unlocked() when in use. This avoids fbdev being restored in drm_driver.last_close when nothing uses it. Additionally fbdev is turned off when the last user is closing. fbcon is a user in this context.
Signed-off-by: Noralf Trønnes <nor...@tronnes.org> --- drivers/gpu/drm/drm_fb_helper.c | 15 +++++++++++++++ include/drm/drm_fb_helper.h | 14 ++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 2c6adf1d80c2..f9dcc7a5761f 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -522,6 +522,9 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper) if (READ_ONCE(fb_helper->deferred_setup)) return 0; + if (!atomic_read(&fb_helper->open_count)) + return 0; + mutex_lock(&fb_helper->lock); ret = restore_fbdev_mode(fb_helper); @@ -781,6 +784,7 @@ void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper, INIT_WORK(&helper->resume_work, drm_fb_helper_resume_worker); INIT_WORK(&helper->dirty_work, drm_fb_helper_dirty_work); helper->dirty_clip.x1 = helper->dirty_clip.y1 = ~0; + atomic_set(&helper->open_count, 1); mutex_init(&helper->lock); helper->funcs = funcs; helper->dev = dev; @@ -1212,6 +1216,7 @@ EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit); * @info: fbdev registered by the helper * @user: 1=userspace, 0=fbcon * + * Increase fbdev use count. * If &fb_ops is wrapped in a library, pin the driver module. */ int drm_fb_helper_fb_open(struct fb_info *info, int user) @@ -1224,6 +1229,8 @@ int drm_fb_helper_fb_open(struct fb_info *info, int user) return -ENODEV; } + atomic_inc(&fb_helper->open_count); + return 0; } EXPORT_SYMBOL(drm_fb_helper_fb_open); @@ -1233,6 +1240,7 @@ EXPORT_SYMBOL(drm_fb_helper_fb_open); * @info: fbdev registered by the helper * @user: 1=userspace, 0=fbcon * + * Decrease fbdev use count and turn off if there are no users left. * If &fb_ops is wrapped in a library, unpin the driver module. */ int drm_fb_helper_fb_release(struct fb_info *info, int user) @@ -1240,6 +1248,10 @@ int drm_fb_helper_fb_release(struct fb_info *info, int user) struct drm_fb_helper *fb_helper = info->par; struct drm_device *dev = fb_helper->dev; + if (atomic_dec_and_test(&fb_helper->open_count) && + !drm_dev_is_unplugged(fb_helper->dev)) + drm_fb_helper_blank(FB_BLANK_POWERDOWN, info); + if (info->fbops->owner != dev->driver->fops->owner) module_put(dev->driver->fops->owner); @@ -1936,6 +1948,9 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, if (ret < 0) return ret; + if (fb_helper->fbdev->fbops->fb_open == drm_fb_helper_fb_open) + atomic_set(&fb_helper->open_count, 0); + strcpy(fb_helper->fb->comm, "[fbcon]"); return 0; } diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index a593f01ff69e..16d8773b60e3 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -232,6 +232,20 @@ struct drm_fb_helper { * See also: @deferred_setup */ int preferred_bpp; + + /** + * @open_count: + * + * Keeps track of fbdev use to know when to not restore fbdev. + * + * Drivers that use drm_fb_helper_fb_open() as their \.fb_open + * callback will get an initial value of 0 and get restore based on + * actual use. Others will get an initial value of 1 which means that + * fbdev will always be restored. Drivers that call + * drm_fb_helper_fb_open() in their \.fb_open, thus needs to set the + * initial value to 0 themselves. + */ + atomic_t open_count; }; /** -- 2.14.2 _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx