Message ID | 20180103222110.45855-6-noralf@tronnes.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Wed, Jan 03, 2018 at 11:21:07PM +0100, Noralf Trønnes wrote: > 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 <noralf@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; Do we really need an atomic_t here? Especially the "disable stuff on last fb_close" would still be race without more locking, and from a quick look at the fbdev core code we're protected with fb_info->lock. I think an unsigned is perfectly fine here. And if we really need atomics, then refcount_t (for the safety checks that provides). With that changed: Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> But before we merge this we definitely need to roll out fb_open/close to all drivers. But I guess that's why the RFC in your series. On that: There's some intersting runtime pm stuff for nouveau/amd/radeon. I guess we'll need to keep that. Plus udl has some defio fun :-/ -Daniel > }; > > /** > -- > 2.14.2 >
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; }; /**
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 <noralf@tronnes.org> --- drivers/gpu/drm/drm_fb_helper.c | 15 +++++++++++++++ include/drm/drm_fb_helper.h | 14 ++++++++++++++ 2 files changed, 29 insertions(+)