[POWERPC] EEH: wait for slot status
authorLinas Vepstas <linas@austin.ibm.com>
Mon, 19 Mar 2007 19:58:07 +0000 (14:58 -0500)
committerPaul Mackerras <paulus@samba.org>
Thu, 22 Mar 2007 11:52:54 +0000 (22:52 +1100)
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: Linas Vepstas <linas@austin.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/platforms/pseries/eeh.c
include/asm-powerpc/ppc-pci.h

index cb8a151bc9e79385cbfa5b2d88034707f5ec0290..c4604f71c962fb0fefe41ce3cc24a2750bb4983d 100644 (file)
@@ -76,6 +76,9 @@
  */
 #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 */
 static int ibm_set_eeh_option;
 static int ibm_set_slot_reset;
@@ -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));
 }
 
+/**
+ * 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
  * @token i/o token, should be address in the form 0xA....
@@ -458,38 +510,6 @@ EXPORT_SYMBOL(eeh_check_failure);
 /* ------------------------------------------------------------- */
 /* 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
  * @pdn pci device node
@@ -596,36 +616,24 @@ int rtas_set_slot_reset(struct pci_dn *pdn)
 {
        int i, rc;
 
-       __rtas_set_slot_reset(pdn);
+       /* Take three shots at resetting the bus */
+       for (i=0; i<3; i++) {
+               __rtas_set_slot_reset(pdn);
 
-       /* Now double check with the firmware to make sure the device is
-        * ready to be used; if not, wait for recovery. */
-       for (i=0; i<10; i++) {
-               rc = eeh_slot_availability (pdn);
+               rc = eeh_wait_for_slot_status(pdn, PCI_BUS_RESET_WAIT_MSEC);
                if (rc == 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) {
                        printk (KERN_ERR "EEH: unrecoverable slot failure %s\n",
                                pdn->node->full_name);
                        return -1;
                }
-
-               msleep (rc+100);
+               printk (KERN_ERR "EEH: bus reset %d failed on slot %s\n",
+                       i+1, pdn->node->full_name);
        }
 
-       rc = eeh_slot_availability (pdn);
-       if (rc)
-               printk (KERN_ERR "EEH: timeout resetting slot %s\n", pdn->node->full_name);
-
-       return rc;
+       return -1;
 }
 
 /* ------------------------------------------------------- */
index f186720d0739abe437e13d3824a1f7552af29cff..d74b2965bb82d007b793a36a593123b0c9cb8e2a 100644 (file)
@@ -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);
 
 /**
- * rtas_pci_enableo - enable IO transfers for this slot
+ * rtas_pci_enable - enable IO transfers for this slot
  * @pdn:       pci device node
  * @function:  either EEH_THAW_MMIO or EEH_THAW_DMA 
  *
@@ -91,6 +91,7 @@ int rtas_pci_enable(struct pci_dn *pdn, int function);
  * Returns a non-zero value if the reset failed.
  */
 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.