Commit d9564ad1 authored by Linas Vepstas's avatar Linas Vepstas Committed by Paul Mackerras

[PATCH] ppc64: mark failed devices

17-eeh-slot-marking-bug.patch

A device that experiences a PCI outage may be just one deivce out
of many that was affected. In order to avoid repeated reports of
a failure, the entire tree of affected devices should be marked
as failed. This patch marks up the entire tree.
Signed-off-by: default avatarLinas Vepstas <linas@linas.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 0c95fbb2
...@@ -478,32 +478,47 @@ static struct device_node * find_device_pe(struct device_node *dn) ...@@ -478,32 +478,47 @@ static struct device_node * find_device_pe(struct device_node *dn)
* an interrupt context, which is bad. * an interrupt context, which is bad.
*/ */
static void __eeh_mark_slot (struct device_node *dn) static void __eeh_mark_slot (struct device_node *dn, int mode_flag)
{ {
while (dn) { while (dn) {
PCI_DN(dn)->eeh_mode |= EEH_MODE_ISOLATED; if (PCI_DN(dn)) {
PCI_DN(dn)->eeh_mode |= mode_flag;
if (dn->child) if (dn->child)
__eeh_mark_slot (dn->child); __eeh_mark_slot (dn->child, mode_flag);
}
dn = dn->sibling; dn = dn->sibling;
} }
} }
static void __eeh_clear_slot (struct device_node *dn) void eeh_mark_slot (struct device_node *dn, int mode_flag)
{
dn = find_device_pe (dn);
PCI_DN(dn)->eeh_mode |= mode_flag;
__eeh_mark_slot (dn->child, mode_flag);
}
static void __eeh_clear_slot (struct device_node *dn, int mode_flag)
{ {
while (dn) { while (dn) {
PCI_DN(dn)->eeh_mode &= ~EEH_MODE_ISOLATED; if (PCI_DN(dn)) {
if (dn->child) PCI_DN(dn)->eeh_mode &= ~mode_flag;
__eeh_clear_slot (dn->child); PCI_DN(dn)->eeh_check_count = 0;
if (dn->child)
__eeh_clear_slot (dn->child, mode_flag);
}
dn = dn->sibling; dn = dn->sibling;
} }
} }
static inline void eeh_clear_slot (struct device_node *dn) void eeh_clear_slot (struct device_node *dn, int mode_flag)
{ {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&confirm_error_lock, flags); spin_lock_irqsave(&confirm_error_lock, flags);
__eeh_clear_slot (dn); dn = find_device_pe (dn);
PCI_DN(dn)->eeh_mode &= ~mode_flag;
PCI_DN(dn)->eeh_check_count = 0;
__eeh_clear_slot (dn->child, mode_flag);
spin_unlock_irqrestore(&confirm_error_lock, flags); spin_unlock_irqrestore(&confirm_error_lock, flags);
} }
...@@ -528,7 +543,6 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) ...@@ -528,7 +543,6 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
int rets[3]; int rets[3];
unsigned long flags; unsigned long flags;
struct pci_dn *pdn; struct pci_dn *pdn;
struct device_node *pe_dn;
int rc = 0; int rc = 0;
__get_cpu_var(total_mmio_ffs)++; __get_cpu_var(total_mmio_ffs)++;
...@@ -630,8 +644,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) ...@@ -630,8 +644,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
/* Avoid repeated reports of this failure, including problems /* Avoid repeated reports of this failure, including problems
* with other functions on this device, and functions under * with other functions on this device, and functions under
* bridges. */ * bridges. */
pe_dn = find_device_pe (dn); eeh_mark_slot (dn, EEH_MODE_ISOLATED);
__eeh_mark_slot (pe_dn);
spin_unlock_irqrestore(&confirm_error_lock, flags); spin_unlock_irqrestore(&confirm_error_lock, flags);
eeh_send_failure_event (dn, dev, rets[0], rets[2]); eeh_send_failure_event (dn, dev, rets[0], rets[2]);
...@@ -743,9 +756,6 @@ rtas_pci_slot_reset(struct pci_dn *pdn, int state) ...@@ -743,9 +756,6 @@ rtas_pci_slot_reset(struct pci_dn *pdn, int state)
rc, state, pdn->node->full_name); rc, state, pdn->node->full_name);
return; return;
} }
if (state == 0)
eeh_clear_slot (pdn->node->parent->child);
} }
/** rtas_set_slot_reset -- assert the pci #RST line for 1/4 second /** rtas_set_slot_reset -- assert the pci #RST line for 1/4 second
...@@ -764,6 +774,12 @@ rtas_set_slot_reset(struct pci_dn *pdn) ...@@ -764,6 +774,12 @@ rtas_set_slot_reset(struct pci_dn *pdn)
#define PCI_BUS_RST_HOLD_TIME_MSEC 250 #define PCI_BUS_RST_HOLD_TIME_MSEC 250
msleep (PCI_BUS_RST_HOLD_TIME_MSEC); msleep (PCI_BUS_RST_HOLD_TIME_MSEC);
/* We might get hit with another EEH freeze as soon as the
* pci slot reset line is dropped. Make sure we don't miss
* these, and clear the flag now. */
eeh_clear_slot (pdn->node, EEH_MODE_ISOLATED);
rtas_pci_slot_reset (pdn, 0); rtas_pci_slot_reset (pdn, 0);
/* After a PCI slot has been reset, the PCI Express spec requires /* After a PCI slot has been reset, the PCI Express spec requires
......
...@@ -87,6 +87,13 @@ void rtas_configure_bridge(struct pci_dn *); ...@@ -87,6 +87,13 @@ void rtas_configure_bridge(struct pci_dn *);
int rtas_write_config(struct pci_dn *, int where, int size, u32 val); int rtas_write_config(struct pci_dn *, int where, int size, u32 val);
/**
* mark and clear slots: find "partition endpoint" PE and set or
* clear the flags for each subnode of the PE.
*/
void eeh_mark_slot (struct device_node *dn, int mode_flag);
void eeh_clear_slot (struct device_node *dn, int mode_flag);
#endif #endif
#endif /* _ASM_POWERPC_PPC_PCI_H */ #endif /* _ASM_POWERPC_PPC_PCI_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment