diff options
-rw-r--r-- | drivers/pci/hotplug/rpadlpar_core.c | 79 | ||||
-rw-r--r-- | drivers/pci/hotplug/rpaphp.h | 2 | ||||
-rw-r--r-- | drivers/pci/hotplug/rpaphp_pci.c | 76 |
3 files changed, 81 insertions, 76 deletions
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index e8593a60ee89..cc03609f45d0 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c | |||
@@ -134,43 +134,6 @@ static void rpadlpar_claim_one_bus(struct pci_bus *b) | |||
134 | rpadlpar_claim_one_bus(child_bus); | 134 | rpadlpar_claim_one_bus(child_bus); |
135 | } | 135 | } |
136 | 136 | ||
137 | static int pci_add_secondary_bus(struct device_node *dn, | ||
138 | struct pci_dev *bridge_dev) | ||
139 | { | ||
140 | struct pci_dn *pdn = dn->data; | ||
141 | struct pci_controller *hose = pdn->phb; | ||
142 | struct pci_bus *child; | ||
143 | u8 sec_busno; | ||
144 | |||
145 | /* Get busno of downstream bus */ | ||
146 | pci_read_config_byte(bridge_dev, PCI_SECONDARY_BUS, &sec_busno); | ||
147 | |||
148 | /* Allocate and add to children of bridge_dev->bus */ | ||
149 | child = pci_add_new_bus(bridge_dev->bus, bridge_dev, sec_busno); | ||
150 | if (!child) { | ||
151 | printk(KERN_ERR "%s: could not add secondary bus\n", __FUNCTION__); | ||
152 | return -ENOMEM; | ||
153 | } | ||
154 | |||
155 | sprintf(child->name, "PCI Bus #%02x", child->number); | ||
156 | |||
157 | /* Fixup subordinate bridge bases and resources */ | ||
158 | pcibios_fixup_bus(child); | ||
159 | |||
160 | /* Claim new bus resources */ | ||
161 | rpadlpar_claim_one_bus(bridge_dev->bus); | ||
162 | |||
163 | if (hose->last_busno < child->number) | ||
164 | hose->last_busno = child->number; | ||
165 | |||
166 | pdn->bussubno = child->number; | ||
167 | |||
168 | /* ioremap() for child bus, which may or may not succeed */ | ||
169 | remap_bus_range(child); | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static struct pci_dev *dlpar_find_new_dev(struct pci_bus *parent, | 137 | static struct pci_dev *dlpar_find_new_dev(struct pci_bus *parent, |
175 | struct device_node *dev_dn) | 138 | struct device_node *dev_dn) |
176 | { | 139 | { |
@@ -188,29 +151,41 @@ static struct pci_dev *dlpar_find_new_dev(struct pci_bus *parent, | |||
188 | static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn) | 151 | static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn) |
189 | { | 152 | { |
190 | struct pci_dn *pdn = dn->data; | 153 | struct pci_dn *pdn = dn->data; |
191 | struct pci_controller *hose = pdn->phb; | 154 | struct pci_controller *phb = pdn->phb; |
192 | struct pci_dev *dev = NULL; | 155 | struct pci_dev *dev = NULL; |
193 | 156 | ||
194 | /* Scan phb bus for EADS device, adding new one to bus->devices */ | 157 | rpaphp_eeh_init_nodes(dn); |
195 | if (!pci_scan_single_device(hose->bus, pdn->devfn)) { | 158 | /* Add EADS device to PHB bus, adding new entry to bus->devices */ |
196 | printk(KERN_ERR "%s: found no device on bus\n", __FUNCTION__); | 159 | dev = of_create_pci_dev(dn, phb->bus, pdn->devfn); |
160 | if (!dev) { | ||
161 | printk(KERN_ERR "%s: failed to create pci dev for %s\n", | ||
162 | __FUNCTION__, dn->full_name); | ||
197 | return NULL; | 163 | return NULL; |
198 | } | 164 | } |
199 | 165 | ||
166 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || | ||
167 | dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) | ||
168 | of_scan_pci_bridge(dn, dev); | ||
169 | |||
170 | rpaphp_init_new_devs(dev->subordinate); | ||
171 | |||
172 | /* Claim new bus resources */ | ||
173 | rpadlpar_claim_one_bus(dev->bus); | ||
174 | |||
175 | /* ioremap() for child bus, which may or may not succeed */ | ||
176 | (void) remap_bus_range(dev->bus); | ||
177 | |||
200 | /* Add new devices to global lists. Register in proc, sysfs. */ | 178 | /* Add new devices to global lists. Register in proc, sysfs. */ |
201 | pci_bus_add_devices(hose->bus); | 179 | pci_bus_add_devices(phb->bus); |
202 | 180 | ||
203 | /* Confirm new bridge dev was created */ | 181 | /* Confirm new bridge dev was created */ |
204 | dev = dlpar_find_new_dev(hose->bus, dn); | 182 | dev = dlpar_find_new_dev(phb->bus, dn); |
205 | if (dev) { | 183 | if (dev) { |
206 | if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { | 184 | if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { |
207 | printk(KERN_ERR "%s: unexpected header type %d\n", | 185 | printk(KERN_ERR "%s: unexpected header type %d\n", |
208 | __FUNCTION__, dev->hdr_type); | 186 | __FUNCTION__, dev->hdr_type); |
209 | return NULL; | 187 | return NULL; |
210 | } | 188 | } |
211 | |||
212 | if (pci_add_secondary_bus(dn, dev)) | ||
213 | return NULL; | ||
214 | } | 189 | } |
215 | 190 | ||
216 | return dev; | 191 | return dev; |
@@ -219,7 +194,6 @@ static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn) | |||
219 | static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn) | 194 | static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn) |
220 | { | 195 | { |
221 | struct pci_dev *dev; | 196 | struct pci_dev *dev; |
222 | int rc; | ||
223 | 197 | ||
224 | if (rpaphp_find_pci_bus(dn)) | 198 | if (rpaphp_find_pci_bus(dn)) |
225 | return -EINVAL; | 199 | return -EINVAL; |
@@ -232,15 +206,6 @@ static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn) | |||
232 | return -EIO; | 206 | return -EIO; |
233 | } | 207 | } |
234 | 208 | ||
235 | if (dn->child) { | ||
236 | rc = rpaphp_config_pci_adapter(dev->subordinate); | ||
237 | if (rc < 0) { | ||
238 | printk(KERN_ERR "%s: unable to enable slot %s\n", | ||
239 | __FUNCTION__, drc_name); | ||
240 | return -EIO; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | /* Add hotplug slot */ | 209 | /* Add hotplug slot */ |
245 | if (rpaphp_add_slot(dn)) { | 210 | if (rpaphp_add_slot(dn)) { |
246 | printk(KERN_ERR "%s: unable to add hotplug slot %s\n", | 211 | printk(KERN_ERR "%s: unable to add hotplug slot %s\n", |
@@ -435,6 +400,8 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn) | |||
435 | __FUNCTION__, drc_name); | 400 | __FUNCTION__, drc_name); |
436 | return -EIO; | 401 | return -EIO; |
437 | } | 402 | } |
403 | } else { | ||
404 | rpaphp_unconfig_pci_adapter(bus); | ||
438 | } | 405 | } |
439 | 406 | ||
440 | if (unmap_bus_range(bus)) { | 407 | if (unmap_bus_range(bus)) { |
diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h index 71ea5f9bb284..57ea71a7bda5 100644 --- a/drivers/pci/hotplug/rpaphp.h +++ b/drivers/pci/hotplug/rpaphp.h | |||
@@ -93,6 +93,8 @@ extern int rpaphp_claim_resource(struct pci_dev *dev, int resource); | |||
93 | extern int rpaphp_enable_pci_slot(struct slot *slot); | 93 | extern int rpaphp_enable_pci_slot(struct slot *slot); |
94 | extern int register_pci_slot(struct slot *slot); | 94 | extern int register_pci_slot(struct slot *slot); |
95 | extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value); | 95 | extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value); |
96 | extern void rpaphp_init_new_devs(struct pci_bus *bus); | ||
97 | extern void rpaphp_eeh_init_nodes(struct device_node *dn); | ||
96 | 98 | ||
97 | extern int rpaphp_config_pci_adapter(struct pci_bus *bus); | 99 | extern int rpaphp_config_pci_adapter(struct pci_bus *bus); |
98 | extern int rpaphp_unconfig_pci_adapter(struct pci_bus *bus); | 100 | extern int rpaphp_unconfig_pci_adapter(struct pci_bus *bus); |
diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c index f7c12d7dfcfc..a7859a84d1ae 100644 --- a/drivers/pci/hotplug/rpaphp_pci.c +++ b/drivers/pci/hotplug/rpaphp_pci.c | |||
@@ -154,8 +154,7 @@ exit: | |||
154 | } | 154 | } |
155 | 155 | ||
156 | /* Must be called before pci_bus_add_devices */ | 156 | /* Must be called before pci_bus_add_devices */ |
157 | static void | 157 | void rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus) |
158 | rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus) | ||
159 | { | 158 | { |
160 | struct pci_dev *dev; | 159 | struct pci_dev *dev; |
161 | 160 | ||
@@ -184,6 +183,20 @@ rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus) | |||
184 | } | 183 | } |
185 | } | 184 | } |
186 | 185 | ||
186 | static void rpaphp_eeh_add_bus_device(struct pci_bus *bus) | ||
187 | { | ||
188 | struct pci_dev *dev; | ||
189 | |||
190 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
191 | eeh_add_device_late(dev); | ||
192 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | ||
193 | struct pci_bus *subbus = dev->subordinate; | ||
194 | if (subbus) | ||
195 | rpaphp_eeh_add_bus_device (subbus); | ||
196 | } | ||
197 | } | ||
198 | } | ||
199 | |||
187 | static int rpaphp_pci_config_bridge(struct pci_dev *dev) | 200 | static int rpaphp_pci_config_bridge(struct pci_dev *dev) |
188 | { | 201 | { |
189 | u8 sec_busno; | 202 | u8 sec_busno; |
@@ -217,6 +230,13 @@ static int rpaphp_pci_config_bridge(struct pci_dev *dev) | |||
217 | return 0; | 230 | return 0; |
218 | } | 231 | } |
219 | 232 | ||
233 | void rpaphp_init_new_devs(struct pci_bus *bus) | ||
234 | { | ||
235 | rpaphp_fixup_new_pci_devices(bus, 0); | ||
236 | rpaphp_eeh_add_bus_device(bus); | ||
237 | } | ||
238 | EXPORT_SYMBOL_GPL(rpaphp_init_new_devs); | ||
239 | |||
220 | /***************************************************************************** | 240 | /***************************************************************************** |
221 | rpaphp_pci_config_slot() will configure all devices under the | 241 | rpaphp_pci_config_slot() will configure all devices under the |
222 | given slot->dn and return the the first pci_dev. | 242 | given slot->dn and return the the first pci_dev. |
@@ -233,36 +253,51 @@ rpaphp_pci_config_slot(struct pci_bus *bus) | |||
233 | if (!dn || !dn->child) | 253 | if (!dn || !dn->child) |
234 | return NULL; | 254 | return NULL; |
235 | 255 | ||
236 | slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); | 256 | if (systemcfg->platform == PLATFORM_PSERIES_LPAR) { |
257 | of_scan_bus(dn, bus); | ||
258 | if (list_empty(&bus->devices)) { | ||
259 | err("%s: No new device found\n", __FUNCTION__); | ||
260 | return NULL; | ||
261 | } | ||
237 | 262 | ||
238 | /* pci_scan_slot should find all children */ | 263 | rpaphp_init_new_devs(bus); |
239 | num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); | ||
240 | if (num) { | ||
241 | rpaphp_fixup_new_pci_devices(bus, 1); | ||
242 | pci_bus_add_devices(bus); | 264 | pci_bus_add_devices(bus); |
243 | } | 265 | dev = list_entry(&bus->devices, struct pci_dev, bus_list); |
244 | if (list_empty(&bus->devices)) { | 266 | } else { |
245 | err("%s: No new device found\n", __FUNCTION__); | 267 | slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); |
246 | return NULL; | 268 | |
247 | } | 269 | /* pci_scan_slot should find all children */ |
248 | list_for_each_entry(dev, &bus->devices, bus_list) { | 270 | num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); |
249 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) | 271 | if (num) { |
250 | rpaphp_pci_config_bridge(dev); | 272 | rpaphp_fixup_new_pci_devices(bus, 1); |
273 | pci_bus_add_devices(bus); | ||
274 | } | ||
275 | if (list_empty(&bus->devices)) { | ||
276 | err("%s: No new device found\n", __FUNCTION__); | ||
277 | return NULL; | ||
278 | } | ||
279 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
280 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) | ||
281 | rpaphp_pci_config_bridge(dev); | ||
282 | |||
283 | rpaphp_eeh_add_bus_device(bus); | ||
284 | } | ||
251 | } | 285 | } |
252 | 286 | ||
253 | return dev; | 287 | return dev; |
254 | } | 288 | } |
255 | 289 | ||
256 | static void enable_eeh(struct device_node *dn) | 290 | void rpaphp_eeh_init_nodes(struct device_node *dn) |
257 | { | 291 | { |
258 | struct device_node *sib; | 292 | struct device_node *sib; |
259 | 293 | ||
260 | for (sib = dn->child; sib; sib = sib->sibling) | 294 | for (sib = dn->child; sib; sib = sib->sibling) |
261 | enable_eeh(sib); | 295 | rpaphp_eeh_init_nodes(sib); |
262 | eeh_add_device_early(dn); | 296 | eeh_add_device_early(dn); |
263 | return; | 297 | return; |
264 | 298 | ||
265 | } | 299 | } |
300 | EXPORT_SYMBOL_GPL(rpaphp_eeh_init_nodes); | ||
266 | 301 | ||
267 | static void print_slot_pci_funcs(struct pci_bus *bus) | 302 | static void print_slot_pci_funcs(struct pci_bus *bus) |
268 | { | 303 | { |
@@ -289,7 +324,7 @@ int rpaphp_config_pci_adapter(struct pci_bus *bus) | |||
289 | if (!dn) | 324 | if (!dn) |
290 | goto exit; | 325 | goto exit; |
291 | 326 | ||
292 | enable_eeh(dn); | 327 | rpaphp_eeh_init_nodes(dn); |
293 | dev = rpaphp_pci_config_slot(bus); | 328 | dev = rpaphp_pci_config_slot(bus); |
294 | if (!dev) { | 329 | if (!dev) { |
295 | err("%s: can't find any devices.\n", __FUNCTION__); | 330 | err("%s: can't find any devices.\n", __FUNCTION__); |
@@ -331,6 +366,7 @@ int rpaphp_unconfig_pci_adapter(struct pci_bus *bus) | |||
331 | } | 366 | } |
332 | return 0; | 367 | return 0; |
333 | } | 368 | } |
369 | EXPORT_SYMBOL_GPL(rpaphp_unconfig_pci_adapter); | ||
334 | 370 | ||
335 | static int setup_pci_hotplug_slot_info(struct slot *slot) | 371 | static int setup_pci_hotplug_slot_info(struct slot *slot) |
336 | { | 372 | { |
@@ -444,8 +480,8 @@ int rpaphp_enable_pci_slot(struct slot *slot) | |||
444 | retval = rpaphp_config_pci_adapter(slot->bus); | 480 | retval = rpaphp_config_pci_adapter(slot->bus); |
445 | if (!retval) { | 481 | if (!retval) { |
446 | slot->state = CONFIGURED; | 482 | slot->state = CONFIGURED; |
447 | dbg("%s: PCI devices in slot[%s] has been configured\n", | 483 | info("%s: devices in slot[%s] configured\n", |
448 | __FUNCTION__, slot->name); | 484 | __FUNCTION__, slot->name); |
449 | } else { | 485 | } else { |
450 | slot->state = NOT_CONFIGURED; | 486 | slot->state = NOT_CONFIGURED; |
451 | dbg("%s: no pci_dev struct for adapter in slot[%s]\n", | 487 | dbg("%s: no pci_dev struct for adapter in slot[%s]\n", |