diff options
Diffstat (limited to 'drivers/pci/hotplug/rpaphp_pci.c')
-rw-r--r-- | drivers/pci/hotplug/rpaphp_pci.c | 141 |
1 files changed, 64 insertions, 77 deletions
diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c index 30d10fcc24b2..54fff5fb0094 100644 --- a/drivers/pci/hotplug/rpaphp_pci.c +++ b/drivers/pci/hotplug/rpaphp_pci.c | |||
@@ -45,6 +45,32 @@ struct pci_dev *rpaphp_find_pci_dev(struct device_node *dn) | |||
45 | return dev; | 45 | return dev; |
46 | } | 46 | } |
47 | 47 | ||
48 | struct pci_bus *find_bus_among_children(struct pci_bus *bus, | ||
49 | struct device_node *dn) | ||
50 | { | ||
51 | struct pci_bus *child = NULL; | ||
52 | struct list_head *tmp; | ||
53 | struct device_node *busdn; | ||
54 | |||
55 | busdn = pci_bus_to_OF_node(bus); | ||
56 | if (busdn == dn) | ||
57 | return bus; | ||
58 | |||
59 | list_for_each(tmp, &bus->children) { | ||
60 | child = find_bus_among_children(pci_bus_b(tmp), dn); | ||
61 | if (child) | ||
62 | break; | ||
63 | } | ||
64 | return child; | ||
65 | } | ||
66 | |||
67 | struct pci_bus *rpaphp_find_pci_bus(struct device_node *dn) | ||
68 | { | ||
69 | BUG_ON(!dn->phb || !dn->phb->bus); | ||
70 | |||
71 | return find_bus_among_children(dn->phb->bus, dn); | ||
72 | } | ||
73 | |||
48 | EXPORT_SYMBOL_GPL(rpaphp_find_pci_dev); | 74 | EXPORT_SYMBOL_GPL(rpaphp_find_pci_dev); |
49 | 75 | ||
50 | int rpaphp_claim_resource(struct pci_dev *dev, int resource) | 76 | int rpaphp_claim_resource(struct pci_dev *dev, int resource) |
@@ -69,11 +95,6 @@ int rpaphp_claim_resource(struct pci_dev *dev, int resource) | |||
69 | 95 | ||
70 | EXPORT_SYMBOL_GPL(rpaphp_claim_resource); | 96 | EXPORT_SYMBOL_GPL(rpaphp_claim_resource); |
71 | 97 | ||
72 | static struct pci_dev *rpaphp_find_bridge_pdev(struct slot *slot) | ||
73 | { | ||
74 | return rpaphp_find_pci_dev(slot->dn); | ||
75 | } | ||
76 | |||
77 | static int rpaphp_get_sensor_state(struct slot *slot, int *state) | 98 | static int rpaphp_get_sensor_state(struct slot *slot, int *state) |
78 | { | 99 | { |
79 | int rc; | 100 | int rc; |
@@ -226,20 +247,22 @@ static int rpaphp_pci_config_bridge(struct pci_dev *dev) | |||
226 | static struct pci_dev * | 247 | static struct pci_dev * |
227 | rpaphp_pci_config_slot(struct device_node *dn, struct pci_bus *bus) | 248 | rpaphp_pci_config_slot(struct device_node *dn, struct pci_bus *bus) |
228 | { | 249 | { |
229 | struct device_node *eads_first_child = dn->child; | ||
230 | struct pci_dev *dev = NULL; | 250 | struct pci_dev *dev = NULL; |
251 | int slotno; | ||
231 | int num; | 252 | int num; |
232 | 253 | ||
233 | dbg("Enter %s: dn=%s bus=%s\n", __FUNCTION__, dn->full_name, bus->name); | 254 | dbg("Enter %s: dn=%s bus=%s\n", __FUNCTION__, dn->full_name, bus->name); |
234 | 255 | ||
235 | if (eads_first_child) { | 256 | if (dn->child) { |
236 | /* pci_scan_slot should find all children of EADs */ | 257 | slotno = PCI_SLOT(dn->child->devfn); |
237 | num = pci_scan_slot(bus, PCI_DEVFN(PCI_SLOT(eads_first_child->devfn), 0)); | 258 | |
259 | /* pci_scan_slot should find all children */ | ||
260 | num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); | ||
238 | if (num) { | 261 | if (num) { |
239 | rpaphp_fixup_new_pci_devices(bus, 1); | 262 | rpaphp_fixup_new_pci_devices(bus, 1); |
240 | pci_bus_add_devices(bus); | 263 | pci_bus_add_devices(bus); |
241 | } | 264 | } |
242 | dev = rpaphp_find_pci_dev(eads_first_child); | 265 | dev = rpaphp_find_pci_dev(dn->child); |
243 | if (!dev) { | 266 | if (!dev) { |
244 | err("No new device found\n"); | 267 | err("No new device found\n"); |
245 | return NULL; | 268 | return NULL; |
@@ -273,31 +296,19 @@ static void print_slot_pci_funcs(struct slot *slot) | |||
273 | 296 | ||
274 | static int rpaphp_config_pci_adapter(struct slot *slot) | 297 | static int rpaphp_config_pci_adapter(struct slot *slot) |
275 | { | 298 | { |
276 | struct pci_bus *pci_bus; | ||
277 | struct pci_dev *dev; | 299 | struct pci_dev *dev; |
278 | int rc = -ENODEV; | 300 | int rc = -ENODEV; |
279 | 301 | ||
280 | dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name); | 302 | dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name); |
281 | 303 | ||
282 | if (slot->bridge) { | 304 | enable_eeh(slot->dn); |
283 | 305 | dev = rpaphp_pci_config_slot(slot->dn, slot->bus); | |
284 | pci_bus = slot->bridge->subordinate; | 306 | if (!dev) { |
285 | if (!pci_bus) { | 307 | err("%s: can't find any devices.\n", __FUNCTION__); |
286 | err("%s: can't find bus structure\n", __FUNCTION__); | 308 | goto exit; |
287 | goto exit; | ||
288 | } | ||
289 | enable_eeh(slot->dn); | ||
290 | dev = rpaphp_pci_config_slot(slot->dn, pci_bus); | ||
291 | if (!dev) { | ||
292 | err("%s: can't find any devices.\n", __FUNCTION__); | ||
293 | goto exit; | ||
294 | } | ||
295 | print_slot_pci_funcs(slot); | ||
296 | rc = 0; | ||
297 | } else { | ||
298 | /* slot is not enabled */ | ||
299 | err("slot doesn't have pci_dev structure\n"); | ||
300 | } | 309 | } |
310 | print_slot_pci_funcs(slot); | ||
311 | rc = 0; | ||
301 | exit: | 312 | exit: |
302 | dbg("Exit %s: rc=%d\n", __FUNCTION__, rc); | 313 | dbg("Exit %s: rc=%d\n", __FUNCTION__, rc); |
303 | return rc; | 314 | return rc; |
@@ -323,13 +334,14 @@ static void rpaphp_eeh_remove_bus_device(struct pci_dev *dev) | |||
323 | 334 | ||
324 | int rpaphp_unconfig_pci_adapter(struct slot *slot) | 335 | int rpaphp_unconfig_pci_adapter(struct slot *slot) |
325 | { | 336 | { |
326 | struct pci_dev *dev; | 337 | struct pci_dev *dev, *tmp; |
327 | int retval = 0; | 338 | int retval = 0; |
328 | 339 | ||
329 | list_for_each_entry(dev, slot->pci_devs, bus_list) | 340 | list_for_each_entry_safe(dev, tmp, slot->pci_devs, bus_list) { |
330 | rpaphp_eeh_remove_bus_device(dev); | 341 | rpaphp_eeh_remove_bus_device(dev); |
342 | pci_remove_bus_device(dev); | ||
343 | } | ||
331 | 344 | ||
332 | pci_remove_behind_bridge(slot->bridge); | ||
333 | slot->state = NOT_CONFIGURED; | 345 | slot->state = NOT_CONFIGURED; |
334 | info("%s: devices in slot[%s] unconfigured.\n", __FUNCTION__, | 346 | info("%s: devices in slot[%s] unconfigured.\n", __FUNCTION__, |
335 | slot->name); | 347 | slot->name); |
@@ -352,66 +364,41 @@ static int setup_pci_hotplug_slot_info(struct slot *slot) | |||
352 | return 0; | 364 | return 0; |
353 | } | 365 | } |
354 | 366 | ||
355 | static int set_phb_slot_name(struct slot *slot) | 367 | static void set_slot_name(struct slot *slot) |
356 | { | 368 | { |
357 | struct device_node *dn; | 369 | struct pci_bus *bus = slot->bus; |
358 | struct pci_controller *phb; | 370 | struct pci_dev *bridge; |
359 | struct pci_bus *bus; | ||
360 | |||
361 | dn = slot->dn; | ||
362 | if (!dn) { | ||
363 | return -EINVAL; | ||
364 | } | ||
365 | phb = dn->phb; | ||
366 | if (!phb) { | ||
367 | return -EINVAL; | ||
368 | } | ||
369 | bus = phb->bus; | ||
370 | if (!bus) { | ||
371 | return -EINVAL; | ||
372 | } | ||
373 | 371 | ||
374 | sprintf(slot->name, "%04x:%02x:%02x.%x", pci_domain_nr(bus), | 372 | bridge = bus->self; |
375 | bus->number, 0, 0); | 373 | if (bridge) |
376 | return 0; | 374 | strcpy(slot->name, pci_name(bridge)); |
375 | else | ||
376 | sprintf(slot->name, "%04x:%02x:00.0", pci_domain_nr(bus), | ||
377 | bus->number); | ||
377 | } | 378 | } |
378 | 379 | ||
379 | static int setup_pci_slot(struct slot *slot) | 380 | static int setup_pci_slot(struct slot *slot) |
380 | { | 381 | { |
382 | struct device_node *dn = slot->dn; | ||
381 | struct pci_bus *bus; | 383 | struct pci_bus *bus; |
382 | int rc; | ||
383 | 384 | ||
384 | if (slot->type == PHB) { | 385 | BUG_ON(!dn); |
385 | rc = set_phb_slot_name(slot); | 386 | bus = rpaphp_find_pci_bus(dn); |
386 | if (rc < 0) { | 387 | if (!bus) { |
387 | err("%s: failed to set phb slot name\n", __FUNCTION__); | 388 | err("%s: no pci_bus for dn %s\n", __FUNCTION__, dn->full_name); |
388 | goto exit_rc; | 389 | goto exit_rc; |
389 | } | ||
390 | } else { | ||
391 | slot->bridge = rpaphp_find_bridge_pdev(slot); | ||
392 | if (!slot->bridge) { | ||
393 | /* slot being added doesn't have pci_dev yet */ | ||
394 | err("%s: no pci_dev for bridge dn %s\n", | ||
395 | __FUNCTION__, slot->name); | ||
396 | goto exit_rc; | ||
397 | } | ||
398 | |||
399 | bus = slot->bridge->subordinate; | ||
400 | if (!bus) | ||
401 | goto exit_rc; | ||
402 | slot->pci_devs = &bus->devices; | ||
403 | |||
404 | dbg("%s set slot->name to %s\n", __FUNCTION__, | ||
405 | pci_name(slot->bridge)); | ||
406 | strcpy(slot->name, pci_name(slot->bridge)); | ||
407 | } | 390 | } |
408 | 391 | ||
392 | slot->bus = bus; | ||
393 | slot->pci_devs = &bus->devices; | ||
394 | set_slot_name(slot); | ||
395 | |||
409 | /* find slot's pci_dev if it's not empty */ | 396 | /* find slot's pci_dev if it's not empty */ |
410 | if (slot->hotplug_slot->info->adapter_status == EMPTY) { | 397 | if (slot->hotplug_slot->info->adapter_status == EMPTY) { |
411 | slot->state = EMPTY; /* slot is empty */ | 398 | slot->state = EMPTY; /* slot is empty */ |
412 | } else { | 399 | } else { |
413 | /* slot is occupied */ | 400 | /* slot is occupied */ |
414 | if (!(slot->dn->child)) { | 401 | if (!dn->child) { |
415 | /* non-empty slot has to have child */ | 402 | /* non-empty slot has to have child */ |
416 | err("%s: slot[%s]'s device_node doesn't have child for adapter\n", | 403 | err("%s: slot[%s]'s device_node doesn't have child for adapter\n", |
417 | __FUNCTION__, slot->name); | 404 | __FUNCTION__, slot->name); |