diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2008-02-23 13:13:25 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-23 13:40:04 -0500 |
commit | 3a2d5b700132f35401f1d9e22fe3c2cab02c2549 (patch) | |
tree | ad991428c41aee92a5f78b06bf73430af0e6f7ae /drivers | |
parent | 39273b58a409cd6d65c9732bdca00bacd1626672 (diff) |
PM: Introduce PM_EVENT_HIBERNATE callback state
During the last step of hibernation in the "platform" mode (with the
help of ACPI) we use the suspend code, including the devices'
->suspend() methods, to prepare the system for entering the ACPI S4
system sleep state.
But at least for some devices the operations performed by the
->suspend() callback in that case must be different from its operations
during regular suspend.
For this reason, introduce the new PM event type PM_EVENT_HIBERNATE and
pass it to the device drivers' ->suspend() methods during the last phase
of hibernation, so that they can distinguish this case and handle it as
appropriate. Modify the drivers that handle PM_EVENT_SUSPEND in a
special way and need to handle PM_EVENT_HIBERNATE in the same way.
These changes are necessary to fix a hibernation regression related
to the i915 driver (ref. http://lkml.org/lkml/2008/2/22/488).
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Pavel Machek <pavel@ucw.cz>
Tested-by: Jeff Chua <jeff.chua.linux@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ata/ahci.c | 2 | ||||
-rw-r--r-- | drivers/ata/ata_piix.c | 2 | ||||
-rw-r--r-- | drivers/ata/libata-core.c | 2 | ||||
-rw-r--r-- | drivers/ide/ppc/pmac.c | 4 | ||||
-rw-r--r-- | drivers/macintosh/mediabay.c | 3 | ||||
-rw-r--r-- | drivers/pci/pci.c | 1 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aic79xx_osm_pci.c | 2 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aic7xxx_osm_pci.c | 2 | ||||
-rw-r--r-- | drivers/scsi/mesh.c | 1 | ||||
-rw-r--r-- | drivers/scsi/sd.c | 3 | ||||
-rw-r--r-- | drivers/usb/host/sl811-hcd.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/u132-hcd.c | 11 | ||||
-rw-r--r-- | drivers/video/chipsfb.c | 2 | ||||
-rw-r--r-- | drivers/video/nvidia/nvidia.c | 2 |
14 files changed, 23 insertions, 15 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 3c06e457b4dc..6dd12f7019a0 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c | |||
@@ -1932,7 +1932,7 @@ static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) | |||
1932 | void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; | 1932 | void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; |
1933 | u32 ctl; | 1933 | u32 ctl; |
1934 | 1934 | ||
1935 | if (mesg.event == PM_EVENT_SUSPEND) { | 1935 | if (mesg.event & PM_EVENT_SLEEP) { |
1936 | /* AHCI spec rev1.1 section 8.3.3: | 1936 | /* AHCI spec rev1.1 section 8.3.3: |
1937 | * Software must disable interrupts prior to requesting a | 1937 | * Software must disable interrupts prior to requesting a |
1938 | * transition of the HBA to D3 state. | 1938 | * transition of the HBA to D3 state. |
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 752e7d2f3b2f..fae8404254c0 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c | |||
@@ -1339,7 +1339,7 @@ static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) | |||
1339 | * cycles and power trying to do something to the sleeping | 1339 | * cycles and power trying to do something to the sleeping |
1340 | * beauty. | 1340 | * beauty. |
1341 | */ | 1341 | */ |
1342 | if (piix_broken_suspend() && mesg.event == PM_EVENT_SUSPEND) { | 1342 | if (piix_broken_suspend() && (mesg.event & PM_EVENT_SLEEP)) { |
1343 | pci_save_state(pdev); | 1343 | pci_save_state(pdev); |
1344 | 1344 | ||
1345 | /* mark its power state as "unknown", since we don't | 1345 | /* mark its power state as "unknown", since we don't |
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 60d1bb556973..4cf8662df99e 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -7368,7 +7368,7 @@ void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg) | |||
7368 | pci_save_state(pdev); | 7368 | pci_save_state(pdev); |
7369 | pci_disable_device(pdev); | 7369 | pci_disable_device(pdev); |
7370 | 7370 | ||
7371 | if (mesg.event == PM_EVENT_SUSPEND) | 7371 | if (mesg.event & PM_EVENT_SLEEP) |
7372 | pci_set_power_state(pdev, PCI_D3hot); | 7372 | pci_set_power_state(pdev, PCI_D3hot); |
7373 | } | 7373 | } |
7374 | 7374 | ||
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 12ac3bfb4f9a..78c9eeb85634 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c | |||
@@ -1254,7 +1254,7 @@ pmac_ide_macio_suspend(struct macio_dev *mdev, pm_message_t mesg) | |||
1254 | int rc = 0; | 1254 | int rc = 0; |
1255 | 1255 | ||
1256 | if (mesg.event != mdev->ofdev.dev.power.power_state.event | 1256 | if (mesg.event != mdev->ofdev.dev.power.power_state.event |
1257 | && mesg.event == PM_EVENT_SUSPEND) { | 1257 | && (mesg.event & PM_EVENT_SLEEP)) { |
1258 | rc = pmac_ide_do_suspend(hwif); | 1258 | rc = pmac_ide_do_suspend(hwif); |
1259 | if (rc == 0) | 1259 | if (rc == 0) |
1260 | mdev->ofdev.dev.power.power_state = mesg; | 1260 | mdev->ofdev.dev.power.power_state = mesg; |
@@ -1364,7 +1364,7 @@ pmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) | |||
1364 | int rc = 0; | 1364 | int rc = 0; |
1365 | 1365 | ||
1366 | if (mesg.event != pdev->dev.power.power_state.event | 1366 | if (mesg.event != pdev->dev.power.power_state.event |
1367 | && mesg.event == PM_EVENT_SUSPEND) { | 1367 | && (mesg.event & PM_EVENT_SLEEP)) { |
1368 | rc = pmac_ide_do_suspend(hwif); | 1368 | rc = pmac_ide_do_suspend(hwif); |
1369 | if (rc == 0) | 1369 | if (rc == 0) |
1370 | pdev->dev.power.power_state = mesg; | 1370 | pdev->dev.power.power_state = mesg; |
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index 51a112815f46..bd8a1d14b45d 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c | |||
@@ -698,7 +698,8 @@ static int media_bay_suspend(struct macio_dev *mdev, pm_message_t state) | |||
698 | { | 698 | { |
699 | struct media_bay_info *bay = macio_get_drvdata(mdev); | 699 | struct media_bay_info *bay = macio_get_drvdata(mdev); |
700 | 700 | ||
701 | if (state.event != mdev->ofdev.dev.power.power_state.event && state.event == PM_EVENT_SUSPEND) { | 701 | if (state.event != mdev->ofdev.dev.power.power_state.event |
702 | && (state.event & PM_EVENT_SLEEP)) { | ||
702 | down(&bay->lock); | 703 | down(&bay->lock); |
703 | bay->sleeping = 1; | 704 | bay->sleeping = 1; |
704 | set_mb_power(bay, 0); | 705 | set_mb_power(bay, 0); |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index ae3df46eaabf..183fddaa38b7 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -554,6 +554,7 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) | |||
554 | case PM_EVENT_PRETHAW: | 554 | case PM_EVENT_PRETHAW: |
555 | /* REVISIT both freeze and pre-thaw "should" use D0 */ | 555 | /* REVISIT both freeze and pre-thaw "should" use D0 */ |
556 | case PM_EVENT_SUSPEND: | 556 | case PM_EVENT_SUSPEND: |
557 | case PM_EVENT_HIBERNATE: | ||
557 | return PCI_D3hot; | 558 | return PCI_D3hot; |
558 | default: | 559 | default: |
559 | printk("Unrecognized suspend event %d\n", state.event); | 560 | printk("Unrecognized suspend event %d\n", state.event); |
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c index 4150c8a8fdc2..dfaaae5e73ae 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c | |||
@@ -89,7 +89,7 @@ ahd_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg) | |||
89 | pci_save_state(pdev); | 89 | pci_save_state(pdev); |
90 | pci_disable_device(pdev); | 90 | pci_disable_device(pdev); |
91 | 91 | ||
92 | if (mesg.event == PM_EVENT_SUSPEND) | 92 | if (mesg.event & PM_EVENT_SLEEP) |
93 | pci_set_power_state(pdev, PCI_D3hot); | 93 | pci_set_power_state(pdev, PCI_D3hot); |
94 | 94 | ||
95 | return rc; | 95 | return rc; |
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c index dd6e21d6f1dd..3d3eaef65fb3 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c | |||
@@ -134,7 +134,7 @@ ahc_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg) | |||
134 | pci_save_state(pdev); | 134 | pci_save_state(pdev); |
135 | pci_disable_device(pdev); | 135 | pci_disable_device(pdev); |
136 | 136 | ||
137 | if (mesg.event == PM_EVENT_SUSPEND) | 137 | if (mesg.event & PM_EVENT_SLEEP) |
138 | pci_set_power_state(pdev, PCI_D3hot); | 138 | pci_set_power_state(pdev, PCI_D3hot); |
139 | 139 | ||
140 | return rc; | 140 | return rc; |
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index 651d09b08f2a..fd63b06d9ef1 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c | |||
@@ -1759,6 +1759,7 @@ static int mesh_suspend(struct macio_dev *mdev, pm_message_t mesg) | |||
1759 | 1759 | ||
1760 | switch (mesg.event) { | 1760 | switch (mesg.event) { |
1761 | case PM_EVENT_SUSPEND: | 1761 | case PM_EVENT_SUSPEND: |
1762 | case PM_EVENT_HIBERNATE: | ||
1762 | case PM_EVENT_FREEZE: | 1763 | case PM_EVENT_FREEZE: |
1763 | break; | 1764 | break; |
1764 | default: | 1765 | default: |
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 37df8bbe7f46..7aee64dbfbeb 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
@@ -1835,8 +1835,7 @@ static int sd_suspend(struct device *dev, pm_message_t mesg) | |||
1835 | goto done; | 1835 | goto done; |
1836 | } | 1836 | } |
1837 | 1837 | ||
1838 | if (mesg.event == PM_EVENT_SUSPEND && | 1838 | if ((mesg.event & PM_EVENT_SLEEP) && sdkp->device->manage_start_stop) { |
1839 | sdkp->device->manage_start_stop) { | ||
1840 | sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); | 1839 | sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); |
1841 | ret = sd_start_stop_device(sdkp, 0); | 1840 | ret = sd_start_stop_device(sdkp, 0); |
1842 | } | 1841 | } |
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index ba370c56172c..59be276ccd9d 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c | |||
@@ -1766,6 +1766,7 @@ sl811h_suspend(struct platform_device *dev, pm_message_t state) | |||
1766 | retval = sl811h_bus_suspend(hcd); | 1766 | retval = sl811h_bus_suspend(hcd); |
1767 | break; | 1767 | break; |
1768 | case PM_EVENT_SUSPEND: | 1768 | case PM_EVENT_SUSPEND: |
1769 | case PM_EVENT_HIBERNATE: | ||
1769 | case PM_EVENT_PRETHAW: /* explicitly discard hw state */ | 1770 | case PM_EVENT_PRETHAW: /* explicitly discard hw state */ |
1770 | port_power(sl811, 0); | 1771 | port_power(sl811, 0); |
1771 | break; | 1772 | break; |
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index ac283b09a63f..6fca06961559 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c | |||
@@ -3214,14 +3214,19 @@ static int u132_suspend(struct platform_device *pdev, pm_message_t state) | |||
3214 | return -ESHUTDOWN; | 3214 | return -ESHUTDOWN; |
3215 | } else { | 3215 | } else { |
3216 | int retval = 0; | 3216 | int retval = 0; |
3217 | if (state.event == PM_EVENT_FREEZE) { | 3217 | |
3218 | switch (state.event) { | ||
3219 | case PM_EVENT_FREEZE: | ||
3218 | retval = u132_bus_suspend(hcd); | 3220 | retval = u132_bus_suspend(hcd); |
3219 | } else if (state.event == PM_EVENT_SUSPEND) { | 3221 | break; |
3222 | case PM_EVENT_SUSPEND: | ||
3223 | case PM_EVENT_HIBERNATE: | ||
3220 | int ports = MAX_U132_PORTS; | 3224 | int ports = MAX_U132_PORTS; |
3221 | while (ports-- > 0) { | 3225 | while (ports-- > 0) { |
3222 | port_power(u132, ports, 0); | 3226 | port_power(u132, ports, 0); |
3223 | } | 3227 | } |
3224 | } | 3228 | break; |
3229 | } | ||
3225 | if (retval == 0) | 3230 | if (retval == 0) |
3226 | pdev->dev.power.power_state = state; | 3231 | pdev->dev.power.power_state = state; |
3227 | return retval; | 3232 | return retval; |
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index 6796ba62c3c6..777389c40988 100644 --- a/drivers/video/chipsfb.c +++ b/drivers/video/chipsfb.c | |||
@@ -459,7 +459,7 @@ static int chipsfb_pci_suspend(struct pci_dev *pdev, pm_message_t state) | |||
459 | 459 | ||
460 | if (state.event == pdev->dev.power.power_state.event) | 460 | if (state.event == pdev->dev.power.power_state.event) |
461 | return 0; | 461 | return 0; |
462 | if (state.event != PM_EVENT_SUSPEND) | 462 | if (!(state.event & PM_EVENT_SLEEP)) |
463 | goto done; | 463 | goto done; |
464 | 464 | ||
465 | acquire_console_sem(); | 465 | acquire_console_sem(); |
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 74517b1b26a6..596652d2831f 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c | |||
@@ -1066,7 +1066,7 @@ static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t mesg) | |||
1066 | acquire_console_sem(); | 1066 | acquire_console_sem(); |
1067 | par->pm_state = mesg.event; | 1067 | par->pm_state = mesg.event; |
1068 | 1068 | ||
1069 | if (mesg.event == PM_EVENT_SUSPEND) { | 1069 | if (mesg.event & PM_EVENT_SLEEP) { |
1070 | fb_set_suspend(info, 1); | 1070 | fb_set_suspend(info, 1); |
1071 | nvidiafb_blank(FB_BLANK_POWERDOWN, info); | 1071 | nvidiafb_blank(FB_BLANK_POWERDOWN, info); |
1072 | nvidia_write_regs(par, &par->SavedReg); | 1072 | nvidia_write_regs(par, &par->SavedReg); |