|
@@ -140,7 +140,9 @@ struct mem_map_entry {
|
|
|
|
|
|
typedef u32 cell_t;
|
|
|
|
|
|
-extern void __start(unsigned long r3, unsigned long r4, unsigned long r5);
|
|
|
+extern void __start(unsigned long r3, unsigned long r4, unsigned long r5,
|
|
|
+ unsigned long r6, unsigned long r7, unsigned long r8,
|
|
|
+ unsigned long r9);
|
|
|
|
|
|
#ifdef CONFIG_PPC64
|
|
|
extern int enter_prom(struct prom_args *args, unsigned long entry);
|
|
@@ -1293,6 +1295,11 @@ static int __initdata prom_rtas_start_cpu;
|
|
|
static u64 __initdata prom_rtas_data;
|
|
|
static u64 __initdata prom_rtas_entry;
|
|
|
|
|
|
+#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL
|
|
|
+static u64 __initdata prom_opal_base;
|
|
|
+static u64 __initdata prom_opal_entry;
|
|
|
+#endif
|
|
|
+
|
|
|
/* XXX Don't change this structure without updating opal-takeover.S */
|
|
|
static struct opal_secondary_data {
|
|
|
s64 ack; /* 0 */
|
|
@@ -1468,6 +1475,76 @@ static void prom_opal_takeover(void)
|
|
|
for (;;)
|
|
|
opal_do_takeover(args);
|
|
|
}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Allocate room for and instantiate OPAL
|
|
|
+ */
|
|
|
+static void __init prom_instantiate_opal(void)
|
|
|
+{
|
|
|
+ phandle opal_node;
|
|
|
+ ihandle opal_inst;
|
|
|
+ u64 base, entry;
|
|
|
+ u64 size = 0, align = 0x10000;
|
|
|
+ u32 rets[2];
|
|
|
+
|
|
|
+ prom_debug("prom_instantiate_opal: start...\n");
|
|
|
+
|
|
|
+ opal_node = call_prom("finddevice", 1, 1, ADDR("/ibm,opal"));
|
|
|
+ prom_debug("opal_node: %x\n", opal_node);
|
|
|
+ if (!PHANDLE_VALID(opal_node))
|
|
|
+ return;
|
|
|
+
|
|
|
+ prom_getprop(opal_node, "opal-runtime-size", &size, sizeof(size));
|
|
|
+ if (size == 0)
|
|
|
+ return;
|
|
|
+ prom_getprop(opal_node, "opal-runtime-alignment", &align,
|
|
|
+ sizeof(align));
|
|
|
+
|
|
|
+ base = alloc_down(size, align, 0);
|
|
|
+ if (base == 0) {
|
|
|
+ prom_printf("OPAL allocation failed !\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ opal_inst = call_prom("open", 1, 1, ADDR("/ibm,opal"));
|
|
|
+ if (!IHANDLE_VALID(opal_inst)) {
|
|
|
+ prom_printf("opening opal package failed (%x)\n", opal_inst);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ prom_printf("instantiating opal at 0x%x...", base);
|
|
|
+
|
|
|
+ if (call_prom_ret("call-method", 4, 3, rets,
|
|
|
+ ADDR("load-opal-runtime"),
|
|
|
+ opal_inst,
|
|
|
+ base >> 32, base & 0xffffffff) != 0
|
|
|
+ || (rets[0] == 0 && rets[1] == 0)) {
|
|
|
+ prom_printf(" failed\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ entry = (((u64)rets[0]) << 32) | rets[1];
|
|
|
+
|
|
|
+ prom_printf(" done\n");
|
|
|
+
|
|
|
+ reserve_mem(base, size);
|
|
|
+
|
|
|
+ prom_debug("opal base = 0x%x\n", base);
|
|
|
+ prom_debug("opal align = 0x%x\n", align);
|
|
|
+ prom_debug("opal entry = 0x%x\n", entry);
|
|
|
+ prom_debug("opal size = 0x%x\n", (long)size);
|
|
|
+
|
|
|
+ prom_setprop(opal_node, "/ibm,opal", "opal-base-address",
|
|
|
+ &base, sizeof(base));
|
|
|
+ prom_setprop(opal_node, "/ibm,opal", "opal-entry-address",
|
|
|
+ &entry, sizeof(entry));
|
|
|
+
|
|
|
+#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL
|
|
|
+ RELOC(prom_opal_base) = base;
|
|
|
+ RELOC(prom_opal_entry) = entry;
|
|
|
+#endif
|
|
|
+ prom_debug("prom_instantiate_opal: end...\n");
|
|
|
+}
|
|
|
+
|
|
|
#endif /* CONFIG_PPC_POWERNV */
|
|
|
|
|
|
/*
|
|
@@ -1863,7 +1940,7 @@ static int __init prom_find_machine_type(void)
|
|
|
int x;
|
|
|
#endif
|
|
|
|
|
|
- /* Look for a PowerMac */
|
|
|
+ /* Look for a PowerMac or a Cell */
|
|
|
len = prom_getprop(_prom->root, "compatible",
|
|
|
compat, sizeof(compat)-1);
|
|
|
if (len > 0) {
|
|
@@ -1889,7 +1966,11 @@ static int __init prom_find_machine_type(void)
|
|
|
}
|
|
|
}
|
|
|
#ifdef CONFIG_PPC64
|
|
|
- /* If not a mac, try to figure out if it's an IBM pSeries or any other
|
|
|
+ /* Try to detect OPAL */
|
|
|
+ if (PHANDLE_VALID(call_prom("finddevice", 1, 1, ADDR("/ibm,opal"))))
|
|
|
+ return PLATFORM_OPAL;
|
|
|
+
|
|
|
+ /* 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 !
|
|
@@ -2116,7 +2197,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
|
|
|
unsigned long soff;
|
|
|
unsigned char *valp;
|
|
|
static char pname[MAX_PROPERTY_NAME];
|
|
|
- int l, room;
|
|
|
+ int l, room, has_phandle = 0;
|
|
|
|
|
|
dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end);
|
|
|
|
|
@@ -2200,19 +2281,26 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
|
|
|
valp = make_room(mem_start, mem_end, l, 4);
|
|
|
call_prom("getprop", 4, 1, node, RELOC(pname), valp, l);
|
|
|
*mem_start = _ALIGN(*mem_start, 4);
|
|
|
+
|
|
|
+ if (!strcmp(RELOC(pname), RELOC("phandle")))
|
|
|
+ has_phandle = 1;
|
|
|
}
|
|
|
|
|
|
- /* Add a "linux,phandle" property. */
|
|
|
- soff = dt_find_string(RELOC("linux,phandle"));
|
|
|
- if (soff == 0)
|
|
|
- prom_printf("WARNING: Can't find string index for"
|
|
|
- " <linux-phandle> node %s\n", path);
|
|
|
- else {
|
|
|
- dt_push_token(OF_DT_PROP, mem_start, mem_end);
|
|
|
- dt_push_token(4, mem_start, mem_end);
|
|
|
- dt_push_token(soff, mem_start, mem_end);
|
|
|
- valp = make_room(mem_start, mem_end, 4, 4);
|
|
|
- *(u32 *)valp = node;
|
|
|
+ /* Add a "linux,phandle" property if no "phandle" property already
|
|
|
+ * existed (can happen with OPAL)
|
|
|
+ */
|
|
|
+ if (!has_phandle) {
|
|
|
+ soff = dt_find_string(RELOC("linux,phandle"));
|
|
|
+ if (soff == 0)
|
|
|
+ prom_printf("WARNING: Can't find string index for"
|
|
|
+ " <linux-phandle> node %s\n", path);
|
|
|
+ else {
|
|
|
+ dt_push_token(OF_DT_PROP, mem_start, mem_end);
|
|
|
+ dt_push_token(4, mem_start, mem_end);
|
|
|
+ dt_push_token(soff, mem_start, mem_end);
|
|
|
+ valp = make_room(mem_start, mem_end, 4, 4);
|
|
|
+ *(u32 *)valp = node;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* do all our children */
|
|
@@ -2746,6 +2834,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
|
|
|
* between pSeries SMP and pSeries LPAR
|
|
|
*/
|
|
|
RELOC(of_platform) = prom_find_machine_type();
|
|
|
+ prom_printf("Detected machine type: %x\n", RELOC(of_platform));
|
|
|
|
|
|
#ifndef CONFIG_RELOCATABLE
|
|
|
/* Bail if this is a kdump kernel. */
|
|
@@ -2807,7 +2896,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
|
|
|
* On non-powermacs, try to instantiate RTAS. PowerMacs don't
|
|
|
* have a usable RTAS implementation.
|
|
|
*/
|
|
|
- if (RELOC(of_platform) != PLATFORM_POWERMAC)
|
|
|
+ if (RELOC(of_platform) != PLATFORM_POWERMAC &&
|
|
|
+ RELOC(of_platform) != PLATFORM_OPAL)
|
|
|
prom_instantiate_rtas();
|
|
|
|
|
|
#ifdef CONFIG_PPC_POWERNV
|
|
@@ -2818,7 +2908,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
|
|
|
prom_opal_hold_cpus();
|
|
|
prom_opal_takeover();
|
|
|
}
|
|
|
- }
|
|
|
+ } else if (RELOC(of_platform) == PLATFORM_OPAL)
|
|
|
+ prom_instantiate_opal();
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
@@ -2826,7 +2917,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
|
|
|
*
|
|
|
* PowerMacs use a different mechanism to spin CPUs
|
|
|
*/
|
|
|
- if (RELOC(of_platform) != PLATFORM_POWERMAC)
|
|
|
+ if (RELOC(of_platform) != PLATFORM_POWERMAC &&
|
|
|
+ RELOC(of_platform) != PLATFORM_OPAL)
|
|
|
prom_hold_cpus();
|
|
|
|
|
|
/*
|
|
@@ -2894,7 +2986,13 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
|
|
|
reloc_got2(-offset);
|
|
|
#endif
|
|
|
|
|
|
- __start(hdr, kbase, 0);
|
|
|
+#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL
|
|
|
+ /* OPAL early debug gets the OPAL base & entry in r8 and r9 */
|
|
|
+ __start(hdr, kbase, 0, 0, 0,
|
|
|
+ RELOC(prom_opal_base), RELOC(prom_opal_entry));
|
|
|
+#else
|
|
|
+ __start(hdr, kbase, 0, 0, 0, 0, 0);
|
|
|
+#endif
|
|
|
|
|
|
return 0;
|
|
|
}
|