From 48f67f54a53bb68619a63c3f38cf7f502ed74b1d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 22 Jan 2009 23:38:31 +0100 Subject: PCI PM: Power up devices before restoring their state Devices that have MSI-X enabled before suspend to RAM or hibernation and that are in a low power state during resume will not be handled correctly by pci_restore_standard_config(). Namely, it first calls pci_restore_state() which calls pci_restore_msi_state(), which in turn executes __pci_restore_msix_state() that accesses the device's memory space to restore the contents of the MSI-X table. However, if the device is in a low power state at this point, it's memory space is not accessible. The easiest way to fix this potential problem is to make pci_restore_standard_config() call pci_restore_state() after it has put the device into the full power state, D0. Fortunately, all of this is done with interrupts off, so the change of ordering should not cause any trouble. Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/pci/pci.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 17bd9325a245..f0aa3d533839 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1393,12 +1393,11 @@ int pci_restore_standard_config(struct pci_dev *dev) pci_power_t prev_state; int error; - pci_restore_state(dev); pci_update_current_state(dev, PCI_D0); prev_state = dev->current_state; if (prev_state == PCI_D0) - return 0; + goto Restore; error = pci_raw_set_power_state(dev, PCI_D0, false); if (error) @@ -1421,7 +1420,8 @@ int pci_restore_standard_config(struct pci_dev *dev) dev->current_state = PCI_D0; - return 0; + Restore: + return pci_restore_state(dev); } /** -- cgit v1.2.3 From 476e7faefc43f106a90b5c96166c59b75de19d30 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 22 Jan 2009 23:39:57 +0100 Subject: PCI PM: Do not wait for buses in B2 or B3 during resume pci_restore_standard_config() adds extra delay for PCI buses in low power states (B2 or B3), but this is only correct for buses in B2, because the buses in B3 are reset when they are put back into B0. Thus we should wait for such buses to settle after the reset, but it's not a good idea to wait that long (1.1 s) with interrupts off. On the other hand, we have never waited for buses in B2 and B3 during resume and it seems reasonable to go back to this well tested behaviour. Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/pci/pci.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index f0aa3d533839..48807556b47a 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1403,19 +1403,19 @@ int pci_restore_standard_config(struct pci_dev *dev) if (error) return error; - if (pci_is_bridge(dev)) { - if (prev_state > PCI_D1) - mdelay(PCI_PM_BUS_WAIT); - } else { - switch(prev_state) { - case PCI_D3cold: - case PCI_D3hot: - mdelay(pci_pm_d3_delay); - break; - case PCI_D2: - udelay(PCI_PM_D2_DELAY); - break; - } + /* + * This assumes that we won't get a bus in B2 or B3 from the BIOS, but + * we've made this assumption forever and it appears to be universally + * satisfied. + */ + switch(prev_state) { + case PCI_D3cold: + case PCI_D3hot: + mdelay(pci_pm_d3_delay); + break; + case PCI_D2: + udelay(PCI_PM_D2_DELAY); + break; } dev->current_state = PCI_D0; -- cgit v1.2.3