summaryrefslogtreecommitdiff
path: root/arch/powerpc/kernel/crash_dump.c
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2010-08-24 14:23:44 +0000
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-11-29 15:48:17 +1100
commitd72e063bb32c06c6c1cec14f6857b7c37ba62d7a (patch)
tree9bab39d568bee4b95e37700b0e87ef7346525953 /arch/powerpc/kernel/crash_dump.c
parent64ff31287693c1f325cb9cb049569c1611438ef1 (diff)
downloadlwn-d72e063bb32c06c6c1cec14f6857b7c37ba62d7a.tar.gz
lwn-d72e063bb32c06c6c1cec14f6857b7c37ba62d7a.zip
powerpc/kdump: Override crash_free_reserved_phys_range to avoid freeing RTAS
The crashkernel region will almost always overlap RTAS. If we free the crashkernel region via "echo 0 > /sys/kernel/kexec_crash_size" then we will free RTAS and the machine will crash in confusing and exciting ways. Override crash_free_reserved_phys_range and check for overlap with RTAS. Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/crash_dump.c')
-rw-r--r--arch/powerpc/kernel/crash_dump.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c
index 8e05c16344e4..0a2af50243cb 100644
--- a/arch/powerpc/kernel/crash_dump.c
+++ b/arch/powerpc/kernel/crash_dump.c
@@ -19,6 +19,7 @@
#include <asm/prom.h>
#include <asm/firmware.h>
#include <asm/uaccess.h>
+#include <asm/rtas.h>
#ifdef DEBUG
#include <asm/udbg.h>
@@ -141,3 +142,35 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
return csize;
}
+
+#ifdef CONFIG_PPC_RTAS
+/*
+ * The crashkernel region will almost always overlap the RTAS region, so
+ * we have to be careful when shrinking the crashkernel region.
+ */
+void crash_free_reserved_phys_range(unsigned long begin, unsigned long end)
+{
+ unsigned long addr;
+ const u32 *basep, *sizep;
+ unsigned int rtas_start = 0, rtas_end = 0;
+
+ basep = of_get_property(rtas.dev, "linux,rtas-base", NULL);
+ sizep = of_get_property(rtas.dev, "rtas-size", NULL);
+
+ if (basep && sizep) {
+ rtas_start = *basep;
+ rtas_end = *basep + *sizep;
+ }
+
+ for (addr = begin; addr < end; addr += PAGE_SIZE) {
+ /* Does this page overlap with the RTAS region? */
+ if (addr <= rtas_end && ((addr + PAGE_SIZE) > rtas_start))
+ continue;
+
+ ClearPageReserved(pfn_to_page(addr >> PAGE_SHIFT));
+ init_page_count(pfn_to_page(addr >> PAGE_SHIFT));
+ free_page((unsigned long)__va(addr));
+ totalram_pages++;
+ }
+}
+#endif