[PATCH] powerpc: Kill _machine and hard-coded platform numbers
[safe/jmp/linux-2.6] / arch / powerpc / kernel / prom_init.c
index 58f0917..d66c5e7 100644 (file)
@@ -94,11 +94,17 @@ extern const struct linux_logo logo_linux_clut224;
 #ifdef CONFIG_PPC64
 #define RELOC(x)        (*PTRRELOC(&(x)))
 #define ADDR(x)                (u32) add_reloc_offset((unsigned long)(x))
+#define OF_WORKAROUNDS 0
 #else
 #define RELOC(x)       (x)
 #define ADDR(x)                (u32) (x)
+#define OF_WORKAROUNDS of_workarounds
+int of_workarounds;
 #endif
 
+#define OF_WA_CLAIM    1       /* do phys/virt claim separately, then map */
+#define OF_WA_LONGTRAIL        2       /* work around longtrail bugs */
+
 #define PROM_BUG() do {                                                \
         prom_printf("kernel BUG at %s line 0x%x!\n",           \
                    RELOC(__FILE__), __LINE__);                 \
@@ -111,11 +117,6 @@ extern const struct linux_logo logo_linux_clut224;
 #define prom_debug(x...)
 #endif
 
-#ifdef CONFIG_PPC32
-#define PLATFORM_POWERMAC      _MACH_Pmac
-#define PLATFORM_CHRP          _MACH_chrp
-#endif
-
 
 typedef u32 prom_arg_t;
 
@@ -128,15 +129,16 @@ struct prom_args {
 
 struct prom_t {
        ihandle root;
-       ihandle chosen;
+       phandle chosen;
        int cpu;
        ihandle stdout;
        ihandle mmumap;
+       ihandle memory;
 };
 
 struct mem_map_entry {
-       unsigned long   base;
-       unsigned long   size;
+       u64     base;
+       u64     size;
 };
 
 typedef u32 cell_t;
@@ -178,6 +180,16 @@ static unsigned long __initdata prom_tce_alloc_start;
 static unsigned long __initdata prom_tce_alloc_end;
 #endif
 
+/* Platforms codes are now obsolete in the kernel. Now only used within this
+ * file and ultimately gone too. Feel free to change them if you need, they
+ * are not shared with anything outside of this file anymore
+ */
+#define PLATFORM_PSERIES       0x0100
+#define PLATFORM_PSERIES_LPAR  0x0101
+#define PLATFORM_LPAR          0x0001
+#define PLATFORM_POWERMAC      0x0400
+#define PLATFORM_GENERIC       0x0500
+
 static int __initdata of_platform;
 
 static char __initdata prom_cmd_line[COMMAND_LINE_SIZE];
@@ -190,6 +202,11 @@ static unsigned long __initdata alloc_bottom;
 static unsigned long __initdata rmo_top;
 static unsigned long __initdata ram_top;
 
+#ifdef CONFIG_KEXEC
+static unsigned long __initdata prom_crashk_base;
+static unsigned long __initdata prom_crashk_size;
+#endif
+
 static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE];
 static int __initdata mem_reserve_cnt;
 
@@ -198,14 +215,6 @@ static cell_t __initdata regbuf[1024];
 
 #define MAX_CPU_THREADS 2
 
