summaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci.c
diff options
context:
space:
mode:
authorAllen Kay <allen.m.kay@intel.com>2009-10-07 19:27:17 +0200
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-11-04 17:47:25 +0100
commitae21ee65e8bc228416bbcc8a1da01c56a847a60c (patch)
treecbcd109c764a8fed06f18a0a4bd3d63208405552 /drivers/pci/pci.c
parentxen: move Xen-testing predicates to common header (diff)
downloadlinux-ae21ee65e8bc228416bbcc8a1da01c56a847a60c.tar.xz
linux-ae21ee65e8bc228416bbcc8a1da01c56a847a60c.zip
PCI: acs p2p upsteram forwarding enabling
Note: dom0 checking in v4 has been separated out into 2/2. This patch enables P2P upstream forwarding in ACS capable PCIe switches. It solves two potential problems in virtualization environment where a PCIe device is assigned to a guest domain using a HW iommu such as VT-d: 1) Unintentional failure caused by guest physical address programmed into the device's DMA that happens to match the memory address range of other downstream ports in the same PCIe switch. This causes the PCI transaction to go to the matching downstream port instead of go to the root complex to get translated by VT-d as it should be. 2) Malicious guest software intentionally attacks another downstream PCIe device by programming the DMA address into the assigned device that matches memory address range of the downstream PCIe port. We are in process of implementing device filtering software in KVM/XEN management software to allow device assignment of PCIe devices behind a PCIe switch only if it has ACS capability and with the P2P upstream forwarding bits enabled. This patch is intended to work for both KVM and Xen environments. Signed-off-by: Allen Kay <allen.m.kay@intel.com> Reviewed-by: Mathew Wilcox <willy@linux.intel.com> Reviewed-by: Chris Wright <chris@sous-sol.org> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r--drivers/pci/pci.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 4859669f0ab5..557218222826 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1546,6 +1546,41 @@ void pci_enable_ari(struct pci_dev *dev)
}
/**
+ * pci_enable_acs - enable ACS if hardware support it
+ * @dev: the PCI device
+ */
+void pci_enable_acs(struct pci_dev *dev)
+{
+ int pos;
+ u16 cap;
+ u16 ctrl;
+
+ if (!dev->is_pcie)
+ return;
+
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
+ if (!pos)
+ return;
+
+ pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap);
+ pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
+
+ /* Source Validation */
+ ctrl |= (cap & PCI_ACS_SV);
+
+ /* P2P Request Redirect */
+ ctrl |= (cap & PCI_ACS_RR);
+
+ /* P2P Completion Redirect */
+ ctrl |= (cap & PCI_ACS_CR);
+
+ /* Upstream Forwarding */
+ ctrl |= (cap & PCI_ACS_UF);
+
+ pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
+}
+
+/**
* pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
* @dev: the PCI device
* @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD)