# load parameter file from ipl device
 #
 .Lagain1:
-       l     %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) # ramdisk loc. is temp
+       l     %r2,.Linitrd                     # ramdisk loc. is temp
         bas   %r14,.Lloader                    # load parameter file
         ltr   %r2,%r2                          # got anything ?
         bz    .Lnopf
        bnh   .Lnotrunc
        la    %r2,895
 .Lnotrunc:
-       l     %r4,INITRD_START+ARCH_OFFSET-PARMAREA(%r12)
+       l     %r4,.Linitrd
        clc   0(3,%r4),.L_hdr                  # if it is HDRx
        bz    .Lagain1                         # skip dataset header
        clc   0(3,%r4),.L_eof                  # if it is EOFx
 # load ramdisk from ipl device
 #      
 .Lagain2:
-       l     %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) # addr of ramdisk
+       l     %r2,.Linitrd                     # addr of ramdisk
+       st    %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12)
         bas   %r14,.Lloader                    # load ramdisk
        st    %r2,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r12) # store size of ramdisk
         ltr   %r2,%r2
         bnz   .Lrdcont
         st    %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) # no ramdisk found
 .Lrdcont:
-       l     %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12)
+       l     %r2,.Linitrd
 
        clc   0(3,%r2),.L_hdr                  # skip HDRx and EOFx 
        bz    .Lagain2
         l     %r1,.Lstartup
         br    %r1
 
+.Linitrd:.long _end + 0x400000                # default address of initrd
 .Lparm:        .long  PARMAREA
 .Lstartup: .long startup
 .Lcvtab:.long  _ebcasc                         # ebcdic to ascii table
 
 #include <linux/kernel_stat.h>
 #include <linux/device.h>
 #include <linux/notifier.h>
+#include <linux/pfn.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
         * partially used pages are not usable - thus
         * we are rounding upwards:
         */
-       start_pfn = (__pa(&_end) + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       end_pfn = max_pfn = memory_end >> PAGE_SHIFT;
+       start_pfn = PFN_UP(__pa(&_end));
+       end_pfn = max_pfn = PFN_DOWN(memory_end);
 
        /* Initialize storage key for kernel pages */
        for (init_pfn = 0 ; init_pfn < start_pfn; init_pfn++)
                page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
 
+#ifdef CONFIG_BLK_DEV_INITRD
+       /*
+        * Move the initrd in case the bitmap of the bootmem allocater
+        * would overwrite it.
+        */
+
+       if (INITRD_START && INITRD_SIZE) {
+               unsigned long bmap_size;
+               unsigned long start;
+
+               bmap_size = bootmem_bootmap_pages(end_pfn - start_pfn + 1);
+               bmap_size = PFN_PHYS(bmap_size);
+
+               if (PFN_PHYS(start_pfn) + bmap_size > INITRD_START) {
+                       start = PFN_PHYS(start_pfn) + bmap_size + PAGE_SIZE;
+
+                       if (start + INITRD_SIZE > memory_end) {
+                               printk("initrd extends beyond end of memory "
+                                      "(0x%08lx > 0x%08lx)\n"
+                                      "disabling initrd\n",
+                                      start + INITRD_SIZE, memory_end);
+                               INITRD_START = INITRD_SIZE = 0;
+                       } else {
+                               printk("Moving initrd (0x%08lx -> 0x%08lx, "
+                                      "size: %ld)\n",
+                                      INITRD_START, start, INITRD_SIZE);
+                               memmove((void *) start, (void *) INITRD_START,
+                                       INITRD_SIZE);
+                               INITRD_START = start;
+                       }
+               }
+       }
+#endif
+
        /*
         * Initialize the boot-time allocator (with low memory only):
         */
        reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size);
 
 #ifdef CONFIG_BLK_DEV_INITRD
-       if (INITRD_START) {
+       if (INITRD_START && INITRD_SIZE) {
                if (INITRD_START + INITRD_SIZE <= memory_end) {
                        reserve_bootmem(INITRD_START, INITRD_SIZE);
                        initrd_start = INITRD_START;