diff options
Diffstat (limited to 'drivers/pci/hotplug/shpchp_ctrl.c')
-rw-r--r-- | drivers/pci/hotplug/shpchp_ctrl.c | 48 |
1 files changed, 32 insertions, 16 deletions
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 23dd61c4c66c..c55103f3cebd 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c | |||
@@ -328,21 +328,20 @@ static int slot_remove(struct pci_func * old_slot) | |||
328 | /** | 328 | /** |
329 | * bridge_slot_remove - Removes a node from the linked list of slots. | 329 | * bridge_slot_remove - Removes a node from the linked list of slots. |
330 | * @bridge: bridge to remove | 330 | * @bridge: bridge to remove |
331 | * @secondaryBus: secondary PCI bus number for bridge being removed | ||
332 | * @subordinateBus: subordinate PCI bus number for bridge being removed | ||
331 | * | 333 | * |
332 | * Returns 0 if successful, !0 otherwise. | 334 | * Returns 0 if successful, !0 otherwise. |
333 | */ | 335 | */ |
334 | static int bridge_slot_remove(struct pci_func *bridge) | 336 | static int bridge_slot_remove(struct pci_func *bridge, u8 secondaryBus, |
337 | u8 subordinateBus) | ||
335 | { | 338 | { |
336 | u8 subordinateBus, secondaryBus; | ||
337 | u8 tempBus; | 339 | u8 tempBus; |
338 | struct pci_func *next; | 340 | struct pci_func *next; |
339 | 341 | ||
340 | if (bridge == NULL) | 342 | if (bridge == NULL) |
341 | return(1); | 343 | return(1); |
342 | 344 | ||
343 | secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF; | ||
344 | subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF; | ||
345 | |||
346 | for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { | 345 | for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { |
347 | next = shpchp_slot_list[tempBus]; | 346 | next = shpchp_slot_list[tempBus]; |
348 | 347 | ||
@@ -410,16 +409,23 @@ struct pci_func *shpchp_slot_find(u8 bus, u8 device, u8 index) | |||
410 | return(NULL); | 409 | return(NULL); |
411 | } | 410 | } |
412 | 411 | ||
413 | static int is_bridge(struct pci_func * func) | 412 | static int is_bridge(struct pci_func *func, struct controller *ctrl) |
414 | { | 413 | { |
415 | /* Check the header type */ | 414 | u8 hdr_type; |
416 | if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01) | 415 | struct pci_bus *bus = ctrl->pci_dev->subordinate; |
416 | |||
417 | /* | ||
418 | * Note: device may have just been hot-added and not yet scanned | ||
419 | * by the pci core, so its pci_dev structure may not exist yet | ||
420 | */ | ||
421 | pci_bus_read_config_byte(bus, PCI_DEVFN(func->device, func->function), | ||
422 | PCI_HEADER_TYPE, &hdr_type); | ||
423 | if ((hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) | ||
417 | return 1; | 424 | return 1; |
418 | else | 425 | else |
419 | return 0; | 426 | return 0; |
420 | } | 427 | } |
421 | 428 | ||
422 | |||
423 | /* The following routines constitute the bulk of the | 429 | /* The following routines constitute the bulk of the |
424 | hotplug controller logic | 430 | hotplug controller logic |
425 | */ | 431 | */ |
@@ -709,8 +715,6 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl) | |||
709 | goto err_exit; | 715 | goto err_exit; |
710 | } | 716 | } |
711 | 717 | ||
712 | shpchp_save_slot_config(ctrl, func); | ||
713 | |||
714 | func->status = 0; | 718 | func->status = 0; |
715 | func->switch_save = 0x10; | 719 | func->switch_save = 0x10; |
716 | func->is_a_board = 0x01; | 720 | func->is_a_board = 0x01; |
@@ -769,10 +773,18 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl) | |||
769 | u8 hp_slot; | 773 | u8 hp_slot; |
770 | u32 rc; | 774 | u32 rc; |
771 | struct slot *p_slot; | 775 | struct slot *p_slot; |
776 | u8 secondary = 0, subordinate = 0; | ||
777 | int remove_bridge; | ||
772 | 778 | ||
773 | if (func == NULL) | 779 | if (func == NULL) |
774 | return(1); | 780 | return(1); |
775 | 781 | ||
782 | if ((remove_bridge = is_bridge(func, ctrl))) { | ||
783 | /* Stash away bus information before we destroy it */ | ||
784 | secondary = func->pci_dev->subordinate->secondary; | ||
785 | subordinate = func->pci_dev->subordinate->subordinate; | ||
786 | } | ||
787 | |||
776 | if (shpchp_unconfigure_device(func)) | 788 | if (shpchp_unconfigure_device(func)) |
777 | return(1); | 789 | return(1); |
778 | 790 | ||
@@ -825,10 +837,11 @@ static u32 remove_board(struct pci_func *func, struct controller *ctrl) | |||
825 | 837 | ||
826 | if (ctrl->add_support) { | 838 | if (ctrl->add_support) { |
827 | while (func) { | 839 | while (func) { |
828 | if (is_bridge(func)) { | 840 | if (remove_bridge) { |
829 | dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, | 841 | dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, |
830 | func->device, func->function); | 842 | func->device, func->function); |
831 | bridge_slot_remove(func); | 843 | bridge_slot_remove(func, secondary, |
844 | subordinate); | ||
832 | } else | 845 | } else |
833 | dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, | 846 | dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, |
834 | func->device, func->function); | 847 | func->device, func->function); |
@@ -1185,9 +1198,12 @@ int shpchp_enable_slot (struct slot *p_slot) | |||
1185 | 1198 | ||
1186 | rc = board_added(func, p_slot->ctrl); | 1199 | rc = board_added(func, p_slot->ctrl); |
1187 | if (rc) { | 1200 | if (rc) { |
1188 | if (is_bridge(func)) | 1201 | if (is_bridge(func, p_slot->ctrl)) { |
1189 | bridge_slot_remove(func); | 1202 | u8 secondary = func->pci_dev->subordinate->secondary; |
1190 | else | 1203 | u8 subordinate = |
1204 | func->pci_dev->subordinate->subordinate; | ||
1205 | bridge_slot_remove(func, secondary, subordinate); | ||
1206 | } else | ||
1191 | slot_remove(func); | 1207 | slot_remove(func); |
1192 | 1208 | ||
1193 | /* Setup slot structure with entry for empty slot */ | 1209 | /* Setup slot structure with entry for empty slot */ |