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 | /** |