Pull video into test branch
[linux-drm-fsl-dcu.git] / arch / powerpc / platforms / pseries / eeh.c
index 4534886e3b4e5c3c4d86f6f9b122a113643ac2b3..da6e5362e7cd8f13f802729e957538cc491e41b3 100644 (file)
@@ -225,6 +225,7 @@ static void __eeh_mark_slot (struct device_node *dn, int mode_flag)
 
 void eeh_mark_slot (struct device_node *dn, int mode_flag)
 {
+       struct pci_dev *dev;
        dn = find_device_pe (dn);
 
        /* Back up one, since config addrs might be shared */
@@ -232,6 +233,12 @@ void eeh_mark_slot (struct device_node *dn, int mode_flag)
                dn = dn->parent;
 
        PCI_DN(dn)->eeh_mode |= mode_flag;
+
+       /* Mark the pci device too */
+       dev = PCI_DN(dn)->pcidev;
+       if (dev)
+               dev->error_state = pci_channel_io_frozen;
+
        __eeh_mark_slot (dn->child, mode_flag);
 }
 
@@ -330,6 +337,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
                        printk (KERN_ERR "EEH: Device driver ignored %d bad reads, panicing\n",
                                pdn->eeh_check_count);
                        dump_stack();
+                       msleep(5000);
                        
                        /* re-read the slot reset state */
                        if (read_slot_reset_state(pdn, rets) != 0)
@@ -478,7 +486,7 @@ eeh_slot_availability(struct pci_dn *pdn)
 
        printk (KERN_ERR "EEH: Slot unavailable: rc=%d, rets=%d %d %d\n",
                rc, rets[0], rets[1], rets[2]);
-       return -1;
+       return -2;
 }
 
 /**
@@ -546,11 +554,10 @@ rtas_pci_slot_reset(struct pci_dn *pdn, int state)
                       BUID_HI(pdn->phb->buid),
                       BUID_LO(pdn->phb->buid),
                       state);
-       if (rc) {
-               printk (KERN_WARNING "EEH: Unable to reset the failed slot, (%d) #RST=%d dn=%s\n", 
+       if (rc)
+               printk (KERN_WARNING "EEH: Unable to reset the failed slot,"
+                       " (%d) #RST=%d dn=%s\n",
                        rc, state, pdn->node->full_name);
-               return;
-       }
 }
 
 /**
@@ -560,11 +567,8 @@ rtas_pci_slot_reset(struct pci_dn *pdn, int state)
  *  Return 0 if success, else a non-zero value.
  */
 
-int
-rtas_set_slot_reset(struct pci_dn *pdn)
+static void __rtas_set_slot_reset(struct pci_dn *pdn)
 {
-       int i, rc;
-
        rtas_pci_slot_reset (pdn, 1);
 
        /* The PCI bus requires that the reset be held high for at least
@@ -585,17 +589,33 @@ rtas_set_slot_reset(struct pci_dn *pdn)
         * up traffic. */
 #define PCI_BUS_SETTLE_TIME_MSEC 1800
        msleep (PCI_BUS_SETTLE_TIME_MSEC);
+}
+
+int rtas_set_slot_reset(struct pci_dn *pdn)
+{
+       int i, rc;
+
+       __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);
-               if (rc < 0)
-                       printk (KERN_ERR "EEH: failed (%d) to reset slot %s\n", rc, pdn->node->full_name);
                if (rc == 0)
                        return 0;
-               if (rc < 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);
        }