powerpc/fsl_pci: Don't set up inbound windows in kdump crash kernel
authorScott Wood <scottwood@freescale.com>
Wed, 7 Oct 2015 03:48:08 +0000 (22:48 -0500)
committerScott Wood <scottwood@freescale.com>
Sat, 17 Oct 2015 05:36:37 +0000 (00:36 -0500)
Otherwise, because the top end of the crash kernel is treated as the
absolute top of memory rather than the beginning of a reserved region,
in-flight DMA from the previous kernel that targets areas above the
crash kernel can trigger a storm of PCI errors.  We only do this for
kdump, not normal kexec, in case kexec is being used to upgrade to a
kernel that wants a different inbound memory map.

Signed-off-by: Scott Wood <scottwood@freescale.com>
Cc: Mingkai Hu <Mingkai.hu@freescale.com>
arch/powerpc/sysdev/fsl_pci.c

index c42609dde8d2ea564cb4786fc105b50c4c394f8c..1c65ef92768dbb553563506373094338ad92e7f9 100644 (file)
@@ -179,6 +179,19 @@ static int setup_one_atmu(struct ccsr_pci __iomem *pci,
        return i;
 }
 
+static bool is_kdump(void)
+{
+       struct device_node *node;
+
+       node = of_find_node_by_type(NULL, "memory");
+       if (!node) {
+               WARN_ON_ONCE(1);
+               return false;
+       }
+
+       return of_property_read_bool(node, "linux,usable-memory");
+}
+
 /* atmu setup for fsl pci/pcie controller */
 static void setup_pci_atmu(struct pci_controller *hose)
 {
@@ -192,6 +205,16 @@ static void setup_pci_atmu(struct pci_controller *hose)
        const char *name = hose->dn->full_name;
        const u64 *reg;
        int len;
+       bool setup_inbound;
+
+       /*
+        * If this is kdump, we don't want to trigger a bunch of PCI
+        * errors by closing the window on in-flight DMA.
+        *
+        * We still run most of the function's logic so that things like
+        * hose->dma_window_size still get set.
+        */
+       setup_inbound = !is_kdump();
 
        if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
                if (in_be32(&pci->block_rev1) >= PCIE_IP_REV_2_2) {
@@ -204,8 +227,11 @@ static void setup_pci_atmu(struct pci_controller *hose)
        /* Disable all windows (except powar0 since it's ignored) */
        for(i = 1; i < 5; i++)
                out_be32(&pci->pow[i].powar, 0);
-       for (i = start_idx; i < end_idx; i++)
-               out_be32(&pci->piw[i].piwar, 0);
+
+       if (setup_inbound) {
+               for (i = start_idx; i < end_idx; i++)
+                       out_be32(&pci->piw[i].piwar, 0);
+       }
 
        /* Setup outbound MEM window */
        for(i = 0, j = 1; i < 3; i++) {
@@ -278,6 +304,7 @@ static void setup_pci_atmu(struct pci_controller *hose)
 
        /* Setup inbound mem window */
        mem = memblock_end_of_DRAM();
+       pr_info("%s: end of DRAM %llx\n", __func__, mem);
 
        /*
         * The msi-address-64 property, if it exists, indicates the physical
@@ -320,12 +347,14 @@ static void setup_pci_atmu(struct pci_controller *hose)
 
                piwar |= ((mem_log - 1) & PIWAR_SZ_MASK);
 
-               /* Setup inbound memory window */
-               out_be32(&pci->piw[win_idx].pitar,  0x00000000);
-               out_be32(&pci->piw[win_idx].piwbar, 0x00000000);
-               out_be32(&pci->piw[win_idx].piwar,  piwar);
-               win_idx--;
+               if (setup_inbound) {
+                       /* Setup inbound memory window */
+                       out_be32(&pci->piw[win_idx].pitar,  0x00000000);
+                       out_be32(&pci->piw[win_idx].piwbar, 0x00000000);
+                       out_be32(&pci->piw[win_idx].piwar,  piwar);
+               }
 
+               win_idx--;
                hose->dma_window_base_cur = 0x00000000;
                hose->dma_window_size = (resource_size_t)sz;
 
@@ -343,13 +372,15 @@ static void setup_pci_atmu(struct pci_controller *hose)
 
                        piwar = (piwar & ~PIWAR_SZ_MASK) | (mem_log - 1);
 
-                       /* Setup inbound memory window */
-                       out_be32(&pci->piw[win_idx].pitar,  0x00000000);
-                       out_be32(&pci->piw[win_idx].piwbear,
-                                       pci64_dma_offset >> 44);
-                       out_be32(&pci->piw[win_idx].piwbar,
-                                       pci64_dma_offset >> 12);
-                       out_be32(&pci->piw[win_idx].piwar,  piwar);
+                       if (setup_inbound) {
+                               /* Setup inbound memory window */
+                               out_be32(&pci->piw[win_idx].pitar,  0x00000000);
+                               out_be32(&pci->piw[win_idx].piwbear,
+                                               pci64_dma_offset >> 44);
+                               out_be32(&pci->piw[win_idx].piwbar,
+                                               pci64_dma_offset >> 12);
+                               out_be32(&pci->piw[win_idx].piwar,  piwar);
+                       }
 
                        /*
                         * install our own dma_set_mask handler to fixup dma_ops
@@ -362,12 +393,15 @@ static void setup_pci_atmu(struct pci_controller *hose)
        } else {
                u64 paddr = 0;
 
-               /* Setup inbound memory window */
-               out_be32(&pci->piw[win_idx].pitar,  paddr >> 12);
-               out_be32(&pci->piw[win_idx].piwbar, paddr >> 12);
-               out_be32(&pci->piw[win_idx].piwar,  (piwar | (mem_log - 1)));
-               win_idx--;
+               if (setup_inbound) {
+                       /* Setup inbound memory window */
+                       out_be32(&pci->piw[win_idx].pitar,  paddr >> 12);
+                       out_be32(&pci->piw[win_idx].piwbar, paddr >> 12);
+                       out_be32(&pci->piw[win_idx].piwar,
+                                (piwar | (mem_log - 1)));
+               }
 
+               win_idx--;
                paddr += 1ull << mem_log;
                sz -= 1ull << mem_log;
 
@@ -375,11 +409,15 @@ static void setup_pci_atmu(struct pci_controller *hose)
                        mem_log = ilog2(sz);
                        piwar |= (mem_log - 1);
 
-                       out_be32(&pci->piw[win_idx].pitar,  paddr >> 12);
-                       out_be32(&pci->piw[win_idx].piwbar, paddr >> 12);
-                       out_be32(&pci->piw[win_idx].piwar,  piwar);
-                       win_idx--;
+                       if (setup_inbound) {
+                               out_be32(&pci->piw[win_idx].pitar,
+                                        paddr >> 12);
+                               out_be32(&pci->piw[win_idx].piwbar,
+                                        paddr >> 12);
+                               out_be32(&pci->piw[win_idx].piwar, piwar);
+                       }
 
+                       win_idx--;
                        paddr += 1ull << mem_log;
                }