diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 8ec24562c94c..893c3dff212c 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1244,8 +1244,8 @@ static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout) } if (delay > timeout) { - pci_warn(dev, "not ready %dms after %s; giving up\n", - delay - 1, reset_type); + pci_err(dev, "not ready %dms after %s; giving up\n", + delay - 1, reset_type); return -ENOTTY; } @@ -1291,7 +1291,18 @@ int pci_power_up(struct pci_dev *dev) bool need_restore; pci_power_t state; u16 pmcsr; + int ret; + /* + * When setting power state to D0, platform_pci_set_power_state() + * ensures main power is on. If it puts the device in D0, it also + * completes any required delays after the transition; if it leaves + * the device in D1, D2, or D3hot, we use the PM Capability to + * transition to D0. + * + * In all cases, the device is either Configuration-Ready or + * inaccessible upon return. + */ platform_pci_set_power_state(dev, PCI_D0); if (!dev->pm_cap) { @@ -1332,10 +1343,19 @@ int pci_power_up(struct pci_dev *dev) pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, 0); /* Mandatory transition delays; see PCI PM 1.2. */ - if (state == PCI_D3hot) + if (state == PCI_D3hot) { pci_dev_d3_sleep(dev); - else if (state == PCI_D2) + if (!(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) { + ret = pci_dev_wait(dev, "power up D3hot->D0uninitialized", + PCIE_RESET_READY_POLL_MS); + if (ret) { + dev->current_state = PCI_D3cold; + return -EIO; + } + } + } else if (state == PCI_D2) { udelay(PCI_PM_D2_DELAY); + } end: dev->current_state = PCI_D0; @@ -1752,7 +1772,7 @@ int pci_save_state(struct pci_dev *dev) EXPORT_SYMBOL(pci_save_state); static void pci_restore_config_dword(struct pci_dev *pdev, int offset, - u32 saved_val, int retry, bool force) + u32 saved_val, bool force) { u32 val; @@ -1760,52 +1780,42 @@ static void pci_restore_config_dword(struct pci_dev *pdev, int offset, if (!force && val == saved_val) return; - for (;;) { - pci_dbg(pdev, "restore config %#04x: %#010x -> %#010x\n", - offset, val, saved_val); - pci_write_config_dword(pdev, offset, saved_val); - if (retry-- <= 0) - return; + pci_dbg(pdev, "restore config %#04x: %#010x -> %#010x\n", offset, val, + saved_val); - pci_read_config_dword(pdev, offset, &val); - if (val == saved_val) - return; - - mdelay(1); - } + pci_write_config_dword(pdev, offset, saved_val); } static void pci_restore_config_space_range(struct pci_dev *pdev, - int start, int end, int retry, - bool force) + int start, int end, bool force) { int index; for (index = end; index >= start; index--) pci_restore_config_dword(pdev, 4 * index, pdev->saved_config_space[index], - retry, force); + force); } static void pci_restore_config_space(struct pci_dev *pdev) { if (pdev->hdr_type == PCI_HEADER_TYPE_NORMAL) { - pci_restore_config_space_range(pdev, 10, 15, 0, false); + pci_restore_config_space_range(pdev, 10, 15, false); /* Restore BARs before the command register. */ - pci_restore_config_space_range(pdev, 4, 9, 10, false); - pci_restore_config_space_range(pdev, 0, 3, 0, false); + pci_restore_config_space_range(pdev, 4, 9, false); + pci_restore_config_space_range(pdev, 0, 3, false); } else if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_restore_config_space_range(pdev, 12, 15, 0, false); + pci_restore_config_space_range(pdev, 12, 15, false); /* * Force rewriting of prefetch registers to avoid S3 resume * issues on Intel PCI bridges that occur when these * registers are not explicitly written. */ - pci_restore_config_space_range(pdev, 9, 11, 0, true); - pci_restore_config_space_range(pdev, 0, 8, 0, false); + pci_restore_config_space_range(pdev, 9, 11, true); + pci_restore_config_space_range(pdev, 0, 8, false); } else { - pci_restore_config_space_range(pdev, 0, 15, 0, false); + pci_restore_config_space_range(pdev, 0, 15, false); } }