diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2010-02-18 17:06:27 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-02-22 11:47:14 -0500 |
commit | 61caf87cb5c2a198966018343a6ce4c5ab6cf8df (patch) | |
tree | 4fa1ab6a366627a8d3113b4be62f9c251307a00a | |
parent | 4386b58349366511df1c4fe1f7917c198f71529a (diff) |
i915 / PM: Fix hibernate regression caused by suspend/resume splitting
Commit 84b79f8d2882b0a84330c04839ed4d3cefd2ff77 (drm/i915: Fix crash
while aborting hibernation) attempted to fix a regression introduced
by commit cbda12d77ea590082edb6d30bd342a67ebc459e0 (drm/i915:
implement new pm ops for i915), but it went too far trying to split
the freeze/suspend and resume/thaw parts of the code. As a result,
it introduced another regression, which only is visible on some systems.
Fix the problem by merging i915_drm_suspend() with
i915_drm_freeze() and moving some code from i915_resume()
into i915_drm_thaw(), so that intel_opregion_free() and
intel_opregion_init() are also executed in the freeze and thaw code
paths, respectively.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Reported-and-tested-by: Pedro Ribeiro <pedrib@gmail.com>
Tested-by: Tino Keitel <tino.keitel@tikei.de>
Acked-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 30 |
1 files changed, 9 insertions, 21 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 79beffcf5936..cf4cb3e9a0c2 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
@@ -176,6 +176,8 @@ MODULE_DEVICE_TABLE(pci, pciidlist); | |||
176 | 176 | ||
177 | static int i915_drm_freeze(struct drm_device *dev) | 177 | static int i915_drm_freeze(struct drm_device *dev) |
178 | { | 178 | { |
179 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
180 | |||
179 | pci_save_state(dev->pdev); | 181 | pci_save_state(dev->pdev); |
180 | 182 | ||
181 | /* If KMS is active, we do the leavevt stuff here */ | 183 | /* If KMS is active, we do the leavevt stuff here */ |
@@ -191,17 +193,12 @@ static int i915_drm_freeze(struct drm_device *dev) | |||
191 | 193 | ||
192 | i915_save_state(dev); | 194 | i915_save_state(dev); |
193 | 195 | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | static void i915_drm_suspend(struct drm_device *dev) | ||
198 | { | ||
199 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
200 | |||
201 | intel_opregion_free(dev, 1); | 196 | intel_opregion_free(dev, 1); |
202 | 197 | ||
203 | /* Modeset on resume, not lid events */ | 198 | /* Modeset on resume, not lid events */ |
204 | dev_priv->modeset_on_lid = 0; | 199 | dev_priv->modeset_on_lid = 0; |
200 | |||
201 | return 0; | ||
205 | } | 202 | } |
206 | 203 | ||
207 | static int i915_suspend(struct drm_device *dev, pm_message_t state) | 204 | static int i915_suspend(struct drm_device *dev, pm_message_t state) |
@@ -221,8 +218,6 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state) | |||
221 | if (error) | 218 | if (error) |
222 | return error; | 219 | return error; |
223 | 220 | ||
224 | i915_drm_suspend(dev); | ||
225 | |||
226 | if (state.event == PM_EVENT_SUSPEND) { | 221 | if (state.event == PM_EVENT_SUSPEND) { |
227 | /* Shut down the device */ | 222 | /* Shut down the device */ |
228 | pci_disable_device(dev->pdev); | 223 | pci_disable_device(dev->pdev); |
@@ -237,6 +232,10 @@ static int i915_drm_thaw(struct drm_device *dev) | |||
237 | struct drm_i915_private *dev_priv = dev->dev_private; | 232 | struct drm_i915_private *dev_priv = dev->dev_private; |
238 | int error = 0; | 233 | int error = 0; |
239 | 234 | ||
235 | i915_restore_state(dev); | ||
236 | |||
237 | intel_opregion_init(dev, 1); | ||
238 | |||
240 | /* KMS EnterVT equivalent */ | 239 | /* KMS EnterVT equivalent */ |
241 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | 240 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { |
242 | mutex_lock(&dev->struct_mutex); | 241 | mutex_lock(&dev->struct_mutex); |
@@ -263,10 +262,6 @@ static int i915_resume(struct drm_device *dev) | |||
263 | 262 | ||
264 | pci_set_master(dev->pdev); | 263 | pci_set_master(dev->pdev); |
265 | 264 | ||
266 | i915_restore_state(dev); | ||
267 | |||
268 | intel_opregion_init(dev, 1); | ||
269 | |||
270 | return i915_drm_thaw(dev); | 265 | return i915_drm_thaw(dev); |
271 | } | 266 | } |
272 | 267 | ||
@@ -423,8 +418,6 @@ static int i915_pm_suspend(struct device *dev) | |||
423 | if (error) | 418 | if (error) |
424 | return error; | 419 | return error; |
425 | 420 | ||
426 | i915_drm_suspend(drm_dev); | ||
427 | |||
428 | pci_disable_device(pdev); | 421 | pci_disable_device(pdev); |
429 | pci_set_power_state(pdev, PCI_D3hot); | 422 | pci_set_power_state(pdev, PCI_D3hot); |
430 | 423 | ||
@@ -464,13 +457,8 @@ static int i915_pm_poweroff(struct device *dev) | |||
464 | { | 457 | { |
465 | struct pci_dev *pdev = to_pci_dev(dev); | 458 | struct pci_dev *pdev = to_pci_dev(dev); |
466 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | 459 | struct drm_device *drm_dev = pci_get_drvdata(pdev); |
467 | int error; | ||
468 | |||
469 | error = i915_drm_freeze(drm_dev); | ||
470 | if (!error) | ||
471 | i915_drm_suspend(drm_dev); | ||
472 | 460 | ||
473 | return error; | 461 | return i915_drm_freeze(drm_dev); |
474 | } | 462 | } |
475 | 463 | ||
476 | const struct dev_pm_ops i915_pm_ops = { | 464 | const struct dev_pm_ops i915_pm_ops = { |