aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/pci.h1
-rw-r--r--drivers/pci/probe.c14
-rw-r--r--drivers/pci/search.c34
-rw-r--r--include/linux/pci.h2
4 files changed, 51 insertions, 0 deletions
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 6fda33de84e8..fc87e14b50de 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -90,3 +90,4 @@ pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
90 return NULL; 90 return NULL;
91} 91}
92 92
93struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 5db6b6690b59..463a5a9d583d 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -837,6 +837,19 @@ static void pci_release_dev(struct device *dev)
837 kfree(pci_dev); 837 kfree(pci_dev);
838} 838}
839 839
840static void set_pcie_port_type(struct pci_dev *pdev)
841{
842 int pos;
843 u16 reg16;
844
845 pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
846 if (!pos)
847 return;
848 pdev->is_pcie = 1;
849 pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
850 pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4;
851}
852
840/** 853/**
841 * pci_cfg_space_size - get the configuration space size of the PCI device. 854 * pci_cfg_space_size - get the configuration space size of the PCI device.
842 * @dev: PCI device 855 * @dev: PCI device
@@ -951,6 +964,7 @@ pci_scan_device(struct pci_bus *bus, int devfn)
951 dev->device = (l >> 16) & 0xffff; 964 dev->device = (l >> 16) & 0xffff;
952 dev->cfg_size = pci_cfg_space_size(dev); 965 dev->cfg_size = pci_cfg_space_size(dev);
953 dev->error_state = pci_channel_io_normal; 966 dev->error_state = pci_channel_io_normal;
967 set_pcie_port_type(dev);
954 968
955 /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer) 969 /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
956 set this higher, assuming the system even supports it. */ 970 set this higher, assuming the system even supports it. */
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index c6e79d01ce3d..b001b5922e33 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -14,6 +14,40 @@
14#include "pci.h" 14#include "pci.h"
15 15
16DECLARE_RWSEM(pci_bus_sem); 16DECLARE_RWSEM(pci_bus_sem);
17/*
18 * find the upstream PCIE-to-PCI bridge of a PCI device
19 * if the device is PCIE, return NULL
20 * if the device isn't connected to a PCIE bridge (that is its parent is a
21 * legacy PCI bridge and the bridge is directly connected to bus 0), return its
22 * parent
23 */
24struct pci_dev *
25pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
26{
27 struct pci_dev *tmp = NULL;
28
29 if (pdev->is_pcie)
30 return NULL;
31 while (1) {
32 if (!pdev->bus->self)
33 break;
34 pdev = pdev->bus->self;
35 /* a p2p bridge */
36 if (!pdev->is_pcie) {
37 tmp = pdev;
38 continue;
39 }
40 /* PCI device should connect to a PCIE bridge */
41 if (pdev->pcie_type != PCI_EXP_TYPE_PCI_BRIDGE) {
42 /* Busted hardware? */
43 WARN_ON_ONCE(1);
44 return NULL;
45 }
46 return pdev;
47 }
48
49 return tmp;
50}
17 51
18static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr) 52static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr)
19{ 53{
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 768b93359f90..5d2281f661f7 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -141,6 +141,7 @@ struct pci_dev {
141 unsigned int class; /* 3 bytes: (base,sub,prog-if) */ 141 unsigned int class; /* 3 bytes: (base,sub,prog-if) */
142 u8 revision; /* PCI revision, low byte of class word */ 142 u8 revision; /* PCI revision, low byte of class word */
143 u8 hdr_type; /* PCI header type (`multi' flag masked out) */ 143 u8 hdr_type; /* PCI header type (`multi' flag masked out) */
144 u8 pcie_type; /* PCI-E device/port type */
144 u8 rom_base_reg; /* which config register controls the ROM */ 145 u8 rom_base_reg; /* which config register controls the ROM */
145 u8 pin; /* which interrupt pin this device uses */ 146 u8 pin; /* which interrupt pin this device uses */
146 147
@@ -183,6 +184,7 @@ struct pci_dev {
183 unsigned int msi_enabled:1; 184 unsigned int msi_enabled:1;
184 unsigned int msix_enabled:1; 185 unsigned int msix_enabled:1;
185 unsigned int is_managed:1; 186 unsigned int is_managed:1;
187 unsigned int is_pcie:1;
186 atomic_t enable_cnt; /* pci_enable_device has been called */ 188 atomic_t enable_cnt; /* pci_enable_device has been called */
187 189
188 u32 saved_config_space[16]; /* config space saved at suspend time */ 190 u32 saved_config_space[16]; /* config space saved at suspend time */