-/* TO GO */
-#ifdef CONFIG_HMT
-struct {
-       unsigned int pir;
-       unsigned int threadid;
-} hmt_thread_data[NR_CPUS];
-#endif /* CONFIG_HMT */
-
 /*
  * Error results ... some OF calls will return "-1" on error, some
  * will return 0, some will return either. To simplify, here are
@@ -263,7 +272,7 @@ static int __init call_prom_ret(const char *service, int nargs, int nret,
        va_end(list);
 
        for (i = 0; i < nret; i++)
-               rets[nargs+i] = 0;
+               args.args[nargs+i] = 0;
 
        if (enter_prom(&args, RELOC(prom_entry)) < 0)
                return PROM_ERROR;
@@ -360,16 +369,36 @@ static void __init prom_printf(const char *format, ...)
 static unsigned int __init prom_claim(unsigned long virt, unsigned long size,
                                unsigned long align)
 {
-       int ret;
        struct prom_t *_prom = &RELOC(prom);
 
-       ret = call_prom("claim", 3, 1, (prom_arg_t)virt, (prom_arg_t)size,
-                       (prom_arg_t)align);
-       if (ret != -1 && _prom->mmumap != 0)
-               /* old pmacs need us to map as well */
+       if (align == 0 && (OF_WORKAROUNDS & OF_WA_CLAIM)) {
+               /*
+                * Old OF requires we claim physical and virtual separately
+                * and then map explicitly (assuming virtual mode)
+                */
+               int ret;
+               prom_arg_t result;
+
+               ret = call_prom_ret("call-method", 5, 2, &result,
+                                   ADDR("claim"), _prom->memory,
+                                   align, size, virt);
+               if (ret != 0 || result == -1)
+                       return -1;
+               ret = call_prom_ret("call-method", 5, 2, &result,
+                                   ADDR("claim"), _prom->mmumap,
+                                   align, size, virt);
+               if (ret != 0) {
+                       call_prom("call-method", 4, 1, ADDR("release"),
+                                 _prom->memory, size, virt);
+                       return -1;
+               }
+               /* the 0x12 is M (coherence) + PP == read/write */
                call_prom("call-method", 6, 1,
-                         ADDR("map"), _prom->mmumap, 0, size, virt, virt);
-       return ret;
+                         ADDR("map"), _prom->mmumap, 0x12, size, virt, virt);
+               return virt;
+       }
+       return call_prom("claim", 3, 1, (prom_arg_t)virt, (prom_arg_t)size,
+                        (prom_arg_t)align);
 }
 
 static void __init __attribute__((noreturn)) prom_panic(const char *reason)
@@ -378,6 +407,11 @@ static void __init __attribute__((noreturn)) prom_panic(const char *reason)
        reason = PTRRELOC(reason);
 #endif
        prom_print(reason);
+       /* Do not call exit because it clears the screen on pmac
+        * it also causes some sort of double-fault on early pmacs */
+       if (RELOC(of_platform) == PLATFORM_POWERMAC)
+               asm("trap\n");
+
        /* ToDo: should put up an SRC here on p/iSeries */
        call_prom("exit", 0, 0);
 
@@ -415,11 +449,52 @@ static int inline prom_getproplen(phandle node, const char *pname)
        return call_prom("getproplen", 2, 1, node, ADDR(pname));
 }
 
-static int inline prom_setprop(phandle node, const char *pname,
-                              void *value, size_t valuelen)
+static void add_string(char **str, const char *q)
 {
-       return call_prom("setprop", 4, 1, node, ADDR(pname),
-                        (u32)(unsigned long) value, (u32) valuelen);
+       char *p = *str;
+
+       while (*q)
+               *p++ = *q++;
+       *p++ = ' ';
+       *str = p;
+}
+
+static char *tohex(unsigned int x)
+{
+       static char digits[] = "0123456789abcdef";
+       static char result[9];
+       int i;
+
+       result[8] = 0;
+       i = 8;
+       do {
+               --i;
+               result[i] = digits[x & 0xf];
+               x >>= 4;
+       } while (x != 0 && i > 0);
+       return &result[i];
+}
+
+static int __init prom_setprop(phandle node, const char *nodename,
+                              const char *pname, void *value, size_t valuelen)
+{
+       char cmd[256], *p;
+
+       if (!(OF_WORKAROUNDS & OF_WA_LONGTRAIL))
+               return call_prom("setprop", 4, 1, node, ADDR(pname),
+                                (u32)(unsigned long) value, (u32) valuelen);
+
+       /* gah... setprop doesn't work on longtrail, have to use interpret */
+       p = cmd;
+       add_string(&p, "dev");
+       add_string(&p, nodename);
+       add_string(&p, tohex((u32)(unsigned long) value));
+       add_string(&p, tohex(valuelen));
+       add_string(&p, tohex(ADDR(pname)));
+       add_string(&p, tohex(strlen(RELOC(pname))));
+       add_string(&p, "property");
+       *p = 0;
+       return call_prom("interpret", 1, 1, (u32)(unsigned long) cmd);
 }
 
 /* We can't use the standard versions because of RELOC headaches. */
@@ -490,7 +565,8 @@ unsigned long prom_memparse(const char *ptr, const char **retptr)
 static void __init early_cmdline_parse(void)
 {
        struct prom_t *_prom = &RELOC(prom);
-       char *opt, *p;
+       const char *opt;
+       char *p;
        int l = 0;
 
        RELOC(prom_cmd_line[0]) = 0;
@@ -527,6 +603,35 @@ static void __init early_cmdline_parse(void)
                RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000);
 #endif
        }
