1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28#include <linux/pci.h>
29#include <linux/export.h>
30#include <asm/pci-bridge.h>
31#include <asm/ppc-pci.h>
32#include <asm/firmware.h>
33#include <asm/eeh.h>
34
35#include "pseries.h"
36
37static struct pci_bus *
38find_bus_among_children(struct pci_bus *bus,
39 struct device_node *dn)
40{
41 struct pci_bus *child = NULL;
42 struct pci_bus *tmp;
43 struct device_node *busdn;
44
45 busdn = pci_bus_to_OF_node(bus);
46 if (busdn == dn)
47 return bus;
48
49 list_for_each_entry(tmp, &bus->children, node) {
50 child = find_bus_among_children(tmp, dn);
51 if (child)
52 break;
53 };
54 return child;
55}
56
57struct pci_bus *
58pcibios_find_pci_bus(struct device_node *dn)
59{
60 struct pci_dn *pdn = dn->data;
61
62 if (!pdn || !pdn->phb || !pdn->phb->bus)
63 return NULL;
64
65 return find_bus_among_children(pdn->phb->bus, dn);
66}
67EXPORT_SYMBOL_GPL(pcibios_find_pci_bus);
68
69struct pci_controller *init_phb_dynamic(struct device_node *dn)
70{
71 struct pci_controller *phb;
72
73 pr_debug("PCI: Initializing new hotplug PHB %s\n", dn->full_name);
74
75 phb = pcibios_alloc_controller(dn);
76 if (!phb)
77 return NULL;
78 rtas_setup_phb(phb);
79 pci_process_bridge_OF_ranges(phb, dn, 0);
80 phb->controller_ops = pseries_pci_controller_ops;
81
82 pci_devs_phb_init_dynamic(phb);
83
84
85 eeh_dev_phb_init_dynamic(phb);
86
87 if (dn->child)
88 eeh_add_device_tree_early(PCI_DN(dn));
89
90 pcibios_scan_phb(phb);
91 pcibios_finish_adding_to_bus(phb->bus);
92
93 return phb;
94}
95EXPORT_SYMBOL_GPL(init_phb_dynamic);
96
97
98int remove_phb_dynamic(struct pci_controller *phb)
99{
100 struct pci_bus *b = phb->bus;
101 struct resource *res;
102 int rc, i;
103
104 pr_debug("PCI: Removing PHB %04x:%02x...\n",
105 pci_domain_nr(b), b->number);
106
107
108 if (!(list_empty(&b->children) && list_empty(&b->devices)))
109 return -EBUSY;
110
111
112
113
114 res = &phb->io_resource;
115 if (res->flags & IORESOURCE_IO) {
116 rc = pcibios_unmap_io_space(b);
117 if (rc) {
118 printk(KERN_ERR "%s: failed to unmap IO on bus %s\n",
119 __func__, b->name);
120 return 1;
121 }
122 }
123
124
125 phb->bus = NULL;
126 pci_remove_bus(b);
127 device_unregister(b->bridge);
128
129
130 if (res->flags & IORESOURCE_IO)
131 release_resource(res);
132
133
134 for (i = 0; i < 3; ++i) {
135 res = &phb->mem_resources[i];
136 if (!(res->flags & IORESOURCE_MEM))
137 continue;
138 release_resource(res);
139 }
140
141
142
143
144
145
146
147 return 0;
148}
149EXPORT_SYMBOL_GPL(remove_phb_dynamic);
150