Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[safe/jmp/linux-2.6] / arch / powerpc / kernel / prom_init.c
index 4ce0105..97d4bd9 100644 (file)
@@ -16,7 +16,6 @@
 #undef DEBUG_PROM
 
 #include <stdarg.h>
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/init.h>
 #include <asm/sections.h>
 #include <asm/machdep.h>
 
-#ifdef CONFIG_LOGO_LINUX_CLUT224
 #include <linux/linux_logo.h>
-extern const struct linux_logo logo_linux_clut224;
-#endif
 
 /*
  * Properties whose value is longer than this get excluded from our
@@ -137,8 +133,8 @@ struct prom_t {
 };
 
 struct mem_map_entry {
-       unsigned long   base;
-       unsigned long   size;
+       u64     base;
+       u64     size;
 };
 
 typedef u32 cell_t;
@@ -174,12 +170,22 @@ static unsigned long __initdata dt_string_start, dt_string_end;
 static unsigned long __initdata prom_initrd_start, prom_initrd_end;
 
 #ifdef CONFIG_PPC64
-static int __initdata iommu_force_on;
-static int __initdata ppc64_iommu_off;
+static int __initdata prom_iommu_force_on;
+static int __initdata prom_iommu_off;
 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];
@@ -198,16 +204,6 @@ static int __initdata mem_reserve_cnt;
 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
@@ -265,7 +261,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;
@@ -400,6 +396,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);
 
@@ -553,7 +554,9 @@ 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;
@@ -561,7 +564,7 @@ static void __init early_cmdline_parse(void)
        if ((long)_prom->chosen > 0)
                l = prom_getprop(_prom->chosen, "bootargs", p, COMMAND_LINE_SIZE-1);
 #ifdef CONFIG_CMDLINE
-       if (l == 0) /* dbl check */
+       if (l <= 0 || p[0] == '\0') /* dbl check */
                strlcpy(RELOC(prom_cmd_line),
                        RELOC(CONFIG_CMDLINE), sizeof(prom_cmd_line));
 #endif /* CONFIG_CMDLINE */
@@ -575,12 +578,11 @@ static void __init early_cmdline_parse(void)
                while (*opt && *opt == ' ')
                        opt++;
                if (!strncmp(opt, RELOC("off"), 3))
-                       RELOC(ppc64_iommu_off) = 1;
+                       RELOC(prom_iommu_off) = 1;
                else if (!strncmp(opt, RELOC("force"), 5))
-                       RELOC(iommu_force_on) = 1;
+                       RELOC(prom_iommu_force_on) = 1;
        }
 #endif
