[PATCH 4/7] arm/devicetree: Reserve memory used by dtb blob
Grant Likely
grant.likely at secretlab.ca
Fri Feb 19 14:27:45 EST 2010
The device tree memory needs to be reserved as bootmem so that it doesn't
get overwritten by normal allocations later.
Signed-off-by: Grant Likely <grant.likely at secretlab.ca>
---
arch/arm/mm/init.c | 102 ++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 83 insertions(+), 19 deletions(-)
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index a340569..2ceb21b 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -17,6 +17,8 @@
#include <linux/initrd.h>
#include <linux/sort.h>
#include <linux/highmem.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
#include <asm/mach-types.h>
#include <asm/sections.h>
@@ -68,6 +70,20 @@ static int __init parse_tag_initrd2(const struct tag *tag)
__tagtable(ATAG_INITRD2, parse_tag_initrd2);
+#if defined(CONFIG_OF_FLATTREE)
+static unsigned long phys_devtree_start __initdata = 0;
+static unsigned long phys_devtree_size __initdata = 0;
+
+static int __init parse_tag_devtree(const struct tag *tag)
+{
+ phys_devtree_start = tag->u.devtree.start;
+ phys_devtree_size = tag->u.devtree.size;
+ return 0;
+}
+
+__tagtable(ATAG_DEVTREE, parse_tag_devtree);
+#endif
+
/*
* This keeps memory configuration data used by a couple memory
* initialization functions, as well as show_mem() for the skipping
@@ -191,29 +207,33 @@ find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages)
return bootmap_pfn;
}
-static int __init check_initrd(struct meminfo *mi)
+static int __init check_region(struct meminfo *mi,
+ unsigned long start, unsigned long size)
{
- int initrd_node = -2;
-#ifdef CONFIG_BLK_DEV_INITRD
- unsigned long end = phys_initrd_start + phys_initrd_size;
-
- /*
- * Make sure that the initrd is within a valid area of
- * memory.
- */
- if (phys_initrd_size) {
- unsigned int i;
+ unsigned long end = start + size - 1;
+ unsigned int i;
- initrd_node = -1;
+ if (!size)
+ return -2;
- for (i = 0; i < mi->nr_banks; i++) {
- struct membank *bank = &mi->bank[i];
- if (bank_phys_start(bank) <= phys_initrd_start &&
- end <= bank_phys_end(bank))
- initrd_node = bank->node;
- }
+ /* Make sure that the region is within a valid bank of memory. */
+ for (i = 0; i < mi->nr_banks; i++) {
+ struct membank *bank = &mi->bank[i];
+ if (bank_phys_start(bank) <= start &&
+ end <= bank_phys_end(bank))
+ return bank->node;
}
+ /* Region is outside of physical memory */
+ return -1;
+}
+
+static int __init check_initrd(struct meminfo *mi)
+{
+ int initrd_node = -2;
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+ initrd_node = check_region(mi, phys_initrd_start, phys_initrd_size);
if (initrd_node == -1) {
printk(KERN_ERR "INITRD: 0x%08lx+0x%08lx extends beyond "
"physical memory - disabling initrd\n",
@@ -225,6 +245,27 @@ static int __init check_initrd(struct meminfo *mi)
return initrd_node;
}
+static int __init check_devtree(struct meminfo *mi)
+{
+ int node = -2;
+
+#if defined(CONFIG_OF_FLATTREE)
+ if ((phys_devtree_start == 0) || (phys_devtree_size == 0))
+ goto out;
+
+ node = check_region(mi, phys_devtree_start, phys_devtree_size);
+ if (node == -1) {
+ phys_devtree_start = phys_devtree_size = 0;
+ pr_err("DEVICETREE: 0x%08lx+0x%08lx extends beyond "
+ "physical memory - disabling device tree\n",
+ phys_devtree_start, phys_devtree_size);
+ }
+#endif
+
+ out:
+ return node;
+}
+
static inline void map_memory_bank(struct membank *bank)
{
#ifdef CONFIG_MMU
@@ -305,6 +346,25 @@ static void __init bootmem_reserve_initrd(int node)
#endif
}
+static void __init bootmem_reserve_devtree(int node)
+{
+#if defined(CONFIG_OF_FLATTREE)
+ pg_data_t *pgdat = NODE_DATA(node);
+ int res;
+
+ res = reserve_bootmem_node(pgdat, phys_devtree_start,
+ phys_devtree_size, BOOTMEM_EXCLUSIVE);
+ if (res) {
+ pr_err("DEVICETREE: 0x%08lx+0x%08lx overlaps in-use "
+ "memory region - disabling device tree\n",
+ phys_devtree_start, phys_devtree_size);
+ return;
+ }
+
+ initial_boot_params = (void *)__phys_to_virt(phys_devtree_start);
+#endif
+}
+
static void __init bootmem_free_node(int node, struct meminfo *mi)
{
unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
@@ -397,7 +457,7 @@ void __init bootmem_init(void)
{
struct meminfo *mi = &meminfo;
unsigned long min, max_low, max_high;
- int node, initrd_node;
+ int node, initrd_node, devtree_node;
sort(&mi->bank, mi->nr_banks, sizeof(mi->bank[0]), meminfo_cmp, NULL);
@@ -405,6 +465,7 @@ void __init bootmem_init(void)
* Locate which node contains the ramdisk image, if any.
*/
initrd_node = check_initrd(mi);
+ devtree_node = check_devtree(mi);
max_low = max_high = 0;
@@ -438,9 +499,12 @@ void __init bootmem_init(void)
/*
* If the initrd is in this node, reserve its memory.
+ * and do the same for the device tree blob
*/
if (node == initrd_node)
bootmem_reserve_initrd(node);
+ if (node == devtree_node)
+ bootmem_reserve_devtree(node);
/*
* Sparsemem tries to allocate bootmem in memory_present(),
More information about the linux-arm-kernel
mailing list