aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/include/asm/eeh.h11
-rw-r--r--arch/powerpc/include/asm/pci-bridge.h1
-rw-r--r--arch/powerpc/kernel/eeh.c28
-rw-r--r--arch/powerpc/kernel/eeh_driver.c7
-rw-r--r--arch/powerpc/kernel/eeh_pe.c7
-rw-r--r--arch/powerpc/kernel/pci-hotplug.c26
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
58struct eeh_pe { 60struct 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);
193struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb); 195struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb);
194struct eeh_pe *eeh_pe_get(struct eeh_dev *edev); 196struct eeh_pe *eeh_pe_get(struct eeh_dev *edev);
195int eeh_add_to_parent_pe(struct eeh_dev *edev); 197int eeh_add_to_parent_pe(struct eeh_dev *edev);
196int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe); 198int eeh_rmv_from_parent_pe(struct eeh_dev *edev);
197void eeh_pe_update_time_stamp(struct eeh_pe *pe); 199void eeh_pe_update_time_stamp(struct eeh_pe *pe);
198void *eeh_pe_dev_traverse(struct eeh_pe *root, 200void *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 *);
214void eeh_add_device_late(struct pci_dev *); 216void eeh_add_device_late(struct pci_dev *);
215void eeh_add_device_tree_late(struct pci_bus *); 217void eeh_add_device_tree_late(struct pci_bus *);
216void eeh_add_sysfs_files(struct pci_bus *); 218void eeh_add_sysfs_files(struct pci_bus *);
217void eeh_remove_device(struct pci_dev *, int); 219void eeh_remove_device(struct pci_dev *);
218void 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
266static inline void eeh_add_sysfs_files(struct pci_bus *bus) { } 267static inline void eeh_add_sysfs_files(struct pci_bus *bus) { }
267 268
268static inline void eeh_remove_device(struct pci_dev *dev, int purge_pe) { } 269static inline void eeh_remove_device(struct pci_dev *dev) { }
269
270static 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)
209extern struct pci_bus *pcibios_find_pci_bus(struct device_node *dn); 209extern 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 */
212extern void __pcibios_remove_pci_devices(struct pci_bus *bus, int purge_pe);
213extern void pcibios_remove_pci_devices(struct pci_bus *bus); 212extern 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 */
975void eeh_remove_device(struct pci_dev *dev, int purge_pe) 974void 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 */
1007void 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}
1019EXPORT_SYMBOL_GPL(eeh_remove_bus_device);
1020
1021static int proc_eeh_show(struct seq_file *m, void *v) 997static 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 */
407int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe) 406int 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 */
30void pcibios_release_device(struct pci_dev *dev) 30void 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 */
46void __pcibios_remove_pci_devices(struct pci_bus *bus, int purge_pe) 42void 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 */
71void pcibios_remove_pci_devices(struct pci_bus *bus)
72{
73 __pcibios_remove_pci_devices(bus, 1);
74}
75EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices); 59EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);
76 60
77/** 61/**