diff options
-rw-r--r-- | drivers/pci/pci.c | 27 |
1 files changed, 19 insertions, 8 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 1835f3a7aa8d..51b6c81671c1 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -1289,12 +1289,12 @@ int pci_save_state(struct pci_dev *dev) | |||
1289 | EXPORT_SYMBOL(pci_save_state); | 1289 | EXPORT_SYMBOL(pci_save_state); |
1290 | 1290 | ||
1291 | static void pci_restore_config_dword(struct pci_dev *pdev, int offset, | 1291 | static void pci_restore_config_dword(struct pci_dev *pdev, int offset, |
1292 | u32 saved_val, int retry) | 1292 | u32 saved_val, int retry, bool force) |
1293 | { | 1293 | { |
1294 | u32 val; | 1294 | u32 val; |
1295 | 1295 | ||
1296 | pci_read_config_dword(pdev, offset, &val); | 1296 | pci_read_config_dword(pdev, offset, &val); |
1297 | if (val == saved_val) | 1297 | if (!force && val == saved_val) |
1298 | return; | 1298 | return; |
1299 | 1299 | ||
1300 | for (;;) { | 1300 | for (;;) { |
@@ -1313,25 +1313,36 @@ static void pci_restore_config_dword(struct pci_dev *pdev, int offset, | |||
1313 | } | 1313 | } |
1314 | 1314 | ||
1315 | static void pci_restore_config_space_range(struct pci_dev *pdev, | 1315 | static void pci_restore_config_space_range(struct pci_dev *pdev, |
1316 | int start, int end, int retry) | 1316 | int start, int end, int retry, |
1317 | bool force) | ||
1317 | { | 1318 | { |
1318 | int index; | 1319 | int index; |
1319 | 1320 | ||
1320 | for (index = end; index >= start; index--) | 1321 | for (index = end; index >= start; index--) |
1321 | pci_restore_config_dword(pdev, 4 * index, | 1322 | pci_restore_config_dword(pdev, 4 * index, |
1322 | pdev->saved_config_space[index], | 1323 | pdev->saved_config_space[index], |
1323 | retry); | 1324 | retry, force); |
1324 | } | 1325 | } |
1325 | 1326 | ||
1326 | static void pci_restore_config_space(struct pci_dev *pdev) | 1327 | static void pci_restore_config_space(struct pci_dev *pdev) |
1327 | { | 1328 | { |
1328 | if (pdev->hdr_type == PCI_HEADER_TYPE_NORMAL) { | 1329 | if (pdev->hdr_type == PCI_HEADER_TYPE_NORMAL) { |
1329 | pci_restore_config_space_range(pdev, 10, 15, 0); | 1330 | pci_restore_config_space_range(pdev, 10, 15, 0, false); |
1330 | /* Restore BARs before the command register. */ | 1331 | /* Restore BARs before the command register. */ |
1331 | pci_restore_config_space_range(pdev, 4, 9, 10); | 1332 | pci_restore_config_space_range(pdev, 4, 9, 10, false); |
1332 | pci_restore_config_space_range(pdev, 0, 3, 0); | 1333 | pci_restore_config_space_range(pdev, 0, 3, 0, false); |
1334 | } else if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | ||
1335 | pci_restore_config_space_range(pdev, 12, 15, 0, false); | ||
1336 | |||
1337 | /* | ||
1338 | * Force rewriting of prefetch registers to avoid S3 resume | ||
1339 | * issues on Intel PCI bridges that occur when these | ||
1340 | * registers are not explicitly written. | ||
1341 | */ | ||
1342 | pci_restore_config_space_range(pdev, 9, 11, 0, true); | ||
1343 | pci_restore_config_space_range(pdev, 0, 8, 0, false); | ||
1333 | } else { | 1344 | } else { |
1334 | pci_restore_config_space_range(pdev, 0, 15, 0); | 1345 | pci_restore_config_space_range(pdev, 0, 15, 0, false); |
1335 | } | 1346 | } |
1336 | } | 1347 | } |
1337 | 1348 | ||