drm/i915: Localise the fbdev console lock frobbing
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>
This commit is contained in:
Родитель
7312e2ddec
Коммит
82e3b8c130
|
@ -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. */
|
||||
|
@ -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
|
||||
|
|
|
@ -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++;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
@ -636,6 +637,15 @@ out:
|
|||
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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
|
Загрузка…
Ссылка в новой задаче