aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/quirks.c
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2012-06-11 01:27:07 -0400
committerBjorn Helgaas <bhelgaas@google.com>2012-06-12 11:21:42 -0400
commitad805758c0eb25bce7b2e3b298d63dc62a1bc71c (patch)
tree031c42d1537e9ee25b7392a652a7799c3914c972 /drivers/pci/quirks.c
parent12ea6cad1c7d046e21decc18b0e2170c6794dc51 (diff)
PCI: add ACS validation utility
In a PCI environment, transactions aren't always required to reach the root bus before being re-routed. Intermediate switches between an endpoint and the root bus can redirect DMA back downstream before things like IOMMUs have a chance to intervene. Legacy PCI is always susceptible to this as it operates on a shared bus. PCIe added a new capability to describe and control this behavior, Access Control Services, or ACS. The utility function pci_acs_enabled() allows us to test the ACS capabilities of an individual devices against a set of flags while pci_acs_path_enabled() tests a complete path from a given downstream device up to the specified upstream device. We also include the ability to add device specific tests as it's likely we'll see devices that do not implement ACS, but want to indicate support for various capabilities in this space. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci/quirks.c')
-rw-r--r--drivers/pci/quirks.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index acd3956b44bd..27e2c8f4ec73 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3230,3 +3230,36 @@ struct pci_dev *pci_get_dma_source(struct pci_dev *dev)
3230 3230
3231 return pci_dev_get(dev); 3231 return pci_dev_get(dev);
3232} 3232}
3233
3234static const struct pci_dev_acs_enabled {
3235 u16 vendor;
3236 u16 device;
3237 int (*acs_enabled)(struct pci_dev *dev, u16 acs_flags);
3238} pci_dev_acs_enabled[] = {
3239 { 0 }
3240};
3241
3242int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags)
3243{
3244 const struct pci_dev_acs_enabled *i;
3245 int ret;
3246
3247 /*
3248 * Allow devices that do not expose standard PCIe ACS capabilities
3249 * or control to indicate their support here. Multi-function express
3250 * devices which do not allow internal peer-to-peer between functions,
3251 * but do not implement PCIe ACS may wish to return true here.
3252 */
3253 for (i = pci_dev_acs_enabled; i->acs_enabled; i++) {
3254 if ((i->vendor == dev->vendor ||
3255 i->vendor == (u16)PCI_ANY_ID) &&
3256 (i->device == dev->device ||
3257 i->device == (u16)PCI_ANY_ID)) {
3258 ret = i->acs_enabled(dev, acs_flags);
3259 if (ret >= 0)
3260 return ret;
3261 }
3262 }
3263
3264 return -ENOTTY;
3265}