aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/prom_init.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/prom_init.c')
-rw-r--r--arch/powerpc/kernel/prom_init.c187
1 files changed, 136 insertions, 51 deletions
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 6dc33d19fc2a..4ce0105c308e 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
102int 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__); \
@@ -111,11 +117,6 @@ extern const struct linux_logo logo_linux_clut224;
111#define prom_debug(x...) 117#define prom_debug(x...)
112#endif 118#endif
113 119
114#ifdef CONFIG_PPC32
115#define PLATFORM_POWERMAC _MACH_Pmac
116#define PLATFORM_CHRP _MACH_chrp
117#endif
118
119 120
120typedef u32 prom_arg_t; 121typedef u32 prom_arg_t;
121 122
@@ -128,10 +129,11 @@ struct prom_args {
128 129
129struct prom_t { 130struct prom_t {
130 ihandle root; 131 ihandle root;
131 ihandle chosen; 132 phandle chosen;
132 int cpu; 133 int cpu;
133 ihandle stdout; 134 ihandle stdout;
134 ihandle mmumap; 135 ihandle mmumap;
136 ihandle memory;
135}; 137};
136 138
137struct mem_map_entry { 139struct mem_map_entry {
@@ -360,16 +362,36 @@ static void __init prom_printf(const char *format, ...)
360static unsigned int __init prom_claim(unsigned long virt, unsigned long size, 362static unsigned int __init prom_claim(unsigned long virt, unsigned long size,
361 unsigned long align) 363 unsigned long align)
362{ 364{
363 int ret;
364 struct prom_t *_prom = &RELOC(prom); 365 struct prom_t *_prom = &RELOC(prom);
365 366
366 ret = call_prom("claim", 3, 1, (prom_arg_t)virt, (prom_arg_t)size, 367 if (align == 0 && (OF_WORKAROUNDS & OF_WA_CLAIM)) {
367 (prom_arg_t)align); 368 /*
368 if (ret != -1 && _prom->mmumap != 0) 369 * Old OF requires we claim physical and virtual separately
369 /* old pmacs need us to map as well */ 370 * and then map explicitly (assuming virtual mode)
371 */
372 int ret;
373 prom_arg_t result;
374
375 ret = call_prom_ret("call-method", 5, 2, &result,
376 ADDR("claim"), _prom->memory,
377 align, size, virt);
378 if (ret != 0 || result == -1)
379 return -1;
380 ret = call_prom_ret("call-method", 5, 2, &result,
381 ADDR("claim"), _prom->mmumap,
382 align, size, virt);
383 if (ret != 0) {
384 call_prom("call-method", 4, 1, ADDR("release"),
385 _prom->memory, size, virt);
386 return -1;
387 }
388 /* the 0x12 is M (coherence) + PP == read/write */
370 call_prom("call-method", 6, 1, 389 call_prom("call-method", 6, 1,
371 ADDR("map"), _prom->mmumap, 0, size, virt, virt); 390 ADDR("map"), _prom->mmumap, 0x12, size, virt, virt);
372 return ret; 391 return virt;
392 }
393 return call_prom("claim", 3, 1, (prom_arg_t)virt, (prom_arg_t)size,
394 (prom_arg_t)align);
373} 395}
374 396
375static void __init __attribute__((noreturn)) prom_panic(const char *reason) 397static void __init __attribute__((noreturn)) prom_panic(const char *reason)
@@ -415,11 +437,52 @@ static int inline prom_getproplen(phandle node, const char *pname)
415 return call_prom("getproplen", 2, 1, node, ADDR(pname)); 437 return call_prom("getproplen", 2, 1, node, ADDR(pname));
416} 438}
417 439
418static int inline prom_setprop(phandle node, const char *pname, 440static void add_string(char **str, const char *q)
419 void *value, size_t valuelen)
420{ 441{
421 return call_prom("setprop", 4, 1, node, ADDR(pname), 442 char *p = *str;
422 (u32)(unsigned long) value, (u32) valuelen); 443
444 while (*q)
445 *p++ = *q++;
446 *p++ = ' ';
447 *str = p;
448}
449
450static char *tohex(unsigned int x)
451{
452 static char digits[] = "0123456789abcdef";
453 static char result[9];
454 int i;
455
456 result[8] = 0;
457 i = 8;
458 do {
459 --i;
460 result[i] = digits[x & 0xf];
461 x >>= 4;
462 } while (x != 0 && i > 0);
463 return &result[i];
464}
465
466static int __init prom_setprop(phandle node, const char *nodename,
467 const char *pname, void *value, size_t valuelen)
468{
469 char cmd[256], *p;
470
471 if (!(OF_WORKAROUNDS & OF_WA_LONGTRAIL))
472 return call_prom("setprop", 4, 1, node, ADDR(pname),
473 (u32)(unsigned long) value, (u32) valuelen);
474
475 /* gah... setprop doesn't work on longtrail, have to use interpret */
476 p = cmd;
477 add_string(&p, "dev");
478 add_string(&p, nodename);
479 add_string(&p, tohex((u32)(unsigned long) value));
480 add_string(&p, tohex(valuelen));
481 add_string(&p, tohex(ADDR(pname)));
482 add_string(&p, tohex(strlen(RELOC(pname))));
483 add_string(&p, "property");
484 *p = 0;
485 return call_prom("interpret", 1, 1, (u32)(unsigned long) cmd);
423} 486}
424 487
425/* We can't use the standard versions because of RELOC headaches. */ 488/* We can't use the standard versions because of RELOC headaches. */
@@ -980,7 +1043,7 @@ static void __init prom_instantiate_rtas(void)
980 1043
981 rtas_inst = call_prom("open", 1, 1, ADDR("/rtas")); 1044 rtas_inst = call_prom("open", 1, 1, ADDR("/rtas"));
982 if (!IHANDLE_VALID(rtas_inst)) { 1045 if (!IHANDLE_VALID(rtas_inst)) {
983 prom_printf("opening rtas package failed"); 1046 prom_printf("opening rtas package failed (%x)\n", rtas_inst);
984 return; 1047 return;
985 } 1048 }
986 1049
@@ -988,7 +1051,7 @@ static void __init prom_instantiate_rtas(void)
988 1051
989 if (call_prom_ret("call-method", 3, 2, &entry, 1052 if (call_prom_ret("call-method", 3, 2, &entry,
990 ADDR("instantiate-rtas"), 1053 ADDR("instantiate-rtas"),
991 rtas_inst, base) == PROM_ERROR 1054 rtas_inst, base) != 0
992 || entry == 0) { 1055 || entry == 0) {
993 prom_printf(" failed\n"); 1056 prom_printf(" failed\n");
994 return; 1057 return;
@@ -997,8 +1060,10 @@ static void __init prom_instantiate_rtas(void)
997 1060
998 reserve_mem(base, size); 1061 reserve_mem(base, size);
999 1062
1000 prom_setprop(rtas_node, "linux,rtas-base", &base, sizeof(base)); 1063 prom_setprop(rtas_node, "/rtas", "linux,rtas-base",
1001 prom_setprop(rtas_node, "linux,rtas-entry", &entry, sizeof(entry)); 1064 &base, sizeof(base));
1065 prom_setprop(rtas_node, "/rtas", "linux,rtas-entry",
1066 &entry, sizeof(entry));
1002 1067
1003 prom_debug("rtas base = 0x%x\n", base); 1068 prom_debug("rtas base = 0x%x\n", base);
1004 prom_debug("rtas entry = 0x%x\n", entry); 1069 prom_debug("rtas entry = 0x%x\n", entry);
@@ -1089,10 +1154,6 @@ static void __init prom_initialize_tce_table(void)
1089 if (base < local_alloc_bottom) 1154 if (base < local_alloc_bottom)
1090 local_alloc_bottom = base; 1155 local_alloc_bottom = base;
1091 1156
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 :-( */ 1157 /* It seems OF doesn't null-terminate the path :-( */
1097 memset(path, 0, sizeof(path)); 1158 memset(path, 0, sizeof(path));
1098 /* Call OF to setup the TCE hardware */ 1159 /* Call OF to setup the TCE hardware */
@@ -1101,6 +1162,10 @@ static void __init prom_initialize_tce_table(void)
1101 prom_printf("package-to-path failed\n"); 1162 prom_printf("package-to-path failed\n");
1102 } 1163 }
1103 1164
1165 /* Save away the TCE table attributes for later use. */
1166 prom_setprop(node, path, "linux,tce-base", &base, sizeof(base));
1167 prom_setprop(node, path, "linux,tce-size", &minsize, sizeof(minsize));
1168
1104 prom_debug("TCE table: %s\n", path); 1169 prom_debug("TCE table: %s\n", path);
1105 prom_debug("\tnode = 0x%x\n", node); 1170 prom_debug("\tnode = 0x%x\n", node);
1106 prom_debug("\tbase = 0x%x\n", base); 1171 prom_debug("\tbase = 0x%x\n", base);
@@ -1342,6 +1407,7 @@ static void __init prom_init_client_services(unsigned long pp)
1342/* 1407/*
1343 * For really old powermacs, we need to map things we claim. 1408 * For really old powermacs, we need to map things we claim.
1344 * For that, we need the ihandle of the mmu. 1409 * For that, we need the ihandle of the mmu.
1410 * Also, on the longtrail, we need to work around other bugs.
1345 */ 1411 */
1346static void __init prom_find_mmu(void) 1412static void __init prom_find_mmu(void)
1347{ 1413{
@@ -1355,12 +1421,19 @@ static void __init prom_find_mmu(void)
1355 if (prom_getprop(oprom, "model", version, sizeof(version)) <= 0) 1421 if (prom_getprop(oprom, "model", version, sizeof(version)) <= 0)
1356 return; 1422 return;
1357 version[sizeof(version) - 1] = 0; 1423 version[sizeof(version) - 1] = 0;
1358 prom_printf("OF version is '%s'\n", version);
1359 /* XXX might need to add other versions here */ 1424 /* XXX might need to add other versions here */
1360 if (strcmp(version, "Open Firmware, 1.0.5") != 0) 1425 if (strcmp(version, "Open Firmware, 1.0.5") == 0)
1426 of_workarounds = OF_WA_CLAIM;
1427 else if (strncmp(version, "FirmWorks,3.", 12) == 0) {
1428 of_workarounds = OF_WA_CLAIM | OF_WA_LONGTRAIL;
1429 call_prom("interpret", 1, 1, "dev /memory 0 to allow-reclaim");
1430 } else
1361 return; 1431 return;
1432 _prom->memory = call_prom("open", 1, 1, ADDR("/memory"));
1362 prom_getprop(_prom->chosen, "mmu", &_prom->mmumap, 1433 prom_getprop(_prom->chosen, "mmu", &_prom->mmumap,
1363 sizeof(_prom->mmumap)); 1434 sizeof(_prom->mmumap));
1435 if (!IHANDLE_VALID(_prom->memory) || !IHANDLE_VALID(_prom->mmumap))
1436 of_workarounds &= ~OF_WA_CLAIM; /* hmmm */
1364} 1437}
1365#else 1438#else
1366#define prom_find_mmu() 1439#define prom_find_mmu()
@@ -1382,16 +1455,17 @@ static void __init prom_init_stdout(void)
1382 memset(path, 0, 256); 1455 memset(path, 0, 256);
1383 call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255); 1456 call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255);
1384 val = call_prom("instance-to-package", 1, 1, _prom->stdout); 1457 val = call_prom("instance-to-package", 1, 1, _prom->stdout);
1385 prom_setprop(_prom->chosen, "linux,stdout-package", &val, sizeof(val)); 1458 prom_setprop(_prom->chosen, "/chosen", "linux,stdout-package",
1459 &val, sizeof(val));
1386 prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device)); 1460 prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device));
1387 prom_setprop(_prom->chosen, "linux,stdout-path", 1461 prom_setprop(_prom->chosen, "/chosen", "linux,stdout-path",
1388 RELOC(of_stdout_device), strlen(RELOC(of_stdout_device))+1); 1462 path, strlen(path) + 1);
1389 1463
1390 /* If it's a display, note it */ 1464 /* If it's a display, note it */
1391 memset(type, 0, sizeof(type)); 1465 memset(type, 0, sizeof(type));
1392 prom_getprop(val, "device_type", type, sizeof(type)); 1466 prom_getprop(val, "device_type", type, sizeof(type));
1393 if (strcmp(type, RELOC("display")) == 0) 1467 if (strcmp(type, RELOC("display")) == 0)
1394 prom_setprop(val, "linux,boot-display", NULL, 0); 1468 prom_setprop(val, path, "linux,boot-display", NULL, 0);
1395} 1469}
1396 1470
1397static void __init prom_close_stdin(void) 1471static void __init prom_close_stdin(void)
@@ -1514,7 +1588,7 @@ static void __init prom_check_displays(void)
1514 1588
1515 /* Success */ 1589 /* Success */
1516 prom_printf("done\n"); 1590 prom_printf("done\n");
1517 prom_setprop(node, "linux,opened", NULL, 0); 1591 prom_setprop(node, path, "linux,opened", NULL, 0);
1518 1592
1519 /* Setup a usable color table when the appropriate 1593 /* Setup a usable color table when the appropriate
1520 * method is available. Should update this to set-colors */ 1594 * method is available. Should update this to set-colors */
@@ -1884,9 +1958,11 @@ static void __init fixup_device_tree(void)
1884 /* interrupt on this revision of u3 is number 0 and level */ 1958 /* interrupt on this revision of u3 is number 0 and level */
1885 interrupts[0] = 0; 1959 interrupts[0] = 0;
1886 interrupts[1] = 1; 1960 interrupts[1] = 1;
1887 prom_setprop(i2c, "interrupts", &interrupts, sizeof(interrupts)); 1961 prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupts",
1962 &interrupts, sizeof(interrupts));
1888 parent = (u32)mpic; 1963 parent = (u32)mpic;
1889 prom_setprop(i2c, "interrupt-parent", &parent, sizeof(parent)); 1964 prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupt-parent",
1965 &parent, sizeof(parent));
1890#endif 1966#endif
1891} 1967}
1892 1968
@@ -1922,11 +1998,11 @@ static void __init prom_check_initrd(unsigned long r3, unsigned long r4)
1922 RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4; 1998 RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4;
1923 1999
1924 val = RELOC(prom_initrd_start); 2000 val = RELOC(prom_initrd_start);
1925 prom_setprop(_prom->chosen, "linux,initrd-start", &val, 2001 prom_setprop(_prom->chosen, "/chosen", "linux,initrd-start",
1926 sizeof(val)); 2002 &val, sizeof(val));
1927 val = RELOC(prom_initrd_end); 2003 val = RELOC(prom_initrd_end);
1928 prom_setprop(_prom->chosen, "linux,initrd-end", &val, 2004 prom_setprop(_prom->chosen, "/chosen", "linux,initrd-end",
1929 sizeof(val)); 2005 &val, sizeof(val));
1930 2006
1931 reserve_mem(RELOC(prom_initrd_start), 2007 reserve_mem(RELOC(prom_initrd_start),
1932 RELOC(prom_initrd_end) - RELOC(prom_initrd_start)); 2008 RELOC(prom_initrd_end) - RELOC(prom_initrd_start));
@@ -1969,14 +2045,15 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
1969 prom_init_client_services(pp); 2045 prom_init_client_services(pp);
1970 2046
1971 /* 2047 /*
1972 * Init prom stdout device 2048 * See if this OF is old enough that we need to do explicit maps
2049 * and other workarounds
1973 */ 2050 */
1974 prom_init_stdout(); 2051 prom_find_mmu();
1975 2052
1976 /* 2053 /*
1977 * See if this OF is old enough that we need to do explicit maps 2054 * Init prom stdout device
1978 */ 2055 */
1979 prom_find_mmu(); 2056 prom_init_stdout();
1980 2057
1981 /* 2058 /*
1982 * Check for an initrd 2059 * Check for an initrd
@@ -1989,14 +2066,15 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
1989 */ 2066 */
1990 RELOC(of_platform) = prom_find_machine_type(); 2067 RELOC(of_platform) = prom_find_machine_type();
1991 getprop_rval = RELOC(of_platform); 2068 getprop_rval = RELOC(of_platform);
1992 prom_setprop(_prom->chosen, "linux,platform", 2069 prom_setprop(_prom->chosen, "/chosen", "linux,platform",
1993 &getprop_rval, sizeof(getprop_rval)); 2070 &getprop_rval, sizeof(getprop_rval));
1994 2071
1995#ifdef CONFIG_PPC_PSERIES 2072#ifdef CONFIG_PPC_PSERIES
1996 /* 2073 /*
1997 * On pSeries, inform the firmware about our capabilities 2074 * On pSeries, inform the firmware about our capabilities
1998 */ 2075 */
1999 if (RELOC(of_platform) & PLATFORM_PSERIES) 2076 if (RELOC(of_platform) == PLATFORM_PSERIES ||
2077 RELOC(of_platform) == PLATFORM_PSERIES_LPAR)
2000 prom_send_capabilities(); 2078 prom_send_capabilities();
2001#endif 2079#endif
2002 2080
@@ -2050,21 +2128,23 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
2050 * Fill in some infos for use by the kernel later on 2128 * Fill in some infos for use by the kernel later on
2051 */ 2129 */
2052 if (RELOC(prom_memory_limit)) 2130 if (RELOC(prom_memory_limit))
2053 prom_setprop(_prom->chosen, "linux,memory-limit", 2131 prom_setprop(_prom->chosen, "/chosen", "linux,memory-limit",
2054 &RELOC(prom_memory_limit), 2132 &RELOC(prom_memory_limit),
2055 sizeof(prom_memory_limit)); 2133 sizeof(prom_memory_limit));
2056#ifdef CONFIG_PPC64 2134#ifdef CONFIG_PPC64
2057 if (RELOC(ppc64_iommu_off)) 2135 if (RELOC(ppc64_iommu_off))
2058 prom_setprop(_prom->chosen, "linux,iommu-off", NULL, 0); 2136 prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off",
2137 NULL, 0);
2059 2138
2060 if (RELOC(iommu_force_on)) 2139 if (RELOC(iommu_force_on))
2061 prom_setprop(_prom->chosen, "linux,iommu-force-on", NULL, 0); 2140 prom_setprop(_prom->chosen, "/chosen", "linux,iommu-force-on",
2141 NULL, 0);
2062 2142
2063 if (RELOC(prom_tce_alloc_start)) { 2143 if (RELOC(prom_tce_alloc_start)) {
2064 prom_setprop(_prom->chosen, "linux,tce-alloc-start", 2144 prom_setprop(_prom->chosen, "/chosen", "linux,tce-alloc-start",
2065 &RELOC(prom_tce_alloc_start), 2145 &RELOC(prom_tce_alloc_start),
2066 sizeof(prom_tce_alloc_start)); 2146 sizeof(prom_tce_alloc_start));
2067 prom_setprop(_prom->chosen, "linux,tce-alloc-end", 2147 prom_setprop(_prom->chosen, "/chosen", "linux,tce-alloc-end",
2068 &RELOC(prom_tce_alloc_end), 2148 &RELOC(prom_tce_alloc_end),
2069 sizeof(prom_tce_alloc_end)); 2149 sizeof(prom_tce_alloc_end));
2070 } 2150 }
@@ -2081,8 +2161,13 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
2081 prom_printf("copying OF device tree ...\n"); 2161 prom_printf("copying OF device tree ...\n");
2082 flatten_device_tree(); 2162 flatten_device_tree();
2083 2163
2084 /* in case stdin is USB and still active on IBM machines... */ 2164 /*
2085 prom_close_stdin(); 2165 * in case stdin is USB and still active on IBM machines...
2166 * Unfortunately quiesce crashes on some powermacs if we have
2167 * closed stdin already (in particular the powerbook 101).
2168 */
2169 if (RELOC(of_platform) != PLATFORM_POWERMAC)
2170 prom_close_stdin();
2086 2171
2087 /* 2172 /*
2088 * Call OF "quiesce" method to shut down pending DMA's from 2173 * Call OF "quiesce" method to shut down pending DMA's from