]> Pileus Git - ~andy/linux/blobdiff - arch/powerpc/kernel/machine_kexec.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/penberg...
[~andy/linux] / arch / powerpc / kernel / machine_kexec.c
index 4f797c0b7148b83fbf2db213eecfa362d7272e75..d59e2b1bdcbac7f1f64cf9d7289092345323f315 100644 (file)
@@ -93,10 +93,35 @@ void __init reserve_crashkernel(void)
                                KDUMP_KERNELBASE);
 
        crashk_res.start = KDUMP_KERNELBASE;
+#else
+       if (!crashk_res.start) {
+               /*
+                * unspecified address, choose a region of specified size
+                * can overlap with initrd (ignoring corruption when retained)
+                * ppc64 requires kernel and some stacks to be in first segemnt
+                */
+               crashk_res.start = KDUMP_KERNELBASE;
+       }
+
+       crash_base = PAGE_ALIGN(crashk_res.start);
+       if (crash_base != crashk_res.start) {
+               printk("Crash kernel base must be aligned to 0x%lx\n",
+                               PAGE_SIZE);
+               crashk_res.start = crash_base;
+       }
+
 #endif
        crash_size = PAGE_ALIGN(crash_size);
        crashk_res.end = crashk_res.start + crash_size - 1;
 
+       /* The crash region must not overlap the current kernel */
+       if (overlaps_crashkernel(__pa(_stext), _end - _stext)) {
+               printk(KERN_WARNING
+                       "Crash kernel can not overlap current kernel\n");
+               crashk_res.start = crashk_res.end = 0;
+               return;
+       }
+
        /* Crash kernel trumps memory limit */
        if (memory_limit && memory_limit <= crashk_res.end) {
                memory_limit = crashk_res.end + 1;
@@ -120,6 +145,7 @@ int overlaps_crashkernel(unsigned long start, unsigned long size)
 
 /* Values we need to export to the second kernel via the device tree. */
 static unsigned long kernel_end;
+static unsigned long crashk_size;
 
 static struct property kernel_end_prop = {
        .name = "linux,kernel-end",
@@ -127,6 +153,39 @@ static struct property kernel_end_prop = {
        .value = &kernel_end,
 };
 
+static struct property crashk_base_prop = {
+       .name = "linux,crashkernel-base",
+       .length = sizeof(unsigned long),
+       .value = &crashk_res.start,
+};
+
+static struct property crashk_size_prop = {
+       .name = "linux,crashkernel-size",
+       .length = sizeof(unsigned long),
+       .value = &crashk_size,
+};
+
+static void __init export_crashk_values(struct device_node *node)
+{
+       struct property *prop;
+
+       /* There might be existing crash kernel properties, but we can't
+        * be sure what's in them, so remove them. */
+       prop = of_find_property(node, "linux,crashkernel-base", NULL);
+       if (prop)
+               prom_remove_property(node, prop);
+
+       prop = of_find_property(node, "linux,crashkernel-size", NULL);
+       if (prop)
+               prom_remove_property(node, prop);
+
+       if (crashk_res.start != 0) {
+               prom_add_property(node, &crashk_base_prop);
+               crashk_size = crashk_res.end - crashk_res.start + 1;
+               prom_add_property(node, &crashk_size_prop);
+       }
+}
+
 static int __init kexec_setup(void)
 {
        struct device_node *node;
@@ -145,6 +204,8 @@ static int __init kexec_setup(void)
        kernel_end = __pa(_end);
        prom_add_property(node, &kernel_end_prop);
 
+       export_crashk_values(node);
+
        of_node_put(node);
        return 0;
 }