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 447e83472c01..1ccf7d49f522 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2360,6 +2360,75 @@ void pci_enable_acs(struct pci_dev *dev)
2360} 2360}
2361 2361
2362/** 2362/**
2363 * pci_acs_enabled - test ACS against required flags for a given device
2364 * @pdev: device to test
2365 * @acs_flags: required PCI ACS flags
2366 *
2367 * Return true if the device supports the provided flags. Automatically
2368 * filters out flags that are not implemented on multifunction devices.
2369 */
2370bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags)
2371{
2372 int pos, ret;
2373 u16 ctrl;
2374
2375 ret = pci_dev_specific_acs_enabled(pdev, acs_flags);
2376 if (ret >= 0)
2377 return ret > 0;
2378
2379 if (!pci_is_pcie(pdev))
2380 return false;
2381
2382 /* Filter out flags not applicable to multifunction */
2383 if (pdev->multifunction)
2384 acs_flags &= (PCI_ACS_RR | PCI_ACS_CR |
2385 PCI_ACS_EC | PCI_ACS_DT);
2386
2387 if (pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM ||
2388 pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
2389 pdev->multifunction) {
2390 pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS);
2391 if (!pos)
2392 return false;
2393
2394 pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl);
2395 if ((ctrl & acs_flags) != acs_flags)
2396 return false;
2397 }
2398
2399 return true;
2400}
2401
2402/**
2403 * pci_acs_path_enable - test ACS flags from start to end in a hierarchy
2404 * @start: starting downstream device
2405 * @end: ending upstream device or NULL to search to the root bus
2406 * @acs_flags: required flags
2407 *
2408 * Walk up a device tree from start to end testing PCI ACS support. If
2409 * any step along the way does not support the required flags, return false.
2410 */
2411bool pci_acs_path_enabled(struct pci_dev *start,
2412 struct pci_dev *end, u16 acs_flags)
2413{
2414 struct pci_dev *pdev, *parent = start;
2415
2416 do {
2417 pdev = parent;
2418
2419 if (!pci_acs_enabled(pdev, acs_flags))
2420 return false;
2421
2422 if (pci_is_root_bus(pdev->bus))
2423 return (end == NULL);
2424
2425 parent = pdev->bus->self;
2426 } while (pdev != end);
2427
2428 return true;
2429}
2430
2431/**
2363 * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge 2432 * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
2364 * @dev: the PCI device 2433 * @dev: the PCI device
2365 * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD) 2434 * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD)