powerpc/powernv: Add support for instanciating OPAL v2 from Open Firmware

OPAL v2 is instantiated in a way similar to RTAS using Open Firmware
client interface calls, and the resulting address and entry point are
put in the device-tree
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 14a43e69
...@@ -140,7 +140,9 @@ struct mem_map_entry { ...@@ -140,7 +140,9 @@ struct mem_map_entry {
typedef u32 cell_t; 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 #ifdef CONFIG_PPC64
extern int enter_prom(struct prom_args *args, unsigned long entry); extern int enter_prom(struct prom_args *args, unsigned long entry);
...@@ -1293,6 +1295,11 @@ static int __initdata prom_rtas_start_cpu; ...@@ -1293,6 +1295,11 @@ static int __initdata prom_rtas_start_cpu;
static u64 __initdata prom_rtas_data; static u64 __initdata prom_rtas_data;
static u64 __initdata prom_rtas_entry; 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 */ /* XXX Don't change this structure without updating opal-takeover.S */
static struct opal_secondary_data { static struct opal_secondary_data {
s64 ack; /* 0 */ s64 ack; /* 0 */
...@@ -1468,6 +1475,76 @@ static void prom_opal_takeover(void) ...@@ -1468,6 +1475,76 @@ static void prom_opal_takeover(void)
for (;;) for (;;)
opal_do_takeover(args); 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 */ #endif /* CONFIG_PPC_POWERNV */
/* /*
...@@ -1863,7 +1940,7 @@ static int __init prom_find_machine_type(void) ...@@ -1863,7 +1940,7 @@ static int __init prom_find_machine_type(void)
int x; int x;
#endif #endif
/* Look for a PowerMac */ /* Look for a PowerMac or a Cell */
len = prom_getprop(_prom->root, "compatible", len = prom_getprop(_prom->root, "compatible",
compat, sizeof(compat)-1); compat, sizeof(compat)-1);
if (len > 0) { if (len > 0) {
...@@ -1889,7 +1966,11 @@ static int __init prom_find_machine_type(void) ...@@ -1889,7 +1966,11 @@ static int __init prom_find_machine_type(void)
} }
} }
#ifdef CONFIG_PPC64 #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 : * PAPR compliant platform. We assume it is if :
* - /device_type is "chrp" (please, do NOT use that for future * - /device_type is "chrp" (please, do NOT use that for future
* non-IBM designs ! * non-IBM designs !
...@@ -2116,7 +2197,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, ...@@ -2116,7 +2197,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
unsigned long soff; unsigned long soff;
unsigned char *valp; unsigned char *valp;
static char pname[MAX_PROPERTY_NAME]; 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); 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, ...@@ -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); valp = make_room(mem_start, mem_end, l, 4);
call_prom("getprop", 4, 1, node, RELOC(pname), valp, l); call_prom("getprop", 4, 1, node, RELOC(pname), valp, l);
*mem_start = _ALIGN(*mem_start, 4); *mem_start = _ALIGN(*mem_start, 4);
if (!strcmp(RELOC(pname), RELOC("phandle")))
has_phandle = 1;
} }
/* Add a "linux,phandle" property. */ /* Add a "linux,phandle" property if no "phandle" property already
soff = dt_find_string(RELOC("linux,phandle")); * existed (can happen with OPAL)
if (soff == 0) */
prom_printf("WARNING: Can't find string index for" if (!has_phandle) {
" <linux-phandle> node %s\n", path); soff = dt_find_string(RELOC("linux,phandle"));
else { if (soff == 0)
dt_push_token(OF_DT_PROP, mem_start, mem_end); prom_printf("WARNING: Can't find string index for"
dt_push_token(4, mem_start, mem_end); " <linux-phandle> node %s\n", path);
dt_push_token(soff, mem_start, mem_end); else {
valp = make_room(mem_start, mem_end, 4, 4); dt_push_token(OF_DT_PROP, mem_start, mem_end);
*(u32 *)valp = node; 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 */ /* do all our children */
...@@ -2746,6 +2834,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, ...@@ -2746,6 +2834,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
* between pSeries SMP and pSeries LPAR * between pSeries SMP and pSeries LPAR
*/ */
RELOC(of_platform) = prom_find_machine_type(); RELOC(of_platform) = prom_find_machine_type();
prom_printf("Detected machine type: %x\n", RELOC(of_platform));
#ifndef CONFIG_RELOCATABLE #ifndef CONFIG_RELOCATABLE
/* Bail if this is a kdump kernel. */ /* Bail if this is a kdump kernel. */
...@@ -2807,7 +2896,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, ...@@ -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 * On non-powermacs, try to instantiate RTAS. PowerMacs don't
* have a usable RTAS implementation. * 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(); prom_instantiate_rtas();
#ifdef CONFIG_PPC_POWERNV #ifdef CONFIG_PPC_POWERNV
...@@ -2818,7 +2908,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, ...@@ -2818,7 +2908,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
prom_opal_hold_cpus(); prom_opal_hold_cpus();
prom_opal_takeover(); prom_opal_takeover();
} }
} } else if (RELOC(of_platform) == PLATFORM_OPAL)
prom_instantiate_opal();
#endif #endif
/* /*
...@@ -2826,7 +2917,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, ...@@ -2826,7 +2917,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
* *
* PowerMacs use a different mechanism to spin CPUs * 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(); prom_hold_cpus();
/* /*
...@@ -2894,7 +2986,13 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, ...@@ -2894,7 +2986,13 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
reloc_got2(-offset); reloc_got2(-offset);
#endif #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; return 0;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment