]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - arch/powerpc/kernel/prom_init.c
[PATCH] powerpc: Add cputable entry for POWER6
[mirror_ubuntu-zesty-kernel.git] / arch / powerpc / kernel / prom_init.c
index ec7153f4d47c2b6d6d0bcef7c241bc15692e2b18..078fb5533541d001db70eb618fb59a791d0b35f6 100644 (file)
@@ -180,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];
@@ -205,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
@@ -405,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);
 
@@ -629,10 +636,96 @@ 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 */
+
+/* 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 */
+
+/* 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 */
+
+/*
+ * 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(0xfffffffe), W(0x0f000001),   /* all 2.04-compliant and earlier */
+       5 - 1,                          /* 5 option vectors */
+
+       /* option vector 1: processor architectures supported */
+       3 - 1,                          /* 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,
+
+       /* option vector 2: Open Firmware options supported */
+       34 - 1,                         /* 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),                          /* 128MB 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 - 1,                          /* length */
+       0,                              /* don't ignore, don't halt */
+       OV3_FP | OV3_VMX,
+
+       /* option vector 4: IBM PAPR implementation */
+       2 - 1,                          /* length */
+       0,                              /* don't halt */
+
+       /* option vector 5: PAPR/OF options */
+       3 - 1,                          /* length */
+       0,                              /* don't ignore, don't halt */
+       OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES,
+};
+
+/* Old method - ELF header with PT_NOTE sections */
 static struct fake_elf {
        Elf32_Ehdr      elfhdr;
        Elf32_Phdr      phdr[2];
@@ -721,8 +814,26 @@ static struct fake_elf {
 
 static void __init prom_send_capabilities(void)
 {
-       ihandle elfloader;
+       ihandle elfloader, root;
+       prom_arg_t ret;
+
+       root = call_prom("open", 1, 1, ADDR("/"));
+       if (root != 0) {
+               /* try calling the ibm,client-architecture-support method */
+               if (call_prom_ret("call-method", 3, 2, &ret,
+                                 ADDR("ibm,client-architecture-support"),
+                                 ADDR(ibm_architecture_vec)) == 0) {
+                       /* the call exists... */
+                       if (ret)
+                               prom_printf("WARNING: ibm,client-architecture"
+                                           "-support call FAILED!\n");
+                       call_prom("close", 1, 0, root);
+                       return;
+               }
+               call_prom("close", 1, 0, root);
+       }
 
+       /* 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");
@@ -986,7 +1097,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;
@@ -1319,10 +1430,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;
@@ -1389,32 +1496,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)
@@ -1525,7 +1606,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) {
@@ -1538,28 +1622,35 @@ 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;
-                       if (strstr(p, RELOC("IBM,CPB")))
-                               return PLATFORM_CELL;
-#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, "device_type",
+                          compat, sizeof(compat)-1);
+       if (len <= 0)
+               return PLATFORM_GENERIC;
+       if (strncmp(compat, RELOC("chrp"), 4))
+               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
 }
 
@@ -2067,7 +2158,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
@@ -2098,6 +2188,12 @@ unsigned long __init prom_init(unsigned long r3, unsigned long 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();
+
        /* Bail if this is a kdump kernel. */
        if (PHYSICAL_START > 0)
                prom_panic("Error: You can't boot a kdump kernel from OF!\n");
@@ -2107,15 +2203,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
         */
        prom_check_initrd(r3, r4);
 
-       /*
-        * 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));
-
 #ifdef CONFIG_PPC_PSERIES
        /*
         * On pSeries, inform the firmware about our capabilities