-
        opt = strstr(RELOC(prom_cmd_line), RELOC("mem="));
        if (opt) {
                opt += 4;
@@ -594,10 +596,137 @@ static void __init early_cmdline_parse(void)
 
 #ifdef CONFIG_PPC_PSERIES
 /*
- * To tell the firmware what our capabilities are, we have to pass
- * it a fake 32-bit ELF header containing a couple of PT_NOTE sections
- * that contain structures that contain the actual values.
+ * There are two methods for telling firmware what our capabilities are.
+ * Newer machines have an "ibm,client-architecture-support" method on the
+ * root node.  For older machines, we have to call the "process-elf-header"
+ * method in the /packages/elf-loader node, passing it a fake 32-bit
+ * ELF header containing a couple of PT_NOTE sections that contain
+ * structures that contain various information.
  */
+
+/*
+ * New method - extensible architecture description vector.
+ *
+ * Because the description vector contains a mix of byte and word
+ * values, we declare it as an unsigned char array, and use this
+ * macro to put word values in.
+ */
+#define W(x)   ((x) >> 24) & 0xff, ((x) >> 16) & 0xff, \
+               ((x) >> 8) & 0xff, (x) & 0xff
+
+/* Option vector bits - generic bits in byte 1 */
+#define OV_IGNORE              0x80    /* ignore this vector */
+#define OV_CESSATION_POLICY    0x40    /* halt if unsupported option present*/
+
+/* Option vector 1: processor architectures supported */
+#define OV1_PPC_2_00           0x80    /* set if we support PowerPC 2.00 */
+#define OV1_PPC_2_01           0x40    /* set if we support PowerPC 2.01 */
+#define OV1_PPC_2_02           0x20    /* set if we support PowerPC 2.02 */
+#define OV1_PPC_2_03           0x10    /* set if we support PowerPC 2.03 */
+#define OV1_PPC_2_04           0x08    /* set if we support PowerPC 2.04 */
+#define OV1_PPC_2_05           0x04    /* set if we support PowerPC 2.05 */
+#define OV1_PPC_2_06           0x02    /* set if we support PowerPC 2.06 */
+
+/* Option vector 2: Open Firmware options supported */
+#define OV2_REAL_MODE          0x20    /* set if we want OF in real mode */
+
+/* Option vector 3: processor options supported */
+#define OV3_FP                 0x80    /* floating point */
+#define OV3_VMX                        0x40    /* VMX/Altivec */
+#define OV3_DFP                        0x20    /* decimal FP */
+
+/* Option vector 5: PAPR/OF options supported */
+#define OV5_LPAR               0x80    /* logical partitioning supported */
+#define OV5_SPLPAR             0x40    /* shared-processor LPAR supported */
+/* ibm,dynamic-reconfiguration-memory property supported */
+#define OV5_DRCONF_MEMORY      0x20
+#define OV5_LARGE_PAGES                0x10    /* large pages supported */
+#define OV5_DONATE_DEDICATE_CPU 0x02   /* donate dedicated CPU support */
+/* PCIe/MSI support.  Without MSI full PCIe is not supported */
+#ifdef CONFIG_PCI_MSI
+#define OV5_MSI                        0x01    /* PCIe/MSI support */
+#else
+#define OV5_MSI                        0x00
+#endif /* CONFIG_PCI_MSI */
+#ifdef CONFIG_PPC_SMLPAR
+#define OV5_CMO                        0x80    /* Cooperative Memory Overcommitment */
+#else
+#define OV5_CMO                        0x00
+#endif
+#define OV5_TYPE1_AFFINITY     0x80    /* Type 1 NUMA affinity */
+
+/* Option Vector 6: IBM PAPR hints */
+#define OV6_LINUX              0x02    /* Linux is our OS */
+
+/*
+ * The architecture vector has an array of PVR mask/value pairs,
+ * followed by # option vectors - 1, followed by the option vectors.
+ */
+static unsigned char ibm_architecture_vec[] = {
+       W(0xfffe0000), W(0x003a0000),   /* POWER5/POWER5+ */
+       W(0xffff0000), W(0x003e0000),   /* POWER6 */
+       W(0xffff0000), W(0x003f0000),   /* POWER7 */
+       W(0xffffffff), W(0x0f000003),   /* all 2.06-compliant */
+       W(0xffffffff), W(0x0f000002),   /* all 2.05-compliant */
+       W(0xfffffffe), W(0x0f000001),   /* all 2.04-compliant and earlier */
+       6 - 1,                          /* 6 option vectors */
+
+       /* option vector 1: processor architectures supported */
+       3 - 2,                          /* length */
+       0,                              /* don't ignore, don't halt */
+       OV1_PPC_2_00 | OV1_PPC_2_01 | OV1_PPC_2_02 | OV1_PPC_2_03 |
+       OV1_PPC_2_04 | OV1_PPC_2_05 | OV1_PPC_2_06,
+
+       /* option vector 2: Open Firmware options supported */
+       34 - 2,                         /* length */
+       OV2_REAL_MODE,
+       0, 0,
+       W(0xffffffff),                  /* real_base */
+       W(0xffffffff),                  /* real_size */
+       W(0xffffffff),                  /* virt_base */
+       W(0xffffffff),                  /* virt_size */
+       W(0xffffffff),                  /* load_base */
+       W(64),                          /* 64MB min RMA */
+       W(0xffffffff),                  /* full client load */
+       0,                              /* min RMA percentage of total RAM */
+       48,                             /* max log_2(hash table size) */
+
+       /* option vector 3: processor options supported */
+       3 - 2,                          /* length */
+       0,                              /* don't ignore, don't halt */
+       OV3_FP | OV3_VMX | OV3_DFP,
+
+       /* option vector 4: IBM PAPR implementation */
+       2 - 2,                          /* length */
+       0,                              /* don't halt */
+
+       /* option vector 5: PAPR/OF options */
+       13 - 2,                         /* length */
+       0,                              /* don't ignore, don't halt */
+       OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY |
+       OV5_DONATE_DEDICATE_CPU | OV5_MSI,
+       0,
+       OV5_CMO,
+       OV5_TYPE1_AFFINITY,
+       0,
+       0,
+       0,
+       /* WARNING: The offset of the "number of cores" field below
+        * must match by the macro below. Update the definition if
+        * the structure layout changes.
+        */
+#define IBM_ARCH_VEC_NRCORES_OFFSET    100
+       W(NR_CPUS),                     /* number of cores supported */
+
+       /* option vector 6: IBM PAPR hints */
+       4 - 2,                          /* length */
+       0,
+       0,
+       OV6_LINUX,
+
+};
+
+/* Old method - ELF header with PT_NOTE sections */
 static struct fake_elf {
        Elf32_Ehdr      elfhdr;
        Elf32_Phdr      phdr[2];
@@ -684,10 +813,89 @@ static struct fake_elf {
        }
 };
 
+static int __init prom_count_smt_threads(void)
+{
+       phandle node;
+       char type[64];
+       unsigned int plen;
+
+       /* Pick up th first CPU node we can find */
+       for (node = 0; prom_next_node(&node); ) {
+               type[0] = 0;
+               prom_getprop(node, "device_type", type, sizeof(type));
+
+               if (strcmp(type, RELOC("cpu")))
+                       continue;
+               /*
+                * There is an entry for each smt thread, each entry being
+                * 4 bytes long.  All cpus should have the same number of
+                * smt threads, so return after finding the first.
+                */
+               plen = prom_getproplen(node, "ibm,ppc-interrupt-server#s");
+               if (plen == PROM_ERROR)
+                       break;
+               plen >>= 2;
+               prom_debug("Found 0x%x smt threads per core\n", (unsigned long)plen);
+
+               /* Sanity check */
+               if (plen < 1 || plen > 64) {
+                       prom_printf("Threads per core 0x%x out of bounds, assuming 1\n",
+                                   (unsigned long)plen);
+                       return 1;
+               }
+               return plen;
+       }
+       prom_debug("No threads found, assuming 1 per core\n");
+
+       return 1;
+
+}
+
+
 static void __init prom_send_capabilities(void)
 {
-       ihandle elfloader;
+       ihandle elfloader, root;
+       prom_arg_t ret;
+       u32 *cores;
+
+       root = call_prom("open", 1, 1, ADDR("/"));
+       if (root != 0) {
+               /* We need to tell the FW about the number of cores we support.
+                *
+                * To do that, we count the number of threads on the first core
+                * (we assume this is the same for all cores) and use it to
+                * divide NR_CPUS.
+                */
+               cores = (u32 *)PTRRELOC(&ibm_architecture_vec[IBM_ARCH_VEC_NRCORES_OFFSET]);
+               if (*cores != NR_CPUS) {
+                       prom_printf("WARNING ! "
+                                   "ibm_architecture_vec structure inconsistent: 0x%x !\n",
+                                   *cores);
+               } else {
+                       *cores = NR_CPUS / prom_count_smt_threads();
+                       prom_printf("Max number of cores passed to firmware: 0x%x\n",
+                                   (unsigned long)*cores);
+               }
+
+               /* try calling the ibm,client-architecture-support method */
+               prom_printf("Calling ibm,client-architecture-support...");
+               if (call_prom_ret("call-method", 3, 2, &ret,
+                                 ADDR("ibm,client-architecture-support"),
+                                 root,
+                                 ADDR(ibm_architecture_vec)) == 0) {
+                       /* the call exists... */
+                       if (ret)
+                               prom_printf("\nWARNING: ibm,client-architecture"
+                                           "-support call FAILED!\n");
+                       call_prom("close", 1, 0, root);
+                       prom_printf(" done\n");
+                       return;
+               }
+               call_prom("close", 1, 0, root);
+               prom_printf(" not implemented\n");
+       }
 
+       /* no ibm,client-architecture-support call, try the old way */
        elfloader = call_prom("open", 1, 1, ADDR("/packages/elf-loader"));
        if (elfloader == 0) {
                prom_printf("couldn't open /packages/elf-loader\n");
@@ -863,9 +1071,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 __init 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)
@@ -887,7 +1095,7 @@ static void reserve_mem(unsigned long base, unsigned long size)
 }
 
 /*
- * Initialize memory allocation mecanism, parse "memory" nodes and
+ * Initialize memory allocation mechanism, parse "memory" nodes and
  * obtain that way the top of memory and RMO to setup out local allocator
  */
 static void __init prom_init_mem(void)
@@ -951,7 +1159,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;
@@ -1003,6 +1211,7 @@ static void __init prom_init_mem(void)
                RELOC(rmo_top) = RELOC(ram_top);
        RELOC(rmo_top) = min(0x30000000ul, RELOC(rmo_top));
        RELOC(alloc_top) = RELOC(rmo_top);
+       RELOC(alloc_top_high) = RELOC(ram_top);
 
        prom_printf("memory layout at init:\n");
        prom_printf("  memory_limit : %x (16 MB aligned)\n", RELOC(prom_memory_limit));
@@ -1047,7 +1256,7 @@ static void __init prom_instantiate_rtas(void)
                return;
        }
 
