aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/prom_init.c
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2005-10-26 07:52:53 -0400
committerPaul Mackerras <paulus@samba.org>2005-10-26 07:52:53 -0400
commitc49888203d7a316cb947bb8a1cf2ae191f28bcd3 (patch)
tree7e2962af5e6978361f04161c5d6fc3765fd21e77 /arch/powerpc/kernel/prom_init.c
parentbbd0abda9cc689a54df509aae00000bbb2a1a7d1 (diff)
powerpc: Fixes to get the Longtrail CHRP a bit further
Talk about buggy firmware... the OF on the Longtrail returns 0 from the claim client service rather than -1 when the claim fails. It also has no device_type on the /memory node and blows up if the output buffer for package-to-path is too big. This also fixes a bug with calling alloc_up with align == 0, where we did _ALIGN_UP(alloc_bottom, 0) which will end up as 0. Lastly, we now check the return value (in r3) from calling the prom, and return -1 from call_prom if we get a negative value back. That is supposed to indicate that the requested client service doesn't exist. Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/prom_init.c')
-rw-r--r--arch/powerpc/kernel/prom_init.c42
1 files changed, 28 insertions, 14 deletions
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index debe9734636e..2ad9947bd675 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -145,11 +145,11 @@ typedef u32 cell_t;
145extern void __start(unsigned long r3, unsigned long r4, unsigned long r5); 145extern void __start(unsigned long r3, unsigned long r4, unsigned long r5);
146 146
147#ifdef CONFIG_PPC64 147#ifdef CONFIG_PPC64
148extern void enter_prom(struct prom_args *args, unsigned long entry); 148extern int enter_prom(struct prom_args *args, unsigned long entry);
149#else 149#else
150static inline void enter_prom(struct prom_args *args, unsigned long entry) 150static inline int enter_prom(struct prom_args *args, unsigned long entry)
151{ 151{
152 ((void (*)(struct prom_args *))entry)(args); 152 return ((int (*)(struct prom_args *))entry)(args);
153} 153}
154#endif 154#endif
155 155
@@ -241,7 +241,8 @@ static int __init call_prom(const char *service, int nargs, int nret, ...)
241 for (i = 0; i < nret; i++) 241 for (i = 0; i < nret; i++)
242 args.args[nargs+i] = 0; 242 args.args[nargs+i] = 0;
243 243
244 enter_prom(&args, RELOC(prom_entry)); 244 if (enter_prom(&args, RELOC(prom_entry)) < 0)
245 return PROM_ERROR;
245 246
246 return (nret > 0) ? args.args[nargs] : 0; 247 return (nret > 0) ? args.args[nargs] : 0;
247} 248}
@@ -265,7 +266,8 @@ static int __init call_prom_ret(const char *service, int nargs, int nret,
265 for (i = 0; i < nret; i++) 266 for (i = 0; i < nret; i++)
266 rets[nargs+i] = 0; 267 rets[nargs+i] = 0;
267 268
268 enter_prom(&args, RELOC(prom_entry)); 269 if (enter_prom(&args, RELOC(prom_entry)) < 0)
270 return PROM_ERROR;
269 271
270 if (rets != NULL) 272 if (rets != NULL)
271 for (i = 1; i < nret; ++i) 273 for (i = 1; i < nret; ++i)
@@ -670,9 +672,11 @@ static void __init prom_send_capabilities(void)
670 */ 672 */
671static unsigned long __init alloc_up(unsigned long size, unsigned long align) 673static unsigned long __init alloc_up(unsigned long size, unsigned long align)
672{ 674{
673 unsigned long base = _ALIGN_UP(RELOC(alloc_bottom), align); 675 unsigned long base = RELOC(alloc_bottom);
674 unsigned long addr = 0; 676 unsigned long addr = 0;
675 677
678 if (align)
679 base = _ALIGN_UP(base, align);
676 prom_debug("alloc_up(%x, %x)\n", size, align); 680 prom_debug("alloc_up(%x, %x)\n", size, align);
677 if (RELOC(ram_top) == 0) 681 if (RELOC(ram_top) == 0)
678 prom_panic("alloc_up() called with mem not initialized\n"); 682 prom_panic("alloc_up() called with mem not initialized\n");
@@ -686,7 +690,7 @@ static unsigned long __init alloc_up(unsigned long size, unsigned long align)
686 base = _ALIGN_UP(base + 0x100000, align)) { 690 base = _ALIGN_UP(base + 0x100000, align)) {
687 prom_debug(" trying: 0x%x\n\r", base); 691 prom_debug(" trying: 0x%x\n\r", base);
688 addr = (unsigned long)prom_claim(base, size, 0); 692 addr = (unsigned long)prom_claim(base, size, 0);
689 if (addr != PROM_ERROR) 693 if (addr != PROM_ERROR && addr != 0)
690 break; 694 break;
691 addr = 0; 695 addr = 0;
692 if (align == 0) 696 if (align == 0)
@@ -746,7 +750,7 @@ static unsigned long __init alloc_down(unsigned long size, unsigned long align,
746 base = _ALIGN_DOWN(base - 0x100000, align)) { 750 base = _ALIGN_DOWN(base - 0x100000, align)) {
747 prom_debug(" trying: 0x%x\n\r", base); 751 prom_debug(" trying: 0x%x\n\r", base);
748 addr = (unsigned long)prom_claim(base, size, 0); 752 addr = (unsigned long)prom_claim(base, size, 0);
749 if (addr != PROM_ERROR) 753 if (addr != PROM_ERROR && addr != 0)
750 break; 754 break;
751 addr = 0; 755 addr = 0;
752 } 756 }
@@ -852,9 +856,16 @@ static void __init prom_init_mem(void)
852 type[0] = 0; 856 type[0] = 0;
853 prom_getprop(node, "device_type", type, sizeof(type)); 857 prom_getprop(node, "device_type", type, sizeof(type));
854 858
859 if (type[0] == 0) {
860 /*
861 * CHRP Longtrail machines have no device_type
862 * on the memory node, so check the name instead...
863 */
864 prom_getprop(node, "name", type, sizeof(type));
865 }
855 if (strcmp(type, RELOC("memory"))) 866 if (strcmp(type, RELOC("memory")))
856 continue; 867 continue;
857 868
858 plen = prom_getprop(node, "reg", RELOC(regbuf), sizeof(regbuf)); 869 plen = prom_getprop(node, "reg", RELOC(regbuf), sizeof(regbuf));
859 if (plen > sizeof(regbuf)) { 870 if (plen > sizeof(regbuf)) {
860 prom_printf("memory node too large for buffer !\n"); 871 prom_printf("memory node too large for buffer !\n");
@@ -1632,18 +1643,21 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
1632 unsigned long soff; 1643 unsigned long soff;
1633 unsigned char *valp; 1644 unsigned char *valp;
1634 static char pname[MAX_PROPERTY_NAME]; 1645 static char pname[MAX_PROPERTY_NAME];
1635 int l; 1646 int l, room;
1636 1647
1637 dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); 1648 dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end);
1638 1649
1639 /* get the node's full name */ 1650 /* get the node's full name */
1640 namep = (char *)*mem_start; 1651 namep = (char *)*mem_start;
1641 l = call_prom("package-to-path", 3, 1, node, 1652 room = *mem_end - *mem_start;
1642 namep, *mem_end - *mem_start); 1653 if (room > 255)
1654 room = 255;
1655 l = call_prom("package-to-path", 3, 1, node, namep, room);
1643 if (l >= 0) { 1656 if (l >= 0) {
1644 /* Didn't fit? Get more room. */ 1657 /* Didn't fit? Get more room. */
1645 if ((l+1) > (*mem_end - *mem_start)) { 1658 if (l >= room) {
1646 namep = make_room(mem_start, mem_end, l+1, 1); 1659 if (l >= *mem_end - *mem_start)
1660 namep = make_room(mem_start, mem_end, l+1, 1);
1647 call_prom("package-to-path", 3, 1, node, namep, l); 1661 call_prom("package-to-path", 3, 1, node, namep, l);
1648 } 1662 }
1649 namep[l] = '\0'; 1663 namep[l] = '\0';