Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Michael S. Tsirkin and committed by
Roland Dreier
13aa6ecb 427abfa2

+59
+59
drivers/infiniband/hw/mthca/mthca_reset.c
··· 49 49 u32 *hca_header = NULL; 50 50 u32 *bridge_header = NULL; 51 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 59 #define MTHCA_RESET_OFFSET 0xf0010 54 60 #define MTHCA_RESET_VALUE swab32(1) ··· 116 110 } 117 111 } 118 112 113 + hca_pcix_cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX); 114 + hca_pcie_cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP); 115 + 119 116 if (bridge) { 120 117 bridge_header = kmalloc(256, GFP_KERNEL); 121 118 if (!bridge_header) { ··· 137 128 "PCI header, aborting.\n"); 138 129 goto out; 139 130 } 131 + } 132 + bridge_pcix_cap = pci_find_capability(bridge, PCI_CAP_ID_PCIX); 133 + if (!bridge_pcix_cap) { 134 + err = -ENODEV; 135 + mthca_err(mdev, "Couldn't locate HCA bridge " 136 + "PCI-X capability, aborting.\n"); 137 + goto out; 140 138 } 141 139 } 142 140 ··· 194 178 good: 195 179 /* Now restore the PCI headers */ 196 180 if (bridge) { 181 + if (pci_write_config_dword(bridge, bridge_pcix_cap + 0x8, 182 + bridge_header[(bridge_pcix_cap + 0x8) / 4])) { 183 + err = -ENODEV; 184 + mthca_err(mdev, "Couldn't restore HCA bridge Upstream " 185 + "split transaction control, aborting.\n"); 186 + goto out; 187 + } 188 + if (pci_write_config_dword(bridge, bridge_pcix_cap + 0xc, 189 + bridge_header[(bridge_pcix_cap + 0xc) / 4])) { 190 + err = -ENODEV; 191 + mthca_err(mdev, "Couldn't restore HCA bridge Downstream " 192 + "split transaction control, aborting.\n"); 193 + goto out; 194 + } 197 195 /* 198 196 * Bridge control register is at 0x3e, so we'll 199 197 * naturally restore it last in this loop. ··· 229 199 err = -ENODEV; 230 200 mthca_err(mdev, "Couldn't restore HCA bridge COMMAND, " 231 201 "aborting.\n"); 202 + goto out; 203 + } 204 + } 205 + 206 + if (hca_pcix_cap) { 207 + if (pci_write_config_dword(mdev->pdev, hca_pcix_cap, 208 + hca_header[hca_pcix_cap / 4])) { 209 + err = -ENODEV; 210 + mthca_err(mdev, "Couldn't restore HCA PCI-X " 211 + "command register, aborting.\n"); 212 + goto out; 213 + } 214 + } 215 + 216 + if (hca_pcie_cap) { 217 + devctl = hca_header[(hca_pcie_cap + PCI_EXP_DEVCTL) / 4]; 218 + if (pci_write_config_word(mdev->pdev, hca_pcie_cap + PCI_EXP_DEVCTL, 219 + devctl)) { 220 + err = -ENODEV; 221 + mthca_err(mdev, "Couldn't restore HCA PCI Express " 222 + "Device Control register, aborting.\n"); 223 + goto out; 224 + } 225 + linkctl = hca_header[(hca_pcie_cap + PCI_EXP_LNKCTL) / 4]; 226 + if (pci_write_config_word(mdev->pdev, hca_pcie_cap + PCI_EXP_LNKCTL, 227 + linkctl)) { 228 + err = -ENODEV; 229 + mthca_err(mdev, "Couldn't restore HCA PCI Express " 230 + "Link control register, aborting.\n"); 232 231 goto out; 233 232 } 234 233 }