aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/shpchp_ctrl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/hotplug/shpchp_ctrl.c')
-rw-r--r--drivers/pci/hotplug/shpchp_ctrl.c48
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 */
334static int bridge_slot_remove(struct pci_func *bridge) 336static 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
413static int is_bridge(struct pci_func * func) 412static 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 */