diff options
| -rw-r--r-- | arch/powerpc/include/asm/eeh.h | 11 | ||||
| -rw-r--r-- | arch/powerpc/include/asm/pci-bridge.h | 1 | ||||
| -rw-r--r-- | arch/powerpc/kernel/eeh.c | 28 | ||||
| -rw-r--r-- | arch/powerpc/kernel/eeh_driver.c | 7 | ||||
| -rw-r--r-- | arch/powerpc/kernel/eeh_pe.c | 7 | ||||
| -rw-r--r-- | arch/powerpc/kernel/pci-hotplug.c | 26 |
6 files changed, 20 insertions, 60 deletions
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index d9d35c27de25..2ce22d7b71a0 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h | |||
| @@ -55,6 +55,8 @@ struct device_node; | |||
| 55 | #define EEH_PE_RECOVERING (1 << 1) /* Recovering PE */ | 55 | #define EEH_PE_RECOVERING (1 << 1) /* Recovering PE */ |
| 56 | #define EEH_PE_PHB_DEAD (1 << 2) /* Dead PHB */ | 56 | #define EEH_PE_PHB_DEAD (1 << 2) /* Dead PHB */ |
| 57 | 57 | ||
| 58 | #define EEH_PE_KEEP (1 << 8) /* Keep PE on hotplug */ | ||
| 59 | |||
| 58 | struct eeh_pe { | 60 | struct eeh_pe { |
| 59 | int type; /* PE type: PHB/Bus/Device */ | 61 | int type; /* PE type: PHB/Bus/Device */ |
| 60 | int state; /* PE EEH dependent mode */ | 62 | int state; /* PE EEH dependent mode */ |
| @@ -193,7 +195,7 @@ int eeh_phb_pe_create(struct pci_controller *phb); | |||
| 193 | struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb); | 195 | struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb); |
| 194 | struct eeh_pe *eeh_pe_get(struct eeh_dev *edev); | 196 | struct eeh_pe *eeh_pe_get(struct eeh_dev *edev); |
| 195 | int eeh_add_to_parent_pe(struct eeh_dev *edev); | 197 | int eeh_add_to_parent_pe(struct eeh_dev *edev); |
| 196 | int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe); | 198 | int eeh_rmv_from_parent_pe(struct eeh_dev *edev); |
| 197 | void eeh_pe_update_time_stamp(struct eeh_pe *pe); | 199 | void eeh_pe_update_time_stamp(struct eeh_pe *pe); |
| 198 | void *eeh_pe_dev_traverse(struct eeh_pe *root, | 200 | void *eeh_pe_dev_traverse(struct eeh_pe *root, |
| 199 | eeh_traverse_func fn, void *flag); | 201 | eeh_traverse_func fn, void *flag); |
| @@ -214,8 +216,7 @@ void eeh_add_device_tree_early(struct device_node *); | |||
| 214 | void eeh_add_device_late(struct pci_dev *); | 216 | void eeh_add_device_late(struct pci_dev *); |
| 215 | void eeh_add_device_tree_late(struct pci_bus *); | 217 | void eeh_add_device_tree_late(struct pci_bus *); |
| 216 | void eeh_add_sysfs_files(struct pci_bus *); | 218 | void eeh_add_sysfs_files(struct pci_bus *); |
| 217 | void eeh_remove_device(struct pci_dev *, int); | 219 | void eeh_remove_device(struct pci_dev *); |
| 218 | void eeh_remove_bus_device(struct pci_dev *, int); | ||
| 219 | 220 | ||
| 220 | /** | 221 | /** |
| 221 | * EEH_POSSIBLE_ERROR() -- test for possible MMIO failure. | 222 | * EEH_POSSIBLE_ERROR() -- test for possible MMIO failure. |
| @@ -265,9 +266,7 @@ static inline void eeh_add_device_tree_late(struct pci_bus *bus) { } | |||
| 265 | 266 | ||
| 266 | static inline void eeh_add_sysfs_files(struct pci_bus *bus) { } | 267 | static inline void eeh_add_sysfs_files(struct pci_bus *bus) { } |
| 267 | 268 | ||
| 268 | static inline void eeh_remove_device(struct pci_dev *dev, int purge_pe) { } | 269 | static inline void eeh_remove_device(struct pci_dev *dev) { } |
| 269 | |||
| 270 | static inline void eeh_remove_bus_device(struct pci_dev *dev, int purge_pe) { } | ||
| 271 | 270 | ||
| 272 | #define EEH_POSSIBLE_ERROR(val, type) (0) | 271 | #define EEH_POSSIBLE_ERROR(val, type) (0) |
| 273 | #define EEH_IO_ERROR_VALUE(size) (-1UL) | 272 | #define EEH_IO_ERROR_VALUE(size) (-1UL) |
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h index 2c1d8cb9b265..32d0d2018faf 100644 --- a/arch/powerpc/include/asm/pci-bridge.h +++ b/arch/powerpc/include/asm/pci-bridge.h | |||
| @@ -209,7 +209,6 @@ static inline struct eeh_dev *of_node_to_eeh_dev(struct device_node *dn) | |||
| 209 | extern struct pci_bus *pcibios_find_pci_bus(struct device_node *dn); | 209 | extern struct pci_bus *pcibios_find_pci_bus(struct device_node *dn); |
| 210 | 210 | ||
| 211 | /** Remove all of the PCI devices under this bus */ | 211 | /** Remove all of the PCI devices under this bus */ |
| 212 | extern void __pcibios_remove_pci_devices(struct pci_bus *bus, int purge_pe); | ||
| 213 | extern void pcibios_remove_pci_devices(struct pci_bus *bus); | 212 | extern void pcibios_remove_pci_devices(struct pci_bus *bus); |
| 214 | 213 | ||
| 215 | /** Discover new pci devices under this bus, and add them */ | 214 | /** Discover new pci devices under this bus, and add them */ |
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index 582ad1ef46a8..ce81477316be 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c | |||
| @@ -964,7 +964,6 @@ EXPORT_SYMBOL_GPL(eeh_add_sysfs_files); | |||
| 964 | /** | 964 | /** |
| 965 | * eeh_remove_device - Undo EEH setup for the indicated pci device | 965 | * eeh_remove_device - Undo EEH setup for the indicated pci device |
| 966 | * @dev: pci device to be removed | 966 | * @dev: pci device to be removed |
| 967 | * @purge_pe: remove the PE or not | ||
| 968 | * | 967 | * |
| 969 | * This routine should be called when a device is removed from | 968 | * This routine should be called when a device is removed from |
| 970 | * a running system (e.g. by hotplug or dlpar). It unregisters | 969 | * a running system (e.g. by hotplug or dlpar). It unregisters |
| @@ -972,7 +971,7 @@ EXPORT_SYMBOL_GPL(eeh_add_sysfs_files); | |||
| 972 | * this device will no longer be detected after this call; thus, | 971 | * this device will no longer be detected after this call; thus, |
| 973 | * i/o errors affecting this slot may leave this device unusable. | 972 | * i/o errors affecting this slot may leave this device unusable. |
| 974 | */ | 973 | */ |
| 975 | void eeh_remove_device(struct pci_dev *dev, int purge_pe) | 974 | void eeh_remove_device(struct pci_dev *dev) |
| 976 | { | 975 | { |
| 977 | struct eeh_dev *edev; | 976 | struct eeh_dev *edev; |
| 978 | 977 | ||
| @@ -990,34 +989,11 @@ void eeh_remove_device(struct pci_dev *dev, int purge_pe) | |||
| 990 | edev->pdev = NULL; | 989 | edev->pdev = NULL; |
| 991 | dev->dev.archdata.edev = NULL; | 990 | dev->dev.archdata.edev = NULL; |
| 992 | 991 | ||
| 993 | eeh_rmv_from_parent_pe(edev, purge_pe); | 992 | eeh_rmv_from_parent_pe(edev); |
| 994 | eeh_addr_cache_rmv_dev(dev); | 993 | eeh_addr_cache_rmv_dev(dev); |
| 995 | eeh_sysfs_remove_device(dev); | 994 | eeh_sysfs_remove_device(dev); |
| 996 | } | 995 | } |
| 997 | 996 | ||
| 998 | /** | ||
| 999 | * eeh_remove_bus_device - Undo EEH setup for the indicated PCI device | ||
| 1000 | * @dev: PCI device | ||
| 1001 | * @purge_pe: remove the corresponding PE or not | ||
| 1002 | * | ||
| 1003 | * This routine must be called when a device is removed from the | ||
| 1004 | * running system through hotplug or dlpar. The corresponding | ||
| 1005 | * PCI address cache will be removed. | ||
| 1006 | */ | ||
| 1007 | void eeh_remove_bus_device(struct pci_dev *dev, int purge_pe) | ||
| 1008 | { | ||
| 1009 | struct pci_bus *bus = dev->subordinate; | ||
| 1010 | struct pci_dev *child, *tmp; | ||
| 1011 | |||
| 1012 | eeh_remove_device(dev, purge_pe); | ||
| 1013 | |||
| 1014 | if (bus && dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | ||
| 1015 | list_for_each_entry_safe(child, tmp, &bus->devices, bus_list) | ||
| 1016 | eeh_remove_bus_device(child, purge_pe); | ||
| 1017 | } | ||
| 1018 | } | ||
| 1019 | EXPORT_SYMBOL_GPL(eeh_remove_bus_device); | ||
| 1020 | |||
| 1021 | static int proc_eeh_show(struct seq_file *m, void *v) | 997 | static int proc_eeh_show(struct seq_file *m, void *v) |
| 1022 | { | 998 | { |
| 1023 | if (0 == eeh_subsystem_enabled) { | 999 | if (0 == eeh_subsystem_enabled) { |
diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index 2b1ce17cae50..9ef3bbb8580a 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c | |||
| @@ -362,8 +362,10 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) | |||
| 362 | * devices are expected to be attached soon when calling | 362 | * devices are expected to be attached soon when calling |
| 363 | * into pcibios_add_pci_devices(). | 363 | * into pcibios_add_pci_devices(). |
| 364 | */ | 364 | */ |
| 365 | if (bus) | 365 | if (bus) { |
| 366 | __pcibios_remove_pci_devices(bus, 0); | 366 | eeh_pe_state_mark(pe, EEH_PE_KEEP); |
| 367 | pcibios_remove_pci_devices(bus); | ||
| 368 | } | ||
| 367 | 369 | ||
| 368 | /* Reset the pci controller. (Asserts RST#; resets config space). | 370 | /* Reset the pci controller. (Asserts RST#; resets config space). |
| 369 | * Reconfigure bridges and devices. Don't try to bring the system | 371 | * Reconfigure bridges and devices. Don't try to bring the system |
| @@ -386,6 +388,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) | |||
| 386 | if (bus) { | 388 | if (bus) { |
| 387 | ssleep(5); | 389 | ssleep(5); |
| 388 | pcibios_add_pci_devices(bus); | 390 | pcibios_add_pci_devices(bus); |
| 391 | eeh_pe_state_clear(pe, EEH_PE_KEEP); | ||
| 389 | } | 392 | } |
| 390 | 393 | ||
| 391 | pe->tstamp = tstamp; | 394 | pe->tstamp = tstamp; |
diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c index 016588a6f5ed..32ef40940bad 100644 --- a/arch/powerpc/kernel/eeh_pe.c +++ b/arch/powerpc/kernel/eeh_pe.c | |||
| @@ -333,7 +333,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev) | |||
| 333 | while (parent) { | 333 | while (parent) { |
| 334 | if (!(parent->type & EEH_PE_INVALID)) | 334 | if (!(parent->type & EEH_PE_INVALID)) |
| 335 | break; | 335 | break; |
| 336 | parent->type &= ~EEH_PE_INVALID; | 336 | parent->type &= ~(EEH_PE_INVALID | EEH_PE_KEEP); |
| 337 | parent = parent->parent; | 337 | parent = parent->parent; |
| 338 | } | 338 | } |
| 339 | pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n", | 339 | pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n", |
| @@ -397,14 +397,13 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev) | |||
| 397 | /** | 397 | /** |
| 398 | * eeh_rmv_from_parent_pe - Remove one EEH device from the associated PE | 398 | * eeh_rmv_from_parent_pe - Remove one EEH device from the associated PE |
| 399 | * @edev: EEH device | 399 | * @edev: EEH device |
| 400 | * @purge_pe: remove PE or not | ||
| 401 | * | 400 | * |
| 402 | * The PE hierarchy tree might be changed when doing PCI hotplug. | 401 | * The PE hierarchy tree might be changed when doing PCI hotplug. |
| 403 | * Also, the PCI devices or buses could be removed from the system | 402 | * Also, the PCI devices or buses could be removed from the system |
| 404 | * during EEH recovery. So we have to call the function remove the | 403 | * during EEH recovery. So we have to call the function remove the |
| 405 | * corresponding PE accordingly if necessary. | 404 | * corresponding PE accordingly if necessary. |
| 406 | */ | 405 | */ |
| 407 | int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe) | 406 | int eeh_rmv_from_parent_pe(struct eeh_dev *edev) |
| 408 | { | 407 | { |
| 409 | struct eeh_pe *pe, *parent, *child; | 408 | struct eeh_pe *pe, *parent, *child; |
| 410 | int cnt; | 409 | int cnt; |
| @@ -431,7 +430,7 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe) | |||
| 431 | if (pe->type & EEH_PE_PHB) | 430 | if (pe->type & EEH_PE_PHB) |
| 432 | break; | 431 | break; |
| 433 | 432 | ||
| 434 | if (purge_pe) { | 433 | if (!(pe->state & EEH_PE_KEEP)) { |
| 435 | if (list_empty(&pe->edevs) && | 434 | if (list_empty(&pe->edevs) && |
| 436 | list_empty(&pe->child_list)) { | 435 | list_empty(&pe->child_list)) { |
| 437 | list_del(&pe->child); | 436 | list_del(&pe->child); |
diff --git a/arch/powerpc/kernel/pci-hotplug.c b/arch/powerpc/kernel/pci-hotplug.c index 3dab2f2801b9..fc0831d4971f 100644 --- a/arch/powerpc/kernel/pci-hotplug.c +++ b/arch/powerpc/kernel/pci-hotplug.c | |||
| @@ -29,49 +29,33 @@ | |||
| 29 | */ | 29 | */ |
| 30 | void pcibios_release_device(struct pci_dev *dev) | 30 | void pcibios_release_device(struct pci_dev *dev) |
| 31 | { | 31 | { |
| 32 | eeh_remove_device(dev, 1); | 32 | eeh_remove_device(dev); |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | /** | 35 | /** |
| 36 | * __pcibios_remove_pci_devices - remove all devices under this bus | 36 | * pcibios_remove_pci_devices - remove all devices under this bus |
| 37 | * @bus: the indicated PCI bus | 37 | * @bus: the indicated PCI bus |
| 38 | * @purge_pe: destroy the PE on removal of PCI devices | ||
| 39 | * | 38 | * |
| 40 | * Remove all of the PCI devices under this bus both from the | 39 | * Remove all of the PCI devices under this bus both from the |
| 41 | * linux pci device tree, and from the powerpc EEH address cache. | 40 | * linux pci device tree, and from the powerpc EEH address cache. |
| 42 | * By default, the corresponding PE will be destroied during the | ||
| 43 | * normal PCI hotplug path. For PCI hotplug during EEH recovery, | ||
| 44 | * the corresponding PE won't be destroied and deallocated. | ||
| 45 | */ | 41 | */ |
| 46 | void __pcibios_remove_pci_devices(struct pci_bus *bus, int purge_pe) | 42 | void pcibios_remove_pci_devices(struct pci_bus *bus) |
| 47 | { | 43 | { |
| 48 | struct pci_dev *dev, *tmp; | 44 | struct pci_dev *dev, *tmp; |
| 49 | struct pci_bus *child_bus; | 45 | struct pci_bus *child_bus; |
| 50 | 46 | ||
| 51 | /* First go down child busses */ | 47 | /* First go down child busses */ |
| 52 | list_for_each_entry(child_bus, &bus->children, node) | 48 | list_for_each_entry(child_bus, &bus->children, node) |
| 53 | __pcibios_remove_pci_devices(child_bus, purge_pe); | 49 | pcibios_remove_pci_devices(child_bus); |
| 54 | 50 | ||
| 55 | pr_debug("PCI: Removing devices on bus %04x:%02x\n", | 51 | pr_debug("PCI: Removing devices on bus %04x:%02x\n", |
| 56 | pci_domain_nr(bus), bus->number); | 52 | pci_domain_nr(bus), bus->number); |
| 57 | list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { | 53 | list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { |
| 58 | pr_debug(" * Removing %s...\n", pci_name(dev)); | 54 | pr_debug(" Removing %s...\n", pci_name(dev)); |
| 59 | eeh_remove_bus_device(dev, purge_pe); | ||
| 60 | pci_stop_and_remove_bus_device(dev); | 55 | pci_stop_and_remove_bus_device(dev); |
| 61 | } | 56 | } |
| 62 | } | 57 | } |
| 63 | 58 | ||
| 64 | /** | ||
| 65 | * pcibios_remove_pci_devices - remove all devices under this bus | ||
| 66 | * @bus: the indicated PCI bus | ||
| 67 | * | ||
| 68 | * Remove all of the PCI devices under this bus both from the | ||
| 69 | * linux pci device tree, and from the powerpc EEH address cache. | ||
| 70 | */ | ||
| 71 | void pcibios_remove_pci_devices(struct pci_bus *bus) | ||
| 72 | { | ||
| 73 | __pcibios_remove_pci_devices(bus, 1); | ||
| 74 | } | ||
| 75 | EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices); | 59 | EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices); |
| 76 | 60 | ||
| 77 | /** | 61 | /** |
