powrpc/powernv: Reset PHB in kdump kernel
authorGavin Shan <gwshan@linux.vnet.ibm.com>
Thu, 24 Apr 2014 08:00:25 +0000 (18:00 +1000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 28 Apr 2014 07:34:57 +0000 (17:34 +1000)
In the kdump scenario, the first kerenl doesn't shutdown PCI devices
and the kdump kerenl clean PHB IODA table at the early probe time.
That means the kdump kerenl can't support PCI transactions piled
by the first kerenl. Otherwise, lots of EEH errors and frozen PEs
will be detected.

In order to avoid the EEH errors, the PHB is resetted to drop all
PCI transaction from the first kerenl.

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/platforms/powernv/eeh-ioda.c
arch/powerpc/platforms/powernv/pci-ioda.c
arch/powerpc/platforms/powernv/pci.h

index 58ef80987eedab40705967ea745b4f628bc667e3..753f08e36dfaa8d4cfa7884b9f27480899abbca7 100644 (file)
@@ -388,13 +388,16 @@ static s64 ioda_eeh_phb_poll(struct pnv_phb *phb)
                if (rc <= 0)
                        break;
 
-               msleep(rc);
+               if (system_state < SYSTEM_RUNNING)
+                       udelay(1000 * rc);
+               else
+                       msleep(rc);
        }
 
        return rc;
 }
 
-static int ioda_eeh_phb_reset(struct pci_controller *hose, int option)
+int ioda_eeh_phb_reset(struct pci_controller *hose, int option)
 {
        struct pnv_phb *phb = hose->private_data;
        s64 rc = OPAL_HARDWARE;
@@ -422,8 +425,12 @@ static int ioda_eeh_phb_reset(struct pci_controller *hose, int option)
         * need the PCI bus settlement delay.
         */
        rc = ioda_eeh_phb_poll(phb);
-       if (option == EEH_RESET_DEACTIVATE)
-               msleep(EEH_PE_RST_SETTLE_TIME);
+       if (option == EEH_RESET_DEACTIVATE) {
+               if (system_state < SYSTEM_RUNNING)
+                       udelay(1000 * EEH_PE_RST_SETTLE_TIME);
+               else
+                       msleep(EEH_PE_RST_SETTLE_TIME);
+       }
 out:
        if (rc != OPAL_SUCCESS)
                return -EIO;
index a179ff00be3e09476d78d1749b9c166c306bc246..8ee4787d3504496bf6c5eae2e57c914b38304010 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/kernel.h>
 #include <linux/pci.h>
+#include <linux/crash_dump.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/string.h>
@@ -1393,6 +1394,17 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
        rc = opal_pci_reset(phb_id, OPAL_PCI_IODA_TABLE_RESET, OPAL_ASSERT_RESET);
        if (rc)
                pr_warning("  OPAL Error %ld performing IODA table reset !\n", rc);
+
+       /* If we're running in kdump kerenl, the previous kerenl never
+        * shutdown PCI devices correctly. We already got IODA table
+        * cleaned out. So we have to issue PHB reset to stop all PCI
+        * transactions from previous kerenl.
+        */
+       if (is_kdump_kernel()) {
+               pr_info("  Issue PHB reset ...\n");
+               ioda_eeh_phb_reset(hose, EEH_RESET_FUNDAMENTAL);
+               ioda_eeh_phb_reset(hose, OPAL_DEASSERT_RESET);
+       }
 }
 
 void __init pnv_pci_init_ioda2_phb(struct device_node *np)
index 34a09740aad3d21bdf9393c421c4815935225047..676232c34328143a4d01719ee7ba5b40b0455965 100644 (file)
@@ -205,5 +205,6 @@ extern void pnv_pci_init_ioda2_phb(struct device_node *np);
 extern void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl,
                                        __be64 *startp, __be64 *endp, bool rm);
 extern void pnv_pci_reset_secondary_bus(struct pci_dev *dev);
+extern int ioda_eeh_phb_reset(struct pci_controller *hose, int option);
 
 #endif /* __POWERNV_PCI_H */