summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPeter Tyser <ptyser@xes-inc.com>2009-12-18 16:50:37 -0600
committerKumar Gala <galak@kernel.crashing.org>2010-02-13 14:23:24 -0600
commitd1d47ec6e62ab08d2ebb925fd9203abfad3adfbf (patch)
treeb699169fa050649c01727047e8e9764e819b3416 /arch
parentfa644298eb24ab05b32acf6cc0f2265b833280e1 (diff)
downloadlinux-d1d47ec6e62ab08d2ebb925fd9203abfad3adfbf.tar.bz2
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: Peter Tyser <ptyser@xes-inc.com> Signed-off-by: Nate Case <ncase@xes-inc.com> Reported-by: Dipen Dudhat <B09055@freescale.com> Tested-by: Dipen Dudhat <B09055@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/platforms/85xx/smp.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 04160a4cc699..a15f582300d8 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -46,6 +46,7 @@ smp_85xx_kick_cpu(int nr)
__iomem u32 *bptr_vaddr;
struct device_node *np;
int n = 0;
+ int ioremappable;
WARN_ON (nr < 0 || nr >= NR_CPUS);
@@ -59,21 +60,37 @@ smp_85xx_kick_cpu(int nr)
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 */
- bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY);
+ if (ioremappable)
+ bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY);
+ else
+ bptr_vaddr = phys_to_virt(*cpu_rel_addr);
local_irq_save(flags);
out_be32(bptr_vaddr + BOOT_ENTRY_PIR, nr);
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. */
while ((__secondary_hold_acknowledge != nr) && (++n < 1000))
mdelay(1);
local_irq_restore(flags);
- iounmap(bptr_vaddr);
+ if (ioremappable)
+ iounmap(bptr_vaddr);
pr_debug("waited %d msecs for CPU #%d.\n", n, nr);
}