Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2133

kernel-2.6.18-238.el5.src.rpm

From: Don Dutile <ddutile@redhat.com>
Date: Fri, 24 Apr 2009 14:37:51 -0400
Subject: [misc] VT-d: add pci_find_upstream_pcie_bridge
Message-id: 49F206FF.3010607@redhat.com
O-Subject: [RHEL5.4 PATCH 2/6] VT-d for KVM: Add upstream's pci_find_upstream_pcie_bridge()
Bugzilla: 480411
RH-Acked-by: Rik van Riel <riel@redhat.com>

BZ 480411

Add upstream's pci_find_upstream_pcie_bridge()
     to common PCI code for use by Intel Vt-d.

Please review & ACK.

- Don

>From 252ba504f5aba7697756d4966ebdf7169860e0d9 Mon Sep 17 00:00:00 2001
From: Mark McLoughlin <markmc@redhat.com>
Date: Tue, 18 Nov 2008 10:30:56 +0000
Subject: [PATCH 2/6] vt-d: add pci_find_upstream_pcie_bridge()

Backport this cset:

  commit 994a65e25df85abc465cfee495557200e8205f9e
  Author: Keshavamurthy, Anil S <anil.s.keshavamurthy@intel.com>
  Date:   Sun Oct 21 16:41:46 2007 -0700

  Intel IOMMU: PCI generic helper function

  When devices are under a p2p bridge, upstream transactions get
  replaced by the device id of the bridge as it owns the PCIE
  transaction.  Hence its necessary to setup translations on behalf
  of the bridge as well.  Due to this limitation all devices under
  a p2p share the same domain in a DMAR.

  We just cache the type of device, if its a native PCIe device or
  not for later use.

The addition of pci_dev::pcie_type and pci_dev::is_pci needs
careful validation wrt. kABI implications. It looks like there's
room for both, though.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>

diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 0e97265..8c8e51c 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -163,3 +163,4 @@ static inline int pci_iov_bus_range(struct pci_bus *bus)
 	return 0;
 }
 #endif /* CONFIG_PCI_IOV */
+struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 255b1bc..e378ffe 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -688,6 +688,19 @@ static void pci_read_irq(struct pci_dev *dev)
 	dev->irq = irq;
 }
 
+static void set_pcie_port_type(struct pci_dev *pdev)
+{
+	int pos;
+	u16 reg16;
+
+	pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+	if (!pos)
+		return;
+	pdev->is_pcie = 1;
+	pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
+	pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4;
+}
+
 /**
  * pci_setup_device - fill in class and map information of a device
  * @dev: the device structure to fill
@@ -713,6 +726,7 @@ int pci_setup_device(struct pci_dev * dev)
 	dev->multifunction = !!(hdr_type & 0x80);
 	dev->cfg_size = pci_cfg_space_size(dev);
 	dev->error_state = pci_channel_io_normal;
+	set_pcie_port_type(dev);
 
 	/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
 	   set this higher, assuming the system even supports it.  */
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 6473e96..55962e7 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -14,6 +14,40 @@
 #include "pci.h"
 
 DECLARE_RWSEM(pci_bus_sem);
+/*
+ * find the upstream PCIE-to-PCI bridge of a PCI device
+ * if the device is PCIE, return NULL
+ * if the device isn't connected to a PCIE bridge (that is its parent is a
+ * legacy PCI bridge and the bridge is directly connected to bus 0), return its
+ * parent
+ */
+struct pci_dev *
+pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
+{
+	struct pci_dev *tmp = NULL;
+
+	if (pdev->is_pcie)
+		return NULL;
+	while (1) {
+		if (!pdev->bus->self)
+			break;
+		pdev = pdev->bus->self;
+		/* a p2p bridge */
+		if (!pdev->is_pcie) {
+			tmp = pdev;
+			continue;
+		}
+		/* PCI device should connect to a PCIE bridge */
+		if (pdev->pcie_type != PCI_EXP_TYPE_PCI_BRIDGE) {
+			/* Busted hardware? */
+			WARN_ON_ONCE(1);
+			return NULL;
+		}
+		return pdev;
+	}
+
+	return tmp;
+}
 
 static struct pci_bus * __devinit
 pci_do_find_bus(struct pci_bus* bus, unsigned char busnr)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 0e2359e..0db1dff 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -140,6 +140,9 @@ struct pci_dev {
 	u8		hdr_type;	/* PCI header type (`multi' flag masked out) */
 	u8		rom_base_reg;	/* which config register controls the ROM */
 	u8		pin;  		/* which interrupt pin this device uses */
+#ifndef __GENKSYMS__
+	u8		pcie_type;	/* PCI-E device/port type */
+#endif
 
 	struct pci_driver *driver;	/* which driver has allocated this device */
 	u64		dma_mask;	/* Mask of the bits of bus address this
@@ -185,6 +188,7 @@ struct pci_dev {
 	unsigned int	is_managed:1;
 	unsigned int	is_physfn:1;
 	unsigned int	is_virtfn:1;
+	unsigned int	is_pcie:1;
 #endif
 
 	u32		saved_config_space[16]; /* config space saved at suspend time */