diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-09-19 14:28:01 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-09-20 02:09:52 -0400 |
commit | 6e35d5dac0c83ebb616ff3b9c2d6155c9a9ccb86 (patch) | |
tree | bbd8641fa69eaa3f62d644e5acb03a657cd1c6b9 | |
parent | 14a43e69ed257a1fadadf9fea2c05adb1686419f (diff) |
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: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r-- | arch/powerpc/kernel/prom_init.c | 136 |
1 files changed, 117 insertions, 19 deletions
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index e3f390427216..e96f5d0d2c78 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c | |||
@@ -140,7 +140,9 @@ struct mem_map_entry { | |||
140 | 140 | ||
141 | typedef u32 cell_t; | 141 | typedef u32 cell_t; |
142 | 142 | ||
143 | extern void __start(unsigned long r3, unsigned long r4, unsigned long r5); | 143 | extern void __start(unsigned long r3, unsigned long r4, unsigned long r5, |
144 | unsigned long r6, unsigned long r7, unsigned long r8, | ||
145 | unsigned long r9); | ||
144 | 146 | ||
145 | #ifdef CONFIG_PPC64 | 147 | #ifdef CONFIG_PPC64 |
146 | extern int enter_prom(struct prom_args *args, unsigned long entry); | 148 | extern int enter_prom(struct prom_args *args, unsigned long entry); |
@@ -1293,6 +1295,11 @@ static int __initdata prom_rtas_start_cpu; | |||
1293 | static u64 __initdata prom_rtas_data; | 1295 | static u64 __initdata prom_rtas_data; |
1294 | static u64 __initdata prom_rtas_entry; | 1296 | static u64 __initdata prom_rtas_entry; |
1295 | 1297 | ||
1298 | #ifdef CONFIG_PPC_EARLY_DEBUG_OPAL | ||
1299 | static u64 __initdata prom_opal_base; | ||
1300 | static u64 __initdata prom_opal_entry; | ||
1301 | #endif | ||
1302 | |||
1296 | /* XXX Don't change this structure without updating opal-takeover.S */ | 1303 | /* XXX Don't change this structure without updating opal-takeover.S */ |
1297 | static struct opal_secondary_data { | 1304 | static struct opal_secondary_data { |
1298 | s64 ack; /* 0 */ | 1305 | s64 ack; /* 0 */ |
@@ -1468,6 +1475,76 @@ static void prom_opal_takeover(void) | |||
1468 | for (;;) | 1475 | for (;;) |
1469 | opal_do_takeover(args); | 1476 | opal_do_takeover(args); |
1470 | } | 1477 | } |
1478 | |||
1479 | /* | ||
1480 | * Allocate room for and instantiate OPAL | ||
1481 | */ | ||
1482 | static void __init prom_instantiate_opal(void) | ||
1483 | { | ||
1484 | phandle opal_node; | ||
1485 | ihandle opal_inst; | ||
1486 | u64 base, entry; | ||
1487 | u64 size = 0, align = 0x10000; | ||
1488 | u32 rets[2]; | ||
1489 | |||
1490 | prom_debug("prom_instantiate_opal: start...\n"); | ||
1491 | |||
1492 | opal_node = call_prom("finddevice", 1, 1, ADDR("/ibm,opal")); | ||
1493 | prom_debug("opal_node: %x\n", opal_node); | ||
1494 | if (!PHANDLE_VALID(opal_node)) | ||
1495 | return; | ||
1496 | |||
1497 | prom_getprop(opal_node, "opal-runtime-size", &size, sizeof(size)); | ||
1498 | if (size == 0) | ||
1499 | return; | ||
1500 | prom_getprop(opal_node, "opal-runtime-alignment", &align, | ||
1501 | sizeof(align)); | ||
1502 | |||
1503 | base = alloc_down(size, align, 0); | ||
1504 | if (base == 0) { | ||
1505 | prom_printf("OPAL allocation failed !\n"); | ||
1506 | return; | ||
1507 | } | ||
1508 | |||
1509 | opal_inst = call_prom("open", 1, 1, ADDR("/ibm,opal")); | ||
1510 | if (!IHANDLE_VALID(opal_inst)) { | ||
1511 | prom_printf("opening opal package failed (%x)\n", opal_inst); | ||
1512 | return; | ||
1513 | } | ||
1514 | |||
1515 | prom_printf("instantiating opal at 0x%x...", base); | ||
1516 | |||
1517 | if (call_prom_ret("call-method", 4, 3, rets, | ||
1518 | ADDR("load-opal-runtime"), | ||
1519 | opal_inst, | ||
1520 | base >> 32, base & 0xffffffff) != 0 | ||
1521 | || (rets[0] == 0 && rets[1] == 0)) { | ||
1522 | prom_printf(" failed\n"); | ||
1523 | return; | ||
1524 | } | ||
1525 | entry = (((u64)rets[0]) << 32) | rets[1]; | ||
1526 | |||
1527 | prom_printf(" done\n"); | ||
1528 | |||
1529 | reserve_mem(base, size); | ||
1530 | |||
1531 | prom_debug("opal base = 0x%x\n", base); | ||
1532 | prom_debug("opal align = 0x%x\n", align); | ||
1533 | prom_debug("opal entry = 0x%x\n", entry); | ||
1534 | prom_debug("opal size = 0x%x\n", (long)size); | ||
1535 | |||
1536 | prom_setprop(opal_node, "/ibm,opal", "opal-base-address", | ||
1537 | &base, sizeof(base)); | ||
1538 | prom_setprop(opal_node, "/ibm,opal", "opal-entry-address", | ||
1539 | &entry, sizeof(entry)); | ||
1540 | |||
1541 | #ifdef CONFIG_PPC_EARLY_DEBUG_OPAL | ||
1542 | RELOC(prom_opal_base) = base; | ||
1543 | RELOC(prom_opal_entry) = entry; | ||
1544 | #endif | ||
1545 | prom_debug("prom_instantiate_opal: end...\n"); | ||
1546 | } | ||
1547 | |||
1471 | #endif /* CONFIG_PPC_POWERNV */ | 1548 | #endif /* CONFIG_PPC_POWERNV */ |
1472 | 1549 | ||
1473 | /* | 1550 | /* |
@@ -1863,7 +1940,7 @@ static int __init prom_find_machine_type(void) | |||
1863 | int x; | 1940 | int x; |
1864 | #endif | 1941 | #endif |
1865 | 1942 | ||
1866 | /* Look for a PowerMac */ | 1943 | /* Look for a PowerMac or a Cell */ |
1867 | len = prom_getprop(_prom->root, "compatible", | 1944 | len = prom_getprop(_prom->root, "compatible", |
1868 | compat, sizeof(compat)-1); | 1945 | compat, sizeof(compat)-1); |
1869 | if (len > 0) { | 1946 | if (len > 0) { |
@@ -1889,7 +1966,11 @@ static int __init prom_find_machine_type(void) | |||
1889 | } | 1966 | } |
1890 | } | 1967 | } |
1891 | #ifdef CONFIG_PPC64 | 1968 | #ifdef CONFIG_PPC64 |
1892 | /* If not a mac, try to figure out if it's an IBM pSeries or any other | 1969 | /* Try to detect OPAL */ |
1970 | if (PHANDLE_VALID(call_prom("finddevice", 1, 1, ADDR("/ibm,opal")))) | ||
1971 | return PLATFORM_OPAL; | ||
1972 | |||
1973 | /* Try to figure out if it's an IBM pSeries or any other | ||
1893 | * PAPR compliant platform. We assume it is if : | 1974 | * PAPR compliant platform. We assume it is if : |
1894 | * - /device_type is "chrp" (please, do NOT use that for future | 1975 | * - /device_type is "chrp" (please, do NOT use that for future |
1895 | * non-IBM designs ! | 1976 | * non-IBM designs ! |
@@ -2116,7 +2197,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | |||
2116 | unsigned long soff; | 2197 | unsigned long soff; |
2117 | unsigned char *valp; | 2198 | unsigned char *valp; |
2118 | static char pname[MAX_PROPERTY_NAME]; | 2199 | static char pname[MAX_PROPERTY_NAME]; |
2119 | int l, room; | 2200 | int l, room, has_phandle = 0; |
2120 | 2201 | ||
2121 | dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); | 2202 | dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); |
2122 | 2203 | ||
@@ -2200,19 +2281,26 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | |||
2200 | valp = make_room(mem_start, mem_end, l, 4); | 2281 | valp = make_room(mem_start, mem_end, l, 4); |
2201 | call_prom("getprop", 4, 1, node, RELOC(pname), valp, l); | 2282 | call_prom("getprop", 4, 1, node, RELOC(pname), valp, l); |
2202 | *mem_start = _ALIGN(*mem_start, 4); | 2283 | *mem_start = _ALIGN(*mem_start, 4); |
2284 | |||
2285 | if (!strcmp(RELOC(pname), RELOC("phandle"))) | ||
2286 | has_phandle = 1; | ||
2203 | } | 2287 | } |
2204 | 2288 | ||
2205 | /* Add a "linux,phandle" property. */ | 2289 | /* Add a "linux,phandle" property if no "phandle" property already |
2206 | soff = dt_find_string(RELOC("linux,phandle")); | 2290 | * existed (can happen with OPAL) |
2207 | if (soff == 0) | 2291 | */ |
2208 | prom_printf("WARNING: Can't find string index for" | 2292 | if (!has_phandle) { |
2209 | " <linux-phandle> node %s\n", path); | 2293 | soff = dt_find_string(RELOC("linux,phandle")); |
2210 | else { | 2294 | if (soff == 0) |
2211 | dt_push_token(OF_DT_PROP, mem_start, mem_end); | 2295 | prom_printf("WARNING: Can't find string index for" |
2212 | dt_push_token(4, mem_start, mem_end); | 2296 | " <linux-phandle> node %s\n", path); |
2213 | dt_push_token(soff, mem_start, mem_end); | 2297 | else { |
2214 | valp = make_room(mem_start, mem_end, 4, 4); | 2298 | dt_push_token(OF_DT_PROP, mem_start, mem_end); |
2215 | *(u32 *)valp = node; | 2299 | dt_push_token(4, mem_start, mem_end); |
2300 | dt_push_token(soff, mem_start, mem_end); | ||
2301 | valp = make_room(mem_start, mem_end, 4, 4); | ||
2302 | *(u32 *)valp = node; | ||
2303 | } | ||
2216 | } | 2304 | } |
2217 | 2305 | ||
2218 | /* do all our children */ | 2306 | /* do all our children */ |
@@ -2746,6 +2834,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
2746 | * between pSeries SMP and pSeries LPAR | 2834 | * between pSeries SMP and pSeries LPAR |
2747 | */ | 2835 | */ |
2748 | RELOC(of_platform) = prom_find_machine_type(); | 2836 | RELOC(of_platform) = prom_find_machine_type(); |
2837 | prom_printf("Detected machine type: %x\n", RELOC(of_platform)); | ||
2749 | 2838 | ||
2750 | #ifndef CONFIG_RELOCATABLE | 2839 | #ifndef CONFIG_RELOCATABLE |
2751 | /* Bail if this is a kdump kernel. */ | 2840 | /* Bail if this is a kdump kernel. */ |
@@ -2807,7 +2896,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
2807 | * On non-powermacs, try to instantiate RTAS. PowerMacs don't | 2896 | * On non-powermacs, try to instantiate RTAS. PowerMacs don't |
2808 | * have a usable RTAS implementation. | 2897 | * have a usable RTAS implementation. |
2809 | */ | 2898 | */ |
2810 | if (RELOC(of_platform) != PLATFORM_POWERMAC) | 2899 | if (RELOC(of_platform) != PLATFORM_POWERMAC && |
2900 | RELOC(of_platform) != PLATFORM_OPAL) | ||
2811 | prom_instantiate_rtas(); | 2901 | prom_instantiate_rtas(); |
2812 | 2902 | ||
2813 | #ifdef CONFIG_PPC_POWERNV | 2903 | #ifdef CONFIG_PPC_POWERNV |
@@ -2818,7 +2908,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
2818 | prom_opal_hold_cpus(); | 2908 | prom_opal_hold_cpus(); |
2819 | prom_opal_takeover(); | 2909 | prom_opal_takeover(); |
2820 | } | 2910 | } |
2821 | } | 2911 | } else if (RELOC(of_platform) == PLATFORM_OPAL) |
2912 | prom_instantiate_opal(); | ||
2822 | #endif | 2913 | #endif |
2823 | 2914 | ||
2824 | /* | 2915 | /* |
@@ -2826,7 +2917,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
2826 | * | 2917 | * |
2827 | * PowerMacs use a different mechanism to spin CPUs | 2918 | * PowerMacs use a different mechanism to spin CPUs |
2828 | */ | 2919 | */ |
2829 | if (RELOC(of_platform) != PLATFORM_POWERMAC) | 2920 | if (RELOC(of_platform) != PLATFORM_POWERMAC && |
2921 | RELOC(of_platform) != PLATFORM_OPAL) | ||
2830 | prom_hold_cpus(); | 2922 | prom_hold_cpus(); |
2831 | 2923 | ||
2832 | /* | 2924 | /* |
@@ -2894,7 +2986,13 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
2894 | reloc_got2(-offset); | 2986 | reloc_got2(-offset); |
2895 | #endif | 2987 | #endif |
2896 | 2988 | ||
2897 | __start(hdr, kbase, 0); | 2989 | #ifdef CONFIG_PPC_EARLY_DEBUG_OPAL |
2990 | /* OPAL early debug gets the OPAL base & entry in r8 and r9 */ | ||
2991 | __start(hdr, kbase, 0, 0, 0, | ||
2992 | RELOC(prom_opal_base), RELOC(prom_opal_entry)); | ||
2993 | #else | ||
2994 | __start(hdr, kbase, 0, 0, 0, 0, 0); | ||
2995 | #endif | ||
2898 | 2996 | ||
2899 | return 0; | 2997 | return 0; |
2900 | } | 2998 | } |