Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 82e3b8c1 authored by Chris Wilson's avatar Chris Wilson Committed by Daniel Vetter
Browse files

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: default avatarChris 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: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 7312e2dd
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -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
+2 −26
Original line number Diff line number Diff line
@@ -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;
+1 −8
Original line number Diff line number Diff line
@@ -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)
+2 −2
Original line number Diff line number Diff line
@@ -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)
{
}

+43 −1
Original line number Diff line number Diff line
@@ -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 @@ 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;
@@ -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)