PCI: fix ARI code to be compatible with mixed ARI/non-ARI systems

The original ARI support code has a compatibility problem with non-ARI
devices. If a device doesn't support ARI, turning on ARI forwarding on
its upper level bridge will cause undefined behavior.

This fix turns on ARI forwarding only when the subordinate devices
support it.

Tested-by: Suresh Siddha <suresh.b.siddha@intel.com>
Signed-off-by: Yu Zhao <yu.zhao@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>

authored by Zhao, Yu and committed by Jesse Barnes 8113587c d2174c3c

+15 -10
+15 -10
drivers/pci/pci.c
··· 1309 int pos; 1310 u32 cap; 1311 u16 ctrl; 1312 1313 - if (!dev->is_pcie) 1314 return; 1315 1316 - if (dev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && 1317 - dev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) 1318 - return; 1319 - 1320 - pos = pci_find_capability(dev, PCI_CAP_ID_EXP); 1321 if (!pos) 1322 return; 1323 1324 - pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP2, &cap); 1325 if (!(cap & PCI_EXP_DEVCAP2_ARI)) 1326 return; 1327 1328 - pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &ctrl); 1329 ctrl |= PCI_EXP_DEVCTL2_ARI; 1330 - pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, ctrl); 1331 1332 - dev->ari_enabled = 1; 1333 } 1334 1335 int
··· 1309 int pos; 1310 u32 cap; 1311 u16 ctrl; 1312 + struct pci_dev *bridge; 1313 1314 + if (!dev->is_pcie || dev->devfn) 1315 return; 1316 1317 + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI); 1318 if (!pos) 1319 return; 1320 1321 + bridge = dev->bus->self; 1322 + if (!bridge || !bridge->is_pcie) 1323 + return; 1324 + 1325 + pos = pci_find_capability(bridge, PCI_CAP_ID_EXP); 1326 + if (!pos) 1327 + return; 1328 + 1329 + pci_read_config_dword(bridge, pos + PCI_EXP_DEVCAP2, &cap); 1330 if (!(cap & PCI_EXP_DEVCAP2_ARI)) 1331 return; 1332 1333 + pci_read_config_word(bridge, pos + PCI_EXP_DEVCTL2, &ctrl); 1334 ctrl |= PCI_EXP_DEVCTL2_ARI; 1335 + pci_write_config_word(bridge, pos + PCI_EXP_DEVCTL2, ctrl); 1336 1337 + bridge->ari_enabled = 1; 1338 } 1339 1340 int