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

Commit 3a2d5b70 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki Committed by Linus Torvalds
Browse files

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: default avatarRafael J. Wysocki <rjw@sisk.pl>
Acked-by: default avatarPavel Machek <pavel@ucw.cz>
Tested-by: default avatarJeff Chua <jeff.chua.linux@gmail.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 39273b58
Loading
Loading
Loading
Loading
+8 −5
Original line number Original line Diff line number Diff line
@@ -310,9 +310,12 @@ used with suspend-to-disk:
    PM_EVENT_SUSPEND -- quiesce the driver and put hardware into a low-power
    PM_EVENT_SUSPEND -- quiesce the driver and put hardware into a low-power
	state.  When used with system sleep states like "suspend-to-RAM" or
	state.  When used with system sleep states like "suspend-to-RAM" or
	"standby", the upcoming resume() call will often be able to rely on
	"standby", the upcoming resume() call will often be able to rely on
	state kept in hardware, or issue system wakeup events.  When used
	state kept in hardware, or issue system wakeup events.
	instead with suspend-to-disk, few devices support this capability;

	most are completely powered off.
    PM_EVENT_HIBERNATE -- Put hardware into a low-power state and enable wakeup
	events as appropriate.  It is only used with hibernation
	(suspend-to-disk) and few devices are able to wake up the system from
	this state; most are completely powered off.


    PM_EVENT_FREEZE -- quiesce the driver, but don't necessarily change into
    PM_EVENT_FREEZE -- quiesce the driver, but don't necessarily change into
	any low power mode.  A system snapshot is about to be taken, often
	any low power mode.  A system snapshot is about to be taken, often
@@ -329,8 +332,8 @@ used with suspend-to-disk:
	wakeup events nor DMA are allowed.
	wakeup events nor DMA are allowed.


To enter "standby" (ACPI S1) or "Suspend to RAM" (STR, ACPI S3) states, or
To enter "standby" (ACPI S1) or "Suspend to RAM" (STR, ACPI S3) states, or
the similarly named APM states, only PM_EVENT_SUSPEND is used; for "Suspend
the similarly named APM states, only PM_EVENT_SUSPEND is used; the other event
to Disk" (STD, hibernate, ACPI S4), all of those event codes are used.
codes are used for hibernation ("Suspend to Disk", STD, ACPI S4).


There's also PM_EVENT_ON, a value which never appears as a suspend event
There's also PM_EVENT_ON, a value which never appears as a suspend event
but is sometimes used to record the "not suspended" device state.
but is sometimes used to record the "not suspended" device state.
+1 −1
Original line number Original line Diff line number Diff line
@@ -1932,7 +1932,7 @@ static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
	u32 ctl;
	u32 ctl;


	if (mesg.event == PM_EVENT_SUSPEND) {
	if (mesg.event & PM_EVENT_SLEEP) {
		/* AHCI spec rev1.1 section 8.3.3:
		/* AHCI spec rev1.1 section 8.3.3:
		 * Software must disable interrupts prior to requesting a
		 * Software must disable interrupts prior to requesting a
		 * transition of the HBA to D3 state.
		 * transition of the HBA to D3 state.
+1 −1
Original line number Original line Diff line number Diff line
@@ -1339,7 +1339,7 @@ static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
	 * cycles and power trying to do something to the sleeping
	 * cycles and power trying to do something to the sleeping
	 * beauty.
	 * beauty.
	 */
	 */
	if (piix_broken_suspend() && mesg.event == PM_EVENT_SUSPEND) {
	if (piix_broken_suspend() && (mesg.event & PM_EVENT_SLEEP)) {
		pci_save_state(pdev);
		pci_save_state(pdev);


		/* mark its power state as "unknown", since we don't
		/* mark its power state as "unknown", since we don't
+1 −1
Original line number Original line Diff line number Diff line
@@ -7368,7 +7368,7 @@ void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg)
	pci_save_state(pdev);
	pci_save_state(pdev);
	pci_disable_device(pdev);
	pci_disable_device(pdev);


	if (mesg.event == PM_EVENT_SUSPEND)
	if (mesg.event & PM_EVENT_SLEEP)
		pci_set_power_state(pdev, PCI_D3hot);
		pci_set_power_state(pdev, PCI_D3hot);
}
}


+2 −2
Original line number Original line Diff line number Diff line
@@ -1254,7 +1254,7 @@ pmac_ide_macio_suspend(struct macio_dev *mdev, pm_message_t mesg)
	int		rc = 0;
	int		rc = 0;


	if (mesg.event != mdev->ofdev.dev.power.power_state.event
	if (mesg.event != mdev->ofdev.dev.power.power_state.event
			&& mesg.event == PM_EVENT_SUSPEND) {
			&& (mesg.event & PM_EVENT_SLEEP)) {
		rc = pmac_ide_do_suspend(hwif);
		rc = pmac_ide_do_suspend(hwif);
		if (rc == 0)
		if (rc == 0)
			mdev->ofdev.dev.power.power_state = mesg;
			mdev->ofdev.dev.power.power_state = mesg;
@@ -1364,7 +1364,7 @@ pmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
	int		rc = 0;
	int		rc = 0;
	
	
	if (mesg.event != pdev->dev.power.power_state.event
	if (mesg.event != pdev->dev.power.power_state.event
			&& mesg.event == PM_EVENT_SUSPEND) {
			&& (mesg.event & PM_EVENT_SLEEP)) {
		rc = pmac_ide_do_suspend(hwif);
		rc = pmac_ide_do_suspend(hwif);
		if (rc == 0)
		if (rc == 0)
			pdev->dev.power.power_state = mesg;
			pdev->dev.power.power_state = mesg;
Loading