diff options
Diffstat (limited to 'arch/powerpc/kernel/prom_init.c')
-rw-r--r-- | arch/powerpc/kernel/prom_init.c | 170 |
1 files changed, 127 insertions, 43 deletions
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 58f0917bd6b6..09db1bb9ec91 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c | |||
@@ -94,11 +94,17 @@ extern const struct linux_logo logo_linux_clut224; | |||
94 | #ifdef CONFIG_PPC64 | 94 | #ifdef CONFIG_PPC64 |
95 | #define RELOC(x) (*PTRRELOC(&(x))) | 95 | #define RELOC(x) (*PTRRELOC(&(x))) |
96 | #define ADDR(x) (u32) add_reloc_offset((unsigned long)(x)) | 96 | #define ADDR(x) (u32) add_reloc_offset((unsigned long)(x)) |
97 | #define OF_WORKAROUNDS 0 | ||
97 | #else | 98 | #else |
98 | #define RELOC(x) (x) | 99 | #define RELOC(x) (x) |
99 | #define ADDR(x) (u32) (x) | 100 | #define ADDR(x) (u32) (x) |
101 | #define OF_WORKAROUNDS of_workarounds | ||
102 | int of_workarounds; | ||
100 | #endif | 103 | #endif |
101 | 104 | ||
105 | #define OF_WA_CLAIM 1 /* do phys/virt claim separately, then map */ | ||
106 | #define OF_WA_LONGTRAIL 2 /* work around longtrail bugs */ | ||
107 | |||
102 | #define PROM_BUG() do { \ | 108 | #define PROM_BUG() do { \ |
103 | prom_printf("kernel BUG at %s line 0x%x!\n", \ | 109 | prom_printf("kernel BUG at %s line 0x%x!\n", \ |
104 | RELOC(__FILE__), __LINE__); \ | 110 | RELOC(__FILE__), __LINE__); \ |
@@ -128,10 +134,11 @@ struct prom_args { | |||
128 | 134 | ||
129 | struct prom_t { | 135 | struct prom_t { |
130 | ihandle root; | 136 | ihandle root; |
131 | ihandle chosen; | 137 | phandle chosen; |
132 | int cpu; | 138 | int cpu; |
133 | ihandle stdout; | 139 | ihandle stdout; |
134 | ihandle mmumap; | 140 | ihandle mmumap; |
141 | ihandle memory; | ||
135 | }; | 142 | }; |
136 | 143 | ||
137 | struct mem_map_entry { | 144 | struct mem_map_entry { |
@@ -360,16 +367,36 @@ static void __init prom_printf(const char *format, ...) | |||
360 | static unsigned int __init prom_claim(unsigned long virt, unsigned long size, | 367 | static unsigned int __init prom_claim(unsigned long virt, unsigned long size, |
361 | unsigned long align) | 368 | unsigned long align) |
362 | { | 369 | { |
363 | int ret; | ||
364 | struct prom_t *_prom = &RELOC(prom); | 370 | struct prom_t *_prom = &RELOC(prom); |
365 | 371 | ||
366 | ret = call_prom("claim", 3, 1, (prom_arg_t)virt, (prom_arg_t)size, | 372 | if (align == 0 && (OF_WORKAROUNDS & OF_WA_CLAIM)) { |
367 | (prom_arg_t)align); | 373 | /* |
368 | if (ret != -1 && _prom->mmumap != 0) | 374 | * Old OF requires we claim physical and virtual separately |
369 | /* old pmacs need us to map as well */ | 375 | * and then map explicitly (assuming virtual mode) |
376 | */ | ||
377 | int ret; | ||
378 | prom_arg_t result; | ||
379 | |||
380 | ret = call_prom_ret("call-method", 5, 2, &result, | ||
381 | ADDR("claim"), _prom->memory, | ||
382 | align, size, virt); | ||
383 | if (ret != 0 || result == -1) | ||
384 | return -1; | ||
385 | ret = call_prom_ret("call-method", 5, 2, &result, | ||
386 | ADDR("claim"), _prom->mmumap, | ||
387 | align, size, virt); | ||
388 | if (ret != 0) { | ||
389 | call_prom("call-method", 4, 1, ADDR("release"), | ||
390 | _prom->memory, size, virt); | ||
391 | return -1; | ||
392 | } | ||
393 | /* the 0x12 is M (coherence) + PP == read/write */ | ||
370 | call_prom("call-method", 6, 1, | 394 | call_prom("call-method", 6, 1, |
371 | ADDR("map"), _prom->mmumap, 0, size, virt, virt); | 395 | ADDR("map"), _prom->mmumap, 0x12, size, virt, virt); |
372 | return ret; | 396 | return virt; |
397 | } | ||
398 | return call_prom("claim", 3, 1, (prom_arg_t)virt, (prom_arg_t)size, | ||
399 | (prom_arg_t)align); | ||
373 | } | 400 | } |
374 | 401 | ||
375 | static void __init __attribute__((noreturn)) prom_panic(const char *reason) | 402 | static void __init __attribute__((noreturn)) prom_panic(const char *reason) |
@@ -415,11 +442,52 @@ static int inline prom_getproplen(phandle node, const char *pname) | |||
415 | return call_prom("getproplen", 2, 1, node, ADDR(pname)); | 442 | return call_prom("getproplen", 2, 1, node, ADDR(pname)); |
416 | } | 443 | } |
417 | 444 | ||
418 | static int inline prom_setprop(phandle node, const char *pname, | 445 | static void add_string(char **str, const char *q) |
419 | void *value, size_t valuelen) | ||
420 | { | 446 | { |
421 | return call_prom("setprop", 4, 1, node, ADDR(pname), | 447 | char *p = *str; |
422 | (u32)(unsigned long) value, (u32) valuelen); | 448 | |
449 | while (*q) | ||
450 | *p++ = *q++; | ||
451 | *p++ = ' '; | ||
452 | *str = p; | ||
453 | } | ||
454 | |||
455 | static char *tohex(unsigned int x) | ||
456 | { | ||
457 | static char digits[] = "0123456789abcdef"; | ||
458 | static char result[9]; | ||
459 | int i; | ||
460 | |||
461 | result[8] = 0; | ||
462 | i = 8; | ||
463 | do { | ||
464 | --i; | ||
465 | result[i] = digits[x & 0xf]; | ||
466 | x >>= 4; | ||
467 | } while (x != 0 && i > 0); | ||
468 | return &result[i]; | ||
469 | } | ||
470 | |||
471 | static int __init prom_setprop(phandle node, const char *nodename, | ||
472 | const char *pname, void *value, size_t valuelen) | ||
473 | { | ||
474 | char cmd[256], *p; | ||
475 | |||
476 | if (!(OF_WORKAROUNDS & OF_WA_LONGTRAIL)) | ||
477 | return call_prom("setprop", 4, 1, node, ADDR(pname), | ||
478 | (u32)(unsigned long) value, (u32) valuelen); | ||
479 | |||
480 | /* gah... setprop doesn't work on longtrail, have to use interpret */ | ||
481 | p = cmd; | ||
482 | add_string(&p, "dev"); | ||
483 | add_string(&p, nodename); | ||
484 | add_string(&p, tohex((u32)(unsigned long) value)); | ||
485 | add_string(&p, tohex(valuelen)); | ||
486 | add_string(&p, tohex(ADDR(pname))); | ||
487 | add_string(&p, tohex(strlen(RELOC(pname)))); | ||
488 | add_string(&p, "property"); | ||
489 | *p = 0; | ||
490 | return call_prom("interpret", 1, 1, (u32)(unsigned long) cmd); | ||
423 | } | 491 | } |
424 | 492 | ||
425 | /* We can't use the standard versions because of RELOC headaches. */ | 493 | /* We can't use the standard versions because of RELOC headaches. */ |
@@ -980,7 +1048,7 @@ static void __init prom_instantiate_rtas(void) | |||
980 | 1048 | ||
981 | rtas_inst = call_prom("open", 1, 1, ADDR("/rtas")); | 1049 | rtas_inst = call_prom("open", 1, 1, ADDR("/rtas")); |
982 | if (!IHANDLE_VALID(rtas_inst)) { | 1050 | if (!IHANDLE_VALID(rtas_inst)) { |
983 | prom_printf("opening rtas package failed"); | 1051 | prom_printf("opening rtas package failed (%x)\n", rtas_inst); |
984 | return; | 1052 | return; |
985 | } | 1053 | } |
986 | 1054 | ||
@@ -988,7 +1056,7 @@ static void __init prom_instantiate_rtas(void) | |||
988 | 1056 | ||
989 | if (call_prom_ret("call-method", 3, 2, &entry, | 1057 | if (call_prom_ret("call-method", 3, 2, &entry, |
990 | ADDR("instantiate-rtas"), | 1058 | ADDR("instantiate-rtas"), |
991 | rtas_inst, base) == PROM_ERROR | 1059 | rtas_inst, base) != 0 |
992 | || entry == 0) { | 1060 | || entry == 0) { |
993 | prom_printf(" failed\n"); | 1061 | prom_printf(" failed\n"); |
994 | return; | 1062 | return; |
@@ -997,8 +1065,10 @@ static void __init prom_instantiate_rtas(void) | |||
997 | 1065 | ||
998 | reserve_mem(base, size); | 1066 | reserve_mem(base, size); |
999 | 1067 | ||
1000 | prom_setprop(rtas_node, "linux,rtas-base", &base, sizeof(base)); | 1068 | prom_setprop(rtas_node, "/rtas", "linux,rtas-base", |
1001 | prom_setprop(rtas_node, "linux,rtas-entry", &entry, sizeof(entry)); | 1069 | &base, sizeof(base)); |
1070 | prom_setprop(rtas_node, "/rtas", "linux,rtas-entry", | ||
1071 | &entry, sizeof(entry)); | ||
1002 | 1072 | ||
1003 | prom_debug("rtas base = 0x%x\n", base); | 1073 | prom_debug("rtas base = 0x%x\n", base); |
1004 | prom_debug("rtas entry = 0x%x\n", entry); | 1074 | prom_debug("rtas entry = 0x%x\n", entry); |
@@ -1089,10 +1159,6 @@ static void __init prom_initialize_tce_table(void) | |||
1089 | if (base < local_alloc_bottom) | 1159 | if (base < local_alloc_bottom) |
1090 | local_alloc_bottom = base; | 1160 | local_alloc_bottom = base; |
1091 | 1161 | ||
1092 | /* Save away the TCE table attributes for later use. */ | ||
1093 | prom_setprop(node, "linux,tce-base", &base, sizeof(base)); | ||
1094 | prom_setprop(node, "linux,tce-size", &minsize, sizeof(minsize)); | ||
1095 | |||
1096 | /* It seems OF doesn't null-terminate the path :-( */ | 1162 | /* It seems OF doesn't null-terminate the path :-( */ |
1097 | memset(path, 0, sizeof(path)); | 1163 | memset(path, 0, sizeof(path)); |
1098 | /* Call OF to setup the TCE hardware */ | 1164 | /* Call OF to setup the TCE hardware */ |
@@ -1101,6 +1167,10 @@ static void __init prom_initialize_tce_table(void) | |||
1101 | prom_printf("package-to-path failed\n"); | 1167 | prom_printf("package-to-path failed\n"); |
1102 | } | 1168 | } |
1103 | 1169 | ||
1170 | /* Save away the TCE table attributes for later use. */ | ||
1171 | prom_setprop(node, path, "linux,tce-base", &base, sizeof(base)); | ||
1172 | prom_setprop(node, path, "linux,tce-size", &minsize, sizeof(minsize)); | ||
1173 | |||
1104 | prom_debug("TCE table: %s\n", path); | 1174 | prom_debug("TCE table: %s\n", path); |
1105 | prom_debug("\tnode = 0x%x\n", node); | 1175 | prom_debug("\tnode = 0x%x\n", node); |
1106 | prom_debug("\tbase = 0x%x\n", base); | 1176 | prom_debug("\tbase = 0x%x\n", base); |
@@ -1342,6 +1412,7 @@ static void __init prom_init_client_services(unsigned long pp) | |||
1342 | /* | 1412 | /* |
1343 | * For really old powermacs, we need to map things we claim. | 1413 | * For really old powermacs, we need to map things we claim. |
1344 | * For that, we need the ihandle of the mmu. | 1414 | * For that, we need the ihandle of the mmu. |
1415 | * Also, on the longtrail, we need to work around other bugs. | ||
1345 | */ | 1416 | */ |
1346 | static void __init prom_find_mmu(void) | 1417 | static void __init prom_find_mmu(void) |
1347 | { | 1418 | { |
@@ -1355,12 +1426,19 @@ static void __init prom_find_mmu(void) | |||
1355 | if (prom_getprop(oprom, "model", version, sizeof(version)) <= 0) | 1426 | if (prom_getprop(oprom, "model", version, sizeof(version)) <= 0) |
1356 | return; | 1427 | return; |
1357 | version[sizeof(version) - 1] = 0; | 1428 | version[sizeof(version) - 1] = 0; |
1358 | prom_printf("OF version is '%s'\n", version); | ||
1359 | /* XXX might need to add other versions here */ | 1429 | /* XXX might need to add other versions here */ |
1360 | if (strcmp(version, "Open Firmware, 1.0.5") != 0) | 1430 | if (strcmp(version, "Open Firmware, 1.0.5") == 0) |
1431 | of_workarounds = OF_WA_CLAIM; | ||
1432 | else if (strncmp(version, "FirmWorks,3.", 12) == 0) { | ||
1433 | of_workarounds = OF_WA_CLAIM | OF_WA_LONGTRAIL; | ||
1434 | call_prom("interpret", 1, 1, "dev /memory 0 to allow-reclaim"); | ||
1435 | } else | ||
1361 | return; | 1436 | return; |
1437 | _prom->memory = call_prom("open", 1, 1, ADDR("/memory")); | ||
1362 | prom_getprop(_prom->chosen, "mmu", &_prom->mmumap, | 1438 | prom_getprop(_prom->chosen, "mmu", &_prom->mmumap, |
1363 | sizeof(_prom->mmumap)); | 1439 | sizeof(_prom->mmumap)); |
1440 | if (!IHANDLE_VALID(_prom->memory) || !IHANDLE_VALID(_prom->mmumap)) | ||
1441 | of_workarounds &= ~OF_WA_CLAIM; /* hmmm */ | ||
1364 | } | 1442 | } |
1365 | #else | 1443 | #else |
1366 | #define prom_find_mmu() | 1444 | #define prom_find_mmu() |
@@ -1382,16 +1460,17 @@ static void __init prom_init_stdout(void) | |||
1382 | memset(path, 0, 256); | 1460 | memset(path, 0, 256); |
1383 | call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255); | 1461 | call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255); |
1384 | val = call_prom("instance-to-package", 1, 1, _prom->stdout); | 1462 | val = call_prom("instance-to-package", 1, 1, _prom->stdout); |
1385 | prom_setprop(_prom->chosen, "linux,stdout-package", &val, sizeof(val)); | 1463 | prom_setprop(_prom->chosen, "/chosen", "linux,stdout-package", |
1464 | &val, sizeof(val)); | ||
1386 | prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device)); | 1465 | prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device)); |
1387 | prom_setprop(_prom->chosen, "linux,stdout-path", | 1466 | prom_setprop(_prom->chosen, "/chosen", "linux,stdout-path", |
1388 | RELOC(of_stdout_device), strlen(RELOC(of_stdout_device))+1); | 1467 | path, strlen(path) + 1); |
1389 | 1468 | ||
1390 | /* If it's a display, note it */ | 1469 | /* If it's a display, note it */ |
1391 | memset(type, 0, sizeof(type)); | 1470 | memset(type, 0, sizeof(type)); |
1392 | prom_getprop(val, "device_type", type, sizeof(type)); | 1471 | prom_getprop(val, "device_type", type, sizeof(type)); |
1393 | if (strcmp(type, RELOC("display")) == 0) | 1472 | if (strcmp(type, RELOC("display")) == 0) |
1394 | prom_setprop(val, "linux,boot-display", NULL, 0); | 1473 | prom_setprop(val, path, "linux,boot-display", NULL, 0); |
1395 | } | 1474 | } |
1396 | 1475 | ||
1397 | static void __init prom_close_stdin(void) | 1476 | static void __init prom_close_stdin(void) |
@@ -1514,7 +1593,7 @@ static void __init prom_check_displays(void) | |||
1514 | 1593 | ||
1515 | /* Success */ | 1594 | /* Success */ |
1516 | prom_printf("done\n"); | 1595 | prom_printf("done\n"); |
1517 | prom_setprop(node, "linux,opened", NULL, 0); | 1596 | prom_setprop(node, path, "linux,opened", NULL, 0); |
1518 | 1597 | ||
1519 | /* Setup a usable color table when the appropriate | 1598 | /* Setup a usable color table when the appropriate |
1520 | * method is available. Should update this to set-colors */ | 1599 | * method is available. Should update this to set-colors */ |
@@ -1884,9 +1963,11 @@ static void __init fixup_device_tree(void) | |||
1884 | /* interrupt on this revision of u3 is number 0 and level */ | 1963 | /* interrupt on this revision of u3 is number 0 and level */ |
1885 | interrupts[0] = 0; | 1964 | interrupts[0] = 0; |
1886 | interrupts[1] = 1; | 1965 | interrupts[1] = 1; |
1887 | prom_setprop(i2c, "interrupts", &interrupts, sizeof(interrupts)); | 1966 | prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupts", |
1967 | &interrupts, sizeof(interrupts)); | ||
1888 | parent = (u32)mpic; | 1968 | parent = (u32)mpic; |
1889 | prom_setprop(i2c, "interrupt-parent", &parent, sizeof(parent)); | 1969 | prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupt-parent", |
1970 | &parent, sizeof(parent)); | ||
1890 | #endif | 1971 | #endif |
1891 | } | 1972 | } |
1892 | 1973 | ||
@@ -1922,11 +2003,11 @@ static void __init prom_check_initrd(unsigned long r3, unsigned long r4) | |||
1922 | RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4; | 2003 | RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4; |
1923 | 2004 | ||
1924 | val = RELOC(prom_initrd_start); | 2005 | val = RELOC(prom_initrd_start); |
1925 | prom_setprop(_prom->chosen, "linux,initrd-start", &val, | 2006 | prom_setprop(_prom->chosen, "/chosen", "linux,initrd-start", |
1926 | sizeof(val)); | 2007 | &val, sizeof(val)); |
1927 | val = RELOC(prom_initrd_end); | 2008 | val = RELOC(prom_initrd_end); |
1928 | prom_setprop(_prom->chosen, "linux,initrd-end", &val, | 2009 | prom_setprop(_prom->chosen, "/chosen", "linux,initrd-end", |
1929 | sizeof(val)); | 2010 | &val, sizeof(val)); |
1930 | 2011 | ||
1931 | reserve_mem(RELOC(prom_initrd_start), | 2012 | reserve_mem(RELOC(prom_initrd_start), |
1932 | RELOC(prom_initrd_end) - RELOC(prom_initrd_start)); | 2013 | RELOC(prom_initrd_end) - RELOC(prom_initrd_start)); |
@@ -1969,14 +2050,15 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
1969 | prom_init_client_services(pp); | 2050 | prom_init_client_services(pp); |
1970 | 2051 | ||
1971 | /* | 2052 | /* |
1972 | * Init prom stdout device | 2053 | * See if this OF is old enough that we need to do explicit maps |
2054 | * and other workarounds | ||
1973 | */ | 2055 | */ |
1974 | prom_init_stdout(); | 2056 | prom_find_mmu(); |
1975 | 2057 | ||
1976 | /* | 2058 | /* |
1977 | * See if this OF is old enough that we need to do explicit maps | 2059 | * Init prom stdout device |
1978 | */ | 2060 | */ |
1979 | prom_find_mmu(); | 2061 | prom_init_stdout(); |
1980 | 2062 | ||
1981 | /* | 2063 | /* |
1982 | * Check for an initrd | 2064 | * Check for an initrd |
@@ -1989,7 +2071,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
1989 | */ | 2071 | */ |
1990 | RELOC(of_platform) = prom_find_machine_type(); | 2072 | RELOC(of_platform) = prom_find_machine_type(); |
1991 | getprop_rval = RELOC(of_platform); | 2073 | getprop_rval = RELOC(of_platform); |
1992 | prom_setprop(_prom->chosen, "linux,platform", | 2074 | prom_setprop(_prom->chosen, "/chosen", "linux,platform", |
1993 | &getprop_rval, sizeof(getprop_rval)); | 2075 | &getprop_rval, sizeof(getprop_rval)); |
1994 | 2076 | ||
1995 | #ifdef CONFIG_PPC_PSERIES | 2077 | #ifdef CONFIG_PPC_PSERIES |
@@ -2050,21 +2132,23 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
2050 | * Fill in some infos for use by the kernel later on | 2132 | * Fill in some infos for use by the kernel later on |
2051 | */ | 2133 | */ |
2052 | if (RELOC(prom_memory_limit)) | 2134 | if (RELOC(prom_memory_limit)) |
2053 | prom_setprop(_prom->chosen, "linux,memory-limit", | 2135 | prom_setprop(_prom->chosen, "/chosen", "linux,memory-limit", |
2054 | &RELOC(prom_memory_limit), | 2136 | &RELOC(prom_memory_limit), |
2055 | sizeof(prom_memory_limit)); | 2137 | sizeof(prom_memory_limit)); |
2056 | #ifdef CONFIG_PPC64 | 2138 | #ifdef CONFIG_PPC64 |
2057 | if (RELOC(ppc64_iommu_off)) | 2139 | if (RELOC(ppc64_iommu_off)) |
2058 | prom_setprop(_prom->chosen, "linux,iommu-off", NULL, 0); | 2140 | prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off", |
2141 | NULL, 0); | ||
2059 | 2142 | ||
2060 | if (RELOC(iommu_force_on)) | 2143 | if (RELOC(iommu_force_on)) |
2061 | prom_setprop(_prom->chosen, "linux,iommu-force-on", NULL, 0); | 2144 | prom_setprop(_prom->chosen, "/chosen", "linux,iommu-force-on", |
2145 | NULL, 0); | ||
2062 | 2146 | ||
2063 | if (RELOC(prom_tce_alloc_start)) { | 2147 | if (RELOC(prom_tce_alloc_start)) { |
2064 | prom_setprop(_prom->chosen, "linux,tce-alloc-start", | 2148 | prom_setprop(_prom->chosen, "/chosen", "linux,tce-alloc-start", |
2065 | &RELOC(prom_tce_alloc_start), | 2149 | &RELOC(prom_tce_alloc_start), |
2066 | sizeof(prom_tce_alloc_start)); | 2150 | sizeof(prom_tce_alloc_start)); |
2067 | prom_setprop(_prom->chosen, "linux,tce-alloc-end", | 2151 | prom_setprop(_prom->chosen, "/chosen", "linux,tce-alloc-end", |
2068 | &RELOC(prom_tce_alloc_end), | 2152 | &RELOC(prom_tce_alloc_end), |
2069 | sizeof(prom_tce_alloc_end)); | 2153 | sizeof(prom_tce_alloc_end)); |
2070 | } | 2154 | } |