-       prom_printf("instantiating rtas at 0x%x ...", base);
+       prom_printf("instantiating rtas at 0x%x...", base);
 
        if (call_prom_ret("call-method", 3, 2, &entry,
                          ADDR("instantiate-rtas"),
@@ -1088,7 +1297,7 @@ static void __init prom_initialize_tce_table(void)
        u64 local_alloc_top, local_alloc_bottom;
        u64 i;
 
-       if (RELOC(ppc64_iommu_off))
+       if (RELOC(prom_iommu_off))
                return;
 
        prom_debug("starting prom_initialize_tce_table\n");
@@ -1110,7 +1319,7 @@ static void __init prom_initialize_tce_table(void)
                if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL))
                        continue;
 
-               /* Keep the old logic in tack to avoid regression. */
+               /* Keep the old logic intact to avoid regression. */
                if (compatible[0] != 0) {
                        if ((strstr(compatible, RELOC("python")) == NULL) &&
                            (strstr(compatible, RELOC("Speedwagon")) == NULL) &&
@@ -1155,7 +1364,7 @@ static void __init prom_initialize_tce_table(void)
                        local_alloc_bottom = base;
 
                /* It seems OF doesn't null-terminate the path :-( */
-               memset(path, 0, sizeof(path));
+               memset(path, 0, PROM_SCRATCH_SIZE);
                /* Call OF to setup the TCE hardware */
                if (call_prom("package-to-path", 3, 1, node,
                              path, PROM_SCRATCH_SIZE-1) == PROM_ERROR) {
@@ -1174,7 +1383,7 @@ static void __init prom_initialize_tce_table(void)
                /* Initialize the table to have a one-to-one mapping
                 * over the allocated size.
                 */
-               tce_entryp = (unsigned long *)base;
+               tce_entryp = (u64 *)base;
                for (i = 0; i < (minsize >> 3) ;tce_entryp++, i++) {
                        tce_entry = (i << PAGE_SHIFT);
                        tce_entry |= 0x3;
@@ -1196,16 +1405,10 @@ static void __init prom_initialize_tce_table(void)
 
        reserve_mem(local_alloc_bottom, local_alloc_top - local_alloc_bottom);
 
-       if (RELOC(prom_memory_limit)) {
-               /*
-                * We align the start to a 16MB boundary so we can map
-                * the TCE area using large pages if possible.
-                * The end should be the top of RAM so no need to align it.
-                */
-               RELOC(prom_tce_alloc_start) = _ALIGN_DOWN(local_alloc_bottom,
-                                                         0x1000000);
-               RELOC(prom_tce_alloc_end) = local_alloc_top;
-       }
+       /* These are only really needed if there is a memory limit in
+        * effect, but we don't know so export them always. */
+       RELOC(prom_tce_alloc_start) = local_alloc_bottom;
+       RELOC(prom_tce_alloc_end) = local_alloc_top;
 
        /* Flag the first invalid entry */
        prom_debug("ending prom_initialize_tce_table\n");
@@ -1230,10 +1433,6 @@ static void __init prom_initialize_tce_table(void)
  *
  * -- Cort
  */
-extern void __secondary_hold(void);
-extern unsigned long __secondary_hold_spinloop;
-extern unsigned long __secondary_hold_acknowledge;
-
 /*
  * We want to reference the copy of __secondary_hold_* in the
  * 0 - 0x100 address range
@@ -1246,22 +1445,12 @@ static void __init prom_hold_cpus(void)
        unsigned int reg;
        phandle node;
        char type[64];
-       int cpuid = 0;
-       unsigned int interrupt_server[MAX_CPU_THREADS];
-       unsigned int cpu_threads, hw_cpu_num;
-       int propsize;
        struct prom_t *_prom = &RELOC(prom);
        unsigned long *spinloop
                = (void *) LOW_ADDR(__secondary_hold_spinloop);
        unsigned long *acknowledge
                = (void *) LOW_ADDR(__secondary_hold_acknowledge);
-#ifdef CONFIG_PPC64
-       /* __secondary_hold is actually a descriptor, not the text address */
-       unsigned long secondary_hold
-               = __pa(*PTRRELOC((unsigned long *)__secondary_hold));
-#else
        unsigned long secondary_hold = LOW_ADDR(__secondary_hold);
-#endif
 
        prom_debug("prom_hold_cpus: start...\n");
        prom_debug("    1) spinloop       = 0x%x\n", (unsigned long)spinloop);
@@ -1278,10 +1467,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;
@@ -1297,7 +1482,6 @@ static void __init prom_hold_cpus(void)
                reg = -1;
                prom_getprop(node, "reg", &reg, sizeof(reg));
 
-               prom_debug("\ncpuid        = 0x%x\n", cpuid);
                prom_debug("cpu hw idx   = 0x%x\n", reg);
 
                /* Init the acknowledge var which will be reset by
@@ -1306,28 +1490,9 @@ static void __init prom_hold_cpus(void)
                 */
                *acknowledge = (unsigned long)-1;
 
-               propsize = prom_getprop(node, "ibm,ppc-interrupt-server#s",
-                                       &interrupt_server,
-                                       sizeof(interrupt_server));
-               if (propsize < 0) {
-                       /* no property.  old hardware has no SMT */
-                       cpu_threads = 1;
-                       interrupt_server[0] = reg; /* fake it with phys id */
-               } else {
-                       /* We have a threaded processor */
-                       cpu_threads = propsize / sizeof(u32);
-                       if (cpu_threads > MAX_CPU_THREADS) {
-                               prom_printf("SMT: too many threads!\n"
-                                           "SMT: found %x, max is %x\n",
-                                           cpu_threads, MAX_CPU_THREADS);
-                               cpu_threads = 1; /* ToDo: panic? */
-                       }
-               }
-
-               hw_cpu_num = interrupt_server[0];
-               if (hw_cpu_num != _prom->cpu) {
+               if (reg != _prom->cpu) {
                        /* Primary Thread of non-boot cpu */
-                       prom_printf("%x : starting cpu hw idx %x... ", cpuid, reg);
+                       prom_printf("starting cpu hw idx %x... ", reg);
                        call_prom("start-cpu", 3, 0, node,
                                  secondary_hold, reg);
 
@@ -1342,42 +1507,9 @@ static void __init prom_hold_cpus(void)
                }
 #ifdef CONFIG_SMP
                else
-                       prom_printf("%x : boot cpu     %x\n", cpuid, reg);
+                       prom_printf("boot cpu hw idx %x\n", reg);
 #endif /* CONFIG_SMP */
-
-               /* 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)
-                           ") exceeded: ignoring extras\n");
 
        prom_debug("prom_hold_cpus: end...\n");
 }
@@ -1484,7 +1616,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) {
@@ -1498,25 +1633,43 @@ static int __init prom_find_machine_type(void)
                            strstr(p, RELOC("MacRISC")))
                                return PLATFORM_POWERMAC;
 #ifdef CONFIG_PPC64
-                       if (strstr(p, RELOC("Momentum,Maple")))
-                               return PLATFORM_MAPLE;
-#endif
+                       /* We must make sure we don't detect the IBM Cell
+                        * blades as pSeries due to some firmware issues,
+                        * so we do it here.
+                        */
+                       if (strstr(p, RELOC("IBM,CBEA")) ||
+                           strstr(p, RELOC("IBM,CPBW-1.0")))
+                               return PLATFORM_GENERIC;
+#endif /* CONFIG_PPC64 */
                        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, "device_type",
+                          compat, sizeof(compat)-1);
+       if (len <= 0)
+               return PLATFORM_GENERIC;
+       if (strcmp(compat, RELOC("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_debug("Hypertas detected, assuming LPAR !\n");
+               return PLATFORM_PSERIES_LPAR;
        }
        return PLATFORM_PSERIES;
 #else
-       return PLATFORM_CHRP;
+       return PLATFORM_GENERIC;
 #endif
 }
 
@@ -1560,7 +1713,7 @@ static void __init prom_check_displays(void)
        };
        const unsigned char *clut;
 
-       prom_printf("Looking for displays\n");
+       prom_debug("Looking for displays\n");
        for (node = 0; prom_next_node(&node); ) {
                memset(type, 0, sizeof(type));
                prom_getprop(node, "device_type", type, sizeof(type));
@@ -1578,7 +1731,7 @@ static void __init prom_check_displays(void)
                if (call_prom("package-to-path", 3, 1, node, path,
                              PROM_SCRATCH_SIZE-10) == PROM_ERROR)
                        continue;
-               prom_printf("found display   : %s, opening ... ", path);
+               prom_printf("found display   : %s, opening... ", path);
                
                ih = call_prom("open", 1, 1, path);
                if (ih == 0) {
@@ -1897,11 +2050,7 @@ static void __init flatten_device_tree(void)
        /* Version 16 is not backward compatible */
        hdr->last_comp_version = 0x10;
 
-       /* Reserve the whole thing and copy the reserve map in, we
-        * also bump mem_reserve_cnt to cause further reservations to
-        * fail since it's too late.
-        */
-       reserve_mem(RELOC(dt_header_start), hdr->totalsize);
+       /* Copy the reserve map in */
        memcpy(rsvmap, RELOC(mem_reserve_map), sizeof(mem_reserve_map));
 
 #ifdef DEBUG_PROM
@@ -1914,6 +2063,9 @@ static void __init flatten_device_tree(void)
                                    RELOC(mem_reserve_map)[i].size);
        }
 #endif
+       /* Bump mem_reserve_cnt to cause further reservations to fail
+        * since it's too late.
+        */
        RELOC(mem_reserve_cnt) = MEM_RESERVE_MAP_SIZE;
 
        prom_printf("Device tree strings 0x%x -> 0x%x\n",
@@ -1923,10 +2075,149 @@ static void __init flatten_device_tree(void)
 
 }
 
+#ifdef CONFIG_PPC_MAPLE
+/* PIBS Version 1.05.0000 04/26/2005 has an incorrect /ht/isa/ranges property.
+ * The values are bad, and it doesn't even have the right number of cells. */
+static void __init fixup_device_tree_maple(void)
+{
+       phandle isa;
+       u32 rloc = 0x01002000; /* IO space; PCI device = 4 */
+       u32 isa_ranges[6];
+       char *name;
+
+       name = "/ht@0/isa@4";
+       isa = call_prom("finddevice", 1, 1, ADDR(name));
+       if (!PHANDLE_VALID(isa)) {
+               name = "/ht@0/isa@6";
+               isa = call_prom("finddevice", 1, 1, ADDR(name));
+               rloc = 0x01003000; /* IO space; PCI device = 6 */
+       }
+       if (!PHANDLE_VALID(isa))
+               return;
 
-static void __init fixup_device_tree(void)
+       if (prom_getproplen(isa, "ranges") != 12)
+               return;
+       if (prom_getprop(isa, "ranges", isa_ranges, sizeof(isa_ranges))
+               == PROM_ERROR)
+               return;
+
+       if (isa_ranges[0] != 0x1 ||
+               isa_ranges[1] != 0xf4000000 ||
+               isa_ranges[2] != 0x00010000)
+               return;
+
+       prom_printf("Fixing up bogus ISA range on Maple/Apache...\n");
+
+       isa_ranges[0] = 0x1;
+       isa_ranges[1] = 0x0;
+       isa_ranges[2] = rloc;
+       isa_ranges[3] = 0x0;
+       isa_ranges[4] = 0x0;
+       isa_ranges[5] = 0x00010000;
+       prom_setprop(isa, name, "ranges",
+                       isa_ranges, sizeof(isa_ranges));
+}
+
+#define CPC925_MC_START                0xf8000000
+#define CPC925_MC_LENGTH       0x1000000
+/* The values for memory-controller don't have right number of cells */
+static void __init fixup_device_tree_maple_memory_controller(void)
+{
+       phandle mc;
+       u32 mc_reg[4];
+       char *name = "/hostbridge@f8000000";
+       struct prom_t *_prom = &RELOC(prom);
+       u32 ac, sc;
+
+       mc = call_prom("finddevice", 1, 1, ADDR(name));
+       if (!PHANDLE_VALID(mc))
+               return;
+
+       if (prom_getproplen(mc, "reg") != 8)
+               return;
+
+       prom_getprop(_prom->root, "#address-cells", &ac, sizeof(ac));
+       prom_getprop(_prom->root, "#size-cells", &sc, sizeof(sc));
+       if ((ac != 2) || (sc != 2))
+               return;
+
+       if (prom_getprop(mc, "reg", mc_reg, sizeof(mc_reg)) == PROM_ERROR)
+               return;
+
+       if (mc_reg[0] != CPC925_MC_START || mc_reg[1] != CPC925_MC_LENGTH)
+               return;
+
+       prom_printf("Fixing up bogus hostbridge on Maple...\n");
+
+       mc_reg[0] = 0x0;
+       mc_reg[1] = CPC925_MC_START;
+       mc_reg[2] = 0x0;
+       mc_reg[3] = CPC925_MC_LENGTH;
+       prom_setprop(mc, name, "reg", mc_reg, sizeof(mc_reg));
+}
+#else
+#define fixup_device_tree_maple()
+#define fixup_device_tree_maple_memory_controller()
+#endif
+
+#ifdef CONFIG_PPC_CHRP
+/*
+ * Pegasos and BriQ lacks the "ranges" property in the isa node
+ * Pegasos needs decimal IRQ 14/15, not hexadecimal
+ * Pegasos has the IDE configured in legacy mode, but advertised as native
+ */
+static void __init fixup_device_tree_chrp(void)
 {
+       phandle ph;
+       u32 prop[6];
+       u32 rloc = 0x01006000; /* IO space; PCI device = 12 */
+       char *name;
+       int rc;
+
+       name = "/pci@80000000/isa@c";
+       ph = call_prom("finddevice", 1, 1, ADDR(name));
+       if (!PHANDLE_VALID(ph)) {
+               name = "/pci@ff500000/isa@6";
+               ph = call_prom("finddevice", 1, 1, ADDR(name));
+               rloc = 0x01003000; /* IO space; PCI device = 6 */
+       }
+       if (PHANDLE_VALID(ph)) {
+               rc = prom_getproplen(ph, "ranges");
+               if (rc == 0 || rc == PROM_ERROR) {
+                       prom_printf("Fixing up missing ISA range on Pegasos...\n");
+
+                       prop[0] = 0x1;
+                       prop[1] = 0x0;
+                       prop[2] = rloc;
+                       prop[3] = 0x0;
+                       prop[4] = 0x0;
+                       prop[5] = 0x00010000;
+                       prom_setprop(ph, name, "ranges", prop, sizeof(prop));
+               }
+       }
+
+       name = "/pci@80000000/ide@C,1";
+       ph = call_prom("finddevice", 1, 1, ADDR(name));
+       if (PHANDLE_VALID(ph)) {
+               prom_printf("Fixing up IDE interrupt on Pegasos...\n");
+               prop[0] = 14;
+               prop[1] = 0x0;
+               prom_setprop(ph, name, "interrupts", prop, 2*sizeof(u32));
+               prom_printf("Fixing up IDE class-code on Pegasos...\n");
+               rc = prom_getprop(ph, "class-code", prop, sizeof(u32));
+               if (rc == sizeof(u32)) {
+                       prop[0] &= ~0x5;
+                       prom_setprop(ph, name, "class-code", prop, sizeof(u32));
+               }
+       }
+}
+#else
+#define fixup_device_tree_chrp()
+#endif
+
 #if defined(CONFIG_PPC64) && defined(CONFIG_PPC_PMAC)
+static void __init fixup_device_tree_pmac(void)
+{
        phandle u3, i2c, mpic;
        u32 u3_rev;
        u32 interrupts[2];
@@ -1963,13 +2254,159 @@ static void __init fixup_device_tree(void)
        parent = (u32)mpic;
        prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupt-parent",
                     &parent, sizeof(parent));
+}
+#else
+#define fixup_device_tree_pmac()
 #endif
+
+#ifdef CONFIG_PPC_EFIKA
+/*
+ * The MPC5200 FEC driver requires an phy-handle property to tell it how
+ * to talk to the phy.  If the phy-handle property is missing, then this
+ * function is called to add the appropriate nodes and link it to the
+ * ethernet node.
+ */
+static void __init fixup_device_tree_efika_add_phy(void)
+{
+       u32 node;
+       char prop[64];
+       int rv;
+
+       /* Check if /builtin/ethernet exists - bail if it doesn't */
+       node = call_prom("finddevice", 1, 1, ADDR("/builtin/ethernet"));
+       if (!PHANDLE_VALID(node))
+               return;
+
+       /* Check if the phy-handle property exists - bail if it does */
+       rv = prom_getprop(node, "phy-handle", prop, sizeof(prop));
+       if (!rv)
+               return;
+
+       /*
+        * At this point the ethernet device doesn't have a phy described.
+        * Now we need to add the missing phy node and linkage
+        */
+
+       /* Check for an MDIO bus node - if missing then create one */
+       node = call_prom("finddevice", 1, 1, ADDR("/builtin/mdio"));
+       if (!PHANDLE_VALID(node)) {
+               prom_printf("Adding Ethernet MDIO node\n");
+               call_prom("interpret", 1, 1,
+                       " s\" /builtin\" find-device"
+                       " new-device"
+                               " 1 encode-int s\" #address-cells\" property"
+                               " 0 encode-int s\" #size-cells\" property"
+                               " s\" mdio\" device-name"
+                               " s\" fsl,mpc5200b-mdio\" encode-string"
+                               " s\" compatible\" property"
+                               " 0xf0003000 0x400 reg"
+                               " 0x2 encode-int"
+                               " 0x5 encode-int encode+"
+                               " 0x3 encode-int encode+"
+                               " s\" interrupts\" property"
+                       " finish-device");
+       };
+
+       /* Check for a PHY device node - if missing then create one and
+        * give it's phandle to the ethernet node */
+       node = call_prom("finddevice", 1, 1,
+                        ADDR("/builtin/mdio/ethernet-phy"));
+       if (!PHANDLE_VALID(node)) {
+               prom_printf("Adding Ethernet PHY node\n");
+               call_prom("interpret", 1, 1,
+                       " s\" /builtin/mdio\" find-device"
+                       " new-device"
+                               " s\" ethernet-phy\" device-name"
+                               " 0x10 encode-int s\" reg\" property"
+                               " my-self"
+                               " ihandle>phandle"
+                       " finish-device"
+                       " s\" /builtin/ethernet\" find-device"
+                               " encode-int"
+                               " s\" phy-handle\" property"
+                       " device-end");
+       }
 }
 
+static void __init fixup_device_tree_efika(void)
+{
+       int sound_irq[3] = { 2, 2, 0 };
+       int bcomm_irq[3*16] = { 3,0,0, 3,1,0, 3,2,0, 3,3,0,
+                               3,4,0, 3,5,0, 3,6,0, 3,7,0,
+                               3,8,0, 3,9,0, 3,10,0, 3,11,0,
+                               3,12,0, 3,13,0, 3,14,0, 3,15,0 };
+       u32 node;
+       char prop[64];
+       int rv, len;
+
+       /* Check if we're really running on a EFIKA */
+       node = call_prom("finddevice", 1, 1, ADDR("/"));
+       if (!PHANDLE_VALID(node))
+               return;
+
+       rv = prom_getprop(node, "model", prop, sizeof(prop));
+       if (rv == PROM_ERROR)
+               return;
+       if (strcmp(prop, "EFIKA5K2"))
+               return;
+
+       prom_printf("Applying EFIKA device tree fixups\n");
+
+       /* Claiming to be 'chrp' is death */
+       node = call_prom("finddevice", 1, 1, ADDR("/"));
+       rv = prom_getprop(node, "device_type", prop, sizeof(prop));
+       if (rv != PROM_ERROR && (strcmp(prop, "chrp") == 0))
+               prom_setprop(node, "/", "device_type", "efika", sizeof("efika"));
+
+       /* CODEGEN,description is exposed in /proc/cpuinfo so
+          fix that too */
+       rv = prom_getprop(node, "CODEGEN,description", prop, sizeof(prop));
+       if (rv != PROM_ERROR && (strstr(prop, "CHRP")))
+               prom_setprop(node, "/", "CODEGEN,description",
+                            "Efika 5200B PowerPC System",
+                            sizeof("Efika 5200B PowerPC System"));
+
+       /* Fixup bestcomm interrupts property */
+       node = call_prom("finddevice", 1, 1, ADDR("/builtin/bestcomm"));
+       if (PHANDLE_VALID(node)) {
+               len = prom_getproplen(node, "interrupts");
+               if (len == 12) {
+                       prom_printf("Fixing bestcomm interrupts property\n");
+                       prom_setprop(node, "/builtin/bestcom", "interrupts",
+                                    bcomm_irq, sizeof(bcomm_irq));
+               }
+       }
+
+       /* Fixup sound interrupts property */
+       node = call_prom("finddevice", 1, 1, ADDR("/builtin/sound"));
+       if (PHANDLE_VALID(node)) {
+               rv = prom_getprop(node, "interrupts", prop, sizeof(prop));
+               if (rv == PROM_ERROR) {
+                       prom_printf("Adding sound interrupts property\n");
+                       prom_setprop(node, "/builtin/sound", "interrupts",
+                                    sound_irq, sizeof(sound_irq));
+               }
+       }
+
+       /* Make sure ethernet phy-handle property exists */
+       fixup_device_tree_efika_add_phy();
+}
+#else
+#define fixup_device_tree_efika()
+#endif
+
+static void __init fixup_device_tree(void)
+{
+       fixup_device_tree_maple();
+       fixup_device_tree_maple_memory_controller();
+       fixup_device_tree_chrp();
+       fixup_device_tree_pmac();
+       fixup_device_tree_efika();
+}
 
 static void __init prom_find_boot_cpu(void)
 {
-               struct prom_t *_prom = &RELOC(prom);
+       struct prom_t *_prom = &RELOC(prom);
        u32 getprop_rval;
        ihandle prom_cpu;
        phandle cpu_pkg;
@@ -1989,12 +2426,12 @@ static void __init prom_find_boot_cpu(void)
 static void __init prom_check_initrd(unsigned long r3, unsigned long r4)
 {
 #ifdef CONFIG_BLK_DEV_INITRD
-               struct prom_t *_prom = &RELOC(prom);
+       struct prom_t *_prom = &RELOC(prom);
 
        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);
@@ -2020,14 +2457,14 @@ static void __init prom_check_initrd(unsigned long r3, unsigned long r4)
 
 unsigned long __init prom_init(unsigned long r3, unsigned long r4,
                               unsigned long pp,
-                              unsigned long r6, unsigned long r7)
+                              unsigned long r6, unsigned long r7,
+                              unsigned long kbase)
 {      
-               struct prom_t *_prom;
+       struct prom_t *_prom;
        unsigned long hdr;
-       u32 getprop_rval;
-       unsigned long offset = reloc_offset();
 
 #ifdef CONFIG_PPC32
+       unsigned long offset = reloc_offset();
        reloc_got2(offset);
 #endif
 
@@ -2055,19 +2492,24 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
         */
        prom_init_stdout();
 
-       /*
-        * Check for an initrd
-        */
-       prom_check_initrd(r3, r4);
+       prom_printf("Preparing to boot %s", RELOC(linux_banner));
 
        /*
         * 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, "/chosen", "linux,platform",
-                    &getprop_rval, sizeof(getprop_rval));
+
+#ifndef CONFIG_RELOCATABLE
+       /* Bail if this is a kdump kernel. */
+       if (PHYSICAL_START > 0)
+               prom_panic("Error: You can't boot a kdump kernel from OF!\n");
+#endif
+
+       /*
+        * Check for an initrd
+        */
+       prom_check_initrd(r3, r4);
 
 #ifdef CONFIG_PPC_PSERIES
        /*
@@ -2081,8 +2523,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
        /*
         * Copy the CPU hold code
         */
-               if (RELOC(of_platform) != PLATFORM_POWERMAC)
-                       copy_and_flush(0, KERNELBASE + offset, 0x100, 0);
+       if (RELOC(of_platform) != PLATFORM_POWERMAC)
+               copy_and_flush(0, kbase, 0x100, 0);
 
        /*
         * Do early parsing of command line
@@ -2132,11 +2574,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
                             &RELOC(prom_memory_limit),
                             sizeof(prom_memory_limit));
 #ifdef CONFIG_PPC64
-       if (RELOC(ppc64_iommu_off))
+       if (RELOC(prom_iommu_off))
                prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off",
                             NULL, 0);
 
-       if (RELOC(iommu_force_on))
+       if (RELOC(prom_iommu_force_on))
                prom_setprop(_prom->chosen, "/chosen", "linux,iommu-force-on",
                             NULL, 0);
 
@@ -2158,7 +2600,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
        /*
         * Now finally create the flattened device-tree
         */
-       prom_printf("copying OF device tree ...\n");
+       prom_printf("copying OF device tree...\n");
        flatten_device_tree();
 
        /*
@@ -2173,7 +2615,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
         * Call OF "quiesce" method to shut down pending DMA's from
         * devices etc...
         */
-       prom_printf("Calling quiesce ...\n");
+       prom_printf("Calling quiesce...\n");
        call_prom("quiesce", 0, 0);
 
        /*
@@ -2189,7 +2631,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
        reloc_got2(-offset);
 #endif
 
-       __start(hdr, KERNELBASE + offset, 0);
+       __start(hdr, kbase, 0);
 
        return 0;
 }