Commit 9c547768 authored by Linas Vepstas's avatar Linas Vepstas Committed by Paul Mackerras

[POWERPC] EEH: wait for slot status

Modify routine that returns PCI slot status to wait for slot status
to become available. This is needed, as slots that are in some remote
card cage may go offline for extended periods of time. New users for
this routine in following patches.
Signed-off-by: default avatarLinas Vepstas <linas@austin.ibm.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 90375f53
...@@ -76,6 +76,9 @@ ...@@ -76,6 +76,9 @@
*/ */
#define EEH_MAX_FAILS 2100000 #define EEH_MAX_FAILS 2100000
/* Time to wait for a PCI slot to retport status, in milliseconds */
#define PCI_BUS_RESET_WAIT_MSEC (60*1000)
/* RTAS tokens */ /* RTAS tokens */
static int ibm_set_eeh_option; static int ibm_set_eeh_option;
static int ibm_set_slot_reset; static int ibm_set_slot_reset;
...@@ -168,6 +171,55 @@ static int read_slot_reset_state(struct pci_dn *pdn, int rets[]) ...@@ -168,6 +171,55 @@ static int read_slot_reset_state(struct pci_dn *pdn, int rets[])
BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid)); BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid));
} }
/**
* eeh_wait_for_slot_status - returns error status of slot
* @pdn pci device node
* @max_wait_msecs maximum number to millisecs to wait
*
* Return negative value if a permanent error, else return
* Partition Endpoint (PE) status value.
*
* If @max_wait_msecs is positive, then this routine will
* sleep until a valid status can be obtained, or until
* the max allowed wait time is exceeded, in which case
* a -2 is returned.
*/
int
eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs)
{
int rc;
int rets[3];
int mwait;
while (1) {
rc = read_slot_reset_state(pdn, rets);
if (rc) return rc;
if (rets[1] == 0) return -1; /* EEH is not supported */
if (rets[0] != 5) return rets[0]; /* return actual status */
if (rets[2] == 0) return -1; /* permanently unavailable */
if (max_wait_msecs <= 0) return -1;
mwait = rets[2];
if (mwait <= 0) {
printk (KERN_WARNING
"EEH: Firmware returned bad wait value=%d\n", mwait);
mwait = 1000;
} else if (mwait > 300*1000) {
printk (KERN_WARNING
"EEH: Firmware is taking too long, time=%d\n", mwait);
mwait = 300*1000;
}
max_wait_msecs -= mwait;
msleep (mwait);
}
printk(KERN_WARNING "EEH: Timed out waiting for slot status\n");
return -2;
}
/** /**
* eeh_token_to_phys - convert EEH address token to phys address * eeh_token_to_phys - convert EEH address token to phys address
* @token i/o token, should be address in the form 0xA.... * @token i/o token, should be address in the form 0xA....
...@@ -458,38 +510,6 @@ EXPORT_SYMBOL(eeh_check_failure); ...@@ -458,38 +510,6 @@ EXPORT_SYMBOL(eeh_check_failure);
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
/* The code below deals with error recovery */ /* The code below deals with error recovery */
/**
* eeh_slot_availability - returns error status of slot
* @pdn pci device node
*
* Return negative value if a permanent error, else return
* a number of milliseconds to wait until the PCI slot is
* ready to be used.
*/
static int
eeh_slot_availability(struct pci_dn *pdn)
{
int rc;
int rets[3];
rc = read_slot_reset_state(pdn, rets);
if (rc) return rc;
if (rets[1] == 0) return -1; /* EEH is not supported */
if (rets[0] == 0) return 0; /* Oll Korrect */
if (rets[0] == 5) {
if (rets[2] == 0) return -1; /* permanently unavailable */
return rets[2]; /* number of millisecs to wait */
}
if (rets[0] == 1)
return 250;
printk (KERN_ERR "EEH: Slot unavailable: rc=%d, rets=%d %d %d\n",
rc, rets[0], rets[1], rets[2]);
return -2;
}
/** /**
* rtas_pci_enable - enable MMIO or DMA transfers for this slot * rtas_pci_enable - enable MMIO or DMA transfers for this slot
* @pdn pci device node * @pdn pci device node
...@@ -596,36 +616,24 @@ int rtas_set_slot_reset(struct pci_dn *pdn) ...@@ -596,36 +616,24 @@ int rtas_set_slot_reset(struct pci_dn *pdn)
{ {
int i, rc; int i, rc;
/* Take three shots at resetting the bus */
for (i=0; i<3; i++) {
__rtas_set_slot_reset(pdn); __rtas_set_slot_reset(pdn);
/* Now double check with the firmware to make sure the device is rc = eeh_wait_for_slot_status(pdn, PCI_BUS_RESET_WAIT_MSEC);
* ready to be used; if not, wait for recovery. */
for (i=0; i<10; i++) {
rc = eeh_slot_availability (pdn);
if (rc == 0) if (rc == 0)
return 0; return 0;
if (rc == -2) {
printk (KERN_ERR "EEH: failed (%d) to reset slot %s\n",
i, pdn->node->full_name);
__rtas_set_slot_reset(pdn);
continue;
}
if (rc < 0) { if (rc < 0) {
printk (KERN_ERR "EEH: unrecoverable slot failure %s\n", printk (KERN_ERR "EEH: unrecoverable slot failure %s\n",
pdn->node->full_name); pdn->node->full_name);
return -1; return -1;
} }
printk (KERN_ERR "EEH: bus reset %d failed on slot %s\n",
msleep (rc+100); i+1, pdn->node->full_name);
} }
rc = eeh_slot_availability (pdn); return -1;
if (rc)
printk (KERN_ERR "EEH: timeout resetting slot %s\n", pdn->node->full_name);
return rc;
} }
/* ------------------------------------------------------- */ /* ------------------------------------------------------- */
......
...@@ -70,7 +70,7 @@ struct pci_dev *pci_get_device_by_addr(unsigned long addr); ...@@ -70,7 +70,7 @@ struct pci_dev *pci_get_device_by_addr(unsigned long addr);
void eeh_slot_error_detail (struct pci_dn *pdn, int severity); void eeh_slot_error_detail (struct pci_dn *pdn, int severity);
/** /**
* rtas_pci_enableo - enable IO transfers for this slot * rtas_pci_enable - enable IO transfers for this slot
* @pdn: pci device node * @pdn: pci device node
* @function: either EEH_THAW_MMIO or EEH_THAW_DMA * @function: either EEH_THAW_MMIO or EEH_THAW_DMA
* *
...@@ -91,6 +91,7 @@ int rtas_pci_enable(struct pci_dn *pdn, int function); ...@@ -91,6 +91,7 @@ int rtas_pci_enable(struct pci_dn *pdn, int function);
* Returns a non-zero value if the reset failed. * Returns a non-zero value if the reset failed.
*/ */
int rtas_set_slot_reset (struct pci_dn *); int rtas_set_slot_reset (struct pci_dn *);
int eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs);
/** /**
* eeh_restore_bars - Restore device configuration info. * eeh_restore_bars - Restore device configuration info.
......
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