i915: fix intel graphics suspend breakage due to resume/lid event confusion
In commitc1c7af6089
("drm/i915: force mode set at lid open time") the intel graphics driver was taught to restore the LVDS mode on lid open. That caused problems with interaction with the suspend/resume code, which commonly runs at the same time (suspend is often caused by the lid close event, while lid open is commonly a resume event), which was worked around with in commit06891e27a9
("drm/i915: fix suspend/resume breakage in lid notifier"). However, in the meantime the lid event code had also grown a user event notifier (commit06324194ee
: "drm/i915: generate a KMS uevent at lid open/close time"), and now _that_ causes problems with suspend/resume and some versions of Xorg reacting to those uevents by setting the mode. So this effectively reverts that commit06324194ee
, and makes the lid open protection logic against suspend/resume more explicit. This fixes at least one laptop. See http://bugzilla.kernel.org/show_bug.cgi?id=14484 for more details. Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org> Cc: Riccardo Magliocchetti <riccardo.magliocchetti@gmail.com> Cc: Eric Anholt <eric@anholt.net> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
b6727b12dd
commit
c9354c85c1
3 changed files with 24 additions and 8 deletions
|
@ -89,7 +89,8 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
|
|||
pci_set_power_state(dev->pdev, PCI_D3hot);
|
||||
}
|
||||
|
||||
dev_priv->suspended = 1;
|
||||
/* Modeset on resume, not lid events */
|
||||
dev_priv->modeset_on_lid = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -124,7 +125,7 @@ static int i915_resume(struct drm_device *dev)
|
|||
drm_helper_resume_force_mode(dev);
|
||||
}
|
||||
|
||||
dev_priv->suspended = 0;
|
||||
dev_priv->modeset_on_lid = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -274,7 +274,7 @@ typedef struct drm_i915_private {
|
|||
struct drm_i915_display_funcs display;
|
||||
|
||||
/* Register state */
|
||||
bool suspended;
|
||||
bool modeset_on_lid;
|
||||
u8 saveLBB;
|
||||
u32 saveDSPACNTR;
|
||||
u32 saveDSPBCNTR;
|
||||
|
|
|
@ -656,6 +656,15 @@ static int intel_lvds_get_modes(struct drm_connector *connector)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lid events. Note the use of 'modeset_on_lid':
|
||||
* - we set it on lid close, and reset it on open
|
||||
* - we use it as a "only once" bit (ie we ignore
|
||||
* duplicate events where it was already properly
|
||||
* set/reset)
|
||||
* - the suspend/resume paths will also set it to
|
||||
* zero, since they restore the mode ("lid open").
|
||||
*/
|
||||
static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
|
||||
void *unused)
|
||||
{
|
||||
|
@ -663,13 +672,19 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
|
|||
container_of(nb, struct drm_i915_private, lid_notifier);
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
|
||||
if (acpi_lid_open() && !dev_priv->suspended) {
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_helper_resume_force_mode(dev);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
if (!acpi_lid_open()) {
|
||||
dev_priv->modeset_on_lid = 1;
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
drm_sysfs_hotplug_event(dev_priv->dev);
|
||||
if (!dev_priv->modeset_on_lid)
|
||||
return NOTIFY_OK;
|
||||
|
||||
dev_priv->modeset_on_lid = 0;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
drm_helper_resume_force_mode(dev);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue