aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r--drivers/pci/pci.c69
1 files changed, 69 insertions, 0 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index a23b071798f6..b743a9afb4dd 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2293,6 +2293,75 @@ void pci_enable_acs(struct pci_dev *dev)
2293} 2293}
2294 2294
2295/** 2295/**
2296 * pci_acs_enabled - test ACS against required flags for a given device
2297 * @pdev: device to test
2298 * @acs_flags: required PCI ACS flags
2299 *
2300 * Return true if the device supports the provided flags. Automatically
2301 * filters out flags that are not implemented on multifunction devices.
2302 */
2303bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags)
2304{
2305 int pos, ret;
2306 u16 ctrl;
2307
2308 ret = pci_dev_specific_acs_enabled(pdev, acs_flags);
2309 if (ret >= 0)
2310 return ret > 0;
2311
2312 if (!pci_is_pcie(pdev))
2313 return false;
2314
2315 /* Filter out flags not applicable to multifunction */
2316 if (pdev->multifunction)
2317 acs_flags &= (PCI_ACS_RR | PCI_ACS_CR |
2318 PCI_ACS_EC | PCI_ACS_DT);
2319
2320 if (pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM ||
2321 pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
2322 pdev->multifunction) {
2323 pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS);
2324 if (!pos)
2325 return false;
2326
2327 pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl);
2328 if ((ctrl & acs_flags) != acs_flags)
2329 return false;
2330 }
2331
2332 return true;
2333}
2334
2335/**
2336 * pci_acs_path_enable - test ACS flags from start to end in a hierarchy
2337 * @start: starting downstream device
2338 * @end: ending upstream device or NULL to search to the root bus
2339 * @acs_flags: required flags
2340 *
2341 * Walk up a device tree from start to end testing PCI ACS support. If
2342 * any step along the way does not support the required flags, return false.
2343 */
2344bool pci_acs_path_enabled(struct pci_dev *start,
2345 struct pci_dev *end, u16 acs_flags)
2346{
2347 struct pci_dev *pdev, *parent = start;
2348
2349 do {
2350 pdev = parent;
2351
2352 if (!pci_acs_enabled(pdev, acs_flags))
2353 return false;
2354
2355 if (pci_is_root_bus(pdev->bus))
2356 return (end == NULL);
2357
2358 parent = pdev->bus->self;
2359 } while (pdev != end);
2360
2361 return true;
2362}
2363
2364/**
2296 * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge 2365 * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
2297 * @dev: the PCI device 2366 * @dev: the PCI device
2298 * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD) 2367 * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD)