]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] ppc64: Move Initrd
authorAndrew Morton <akpm@osdl.org>
Mon, 26 Apr 2004 15:58:38 +0000 (08:58 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Mon, 26 Apr 2004 15:58:38 +0000 (08:58 -0700)
From: Rusty Russell <rusty@rustcorp.com.au>

This patch moves the initrd when "make_room" runs out of space, rather than
stepping over it.  The problem with stepping over it is that it gets copied
with the kernel when this happens, which wastes space.

Also ensures that the initrd isn't where the kernel wants to be moved to: if
it is, it gets moved out the way.

arch/ppc64/kernel/prom.c

index 51b5669bfb88857d66c7fa8dcc67be6d1a9456c0..428fecef963d439d4d482392a818fd151633153a 100644 (file)
@@ -1539,7 +1539,7 @@ static unsigned long __init check_display(unsigned long mem)
        return DOUBLEWORD_ALIGN(mem);
 }
 
-/* Return (relocated) pointer to this much memory: skips initrd if any. */
+/* Return (relocated) pointer to this much memory: moves initrd if reqd. */
 static void __init *__make_room(unsigned long *mem_start, unsigned long *mem_end,
                                unsigned long needed, unsigned long align)
 {
@@ -1548,11 +1548,21 @@ static void __init *__make_room(unsigned long *mem_start, unsigned long *mem_end
 
        *mem_start = ALIGN(*mem_start, align);
        if (*mem_start + needed > *mem_end) {
+               /* FIXME: Apple OF doesn't map unclaimed mem.  If this
+                * ever happened on G5, we'd need to fix. */
+               unsigned long initrd_len;
+
                if (*mem_end != RELOC(initrd_start))
                        prom_panic(RELOC("No memory for copy_device_tree"));
-               *mem_start = RELOC(initrd_end);
-               /* We can't pass huge values to OF, so use 1G. */
-               *mem_end = *mem_start + 1024*1024*1024;
+
+               prom_print("Huge device_tree: moving initrd\n");
+               /* Move by 4M. */
+               initrd_len = RELOC(initrd_end) - RELOC(initrd_start);
+               *mem_end = RELOC(initrd_start) + 4 * 1024 * 1024;
+               memmove((void *)*mem_end, (void *)RELOC(initrd_start),
+                       initrd_len);
+               RELOC(initrd_start) = *mem_end;
+               RELOC(initrd_end) = RELOC(initrd_start) + initrd_len;
        }
 
        ret = (void *)*mem_start;
@@ -1977,10 +1987,22 @@ prom_init(unsigned long r3, unsigned long r4, unsigned long pp,
 #endif /* DEBUG_PROM */
 
        lmb_reserve(0, __pa(RELOC(klimit)));
+
 #ifdef CONFIG_BLK_DEV_INITRD
-       /* If this didn't cover the initrd, do so now */
-       if (mem < RELOC(initrd_start))
-               lmb_reserve(RELOC(initrd_start), RELOC(initrd_end) - RELOC(initrd_start));
+       if (RELOC(initrd_start)) {
+               unsigned long initrd_len;
+               initrd_len = RELOC(initrd_end) - RELOC(initrd_start);
+
+               /* Move initrd if it's where we're going to copy kernel. */
+               if (RELOC(initrd_start) < __pa(RELOC(klimit))) {
+                       memmove((void *)mem, (void *)RELOC(initrd_start),
+                               initrd_len);
+                       RELOC(initrd_start) = mem;
+                       RELOC(initrd_end) = mem + initrd_len;
+               }
+
+               lmb_reserve(RELOC(initrd_start), initrd_len);
+       }
 #endif /* CONFIG_BLK_DEV_INITRD */
 
        if (_systemcfg->platform == PLATFORM_PSERIES)