From 8266552af96d29de043b3fcddd5ce80f1be719e2 Mon Sep 17 00:00:00 2001 From: "Keshavamurthy, Anil S" Date: Sun, 21 Oct 2007 16:41:46 -0700 Subject: [PATCH] --- yaml --- r: 71967 b: refs/heads/master c: 994a65e25df85abc465cfee495557200e8205f9e h: refs/heads/master i: 71965: 301a54049dafee0f80027172e149593bbf89aa22 71963: 043b358d44c64cb45219024d5da626f72d969ab5 71959: b4f4935abfbf102307f9ec24bae6468facbcf30f 71951: 1e3d6a9504e184ed9b541042d565d5af2e843a0b 71935: a69fa14142e4dbea3c212c36ce2029b7dc6b7967 v: v3 --- [refs] | 2 +- trunk/drivers/pci/pci.h | 1 + trunk/drivers/pci/probe.c | 14 ++++++++++++++ trunk/drivers/pci/search.c | 34 ++++++++++++++++++++++++++++++++++ trunk/include/linux/pci.h | 2 ++ 5 files changed, 52 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index a0305f95347e..6a1f667ffa79 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 10e5247f40f3bf7508a0ed2848c9cae37bddf4bc +refs/heads/master: 994a65e25df85abc465cfee495557200e8205f9e diff --git a/trunk/drivers/pci/pci.h b/trunk/drivers/pci/pci.h index 6fda33de84e8..fc87e14b50de 100644 --- a/trunk/drivers/pci/pci.h +++ b/trunk/drivers/pci/pci.h @@ -90,3 +90,4 @@ pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev) return NULL; } +struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev); diff --git a/trunk/drivers/pci/probe.c b/trunk/drivers/pci/probe.c index 5db6b6690b59..463a5a9d583d 100644 --- a/trunk/drivers/pci/probe.c +++ b/trunk/drivers/pci/probe.c @@ -837,6 +837,19 @@ static void pci_release_dev(struct device *dev) kfree(pci_dev); } +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, ®16); + pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4; +} + /** * pci_cfg_space_size - get the configuration space size of the PCI device. * @dev: PCI device @@ -951,6 +964,7 @@ pci_scan_device(struct pci_bus *bus, int devfn) dev->device = (l >> 16) & 0xffff; 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/trunk/drivers/pci/search.c b/trunk/drivers/pci/search.c index c6e79d01ce3d..b001b5922e33 100644 --- a/trunk/drivers/pci/search.c +++ b/trunk/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 *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr) { diff --git a/trunk/include/linux/pci.h b/trunk/include/linux/pci.h index 768b93359f90..5d2281f661f7 100644 --- a/trunk/include/linux/pci.h +++ b/trunk/include/linux/pci.h @@ -141,6 +141,7 @@ struct pci_dev { unsigned int class; /* 3 bytes: (base,sub,prog-if) */ u8 revision; /* PCI revision, low byte of class word */ u8 hdr_type; /* PCI header type (`multi' flag masked out) */ + u8 pcie_type; /* PCI-E device/port type */ u8 rom_base_reg; /* which config register controls the ROM */ u8 pin; /* which interrupt pin this device uses */ @@ -183,6 +184,7 @@ struct pci_dev { unsigned int msi_enabled:1; unsigned int msix_enabled:1; unsigned int is_managed:1; + unsigned int is_pcie:1; atomic_t enable_cnt; /* pci_enable_device has been called */ u32 saved_config_space[16]; /* config space saved at suspend time */