Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1930bb5c authored by Scott Wood's avatar Scott Wood
Browse files

powerpc/fsl_pci: Don't set up inbound windows in kdump crash kernel



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: default avatarScott Wood <scottwood@freescale.com>
Cc: Mingkai Hu <Mingkai.hu@freescale.com>
parent 1112450a
Loading
Loading
Loading
Loading
+61 −23
Original line number Diff line number Diff line
@@ -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);

	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);

		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--;
		}

		win_idx--;
		hose->dma_window_base_cur = 0x00000000;
		hose->dma_window_size = (resource_size_t)sz;

@@ -343,6 +372,7 @@ static void setup_pci_atmu(struct pci_controller *hose)

			piwar = (piwar & ~PIWAR_SZ_MASK) | (mem_log - 1);

			if (setup_inbound) {
				/* Setup inbound memory window */
				out_be32(&pci->piw[win_idx].pitar,  0x00000000);
				out_be32(&pci->piw[win_idx].piwbear,
@@ -350,6 +380,7 @@ static void setup_pci_atmu(struct pci_controller *hose)
				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;

		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--;
			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);
			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--;
			}

			win_idx--;
			paddr += 1ull << mem_log;
		}