+config CRASHLOG
+ bool "Crash logging"
-+ depends on (!NO_BOOTMEM || HAVE_MEMBLOCK) && !(ARM || SPARC || PPC)
++ depends on (!NO_BOOTMEM || HAVE_MEMBLOCK)
+
config BLK_DEV_INITRD
bool "Initial RAM filesystem and RAM disk (initramfs/initrd) support"
--- /dev/null
+++ b/kernel/crashlog.c
-@@ -0,0 +1,181 @@
+@@ -0,0 +1,213 @@
+/*
+ * Crash information logger
+ * Copyright (C) 2010 Felix Fietkau <nbd@nbd.name>
+#include <linux/kmsg_dump.h>
+#include <linux/module.h>
+#include <linux/pfn.h>
++#include <linux/vmalloc.h>
+#include <asm/io.h>
+
+#define CRASHLOG_PAGES 4
+
+extern struct list_head *crashlog_modules;
+
++static bool crashlog_set_addr(phys_addr_t addr, phys_addr_t size)
++{
++ /* Limit to lower 64 MB to avoid highmem */
++ phys_addr_t limit = 64 * 1024 * 1024;
++
++ if (crashlog_addr)
++ return false;
++
++ if (addr > limit)
++ return false;
++
++ if (addr + size > limit)
++ size = limit - addr;
++
++ crashlog_addr = addr;
++
++ if (addr + size > CRASHLOG_OFFSET)
++ crashlog_addr += size - CRASHLOG_OFFSET;
++
++ return true;
++}
++
+#ifndef CONFIG_NO_BOOTMEM
+void __init crashlog_init_bootmem(bootmem_data_t *bdata)
+{
-+ unsigned long addr;
++ phys_addr_t start, end;
+
-+ if (crashlog_addr)
++ start = PFN_PHYS(bdata->node_low_pfn);
++ end = PFN_PHYS(bdata->node_min_pfn);
++ if (!crashlog_set_addr(start, end - start))
+ return;
+
-+ addr = PFN_PHYS(bdata->node_low_pfn) - CRASHLOG_OFFSET;
-+ if (reserve_bootmem(addr, CRASHLOG_SIZE, BOOTMEM_EXCLUSIVE) < 0) {
-+ printk("Crashlog failed to allocate RAM at address 0x%lx\n", addr);
-+ bdata->node_low_pfn -= CRASHLOG_PAGES;
-+ addr = PFN_PHYS(bdata->node_low_pfn);
++ if (reserve_bootmem(crashlog_addr, CRASHLOG_SIZE, BOOTMEM_EXCLUSIVE) < 0) {
++ printk("Crashlog failed to allocate RAM at address 0x%lx\n",
++ crashlog_addr);
++ crashlog_addr = 0;
+ }
-+ crashlog_addr = addr;
+}
+#endif
+
+#ifdef CONFIG_HAVE_MEMBLOCK
+void __init_memblock crashlog_init_memblock(phys_addr_t addr, phys_addr_t size)
+{
-+ if (crashlog_addr)
++ if (!crashlog_set_addr(addr, size))
+ return;
+
-+ addr += size - CRASHLOG_OFFSET;
-+ if (memblock_reserve(addr, CRASHLOG_SIZE)) {
-+ printk("Crashlog failed to allocate RAM at address 0x%lx\n", (unsigned long) addr);
-+ return;
++ if (memblock_reserve(crashlog_addr, CRASHLOG_SIZE)) {
++ printk("Crashlog failed to allocate RAM at address 0x%lx\n",
++ crashlog_addr);
++ crashlog_addr = 0;
+ }
-+
-+ crashlog_addr = addr;
+}
+#endif
+
+
+int __init crashlog_init_fs(void)
+{
-+ if (!crashlog_addr)
++ struct page *pages[CRASHLOG_PAGES];
++ pgprot_t prot;
++ int i;
++
++ if (!crashlog_addr) {
++ printk("No memory allocated for crashlog\n");
+ return -ENOMEM;
++ }
+
-+ crashlog_buf = ioremap(crashlog_addr, CRASHLOG_SIZE);
++ printk("Crashlog allocated RAM at address 0x%lx\n", (unsigned long) crashlog_addr);
++ for (i = 0; i < CRASHLOG_PAGES; i++)
++ pages[i] = pfn_to_page((crashlog_addr >> PAGE_SHIFT) + i);
++
++ prot = pgprot_writecombine(PAGE_KERNEL);
++ crashlog_buf = vmap(pages, CRASHLOG_PAGES, VM_MAP, prot);
+
+ crashlog_copy();
+
+ return 0;
+}
+module_init(crashlog_init_fs);
---- a/mm/bootmem.c
-+++ b/mm/bootmem.c
-@@ -15,6 +15,7 @@
- #include <linux/export.h>
- #include <linux/kmemleak.h>
- #include <linux/range.h>
-+#include <linux/crashlog.h>
- #include <linux/memblock.h>
- #include <linux/bug.h>
- #include <linux/io.h>
-@@ -177,6 +178,7 @@ static unsigned long __init free_all_boo
- if (!bdata->node_bootmem_map)
- return 0;
-
-+ crashlog_init_bootmem(bdata);
- map = bdata->node_bootmem_map;
- start = bdata->node_min_pfn;
- end = bdata->node_low_pfn;
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -275,6 +275,9 @@ static void mod_update_bounds(struct mod
memblock_set_region_node(rgn, nid);
type->cnt++;
type->total_size += size;
-+ if (type == &memblock.memory && idx == 0)
++ if (type == &memblock.memory)
+ crashlog_init_memblock(base, size);
}
/**
+@@ -541,6 +544,8 @@ int __init_memblock memblock_add_range(s
+ type->regions[0].flags = flags;
+ memblock_set_region_node(&type->regions[0], nid);
+ type->total_size = size;
++ if (type == &memblock.memory)
++ crashlog_init_memblock(base, size);
+ return 0;
+ }
+ repeat:
+--- a/mm/bootmem.c
++++ b/mm/bootmem.c
+@@ -15,6 +15,7 @@
+ #include <linux/export.h>
+ #include <linux/kmemleak.h>
+ #include <linux/range.h>
++#include <linux/crashlog.h>
+ #include <linux/memblock.h>
+ #include <linux/bug.h>
+ #include <linux/io.h>
+@@ -177,6 +178,7 @@ static unsigned long __init free_all_boo
+ if (!bdata->node_bootmem_map)
+ return 0;
+
++ crashlog_init_bootmem(bdata);
+ map = bdata->node_bootmem_map;
+ start = bdata->node_min_pfn;
+ end = bdata->node_low_pfn;