Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 330329
b: refs/heads/master
c: 20ee6a9
h: refs/heads/master
i:
  330327: d8c2bc1
v: v3
  • Loading branch information
Gavin Shan authored and Benjamin Herrenschmidt committed Sep 18, 2012
1 parent 73b2562 commit c7ea2dc
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 31 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5efc3ad7325d81b5a8e09bc14d5e21ce7272d934
refs/heads/master: 20ee6a970858a0f5711ea32cb7f855a81704cb53
6 changes: 3 additions & 3 deletions trunk/arch/powerpc/include/asm/eeh.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ static inline void eeh_unlock(void)
typedef void *(*eeh_traverse_func)(void *data, void *flag);
int __devinit eeh_phb_pe_create(struct pci_controller *phb);
int eeh_add_to_parent_pe(struct eeh_dev *edev);
int eeh_rmv_from_parent_pe(struct eeh_dev *edev);
int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe);
void *eeh_pe_dev_traverse(struct eeh_pe *root,
eeh_traverse_func fn, void *flag);
void eeh_pe_restore_bars(struct eeh_pe *pe);
Expand All @@ -201,7 +201,7 @@ int eeh_dev_check_failure(struct eeh_dev *edev);
void __init eeh_addr_cache_build(void);
void eeh_add_device_tree_early(struct device_node *);
void eeh_add_device_tree_late(struct pci_bus *);
void eeh_remove_bus_device(struct pci_dev *);
void eeh_remove_bus_device(struct pci_dev *, int);

/**
* EEH_POSSIBLE_ERROR() -- test for possible MMIO failure.
Expand Down Expand Up @@ -240,7 +240,7 @@ static inline void eeh_add_device_tree_early(struct device_node *dn) { }

static inline void eeh_add_device_tree_late(struct pci_bus *bus) { }

static inline void eeh_remove_bus_device(struct pci_dev *dev) { }
static inline void eeh_remove_bus_device(struct pci_dev *dev, int purge_pe) { }

static inline void eeh_lock(void) { }
static inline void eeh_unlock(void) { }
Expand Down
1 change: 1 addition & 0 deletions trunk/arch/powerpc/include/asm/pci-bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ static inline struct eeh_dev *of_node_to_eeh_dev(struct device_node *dn)
extern struct pci_bus *pcibios_find_pci_bus(struct device_node *dn);

/** Remove all of the PCI devices under this bus */
extern void __pcibios_remove_pci_devices(struct pci_bus *bus, int purge_pe);
extern void pcibios_remove_pci_devices(struct pci_bus *bus);

/** Discover new pci devices under this bus, and add them */
Expand Down
12 changes: 7 additions & 5 deletions trunk/arch/powerpc/platforms/pseries/eeh.c
Original file line number Diff line number Diff line change
Expand Up @@ -817,14 +817,15 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_late);
/**
* eeh_remove_device - Undo EEH setup for the indicated pci device
* @dev: pci device to be removed
* @purge_pe: remove the PE or not
*
* This routine should be called when a device is removed from
* a running system (e.g. by hotplug or dlpar). It unregisters
* the PCI device from the EEH subsystem. I/O errors affecting
* this device will no longer be detected after this call; thus,
* i/o errors affecting this slot may leave this device unusable.
*/
static void eeh_remove_device(struct pci_dev *dev)
static void eeh_remove_device(struct pci_dev *dev, int purge_pe)
{
struct eeh_dev *edev;

Expand All @@ -843,29 +844,30 @@ static void eeh_remove_device(struct pci_dev *dev)
dev->dev.archdata.edev = NULL;
pci_dev_put(dev);

eeh_rmv_from_parent_pe(edev);
eeh_rmv_from_parent_pe(edev, purge_pe);
eeh_addr_cache_rmv_dev(dev);
eeh_sysfs_remove_device(dev);
}

/**
* eeh_remove_bus_device - Undo EEH setup for the indicated PCI device
* @dev: PCI device
* @purge_pe: remove the corresponding PE or not
*
* This routine must be called when a device is removed from the
* running system through hotplug or dlpar. The corresponding
* PCI address cache will be removed.
*/
void eeh_remove_bus_device(struct pci_dev *dev)
void eeh_remove_bus_device(struct pci_dev *dev, int purge_pe)
{
struct pci_bus *bus = dev->subordinate;
struct pci_dev *child, *tmp;

eeh_remove_device(dev);
eeh_remove_device(dev, purge_pe);

if (bus && dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
list_for_each_entry_safe(child, tmp, &bus->devices, bus_list)
eeh_remove_bus_device(child);
eeh_remove_bus_device(child, purge_pe);
}
}
EXPORT_SYMBOL_GPL(eeh_remove_bus_device);
Expand Down
8 changes: 7 additions & 1 deletion trunk/arch/powerpc/platforms/pseries/eeh_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,14 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
/* pcibios will clear the counter; save the value */
cnt = pe->freeze_count;