+
+#ifdef CONFIG_KEXEC
+       /*
+        * crashkernel=size@addr specifies the location to reserve for
+        * crash kernel.
+        */
+       opt = strstr(RELOC(prom_cmd_line), RELOC("crashkernel="));
+       if (opt) {
+               opt += 12;
+               RELOC(prom_crashk_size) = 
+                       prom_memparse(opt, (const char **)&opt);
+
+               if (ALIGN(RELOC(prom_crashk_size), 0x1000000) !=
+                       RELOC(prom_crashk_size)) {
+                       prom_printf("Warning: crashkernel size is not "
+                                       "aligned to 16MB\n");
+               }
+
+               /*
+                * At present, the crash kernel always run at 32MB.
+                * Just ignore whatever user passed.
+                */
+               RELOC(prom_crashk_base) = 0x2000000;
+               if (*opt == '@') {
+                       prom_printf("Warning: PPC64 kdump kernel always runs "
+                                       "at 32 MB\n");
+               }
+       }
+#endif
 }
 
 #ifdef CONFIG_PPC_PSERIES
@@ -800,9 +905,9 @@ static unsigned long __init prom_next_cell(int s, cell_t **cellp)
  * If problems seem to show up, it would be a good start to track
  * them down.
  */
-static void reserve_mem(unsigned long base, unsigned long size)
+static void reserve_mem(u64 base, u64 size)
 {
-       unsigned long top = base + size;
+       u64 top = base + size;
        unsigned long cnt = RELOC(mem_reserve_cnt);
 
        if (size == 0)
@@ -888,7 +993,7 @@ static void __init prom_init_mem(void)
                        if (size == 0)
                                continue;
                        prom_debug("    %x %x\n", base, size);
-                       if (base == 0)
+                       if (base == 0 && (RELOC(of_platform) & PLATFORM_LPAR))
                                RELOC(rmo_top) = size;
                        if ((base + size) > RELOC(ram_top))
                                RELOC(ram_top) = base + size;
@@ -948,6 +1053,12 @@ static void __init prom_init_mem(void)
        prom_printf("  alloc_top_hi : %x\n", RELOC(alloc_top_high));
        prom_printf("  rmo_top      : %x\n", RELOC(rmo_top));
        prom_printf("  ram_top      : %x\n", RELOC(ram_top));
+#ifdef CONFIG_KEXEC
+       if (RELOC(prom_crashk_base)) {
+               prom_printf("  crashk_base  : %x\n",  RELOC(prom_crashk_base));
+               prom_printf("  crashk_size  : %x\n", RELOC(prom_crashk_size));
+       }
+#endif
 }
 
 
@@ -980,7 +1091,7 @@ static void __init prom_instantiate_rtas(void)
 
        rtas_inst = call_prom("open", 1, 1, ADDR("/rtas"));
        if (!IHANDLE_VALID(rtas_inst)) {
-               prom_printf("opening rtas package failed");
+               prom_printf("opening rtas package failed (%x)\n", rtas_inst);
                return;
        }
 
@@ -988,7 +1099,7 @@ static void __init prom_instantiate_rtas(void)
 
        if (call_prom_ret("call-method", 3, 2, &entry,
                          ADDR("instantiate-rtas"),
-                         rtas_inst, base) == PROM_ERROR
+                         rtas_inst, base) != 0
            || entry == 0) {
                prom_printf(" failed\n");
                return;
@@ -997,8 +1108,10 @@ static void __init prom_instantiate_rtas(void)
 
        reserve_mem(base, size);
 
-       prom_setprop(rtas_node, "linux,rtas-base", &base, sizeof(base));
-       prom_setprop(rtas_node, "linux,rtas-entry", &entry, sizeof(entry));
+       prom_setprop(rtas_node, "/rtas", "linux,rtas-base",
+                    &base, sizeof(base));
+       prom_setprop(rtas_node, "/rtas", "linux,rtas-entry",
+                    &entry, sizeof(entry));
 
        prom_debug("rtas base     = 0x%x\n", base);
        prom_debug("rtas entry    = 0x%x\n", entry);
@@ -1089,10 +1202,6 @@ static void __init prom_initialize_tce_table(void)
                if (base < local_alloc_bottom)
                        local_alloc_bottom = base;
 
-               /* Save away the TCE table attributes for later use. */
-               prom_setprop(node, "linux,tce-base", &base, sizeof(base));
-               prom_setprop(node, "linux,tce-size", &minsize, sizeof(minsize));
-
                /* It seems OF doesn't null-terminate the path :-( */
                memset(path, 0, sizeof(path));
                /* Call OF to setup the TCE hardware */
@@ -1101,6 +1210,10 @@ static void __init prom_initialize_tce_table(void)
                        prom_printf("package-to-path failed\n");
                }
 
