powerpc: introduce early_get_first_memblock_info
authorKevin Hao <haokexin@gmail.com>
Tue, 24 Dec 2013 07:12:08 +0000 (15:12 +0800)
committerScott Wood <scottwood@freescale.com>
Thu, 9 Jan 2014 23:52:17 +0000 (17:52 -0600)
For a relocatable kernel since it can be loaded at any place, there
is no any relation between the kernel start addr and the memstart_addr.
So we can't calculate the memstart_addr from kernel start addr. And
also we can't wait to do the relocation after we get the real
memstart_addr from device tree because it is so late. So introduce
a new function we can use to get the first memblock address and size
in a very early stage (before machine_init).

Signed-off-by: Kevin Hao <haokexin@gmail.com>
Signed-off-by: Scott Wood <scottwood@freescale.com>
arch/powerpc/kernel/prom.c
include/linux/of_fdt.h

index fa0ad8a..f58c0d3 100644 (file)
@@ -523,6 +523,20 @@ static int __init early_init_dt_scan_memory_ppc(unsigned long node,
        return early_init_dt_scan_memory(node, uname, depth, data);
 }
 
+/*
+ * For a relocatable kernel, we need to get the memstart_addr first,
+ * then use it to calculate the virtual kernel start address. This has
+ * to happen at a very early stage (before machine_init). In this case,
+ * we just want to get the memstart_address and would not like to mess the
+ * memblock at this stage. So introduce a variable to skip the memblock_add()
+ * for this reason.
+ */
+#ifdef CONFIG_RELOCATABLE
+static int add_mem_to_memblock = 1;
+#else
+#define add_mem_to_memblock 1
+#endif
+
 void __init early_init_dt_add_memory_arch(u64 base, u64 size)
 {
 #ifdef CONFIG_PPC64
@@ -543,7 +557,8 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
        }
 
        /* Add the chunk to the MEMBLOCK list */
-       memblock_add(base, size);
+       if (add_mem_to_memblock)
+               memblock_add(base, size);
 }
 
 static void __init early_reserve_mem_dt(void)
@@ -740,6 +755,30 @@ void __init early_init_devtree(void *params)
        DBG(" <- early_init_devtree()\n");
 }
 
+#ifdef CONFIG_RELOCATABLE
+/*
+ * This function run before early_init_devtree, so we have to init
+ * initial_boot_params.
+ */
+void __init early_get_first_memblock_info(void *params, phys_addr_t *size)
+{
+       /* Setup flat device-tree pointer */
+       initial_boot_params = params;
+
+       /*
+        * Scan the memory nodes and set add_mem_to_memblock to 0 to avoid
+        * mess the memblock.
+        */
+       add_mem_to_memblock = 0;
+       of_scan_flat_dt(early_init_dt_scan_root, NULL);
+       of_scan_flat_dt(early_init_dt_scan_memory_ppc, NULL);
+       add_mem_to_memblock = 1;
+
+       if (size)
+               *size = first_memblock_size;
+}
+#endif
+
 /*******
  *
  * New implementation of the OF "find" APIs, return a refcounted
index 0beaee9..2b77058 100644 (file)
@@ -116,6 +116,7 @@ extern const void *of_flat_dt_match_machine(const void *default_match,
 extern void unflatten_device_tree(void);
 extern void unflatten_and_copy_device_tree(void);
 extern void early_init_devtree(void *);
+extern void early_get_first_memblock_info(void *, phys_addr_t *);
 #else /* CONFIG_OF_FLATTREE */
 static inline const char *of_flat_dt_get_machine_name(void) { return NULL; }
 static inline void unflatten_device_tree(void) {}