Skip to content

Commit

Permalink
powerpc/fsl_pci: Don't set up inbound windows in kdump crash kernel
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Scott Wood committed Oct 17, 2015
1 parent 1112450 commit 1930bb5
Showing 1 changed file with 61 additions and 23 deletions.
84 changes: 61 additions & 23 deletions arch/powerpc/sysdev/fsl_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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) {
Expand All @@ -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++) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand All @@ -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
Expand All @@ -362,24 +393,31 @@ 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;

if (sz) {
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;
}

Expand Down

0 comments on commit 1930bb5

Please sign in to comment.