diff options
Diffstat (limited to 'drivers/pci/search.c')
-rw-r--r-- | drivers/pci/search.c | 34 |
1 files changed, 34 insertions, 0 deletions
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 | { |