+               /* Save away the TCE table attributes for later use. */
+               prom_setprop(node, path, "linux,tce-base", &base, sizeof(base));
+               prom_setprop(node, path, "linux,tce-size", &minsize, sizeof(minsize));
+
                prom_debug("TCE table: %s\n", path);
                prom_debug("\tnode = 0x%x\n", node);
                prom_debug("\tbase = 0x%x\n", base);
@@ -1213,10 +1326,6 @@ static void __init prom_hold_cpus(void)
         */
        *spinloop = 0;
 
-#ifdef CONFIG_HMT
-       for (i = 0; i < NR_CPUS; i++)
-               RELOC(hmt_thread_data)[i].pir = 0xdeadbeef;
-#endif
        /* look for cpus */
        for (node = 0; prom_next_node(&node); ) {
                type[0] = 0;
@@ -1283,32 +1392,6 @@ static void __init prom_hold_cpus(void)
                /* Reserve cpu #s for secondary threads.   They start later. */
                cpuid += cpu_threads;
        }
-#ifdef CONFIG_HMT
-       /* Only enable HMT on processors that provide support. */
-       if (__is_processor(PV_PULSAR) || 
-           __is_processor(PV_ICESTAR) ||
-           __is_processor(PV_SSTAR)) {
-               prom_printf("    starting secondary threads\n");
-
-               for (i = 0; i < NR_CPUS; i += 2) {
-                       if (!cpu_online(i))
-                               continue;
-
-                       if (i == 0) {
-                               unsigned long pir = mfspr(SPRN_PIR);
-                               if (__is_processor(PV_PULSAR)) {
-                                       RELOC(hmt_thread_data)[i].pir = 
-                                               pir & 0x1f;
-                               } else {
-                                       RELOC(hmt_thread_data)[i].pir = 
-                                               pir & 0x3ff;
-                               }
-                       }
-               }
-       } else {
-               prom_printf("Processor is not HMT capable\n");
-       }
-#endif
 
        if (cpuid > NR_CPUS)
                prom_printf("WARNING: maximum CPUs (" __stringify(NR_CPUS)
@@ -1342,6 +1425,7 @@ static void __init prom_init_client_services(unsigned long pp)
 /*
  * For really old powermacs, we need to map things we claim.
  * For that, we need the ihandle of the mmu.
+ * Also, on the longtrail, we need to work around other bugs.
  */
 static void __init prom_find_mmu(void)
 {
@@ -1355,12 +1439,19 @@ static void __init prom_find_mmu(void)
        if (prom_getprop(oprom, "model", version, sizeof(version)) <= 0)
                return;
        version[sizeof(version) - 1] = 0;
-       prom_printf("OF version is '%s'\n", version);
        /* XXX might need to add other versions here */
-       if (strcmp(version, "Open Firmware, 1.0.5") != 0)
+       if (strcmp(version, "Open Firmware, 1.0.5") == 0)
+               of_workarounds = OF_WA_CLAIM;
+       else if (strncmp(version, "FirmWorks,3.", 12) == 0) {
+               of_workarounds = OF_WA_CLAIM | OF_WA_LONGTRAIL;
+               call_prom("interpret", 1, 1, "dev /memory 0 to allow-reclaim");
+       } else
                return;
+       _prom->memory = call_prom("open", 1, 1, ADDR("/memory"));
        prom_getprop(_prom->chosen, "mmu", &_prom->mmumap,
                     sizeof(_prom->mmumap));
+       if (!IHANDLE_VALID(_prom->memory) || !IHANDLE_VALID(_prom->mmumap))
+               of_workarounds &= ~OF_WA_CLAIM;         /* hmmm */
 }
 #else
 #define prom_find_mmu()
@@ -1382,16 +1473,17 @@ static void __init prom_init_stdout(void)
        memset(path, 0, 256);
        call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255);
        val = call_prom("instance-to-package", 1, 1, _prom->stdout);
-       prom_setprop(_prom->chosen, "linux,stdout-package", &val, sizeof(val));
+       prom_setprop(_prom->chosen, "/chosen", "linux,stdout-package",
+                    &val, sizeof(val));
        prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device));
