diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2012-04-16 17:07:50 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-04-16 21:33:35 -0400 |
commit | a6cb9ee7cabe68002c3f2ab07224ea27d2617cf1 (patch) | |
tree | fb3fc13b4b58e010b1b08c1ae89df810382063dc | |
parent | 5191d566c023079fa283adc48b71854e9d74ffd5 (diff) |
PCI: Retry BARs restoration for Type 0 headers only
Some shortcomings introduced into pci_restore_state() by commit
26f41062f28d ("PCI: check for pci bar restore completion and retry")
have been fixed by recent commit ebfc5b802fa76 ("PCI: Fix regression in
pci_restore_state(), v3"), but that commit treats all PCI devices as
those with Type 0 configuration headers.
That is not entirely correct, because Type 1 and Type 2 headers have
different layouts. In particular, the area occupied by BARs in Type 0
config headers contains the secondary status register in Type 1 ones and
it doesn't make sense to retry the restoration of that register even if
the value read back from it after a write is not the same as the written
one (it very well may be different).
For this reason, make pci_restore_state() only retry the restoration
of BARs for Type 0 config headers. This effectively makes it behave
as before commit 26f41062f28d for all header types except for Type 0.
Tested-by: Mikko Vinni <mmvinni@yahoo.com>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/pci/pci.c | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index d20f1334792b..111569ccab43 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -991,8 +991,8 @@ static void pci_restore_config_dword(struct pci_dev *pdev, int offset, | |||
991 | } | 991 | } |
992 | } | 992 | } |
993 | 993 | ||
994 | static void pci_restore_config_space(struct pci_dev *pdev, int start, int end, | 994 | static void pci_restore_config_space_range(struct pci_dev *pdev, |
995 | int retry) | 995 | int start, int end, int retry) |
996 | { | 996 | { |
997 | int index; | 997 | int index; |
998 | 998 | ||
@@ -1002,6 +1002,18 @@ static void pci_restore_config_space(struct pci_dev *pdev, int start, int end, | |||
1002 | retry); | 1002 | retry); |
1003 | } | 1003 | } |
1004 | 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 | |||
1005 | /** | 1017 | /** |
1006 | * pci_restore_state - Restore the saved state of a PCI device | 1018 | * pci_restore_state - Restore the saved state of a PCI device |
1007 | * @dev: - PCI device that we're dealing with | 1019 | * @dev: - PCI device that we're dealing with |
@@ -1015,13 +1027,7 @@ void pci_restore_state(struct pci_dev *dev) | |||
1015 | pci_restore_pcie_state(dev); | 1027 | pci_restore_pcie_state(dev); |
1016 | pci_restore_ats_state(dev); | 1028 | pci_restore_ats_state(dev); |
1017 | 1029 | ||
1018 | pci_restore_config_space(dev, 10, 15, 0); | 1030 | pci_restore_config_space(dev); |
1019 | /* | ||
1020 | * The Base Address register should be programmed before the command | ||
1021 | * register(s) | ||
1022 | */ | ||
1023 | pci_restore_config_space(dev, 4, 9, 10); | ||
1024 | pci_restore_config_space(dev, 0, 3, 0); | ||
1025 | 1031 | ||
1026 | pci_restore_pcix_state(dev); | 1032 | pci_restore_pcix_state(dev); |
1027 | pci_restore_msi_state(dev); | 1033 | pci_restore_msi_state(dev); |