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

Commit d1d47ec6 authored by Peter Tyser's avatar Peter Tyser Committed by Kumar Gala
Browse files

powerpc/85xx: Fix SMP when "cpu-release-addr" is in lowmem



Recent U-Boot commit 5ccd29c3679b3669b0bde5c501c1aa0f325a7acb caused
the "cpu-release-addr" device tree property to contain the physical RAM
location that secondary cores were spinning at.  Previously, the
"cpu-release-addr" property contained a value referencing the boot page
translation address range of 0xfffffxxx, which then indirectly accessed
RAM.

The "cpu-release-addr" is currently ioremapped and the secondary cores
kicked.  However, due to the recent change in "cpu-release-addr", it
sometimes points to a memory location in low memory that cannot be
ioremapped.  For example on a P2020-based board with 512MB of RAM the
following error occurs on bootup:

  <...>
  mpic: requesting IPIs ...
  __ioremap(): phys addr 0x1ffff000 is RAM lr c05df9a0
  Unable to handle kernel paging request for data at address 0x00000014
  Faulting instruction address: 0xc05df9b0
  Oops: Kernel access of bad area, sig: 11 [#1]
  SMP NR_CPUS=2 P2020 RDB
  Modules linked in:
  <... eventual kernel panic>

Adding logic to conditionally ioremap or access memory directly resolves
the issue.

Signed-off-by: default avatarPeter Tyser <ptyser@xes-inc.com>
Signed-off-by: default avatarNate Case <ncase@xes-inc.com>
Reported-by: default avatarDipen Dudhat <B09055@freescale.com>
Tested-by: default avatarDipen Dudhat <B09055@freescale.com>
Signed-off-by: default avatarKumar Gala <galak@kernel.crashing.org>
parent fa644298
Loading
Loading
Loading
Loading
+19 −2
Original line number Original line Diff line number Diff line
@@ -46,6 +46,7 @@ smp_85xx_kick_cpu(int nr)
	__iomem u32 *bptr_vaddr;
	__iomem u32 *bptr_vaddr;
	struct device_node *np;
	struct device_node *np;
	int n = 0;
	int n = 0;
	int ioremappable;


	WARN_ON (nr < 0 || nr >= NR_CPUS);
	WARN_ON (nr < 0 || nr >= NR_CPUS);


@@ -59,20 +60,36 @@ smp_85xx_kick_cpu(int nr)
		return;
		return;
	}
	}


	/*
	 * A secondary core could be in a spinloop in the bootpage
	 * (0xfffff000), somewhere in highmem, or somewhere in lowmem.
	 * The bootpage and highmem can be accessed via ioremap(), but
	 * we need to directly access the spinloop if its in lowmem.
	 */
	ioremappable = *cpu_rel_addr > virt_to_phys(high_memory);

	/* Map the spin table */
	/* Map the spin table */
	if (ioremappable)
		bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY);
		bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY);
	else
		bptr_vaddr = phys_to_virt(*cpu_rel_addr);


	local_irq_save(flags);
	local_irq_save(flags);


	out_be32(bptr_vaddr + BOOT_ENTRY_PIR, nr);
	out_be32(bptr_vaddr + BOOT_ENTRY_PIR, nr);
	out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start));
	out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start));


	if (!ioremappable)
		flush_dcache_range((ulong)bptr_vaddr,
				(ulong)(bptr_vaddr + SIZE_BOOT_ENTRY));

	/* Wait a bit for the CPU to ack. */
	/* Wait a bit for the CPU to ack. */
	while ((__secondary_hold_acknowledge != nr) && (++n < 1000))
	while ((__secondary_hold_acknowledge != nr) && (++n < 1000))
		mdelay(1);
		mdelay(1);


	local_irq_restore(flags);
	local_irq_restore(flags);


	if (ioremappable)
		iounmap(bptr_vaddr);
		iounmap(bptr_vaddr);


	pr_debug("waited %d msecs for CPU #%d.\n", n, nr);
	pr_debug("waited %d msecs for CPU #%d.\n", n, nr);