Merge branch 'topic/alex-vfio-prep' into next
* topic/alex-vfio-prep: PCI: misc pci_reg additions PCI: create common pcibios_err_to_errno PCI: export pci_user functions for use by other drivers PCI: add ACS validation utility PCI: add PCI DMA source ID quirk
This commit is contained in:
@@ -2292,6 +2292,75 @@ void pci_enable_acs(struct pci_dev *dev)
|
||||
pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_acs_enabled - test ACS against required flags for a given device
|
||||
* @pdev: device to test
|
||||
* @acs_flags: required PCI ACS flags
|
||||
*
|
||||
* Return true if the device supports the provided flags. Automatically
|
||||
* filters out flags that are not implemented on multifunction devices.
|
||||
*/
|
||||
bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags)
|
||||
{
|
||||
int pos, ret;
|
||||
u16 ctrl;
|
||||
|
||||
ret = pci_dev_specific_acs_enabled(pdev, acs_flags);
|
||||
if (ret >= 0)
|
||||
return ret > 0;
|
||||
|
||||
if (!pci_is_pcie(pdev))
|
||||
return false;
|
||||
|
||||
/* Filter out flags not applicable to multifunction */
|
||||
if (pdev->multifunction)
|
||||
acs_flags &= (PCI_ACS_RR | PCI_ACS_CR |
|
||||
PCI_ACS_EC | PCI_ACS_DT);
|
||||
|
||||
if (pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM ||
|
||||
pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
|
||||
pdev->multifunction) {
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS);
|
||||
if (!pos)
|
||||
return false;
|
||||
|
||||
pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl);
|
||||
if ((ctrl & acs_flags) != acs_flags)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_acs_path_enable - test ACS flags from start to end in a hierarchy
|
||||
* @start: starting downstream device
|
||||
* @end: ending upstream device or NULL to search to the root bus
|
||||
* @acs_flags: required flags
|
||||
*
|
||||
* Walk up a device tree from start to end testing PCI ACS support. If
|
||||
* any step along the way does not support the required flags, return false.
|
||||
*/
|
||||
bool pci_acs_path_enabled(struct pci_dev *start,
|
||||
struct pci_dev *end, u16 acs_flags)
|
||||
{
|
||||
struct pci_dev *pdev, *parent = start;
|
||||
|
||||
do {
|
||||
pdev = parent;
|
||||
|
||||
if (!pci_acs_enabled(pdev, acs_flags))
|
||||
return false;
|
||||
|
||||
if (pci_is_root_bus(pdev->bus))
|
||||
return (end == NULL);
|
||||
|
||||
parent = pdev->bus->self;
|
||||
} while (pdev != end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
|
||||
* @dev: the PCI device
|
||||
|
Reference in New Issue
Block a user