Skip to content

Commit

Permalink
drm/i915: Localise the fbdev console lock frobbing
Browse files Browse the repository at this point in the history
Rather than take and release the console_lock() around a non-existent
DRM_I915_FBDEV, move the lock acquisation into the callee where it will
be compiled out by the config option entirely. This includes moving the
deferred fb_set_suspend() dance and encapsulating it entirely within
intel_fbdev.c.

v2: Use an integral work item so that we can explicitly flush the work
upon suspend/unload.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
[danvet: Add the flush_work in fbdev_fini per the mailing list
discussion. And s/BUG_ON/WARN_ON/ because.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
  • Loading branch information
Chris Wilson authored and Daniel Vetter committed Aug 13, 2014
1 parent 7312e2d commit 82e3b8c
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 40 deletions.
3 changes: 0 additions & 3 deletions drivers/gpu/drm/i915/i915_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -1350,8 +1350,6 @@ static int i915_load_modeset_init(struct drm_device *dev)
if (ret)
goto cleanup_irq;

INIT_WORK(&dev_priv->console_resume_work, intel_console_resume);

intel_modeset_gem_init(dev);

/* Always safe in the mode setting case. */
Expand Down Expand Up @@ -1864,7 +1862,6 @@ int i915_driver_unload(struct drm_device *dev)
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
intel_fbdev_fini(dev);
intel_modeset_cleanup(dev);
cancel_work_sync(&dev_priv->console_resume_work);

/*
* free the memory space allocated for the child device
Expand Down
28 changes: 2 additions & 26 deletions drivers/gpu/drm/i915/i915_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -558,9 +558,7 @@ static int i915_drm_freeze(struct drm_device *dev)
intel_uncore_forcewake_reset(dev, false);
intel_opregion_fini(dev);

console_lock();
intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED);
console_unlock();
intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED, true);

dev_priv->suspend_count++;

Expand Down Expand Up @@ -599,18 +597,6 @@ int i915_suspend(struct drm_device *dev, pm_message_t state)
return 0;
}

void intel_console_resume(struct work_struct *work)
{
struct drm_i915_private *dev_priv =
container_of(work, struct drm_i915_private,
console_resume_work);
struct drm_device *dev = dev_priv->dev;

console_lock();
intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING);
console_unlock();
}

static int i915_drm_thaw_early(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
Expand Down Expand Up @@ -681,17 +667,7 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)

intel_opregion_init(dev);

/*
* The console lock can be pretty contented on resume due
* to all the printk activity. Try to keep it out of the hot
* path of resume if possible.
*/
if (console_trylock()) {
intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING);
console_unlock();
} else {
schedule_work(&dev_priv->console_resume_work);
}
intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING, false);

mutex_lock(&dev_priv->modeset_restore_lock);
dev_priv->modeset_restore = MODESET_DONE;
Expand Down
9 changes: 1 addition & 8 deletions drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1586,14 +1586,9 @@ struct drm_i915_private {
#ifdef CONFIG_DRM_I915_FBDEV
/* list of fbdev register on this device */
struct intel_fbdev *fbdev;
struct work_struct fbdev_suspend_work;
#endif

/*
* The console may be contended at resume, but we don't
* want it to block on it.
*/
struct work_struct console_resume_work;

struct drm_property *broadcast_rgb_property;
struct drm_property *force_audio_property;

Expand Down Expand Up @@ -2225,8 +2220,6 @@ extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv);
extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool on);

extern void intel_console_resume(struct work_struct *work);

/* i915_irq.c */
void i915_queue_hangcheck(struct drm_device *dev);
__printf(3, 4)
Expand Down
4 changes: 2 additions & 2 deletions drivers/gpu/drm/i915/intel_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -948,7 +948,7 @@ void intel_dvo_init(struct drm_device *dev);
extern int intel_fbdev_init(struct drm_device *dev);
extern void intel_fbdev_initial_config(struct drm_device *dev);
extern void intel_fbdev_fini(struct drm_device *dev);
extern void intel_fbdev_set_suspend(struct drm_device *dev, int state);
extern void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous);
extern void intel_fbdev_output_poll_changed(struct drm_device *dev);
extern void intel_fbdev_restore_mode(struct drm_device *dev);
#else
Expand All @@ -965,7 +965,7 @@ static inline void intel_fbdev_fini(struct drm_device *dev)
{
}

static inline void intel_fbdev_set_suspend(struct drm_device *dev, int state)
static inline void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous)
{
}

Expand Down
44 changes: 43 additions & 1 deletion drivers/gpu/drm/i915/intel_fbdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/console.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
Expand Down Expand Up @@ -636,6 +637,15 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
return false;
}

static void intel_fbdev_suspend_worker(struct work_struct *work)
{
intel_fbdev_set_suspend(container_of(work,
struct drm_i915_private,
fbdev_suspend_work)->dev,
FBINFO_STATE_RUNNING,
true);
}

int intel_fbdev_init(struct drm_device *dev)
{
struct intel_fbdev *ifbdev;
Expand All @@ -662,6 +672,8 @@ int intel_fbdev_init(struct drm_device *dev)
}

dev_priv->fbdev = ifbdev;
INIT_WORK(&dev_priv->fbdev_suspend_work, intel_fbdev_suspend_worker);

drm_fb_helper_single_add_all_connectors(&ifbdev->helper);

return 0;
Expand All @@ -682,12 +694,14 @@ void intel_fbdev_fini(struct drm_device *dev)
if (!dev_priv->fbdev)
return;

flush_work(&dev_priv->fbdev_suspend_work);

intel_fbdev_destroy(dev, dev_priv->fbdev);
kfree(dev_priv->fbdev);
dev_priv->fbdev = NULL;
}

void intel_fbdev_set_suspend(struct drm_device *dev, int state)
void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_fbdev *ifbdev = dev_priv->fbdev;
Expand All @@ -698,6 +712,33 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state)

info = ifbdev->helper.fbdev;

if (synchronous) {
/* Flush any pending work to turn the console on, and then
* wait to turn it off. It must be synchronous as we are
* about to suspend or unload the driver.
*
* Note that from within the work-handler, we cannot flush
* ourselves, so only flush outstanding work upon suspend!
*/
if (state != FBINFO_STATE_RUNNING)
flush_work(&dev_priv->fbdev_suspend_work);
console_lock();
} else {
/*
* The console lock can be pretty contented on resume due
* to all the printk activity. Try to keep it out of the hot
* path of resume if possible.
*/
WARN_ON(state != FBINFO_STATE_RUNNING);
if (!console_trylock()) {
/* Don't block our own workqueue as this can
* be run in parallel with other i915.ko tasks.
*/
schedule_work(&dev_priv->fbdev_suspend_work);
return;
}
}

/* On resume from hibernation: If the object is shmemfs backed, it has
* been restored from swap. If the object is stolen however, it will be
* full of whatever garbage was left in there.
Expand All @@ -706,6 +747,7 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state)
memset_io(info->screen_base, 0, info->screen_size);

fb_set_suspend(info, state);
console_unlock();
}

void intel_fbdev_output_poll_changed(struct drm_device *dev)
Expand Down

0 comments on commit 82e3b8c

Please sign in to comment.