-       prom_setprop(_prom->chosen, "linux,stdout-path",
-                    RELOC(of_stdout_device), strlen(RELOC(of_stdout_device))+1);
+       prom_setprop(_prom->chosen, "/chosen", "linux,stdout-path",
+                    path, strlen(path) + 1);
 
        /* If it's a display, note it */
        memset(type, 0, sizeof(type));
        prom_getprop(val, "device_type", type, sizeof(type));
        if (strcmp(type, RELOC("display")) == 0)
-               prom_setprop(val, "linux,boot-display", NULL, 0);
+               prom_setprop(val, path, "linux,boot-display", NULL, 0);
 }
 
 static void __init prom_close_stdin(void)
@@ -1410,7 +1502,10 @@ static int __init prom_find_machine_type(void)
        int len, i = 0;
 #ifdef CONFIG_PPC64
        phandle rtas;
+       int x;
 #endif
+
+       /* Look for a PowerMac */
        len = prom_getprop(_prom->root, "compatible",
                           compat, sizeof(compat)-1);
        if (len > 0) {
@@ -1423,26 +1518,36 @@ static int __init prom_find_machine_type(void)
                        if (strstr(p, RELOC("Power Macintosh")) ||
                            strstr(p, RELOC("MacRISC")))
                                return PLATFORM_POWERMAC;
-#ifdef CONFIG_PPC64
-                       if (strstr(p, RELOC("Momentum,Maple")))
-                               return PLATFORM_MAPLE;
-#endif
                        i += sl + 1;
                }
        }
 #ifdef CONFIG_PPC64
+       /* If not a mac, try to figure out if it's an IBM pSeries or any other
+        * PAPR compliant platform. We assume it is if :
+        *  - /device_type is "chrp" (please, do NOT use that for future
+        *    non-IBM designs !
+        *  - it has /rtas
+        */
+       len = prom_getprop(_prom->root, "model",
+                          compat, sizeof(compat)-1);
+       if (len <= 0)
+               return PLATFORM_GENERIC;
+       compat[len] = 0;
+       if (strcmp(compat, "chrp"))
+               return PLATFORM_GENERIC;
+
        /* Default to pSeries. We need to know if we are running LPAR */
        rtas = call_prom("finddevice", 1, 1, ADDR("/rtas"));
-       if (PHANDLE_VALID(rtas)) {
-               int x = prom_getproplen(rtas, "ibm,hypertas-functions");
-               if (x != PROM_ERROR) {
-                       prom_printf("Hypertas detected, assuming LPAR !\n");
-                       return PLATFORM_PSERIES_LPAR;
-               }
+       if (!PHANDLE_VALID(rtas))
+               return PLATFORM_GENERIC;
+       x = prom_getproplen(rtas, "ibm,hypertas-functions");
+       if (x != PROM_ERROR) {
+               prom_printf("Hypertas detected, assuming LPAR !\n");
+               return PLATFORM_PSERIES_LPAR;
        }
        return PLATFORM_PSERIES;
 #else
-       return PLATFORM_CHRP;
+       return PLATFORM_GENERIC;
 #endif
 }
 
@@ -1514,7 +1619,7 @@ static void __init prom_check_displays(void)
 
                /* Success */
                prom_printf("done\n");
-               prom_setprop(node, "linux,opened", NULL, 0);
+               prom_setprop(node, path, "linux,opened", NULL, 0);
 
                /* Setup a usable color table when the appropriate
                 * method is available. Should update this to set-colors */
@@ -1884,9 +1989,11 @@ static void __init fixup_device_tree(void)
        /* interrupt on this revision of u3 is number 0 and level */
        interrupts[0] = 0;
        interrupts[1] = 1;
-       prom_setprop(i2c, "interrupts", &interrupts, sizeof(interrupts));
+       prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupts",
+                    &interrupts, sizeof(interrupts));
        parent = (u32)mpic;
-       prom_setprop(i2c, "interrupt-parent", &parent, sizeof(parent));
+       prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupt-parent",
+                    &parent, sizeof(parent));
 #endif
 }
 
