diff options
author | Paul Mackerras <paulus@samba.org> | 2005-10-26 07:52:53 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2005-10-26 07:52:53 -0400 |
commit | c49888203d7a316cb947bb8a1cf2ae191f28bcd3 (patch) | |
tree | 7e2962af5e6978361f04161c5d6fc3765fd21e77 /arch/powerpc/kernel/prom_init.c | |
parent | bbd0abda9cc689a54df509aae00000bbb2a1a7d1 (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.c | 42 |
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; | |||
145 | extern void __start(unsigned long r3, unsigned long r4, unsigned long r5); | 145 | extern void __start(unsigned long r3, unsigned long r4, unsigned long r5); |
146 | 146 | ||
147 | #ifdef CONFIG_PPC64 | 147 | #ifdef CONFIG_PPC64 |
148 | extern void enter_prom(struct prom_args *args, unsigned long entry); | 148 | extern int enter_prom(struct prom_args *args, unsigned long entry); |
149 | #else | 149 | #else |
150 | static inline void enter_prom(struct prom_args *args, unsigned long entry) | 150 | static 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 | */ |
671 | static unsigned long __init alloc_up(unsigned long size, unsigned long align) | 673 | static 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'; |