[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: Linas Vepstas <linas@linas.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
This commit is contained in:
parent
0c95fbb256
commit
d9564ad114
|
@ -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)
|
||||||
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)
|
||||||
/* 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)
|
||||||
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)
|
||||||
|
|
||||||
#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 *);
|
||||||
|
|
||||||
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 */
|
||||||
|
|
Loading…
Reference in New Issue