diff options
-rw-r--r-- | drivers/pci/pci.h | 1 | ||||
-rw-r--r-- | drivers/pci/probe.c | 14 | ||||
-rw-r--r-- | drivers/pci/search.c | 34 | ||||
-rw-r--r-- | include/linux/pci.h | 2 |
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 | ||
93 | 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 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 | ||
840 | static 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, ®16); | ||
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 | ||
16 | DECLARE_RWSEM(pci_bus_sem); | 16 | DECLARE_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 | */ | ||
24 | struct pci_dev * | ||
25 | pci_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 | ||
18 | static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr) | 52 | static 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 */ |