aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAllen Kay <allen.m.kay@intel.com>2009-10-07 13:27:17 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-11-04 11:47:25 -0500
commitae21ee65e8bc228416bbcc8a1da01c56a847a60c (patch)
treecbcd109c764a8fed06f18a0a4bd3d63208405552
parent1ccbf5344c3daef046d2323190cc6807c44f1917 (diff)
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>
-rw-r--r--drivers/pci/pci.c35
-rw-r--r--drivers/pci/pci.h2
-rw-r--r--drivers/pci/probe.c5
-rw-r--r--include/linux/pci_regs.h13
4 files changed, 55 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)
1546} 1546}
1547 1547
1548/** 1548/**
1549 * pci_enable_acs - enable ACS if hardware support it
1550 * @dev: the PCI device
1551 */
1552void pci_enable_acs(struct pci_dev *dev)
1553{
1554 int pos;
1555 u16 cap;
1556 u16 ctrl;
1557
1558 if (!dev->is_pcie)
1559 return;
1560
1561 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
1562 if (!pos)
1563 return;
1564
1565 pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap);
1566 pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
1567
1568 /* Source Validation */
1569 ctrl |= (cap & PCI_ACS_SV);
1570
1571 /* P2P Request Redirect */
1572 ctrl |= (cap & PCI_ACS_RR);
1573
1574 /* P2P Completion Redirect */
1575 ctrl |= (cap & PCI_ACS_CR);
1576
1577 /* Upstream Forwarding */
1578 ctrl |= (cap & PCI_ACS_UF);
1579
1580 pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
1581}
1582
1583/**
1549 * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge 1584 * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
1550 * @dev: the PCI device 1585 * @dev: the PCI device
1551 * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD) 1586 * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index d92d1954a2fb..33ed8e0aba1e 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -311,4 +311,6 @@ static inline int pci_resource_alignment(struct pci_dev *dev,
311 return resource_alignment(res); 311 return resource_alignment(res);
312} 312}
313 313
314extern void pci_enable_acs(struct pci_dev *dev);
315
314#endif /* DRIVERS_PCI_H */ 316#endif /* DRIVERS_PCI_H */
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 2adb47574d86..aac5b156a5c5 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -10,6 +10,7 @@
10#include <linux/module.h> 10#include <linux/module.h>
11#include <linux/cpumask.h> 11#include <linux/cpumask.h>
12#include <linux/pci-aspm.h> 12#include <linux/pci-aspm.h>
13#include <linux/iommu.h>
13#include "pci.h" 14#include "pci.h"
14 15
15#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ 16#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */
@@ -1004,6 +1005,10 @@ static void pci_init_capabilities(struct pci_dev *dev)
1004 1005
1005 /* Single Root I/O Virtualization */ 1006 /* Single Root I/O Virtualization */
1006 pci_iov_init(dev); 1007 pci_iov_init(dev);
1008
1009 /* Enable ACS P2P upstream forwarding */
1010 if (iommu_found())
1011 pci_enable_acs(dev);
1007} 1012}
1008 1013
1009void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) 1014void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index dd0bed4f1cf0..d798770f08cd 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -502,6 +502,7 @@
502#define PCI_EXT_CAP_ID_VC 2 502#define PCI_EXT_CAP_ID_VC 2
503#define PCI_EXT_CAP_ID_DSN 3 503#define PCI_EXT_CAP_ID_DSN 3
504#define PCI_EXT_CAP_ID_PWR 4 504#define PCI_EXT_CAP_ID_PWR 4
505#define PCI_EXT_CAP_ID_ACS 13
505#define PCI_EXT_CAP_ID_ARI 14 506#define PCI_EXT_CAP_ID_ARI 14
506#define PCI_EXT_CAP_ID_ATS 15 507#define PCI_EXT_CAP_ID_ATS 15
507#define PCI_EXT_CAP_ID_SRIOV 16 508#define PCI_EXT_CAP_ID_SRIOV 16
@@ -662,4 +663,16 @@
662#define PCI_SRIOV_VFM_MO 0x2 /* Active.MigrateOut */ 663#define PCI_SRIOV_VFM_MO 0x2 /* Active.MigrateOut */
663#define PCI_SRIOV_VFM_AV 0x3 /* Active.Available */ 664#define PCI_SRIOV_VFM_AV 0x3 /* Active.Available */
664 665
666/* Access Control Service */
667#define PCI_ACS_CAP 0x04 /* ACS Capability Register */
668#define PCI_ACS_SV 0x01 /* Source Validation */
669#define PCI_ACS_TB 0x02 /* Translation Blocking */
670#define PCI_ACS_RR 0x04 /* P2P Request Redirect */
671#define PCI_ACS_CR 0x08 /* P2P Completion Redirect */
672#define PCI_ACS_UF 0x10 /* Upstream Forwarding */
673#define PCI_ACS_EC 0x20 /* P2P Egress Control */
674#define PCI_ACS_DT 0x40 /* Direct Translated P2P */
675#define PCI_ACS_CTRL 0x06 /* ACS Control Register */
676#define PCI_ACS_EGRESS_CTL_V 0x08 /* ACS Egress Control Vector */
677
665#endif /* LINUX_PCI_REGS_H */ 678#endif /* LINUX_PCI_REGS_H */