diff options
author | Michael S. Tsirkin <mst@mellanox.co.il> | 2006-06-12 09:57:51 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2006-06-17 23:37:00 -0400 |
commit | 13aa6ecb47990cfc78e20e347fdd3f1df6189426 (patch) | |
tree | d26f2ed61becb6603aff5dc1467270a370483333 /drivers | |
parent | 427abfa28afedffadfca9dd8b067eb6d36bac53f (diff) |
IB/mthca: restore missing PCI registers after reset
mthca does not restore the following PCI-X/PCI Express registers after reset:
PCI-X device: PCI-X command register
PCI-X bridge: upstream and downstream split transaction registers
PCI Express : PCI Express device control and link control registers
This causes instability and/or bad performance on systems where one of
these registers is set to a non-default value by BIOS.
Signed-off-by: Michael S. Tsirkin <mst@mellanox.co.il>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/infiniband/hw/mthca/mthca_reset.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/mthca/mthca_reset.c b/drivers/infiniband/hw/mthca/mthca_reset.c index df5e494a9d38..f4fddd5327f5 100644 --- a/drivers/infiniband/hw/mthca/mthca_reset.c +++ b/drivers/infiniband/hw/mthca/mthca_reset.c | |||
@@ -49,6 +49,12 @@ int mthca_reset(struct mthca_dev *mdev) | |||
49 | u32 *hca_header = NULL; | 49 | u32 *hca_header = NULL; |
50 | u32 *bridge_header = NULL; | 50 | u32 *bridge_header = NULL; |
51 | struct pci_dev *bridge = NULL; | 51 | struct pci_dev *bridge = NULL; |
52 | int bridge_pcix_cap = 0; | ||
53 | int hca_pcie_cap = 0; | ||
54 | int hca_pcix_cap = 0; | ||
55 | |||
56 | u16 devctl; | ||
57 | u16 linkctl; | ||
52 | 58 | ||
53 | #define MTHCA_RESET_OFFSET 0xf0010 | 59 | #define MTHCA_RESET_OFFSET 0xf0010 |
54 | #define MTHCA_RESET_VALUE swab32(1) | 60 | #define MTHCA_RESET_VALUE swab32(1) |
@@ -110,6 +116,9 @@ int mthca_reset(struct mthca_dev *mdev) | |||
110 | } | 116 | } |
111 | } | 117 | } |
112 | 118 | ||
119 | hca_pcix_cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX); | ||
120 | hca_pcie_cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP); | ||
121 | |||
113 | if (bridge) { | 122 | if (bridge) { |
114 | bridge_header = kmalloc(256, GFP_KERNEL); | 123 | bridge_header = kmalloc(256, GFP_KERNEL); |
115 | if (!bridge_header) { | 124 | if (!bridge_header) { |
@@ -129,6 +138,13 @@ int mthca_reset(struct mthca_dev *mdev) | |||
129 | goto out; | 138 | goto out; |
130 | } | 139 | } |
131 | } | 140 | } |
141 | bridge_pcix_cap = pci_find_capability(bridge, PCI_CAP_ID_PCIX); | ||
142 | if (!bridge_pcix_cap) { | ||
143 | err = -ENODEV; | ||
144 | mthca_err(mdev, "Couldn't locate HCA bridge " | ||
145 | "PCI-X capability, aborting.\n"); | ||
146 | goto out; | ||
147 | } | ||
132 | } | 148 | } |
133 | 149 | ||
134 | /* actually hit reset */ | 150 | /* actually hit reset */ |
@@ -178,6 +194,20 @@ int mthca_reset(struct mthca_dev *mdev) | |||
178 | good: | 194 | good: |
179 | /* Now restore the PCI headers */ | 195 | /* Now restore the PCI headers */ |
180 | if (bridge) { | 196 | if (bridge) { |
197 | if (pci_write_config_dword(bridge, bridge_pcix_cap + 0x8, | ||
198 | bridge_header[(bridge_pcix_cap + 0x8) / 4])) { | ||
199 | err = -ENODEV; | ||
200 | mthca_err(mdev, "Couldn't restore HCA bridge Upstream " | ||
201 | "split transaction control, aborting.\n"); | ||
202 | goto out; | ||
203 | } | ||
204 | if (pci_write_config_dword(bridge, bridge_pcix_cap + 0xc, | ||
205 | bridge_header[(bridge_pcix_cap + 0xc) / 4])) { | ||
206 | err = -ENODEV; | ||
207 | mthca_err(mdev, "Couldn't restore HCA bridge Downstream " | ||
208 | "split transaction control, aborting.\n"); | ||
209 | goto out; | ||
210 | } | ||
181 | /* | 211 | /* |
182 | * Bridge control register is at 0x3e, so we'll | 212 | * Bridge control register is at 0x3e, so we'll |
183 | * naturally restore it last in this loop. | 213 | * naturally restore it last in this loop. |
@@ -203,6 +233,35 @@ good: | |||
203 | } | 233 | } |
204 | } | 234 | } |
205 | 235 | ||
236 | if (hca_pcix_cap) { | ||
237 | if (pci_write_config_dword(mdev->pdev, hca_pcix_cap, | ||
238 | hca_header[hca_pcix_cap / 4])) { | ||
239 | err = -ENODEV; | ||
240 | mthca_err(mdev, "Couldn't restore HCA PCI-X " | ||
241 | "command register, aborting.\n"); | ||
242 | goto out; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | if (hca_pcie_cap) { | ||
247 | devctl = hca_header[(hca_pcie_cap + PCI_EXP_DEVCTL) / 4]; | ||
248 | if (pci_write_config_word(mdev->pdev, hca_pcie_cap + PCI_EXP_DEVCTL, | ||
249 | devctl)) { | ||
250 | err = -ENODEV; | ||
251 | mthca_err(mdev, "Couldn't restore HCA PCI Express " | ||
252 | "Device Control register, aborting.\n"); | ||
253 | goto out; | ||
254 | } | ||
255 | linkctl = hca_header[(hca_pcie_cap + PCI_EXP_LNKCTL) / 4]; | ||
256 | if (pci_write_config_word(mdev->pdev, hca_pcie_cap + PCI_EXP_LNKCTL, | ||
257 | linkctl)) { | ||
258 | err = -ENODEV; | ||
259 | mthca_err(mdev, "Couldn't restore HCA PCI Express " | ||
260 | "Link control register, aborting.\n"); | ||
261 | goto out; | ||
262 | } | ||
263 | } | ||
264 | |||
206 | for (i = 0; i < 16; ++i) { | 265 | for (i = 0; i < 16; ++i) { |
207 | if (i * 4 == PCI_COMMAND) | 266 | if (i * 4 == PCI_COMMAND) |
208 | continue; | 267 | continue; |