@@ -1918,15 +2025,15 @@ static void __init prom_check_initrd(unsigned long r3, unsigned long r4)
        if (r3 && r4 && r4 != 0xdeadbeef) {
                unsigned long val;
 
-               RELOC(prom_initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3;
+               RELOC(prom_initrd_start) = is_kernel_addr(r3) ? __pa(r3) : r3;
                RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4;
 
                val = RELOC(prom_initrd_start);
-               prom_setprop(_prom->chosen, "linux,initrd-start", &val,
-                            sizeof(val));
+               prom_setprop(_prom->chosen, "/chosen", "linux,initrd-start",
+                            &val, sizeof(val));
                val = RELOC(prom_initrd_end);
-               prom_setprop(_prom->chosen, "linux,initrd-end", &val,
-                            sizeof(val));
+               prom_setprop(_prom->chosen, "/chosen", "linux,initrd-end",
+                            &val, sizeof(val));
 
                reserve_mem(RELOC(prom_initrd_start),
                            RELOC(prom_initrd_end) - RELOC(prom_initrd_start));
@@ -1948,7 +2055,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
 {      
                struct prom_t *_prom;
        unsigned long hdr;
-       u32 getprop_rval;
        unsigned long offset = reloc_offset();
 
 #ifdef CONFIG_PPC32
@@ -1969,34 +2075,37 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
        prom_init_client_services(pp);
 
        /*
-        * Init prom stdout device
-        */
-       prom_init_stdout();
-
-       /*
         * See if this OF is old enough that we need to do explicit maps
+        * and other workarounds
         */
        prom_find_mmu();
 
        /*
-        * Check for an initrd
+        * Init prom stdout device
         */
-       prom_check_initrd(r3, r4);
+       prom_init_stdout();
 
        /*
         * Get default machine type. At this point, we do not differentiate
         * between pSeries SMP and pSeries LPAR
         */
        RELOC(of_platform) = prom_find_machine_type();
-       getprop_rval = RELOC(of_platform);
-       prom_setprop(_prom->chosen, "linux,platform",
-                    &getprop_rval, sizeof(getprop_rval));
+
+       /* Bail if this is a kdump kernel. */
+       if (PHYSICAL_START > 0)
+               prom_panic("Error: You can't boot a kdump kernel from OF!\n");
+
+       /*
+        * Check for an initrd
+        */
+       prom_check_initrd(r3, r4);
 
 #ifdef CONFIG_PPC_PSERIES
        /*
         * On pSeries, inform the firmware about our capabilities
         */
-       if (RELOC(of_platform) & PLATFORM_PSERIES)
+       if (RELOC(of_platform) == PLATFORM_PSERIES ||
+           RELOC(of_platform) == PLATFORM_PSERIES_LPAR)
                prom_send_capabilities();
 #endif
 
@@ -2016,6 +2125,10 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
         */
        prom_init_mem();
 
+#ifdef CONFIG_KEXEC
+       if (RELOC(prom_crashk_base))
+               reserve_mem(RELOC(prom_crashk_base), RELOC(prom_crashk_size));
+#endif
        /*
         * Determine which cpu is actually running right _now_
         */
@@ -2050,26 +2163,38 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
         * Fill in some infos for use by the kernel later on
         */
        if (RELOC(prom_memory_limit))
-               prom_setprop(_prom->chosen, "linux,memory-limit",
+               prom_setprop(_prom->chosen, "/chosen", "linux,memory-limit",
                             &RELOC(prom_memory_limit),
                             sizeof(prom_memory_limit));
 #ifdef CONFIG_PPC64
        if (RELOC(ppc64_iommu_off))
-               prom_setprop(_prom->chosen, "linux,iommu-off", NULL, 0);
+               prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off",
+                            NULL, 0);
 
        if (RELOC(iommu_force_on))
-               prom_setprop(_prom->chosen, "linux,iommu-force-on", NULL, 0);
+               prom_setprop(_prom->chosen, "/chosen", "linux,iommu-force-on",
+                            NULL, 0);
 
        if (RELOC(prom_tce_alloc_start)) {
-               prom_setprop(_prom->chosen, "linux,tce-alloc-start",
+               prom_setprop(_prom->chosen, "/chosen", "linux,tce-alloc-start",
                             &RELOC(prom_tce_alloc_start),
                             sizeof(prom_tce_alloc_start));
-               prom_setprop(_prom->chosen, "linux,tce-alloc-end",
+               prom_setprop(_prom->chosen, "/chosen", "linux,tce-alloc-end",
                             &RELOC(prom_tce_alloc_end),
                             sizeof(prom_tce_alloc_end));
        }
 #endif
 
+#ifdef CONFIG_KEXEC
+       if (RELOC(prom_crashk_base)) {
+               prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-base",
+                       PTRRELOC(&prom_crashk_base),
+                       sizeof(RELOC(prom_crashk_base)));
+               prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-size",
+                       PTRRELOC(&prom_crashk_size),
+                       sizeof(RELOC(prom_crashk_size)));
+       }
+#endif
        /*
         * Fixup any known bugs in the device-tree
         */