/*
* We don't remove the corresponding PE instances because
* we need the information afterwords. The attached EEH
* devices are expected to be attached soon when calling
* into pcibios_add_pci_devices().
*/
if (bus)
pcibios_remove_pci_devices(bus);
__pcibios_remove_pci_devices(bus, 0);

/* Reset the pci controller. (Asserts RST#; resets config space).
* Reconfigure bridges and devices. Don't try to bring the system
Expand Down
35 changes: 23 additions & 12 deletions trunk/arch/powerpc/platforms/pseries/eeh_pe.c
Original file line number Diff line number Diff line change
Expand Up @@ -395,13 +395,14 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
/**
* eeh_rmv_from_parent_pe - Remove one EEH device from the associated PE
* @edev: EEH device
* @purge_pe: remove PE or not
*
* The PE hierarchy tree might be changed when doing PCI hotplug.
* Also, the PCI devices or buses could be removed from the system
* during EEH recovery. So we have to call the function remove the
* corresponding PE accordingly if necessary.
*/
int eeh_rmv_from_parent_pe(struct eeh_dev *edev)
int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe)
{
struct eeh_pe *pe, *parent, *child;
int cnt;
Expand All @@ -428,19 +429,29 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev)
if (pe->type & EEH_PE_PHB)
break;

if (list_empty(&pe->edevs)) {
cnt = 0;
list_for_each_entry(child, &pe->child_list, child) {
if (!(pe->type & EEH_PE_INVALID)) {
cnt++;
break;
}
if (purge_pe) {
if (list_empty(&pe->edevs) &&
list_empty(&pe->child_list)) {
list_del(&pe->child);
kfree(pe);
} else {
break;
}
} else {
if (list_empty(&pe->edevs)) {
cnt = 0;
list_for_each_entry(child, &pe->child_list, child) {
if (!(pe->type & EEH_PE_INVALID)) {
cnt++;
break;
}
}

if (!cnt)
pe->type |= EEH_PE_INVALID;
else
break;
if (!cnt)
pe->type |= EEH_PE_INVALID;
else
break;
}
}

pe = parent;
Expand Down
32 changes: 24 additions & 8 deletions trunk/arch/powerpc/platforms/pseries/pci_dlpar.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,27 +65,43 @@ pcibios_find_pci_bus(struct device_node *dn)
EXPORT_SYMBOL_GPL(pcibios_find_pci_bus);

/**
* pcibios_remove_pci_devices - remove all devices under this bus
* __pcibios_remove_pci_devices - remove all devices under this bus
* @bus: the indicated PCI bus
* @purge_pe: destroy the PE on removal of PCI devices
*
* Remove all of the PCI devices under this bus both from the
* linux pci device tree, and from the powerpc EEH address cache.
* By default, the corresponding PE will be destroied during the
* normal PCI hotplug path. For PCI hotplug during EEH recovery,
* the corresponding PE won't be destroied and deallocated.
*/
void pcibios_remove_pci_devices(struct pci_bus *bus)
void __pcibios_remove_pci_devices(struct pci_bus *bus, int purge_pe)
{
struct pci_dev *dev, *tmp;
struct pci_dev *dev, *tmp;
struct pci_bus *child_bus;

/* First go down child busses */
list_for_each_entry(child_bus, &bus->children, node)
pcibios_remove_pci_devices(child_bus);
__pcibios_remove_pci_devices(child_bus, purge_pe);

pr_debug("PCI: Removing devices on bus %04x:%02x\n",
pci_domain_nr(bus), bus->number);
pci_domain_nr(bus), bus->number);
list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
pr_debug(" * Removing %s...\n", pci_name(dev));
eeh_remove_bus_device(dev);
pci_stop_and_remove_bus_device(dev);
}
eeh_remove_bus_device(dev, purge_pe);
pci_stop_and_remove_bus_device(dev);
}
}

/**
* pcibios_remove_pci_devices - remove all devices under this bus
*
* Remove all of the PCI devices under this bus both from the
* linux pci device tree, and from the powerpc EEH address cache.
*/
void pcibios_remove_pci_devices(struct pci_bus *bus)
{
__pcibios_remove_pci_devices(bus, 1);
}
EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);

Expand Down
2 changes: 1 addition & 1 deletion trunk/drivers/pci/hotplug/rpadlpar_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
/* Remove the EADS bridge device itself */
BUG_ON(!bus->self);
pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self));
eeh_remove_bus_device(bus->self);
eeh_remove_bus_device(bus->self, true);
pci_stop_and_remove_bus_device(bus->self);

return 0;
Expand Down

0 comments on commit c7ea2dc

Please sign in to comment.