diff options
Diffstat (limited to 'drivers/pci/pci.c')
| -rw-r--r-- | drivers/pci/pci.c | 71 |
1 files changed, 49 insertions, 22 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 815674415267..111569ccab43 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
| @@ -967,16 +967,59 @@ pci_save_state(struct pci_dev *dev) | |||
| 967 | return 0; | 967 | return 0; |
| 968 | } | 968 | } |
| 969 | 969 | ||
| 970 | static void pci_restore_config_dword(struct pci_dev *pdev, int offset, | ||
| 971 | u32 saved_val, int retry) | ||
| 972 | { | ||
| 973 | u32 val; | ||
| 974 | |||
| 975 | pci_read_config_dword(pdev, offset, &val); | ||
| 976 | if (val == saved_val) | ||
| 977 | return; | ||
| 978 | |||
| 979 | for (;;) { | ||
| 980 | dev_dbg(&pdev->dev, "restoring config space at offset " | ||
| 981 | "%#x (was %#x, writing %#x)\n", offset, val, saved_val); | ||
| 982 | pci_write_config_dword(pdev, offset, saved_val); | ||
| 983 | if (retry-- <= 0) | ||
| 984 | return; | ||
| 985 | |||
| 986 | pci_read_config_dword(pdev, offset, &val); | ||
| 987 | if (val == saved_val) | ||
| 988 | return; | ||
| 989 | |||
| 990 | mdelay(1); | ||
| 991 | } | ||
| 992 | } | ||
| 993 | |||
| 994 | static void pci_restore_config_space_range(struct pci_dev *pdev, | ||
| 995 | int start, int end, int retry) | ||
| 996 | { | ||
| 997 | int index; | ||
| 998 | |||
| 999 | for (index = end; index >= start; index--) | ||
| 1000 | pci_restore_config_dword(pdev, 4 * index, | ||
| 1001 | pdev->saved_config_space[index], | ||
| 1002 | retry); | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | static void pci_restore_config_space(struct pci_dev *pdev) | ||
| 1006 | { | ||
| 1007 | if (pdev->hdr_type == PCI_HEADER_TYPE_NORMAL) { | ||
| 1008 | pci_restore_config_space_range(pdev, 10, 15, 0); | ||
| 1009 | /* Restore BARs before the command register. */ | ||
| 1010 | pci_restore_config_space_range(pdev, 4, 9, 10); | ||
| 1011 | pci_restore_config_space_range(pdev, 0, 3, 0); | ||
| 1012 | } else { | ||
| 1013 | pci_restore_config_space_range(pdev, 0, 15, 0); | ||
| 1014 | } | ||
| 1015 | } | ||
| 1016 | |||
| 970 | /** | 1017 | /** |
| 971 | * pci_restore_state - Restore the saved state of a PCI device | 1018 | * pci_restore_state - Restore the saved state of a PCI device |
| 972 | * @dev: - PCI device that we're dealing with | 1019 | * @dev: - PCI device that we're dealing with |
| 973 | */ | 1020 | */ |
| 974 | void pci_restore_state(struct pci_dev *dev) | 1021 | void pci_restore_state(struct pci_dev *dev) |
| 975 | { | 1022 | { |
| 976 | int i; | ||
| 977 | u32 val; | ||
| 978 | int tries; | ||
| 979 | |||
| 980 | if (!dev->state_saved) | 1023 | if (!dev->state_saved) |
| 981 | return; | 1024 | return; |
| 982 | 1025 | ||
| @@ -984,24 +1027,8 @@ void pci_restore_state(struct pci_dev *dev) | |||
| 984 | pci_restore_pcie_state(dev); | 1027 | pci_restore_pcie_state(dev); |
| 985 | pci_restore_ats_state(dev); | 1028 | pci_restore_ats_state(dev); |
| 986 | 1029 | ||
| 987 | /* | 1030 | pci_restore_config_space(dev); |
| 988 | * The Base Address register should be programmed before the command | 1031 | |
| 989 | * register(s) | ||
| 990 | */ | ||
| 991 | for (i = 15; i >= 0; i--) { | ||
| 992 | pci_read_config_dword(dev, i * 4, &val); | ||
| 993 | tries = 10; | ||
| 994 | while (tries && val != dev->saved_config_space[i]) { | ||
| 995 | dev_dbg(&dev->dev, "restoring config " | ||
| 996 | "space at offset %#x (was %#x, writing %#x)\n", | ||
| 997 | i, val, (int)dev->saved_config_space[i]); | ||
| 998 | pci_write_config_dword(dev,i * 4, | ||
| 999 | dev->saved_config_space[i]); | ||
| 1000 | pci_read_config_dword(dev, i * 4, &val); | ||
| 1001 | mdelay(10); | ||
| 1002 | tries--; | ||
| 1003 | } | ||
| 1004 | } | ||
| 1005 | pci_restore_pcix_state(dev); | 1032 | pci_restore_pcix_state(dev); |
| 1006 | pci_restore_msi_state(dev); | 1033 | pci_restore_msi_state(dev); |
| 1007 | pci_restore_iov_state(dev); | 1034 | pci_restore_iov_state(dev); |
