|
@@ -1289,12 +1289,12 @@ 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)
|
|
|
+ u32 saved_val, int retry, bool force)
|
|
|
{
|
|
|
u32 val;
|
|
|
|
|
|
pci_read_config_dword(pdev, offset, &val);
|
|
|
- if (val == saved_val)
|
|
|
+ if (!force && val == saved_val)
|
|
|
return;
|
|
|
|
|
|
for (;;) {
|
|
@@ -1313,25 +1313,36 @@ static void pci_restore_config_dword(struct pci_dev *pdev, int offset,
|
|
|
}
|
|
|
|
|
|
static void pci_restore_config_space_range(struct pci_dev *pdev,
|
|
|
- int start, int end, int retry)
|
|
|
+ int start, int end, int retry,
|
|
|
+ bool force)
|
|
|
{
|
|
|
int index;
|
|
|
|
|
|
for (index = end; index >= start; index--)
|
|
|
pci_restore_config_dword(pdev, 4 * index,
|
|
|
pdev->saved_config_space[index],
|
|
|
- retry);
|
|
|
+ retry, 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);
|
|
|
+ pci_restore_config_space_range(pdev, 10, 15, 0, false);
|
|
|
/* Restore BARs before the command register. */
|
|
|
- pci_restore_config_space_range(pdev, 4, 9, 10);
|
|
|
- pci_restore_config_space_range(pdev, 0, 3, 0);
|
|
|
+ pci_restore_config_space_range(pdev, 4, 9, 10, false);
|
|
|
+ pci_restore_config_space_range(pdev, 0, 3, 0, false);
|
|
|
+ } else if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
|
|
|
+ pci_restore_config_space_range(pdev, 12, 15, 0, 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);
|
|
|
} else {
|
|
|
- pci_restore_config_space_range(pdev, 0, 15, 0);
|
|
|
+ pci_restore_config_space_range(pdev, 0, 15, 0, false);
|
|
|
}
|
|
|
}
|
|
|
|