aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2005-11-09 20:00:55 -0500
committerPaul Mackerras <paulus@samba.org>2005-11-09 20:00:55 -0500
commita23414beb6607dfd40d3245f7df9dd97a4e2c82b (patch)
tree7fb2e368a462fab4ce4cc275281ecd22e284653a /arch/powerpc/kernel
parent8b553f32db3bf5d0ec0819c595932eb21cd45945 (diff)
ppc/powerpc: workarounds for old Open Firmware versions
This adds code to work around some problems with old versions of Open Firmware, such as on the early powermacs (7500 etc.) and the "Longtrail" CHRP machine. On these machines we have to claim the physical and virtual address ranges explicitly when claiming memory and then set up a V->P mapping. The Longtrail has more problems: setprop doesn't work, and we have to set an "allow-reclaim" variable to 0 in order to get claim on physical memory ranges to fail if the memory is already claimed. Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/prom.c9
-rw-r--r--arch/powerpc/kernel/prom_init.c170
2 files changed, 135 insertions, 44 deletions
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index f645adb57534..5af39f866735 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -1264,7 +1264,14 @@ static int __init early_init_dt_scan_memory(unsigned long node,
1264 unsigned long l; 1264 unsigned long l;
1265 1265
1266 /* We are scanning "memory" nodes only */ 1266 /* We are scanning "memory" nodes only */
1267 if (type == NULL || strcmp(type, "memory") != 0) 1267 if (type == NULL) {
1268 /*
1269 * The longtrail doesn't have a device_type on the
1270 * /memory node, so look for the node called /memory@0.
1271 */
1272 if (depth != 1 || strcmp(uname, "memory@0") != 0)
1273 return 0;
1274 } else if (strcmp(type, "memory") != 0)
1268 return 0; 1275 return 0;
1269 1276
1270 reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l); 1277 reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l);
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
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__); \
@@ -128,10 +134,11 @@ struct prom_args {
128 134
129struct prom_t { 135struct 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
137struct mem_map_entry { 144struct mem_map_entry {
@@ -360,16 +367,36 @@ static void __init prom_printf(const char *format, ...)
360static unsigned int __init prom_claim(unsigned long virt, unsigned long size, 367static 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
375static void __init __attribute__((noreturn)) prom_panic(const char *reason) 402static 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
418static int inline prom_setprop(phandle node, const char *pname, 445static 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
455static 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
471static 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 */
1346static void __init prom_find_mmu(void) 1417static 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
1397static void __init prom_close_stdin(void) 1476static 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 }