mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
Merge branch 'pci/reset'
- Log device readiness timeouts as errors, not warnings (Bjorn Helgaas) - Wait for device readiness after soft reset (D3hot -> D0uninitialized transition), when the device may respond with Request Retry Status if it needs more time to initialize (Bjorn Helgaas) - Drop unnecessary retries when restoring BARs (Lukas Wunner) * pci/reset: PCI: Drop unnecessary retries when restoring BARs PCI: Wait for device readiness after D3hot -> D0uninitialized transition PCI: Log device readiness timeouts as errors
This commit is contained in:
commit
77d94e1436
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user