aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/kernel/prom.c9
-rw-r--r--arch/powerpc/kernel/prom_init.c170
-rw-r--r--arch/powerpc/platforms/chrp/setup.c4
-rw-r--r--arch/ppc/boot/include/of1275.h3
-rw-r--r--arch/ppc/boot/of1275/Makefile2
-rw-r--r--arch/ppc/boot/of1275/call_prom.c74
-rw-r--r--arch/ppc/boot/of1275/claim.c97
-rw-r--r--arch/ppc/boot/of1275/finddevice.c19
8 files changed, 295 insertions, 83 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 }
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index ecd32d5d85f4..4099ddab9205 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -361,7 +361,9 @@ static void __init chrp_find_openpic(void)
361 printk(KERN_INFO "OpenPIC at %lx\n", opaddr); 361 printk(KERN_INFO "OpenPIC at %lx\n", opaddr);
362 362
363 irq_count = NR_IRQS - NUM_ISA_INTERRUPTS - 4; /* leave room for IPIs */ 363 irq_count = NR_IRQS - NUM_ISA_INTERRUPTS - 4; /* leave room for IPIs */
364 prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS - 4); 364 prom_get_irq_senses(init_senses, NUM_ISA_INTERRUPTS, NR_IRQS - 4);
365 /* i8259 cascade is always positive level */
366 init_senses[0] = IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE;
365 367
366 iranges = (unsigned int *) get_property(np, "interrupt-ranges", &len); 368 iranges = (unsigned int *) get_property(np, "interrupt-ranges", &len);
367 if (iranges == NULL) 369 if (iranges == NULL)
diff --git a/arch/ppc/boot/include/of1275.h b/arch/ppc/boot/include/of1275.h
index 69173df76db0..4ed88acfa73a 100644
--- a/arch/ppc/boot/include/of1275.h
+++ b/arch/ppc/boot/include/of1275.h
@@ -19,6 +19,9 @@ extern prom_entry of_prom_entry;
19 19
20/* function declarations */ 20/* function declarations */
21 21
22int call_prom(const char *service, int nargs, int nret, ...);
23int call_prom_ret(const char *service, int nargs, int nret,
24 unsigned int *rets, ...);
22void * claim(unsigned int virt, unsigned int size, unsigned int align); 25void * claim(unsigned int virt, unsigned int size, unsigned int align);
23int map(unsigned int phys, unsigned int virt, unsigned int size); 26int map(unsigned int phys, unsigned int virt, unsigned int size);
24void enter(void); 27void enter(void);
diff --git a/arch/ppc/boot/of1275/Makefile b/arch/ppc/boot/of1275/Makefile
index 02e6f235d7cb..0b979c004972 100644
--- a/arch/ppc/boot/of1275/Makefile
+++ b/arch/ppc/boot/of1275/Makefile
@@ -3,4 +3,4 @@
3# 3#
4 4
5lib-y := claim.o enter.o exit.o finddevice.o getprop.o ofinit.o \ 5lib-y := claim.o enter.o exit.o finddevice.o getprop.o ofinit.o \
6 ofstdio.o read.o release.o write.o map.o 6 ofstdio.o read.o release.o write.o map.o call_prom.o
diff --git a/arch/ppc/boot/of1275/call_prom.c b/arch/ppc/boot/of1275/call_prom.c
new file mode 100644
index 000000000000..9479a3a2b8c7
--- /dev/null
+++ b/arch/ppc/boot/of1275/call_prom.c
@@ -0,0 +1,74 @@
1/*
2 * Copyright (C) 1996-2005 Paul Mackerras.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9
10#include "of1275.h"
11#include <stdarg.h>
12
13int call_prom(const char *service, int nargs, int nret, ...)
14{
15 int i;
16 struct prom_args {
17 const char *service;
18 int nargs;
19 int nret;
20 unsigned int args[12];
21 } args;
22 va_list list;
23
24 args.service = service;
25 args.nargs = nargs;
26 args.nret = nret;
27
28 va_start(list, nret);
29 for (i = 0; i < nargs; i++)
30 args.args[i] = va_arg(list, unsigned int);
31 va_end(list);
32
33 for (i = 0; i < nret; i++)
34 args.args[nargs+i] = 0;
35
36 if (of_prom_entry(&args) < 0)
37 return -1;
38
39 return (nret > 0)? args.args[nargs]: 0;
40}
41
42int call_prom_ret(const char *service, int nargs, int nret,
43 unsigned int *rets, ...)
44{
45 int i;
46 struct prom_args {
47 const char *service;
48 int nargs;
49 int nret;
50 unsigned int args[12];
51 } args;
52 va_list list;
53
54 args.service = service;
55 args.nargs = nargs;
56 args.nret = nret;
57
58 va_start(list, rets);
59 for (i = 0; i < nargs; i++)
60 args.args[i] = va_arg(list, unsigned int);
61 va_end(list);
62
63 for (i = 0; i < nret; i++)
64 args.args[nargs+i] = 0;
65
66 if (of_prom_entry(&args) < 0)
67 return -1;
68
69 if (rets != (void *) 0)
70 for (i = 1; i < nret; ++i)
71 rets[i-1] = args.args[nargs+i];
72
73 return (nret > 0)? args.args[nargs]: 0;
74}
diff --git a/arch/ppc/boot/of1275/claim.c b/arch/ppc/boot/of1275/claim.c
index 13169a5c4339..1ed3aeeff8ae 100644
--- a/arch/ppc/boot/of1275/claim.c
+++ b/arch/ppc/boot/of1275/claim.c
@@ -9,27 +9,84 @@
9 */ 9 */
10 10
11#include "of1275.h" 11#include "of1275.h"
12#include "nonstdio.h"
12 13
13void * 14/*
14claim(unsigned int virt, unsigned int size, unsigned int align) 15 * Older OF's require that when claiming a specific range of addresses,
16 * we claim the physical space in the /memory node and the virtual
17 * space in the chosen mmu node, and then do a map operation to
18 * map virtual to physical.
19 */
20static int need_map = -1;
21static ihandle chosen_mmu;
22static phandle memory;
23
24/* returns true if s2 is a prefix of s1 */
25static int string_match(const char *s1, const char *s2)
26{
27 for (; *s2; ++s2)
28 if (*s1++ != *s2)
29 return 0;
30 return 1;
31}
32
33static int check_of_version(void)
34{
35 phandle oprom, chosen;
36 char version[64];
37
38 oprom = finddevice("/openprom");
39 if (oprom == OF_INVALID_HANDLE)
40 return 0;
41 if (getprop(oprom, "model", version, sizeof(version)) <= 0)
42 return 0;
43 version[sizeof(version)-1] = 0;
44 printf("OF version = '%s'\n", version);
45 if (!string_match(version, "Open Firmware, 1.")
46 && !string_match(version, "FirmWorks,3."))
47 return 0;
48 chosen = finddevice("/chosen");
49 if (chosen == OF_INVALID_HANDLE) {
50 chosen = finddevice("/chosen@0");
51 if (chosen == OF_INVALID_HANDLE) {
52 printf("no chosen\n");
53 return 0;
54 }
55 }
56 if (getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) {
57 printf("no mmu\n");
58 return 0;
59 }
60 memory = (ihandle) call_prom("open", 1, 1, "/memory");
61 if (memory == OF_INVALID_HANDLE) {
62 memory = (ihandle) call_prom("open", 1, 1, "/memory@0");
63 if (memory == OF_INVALID_HANDLE) {
64 printf("no memory node\n");
65 return 0;
66 }
67 }
68 printf("old OF detected\n");
69 return 1;
70}
71
72void *claim(unsigned int virt, unsigned int size, unsigned int align)
15{ 73{
16 struct prom_args { 74 int ret;
17 char *service; 75 unsigned int result;
18 int nargs;
19 int nret;
20 unsigned int virt;
21 unsigned int size;
22 unsigned int align;
23 void *ret;
24 } args;
25 76
26 args.service = "claim"; 77 if (need_map < 0)
27 args.nargs = 3; 78 need_map = check_of_version();
28 args.nret = 1; 79 if (align || !need_map)
29 args.virt = virt; 80 return (void *) call_prom("claim", 3, 1, virt, size, align);
30 args.size = size; 81
31 args.align = align; 82 ret = call_prom_ret("call-method", 5, 2, &result, "claim", memory,
32 args.ret = (void *) 0; 83 align, size, virt);
33 (*of_prom_entry)(&args); 84 if (ret != 0 || result == -1)
34 return args.ret; 85 return (void *) -1;
86 ret = call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu,
87 align, size, virt);
88 /* 0x12 == coherent + read/write */
89 ret = call_prom("call-method", 6, 1, "map", chosen_mmu,
90 0x12, size, virt, virt);
91 return virt;
35} 92}
diff --git a/arch/ppc/boot/of1275/finddevice.c b/arch/ppc/boot/of1275/finddevice.c
index 2c0f7cbb793e..0dcb1201b772 100644
--- a/arch/ppc/boot/of1275/finddevice.c
+++ b/arch/ppc/boot/of1275/finddevice.c
@@ -10,22 +10,7 @@
10 10
11#include "of1275.h" 11#include "of1275.h"
12 12
13phandle 13phandle finddevice(const char *name)
14finddevice(const char *name)
15{ 14{
16 struct prom_args { 15 return (phandle) call_prom("finddevice", 1, 1, name);
17 char *service;
18 int nargs;
19 int nret;
20 const char *devspec;
21 phandle device;
22 } args;
23
24 args.service = "finddevice";
25 args.nargs = 1;
26 args.nret = 1;
27 args.devspec = name;
28 args.device = OF_INVALID_HANDLE;
29 (*of_prom_entry)(&args);
30 return args.device;
31} 16}