PCI PM fixes for 2.6.29
cover PCI PM fixes for 2.6.29
Hi Jesse,
The following two patches contain fixes of PCI suspend-resume routines.
The first one corrects the suspend-resume handling for PCI Express ports after commit 2bdc985ac3fcdb4ae9672feeb14de2c525967899 (in your tree).
The second one is a fix for devices without PM capability.
Sorry for being late with them, but I had to make sure that the first patch doesn't break the test box affected by bug #12121 again.
Thanks,
Rafael
PATCH 1/2 PCI PM: Split PCI Express port suspend-resume
From: Rafael J. Wysocki <[email protected]>
Suspend-resume of PCI Express ports has recently been moved into _suspend_late() and _resume_early() callbacks, but some functions executed from there should not be called with interrupts disabled, eg. pci_enable_device(). For this reason, split the suspend-resume of PCI Express ports into parts to be executed with interrupts disabled and with interrupts enabled.
--- drivers/pci/pcie/portdrv_pci.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-)
drivers/pci/pcie/portdrv_pci.c +17 -6
@@ -41,7 +41,6 @@ static int pcie_portdrv_restore_config(s {int retval; -pci_restore_state (dev); retval =pci_enable_device (dev);if (retval)return retval;
@@ -50,23 +49,32 @@ static int pcie_portdrv_restore_config(s }#ifdef CONFIG_PM -static int pcie_portdrv_suspend_late (struct pci_dev *dev,pm_message_t state) +static int pcie_portdrv_suspend (struct pci_dev *dev,pm_message_t state) { -int ret =pcie_port_device_suspend (dev, state); +return pcie_port_device_suspend (dev, state); + +} -if (!ret) - ret =pcie_portdrv_save_config (dev); -return ret; +static int pcie_portdrv_suspend_late (struct pci_dev *dev,pm_message_t state) +{ +return pci_save_state (dev); }static int pcie_portdrv_resume_early (struct pci_dev *dev) { +return pci_restore_state (dev); +} + +static int pcie_portdrv_resume (struct pci_dev *dev) +{pcie_portdrv_restore_config (dev);return pcie_port_device_resume (dev); }#else +#define pcie_portdrv_suspend NULL#define pcie_portdrv_suspend_late NULL#define pcie_portdrv_resume_early NULL +#define pcie_portdrv_resume NULL#endif /*
@@ -221,6 +229,7 @@ static pci_ers_result_t pcie_portdrv_slo/* If fatal, restore cfg space for possible link reset at upstream */ if (dev->error_state == pci_channel_io_frozen) { +pci_restore_state (dev);pcie_portdrv_restore_config (dev);pci_enable_pcie_error_reporting (dev); }
@@ -282,8 +291,10 @@ static struct pci_driver pcie_portdriver .probe = pcie_portdrv_probe, .remove = pcie_portdrv_remove, + .suspend = pcie_portdrv_suspend, .suspend_late = pcie_portdrv_suspend_late, .resume_early = pcie_portdrv_resume_early, + .resume = pcie_portdrv_resume, .err_handler = &pcie_portdrv_err_handler, };
PATCH 2/2 PCI PM: Fix pci_update_current_state
In reply to Rafael J. WysockiFrom: Rafael J. Wysocki <[email protected]>
Currently, PCI devices without the PM capability that are power manageable by the platform (eg. ACPI) are not handled correctly by pci_set_power_state(), because their current_state field is not updated to reflect the new power state of the device. Fix this by making pci_update_current_state() accept additional argument representing the power state of the device as set by the platform.
--- drivers/pci/pci.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/pci/pci.c +6 -3
@@ -524,14 +524,17 @@ pci_raw_set_power_state(struct pci_dev ** pci_update_current_state - Read PCI power state of given device from its * PCI PM registers and cache it * @dev: PCI device to handle. +* @state: State to cache in case the device doesn't have the PM capability */ -static void pci_update_current_state (struct pci_dev *dev) +static void pci_update_current_state (struct pci_dev *dev,pci_power_t state) {if (dev->pm_cap) {u16 pmcsr;pci_read_config_word (dev, dev->pm_cap +PCI_PM_CTRL , &pmcsr); dev->current_state = (pmcsr &PCI_PM_CTRL_STATE_MASK ); + }else { + dev->current_state = state; } }
@@ -574,7 +577,7 @@ int pci_set_power_state(struct pci_dev **/ int ret =platform_pci_set_power_state (dev,PCI_D0 );if (!ret) -pci_update_current_state (dev); +pci_update_current_state (dev,PCI_D0 ); }/* This device is quirked not to be put into D3, so don't put it in D3 */
@@ -587,7 +590,7 @@ int pci_set_power_state(struct pci_dev */* Allow the platform to finalize the transition */ int ret =platform_pci_set_power_state (dev, state);if (!ret) { -pci_update_current_state (dev); +pci_update_current_state (dev, state); error =0 ; } }