aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorLinas Vepstas <linas@linas.org>2005-11-03 18:55:01 -0600
committerPaul Mackerras <paulus@samba.org>2006-01-10 15:30:23 +1100
commit3914ac7b0e672131dc2ac8b415ada79c4ccbbb31 (patch)
tree10ea50e28257b6495cd2cb1e4f64e22fee88f20f /arch/powerpc
parentb6495c0c8f100b882d85774f44529519befefba9 (diff)
downloadlinux-3914ac7b0e672131dc2ac8b415ada79c4ccbbb31.tar.gz
[PATCH] powerpc: handle multifunction PCI devices properly
239-eeh-multifunction-consolidate.patch New-style firmware will often place multiple different functions under a non-EEH-aware parent. However, these devices might share a common PE "partition endpoint" and config address, ad thus any EEH events will affect all of the devices in common. This patch makes the effort to find all of these common devices and handle them together. Signed-off-by: Linas Vepstas <linas@austin.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org> (cherry picked from 216810296bb97d39da8e176822e9de78d2f00187 commit)
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c13
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c20
2 files changed, 29 insertions, 4 deletions
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index b0fa76d0c78ac..02bc1f9d20b97 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -223,6 +223,11 @@ static void __eeh_mark_slot (struct device_node *dn, int mode_flag)
void eeh_mark_slot (struct device_node *dn, int mode_flag)
{
dn = find_device_pe (dn);
+
+ /* Back up one, since config addrs might be shared */
+ if (PCI_DN(dn) && PCI_DN(dn)->eeh_pe_config_addr)
+ dn = dn->parent;
+
PCI_DN(dn)->eeh_mode |= mode_flag;
__eeh_mark_slot (dn->child, mode_flag);
}
@@ -244,7 +249,13 @@ void eeh_clear_slot (struct device_node *dn, int mode_flag)
{
unsigned long flags;
spin_lock_irqsave(&confirm_error_lock, flags);
+
dn = find_device_pe (dn);
+
+ /* Back up one, since config addrs might be shared */
+ if (PCI_DN(dn) && PCI_DN(dn)->eeh_pe_config_addr)
+ dn = dn->parent;
+
PCI_DN(dn)->eeh_mode &= ~mode_flag;
PCI_DN(dn)->eeh_check_count = 0;
__eeh_clear_slot (dn->child, mode_flag);
@@ -609,7 +620,7 @@ void eeh_restore_bars(struct pci_dn *pdn)
if (!pdn)
return;
- if (! pdn->eeh_is_bridge)
+ if ((pdn->eeh_mode & EEH_MODE_SUPPORTED) && (!pdn->eeh_is_bridge))
__restore_bars (pdn);
dn = pdn->node->child;
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index 242b2923360d0..1c97c89597fb6 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -213,9 +213,23 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
if (rc)
return rc;
- /* Walk over all functions on this device */
- rtas_configure_bridge(pe_dn);
- eeh_restore_bars(pe_dn);
+ /* New-style config addrs might be shared across multiple devices,
+ * Walk over all functions on this device */
+ if (pe_dn->eeh_pe_config_addr) {
+ struct device_node *pe = pe_dn->node;
+ pe = pe->parent->child;
+ while (pe) {
+ struct pci_dn *ppe = PCI_DN(pe);
+ if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) {
+ rtas_configure_bridge(ppe);
+ eeh_restore_bars(ppe);
+ }
+ pe = pe->sibling;
+ }
+ } else {
+ rtas_configure_bridge(pe_dn);
+ eeh_restore_bars(pe_dn);
+ }
/* Give the system 5 seconds to finish running the user-space
* hotplug shutdown scripts, e.g. ifdown for ethernet. Yes,