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>
This commit is contained in:
parent
bbd0abda9c
commit
c49888203d
3 changed files with 30 additions and 15 deletions
|
@ -145,11 +145,11 @@ typedef u32 cell_t;
|
||||||
extern void __start(unsigned long r3, unsigned long r4, unsigned long r5);
|
extern void __start(unsigned long r3, unsigned long r4, unsigned long r5);
|
||||||
|
|
||||||
#ifdef CONFIG_PPC64
|
#ifdef CONFIG_PPC64
|
||||||
extern void enter_prom(struct prom_args *args, unsigned long entry);
|
extern int enter_prom(struct prom_args *args, unsigned long entry);
|
||||||
#else
|
#else
|
||||||
static inline void enter_prom(struct prom_args *args, unsigned long entry)
|
static inline int enter_prom(struct prom_args *args, unsigned long entry)
|
||||||
{
|
{
|
||||||
((void (*)(struct prom_args *))entry)(args);
|
return ((int (*)(struct prom_args *))entry)(args);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -241,7 +241,8 @@ static int __init call_prom(const char *service, int nargs, int nret, ...)
|
||||||
for (i = 0; i < nret; i++)
|
for (i = 0; i < nret; i++)
|
||||||
args.args[nargs+i] = 0;
|
args.args[nargs+i] = 0;
|
||||||
|
|
||||||
enter_prom(&args, RELOC(prom_entry));
|
if (enter_prom(&args, RELOC(prom_entry)) < 0)
|
||||||
|
return PROM_ERROR;
|
||||||
|
|
||||||
return (nret > 0) ? args.args[nargs] : 0;
|
return (nret > 0) ? args.args[nargs] : 0;
|
||||||
}
|
}
|
||||||
|
@ -265,7 +266,8 @@ static int __init call_prom_ret(const char *service, int nargs, int nret,
|
||||||
for (i = 0; i < nret; i++)
|
for (i = 0; i < nret; i++)
|
||||||
rets[nargs+i] = 0;
|
rets[nargs+i] = 0;
|
||||||
|
|
||||||
enter_prom(&args, RELOC(prom_entry));
|
if (enter_prom(&args, RELOC(prom_entry)) < 0)
|
||||||
|
return PROM_ERROR;
|
||||||
|
|
||||||
if (rets != NULL)
|
if (rets != NULL)
|
||||||
for (i = 1; i < nret; ++i)
|
for (i = 1; i < nret; ++i)
|
||||||
|
@ -670,9 +672,11 @@ static void __init prom_send_capabilities(void)
|
||||||
*/
|
*/
|
||||||
static unsigned long __init alloc_up(unsigned long size, unsigned long align)
|
static unsigned long __init alloc_up(unsigned long size, unsigned long align)
|
||||||
{
|
{
|
||||||
unsigned long base = _ALIGN_UP(RELOC(alloc_bottom), align);
|
unsigned long base = RELOC(alloc_bottom);
|
||||||
unsigned long addr = 0;
|
unsigned long addr = 0;
|
||||||
|
|
||||||
|
if (align)
|
||||||
|
base = _ALIGN_UP(base, align);
|
||||||
prom_debug("alloc_up(%x, %x)\n", size, align);
|
prom_debug("alloc_up(%x, %x)\n", size, align);
|
||||||
if (RELOC(ram_top) == 0)
|
if (RELOC(ram_top) == 0)
|
||||||
prom_panic("alloc_up() called with mem not initialized\n");
|
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)
|
||||||
base = _ALIGN_UP(base + 0x100000, align)) {
|
base = _ALIGN_UP(base + 0x100000, align)) {
|
||||||
prom_debug(" trying: 0x%x\n\r", base);
|
prom_debug(" trying: 0x%x\n\r", base);
|
||||||
addr = (unsigned long)prom_claim(base, size, 0);
|
addr = (unsigned long)prom_claim(base, size, 0);
|
||||||
if (addr != PROM_ERROR)
|
if (addr != PROM_ERROR && addr != 0)
|
||||||
break;
|
break;
|
||||||
addr = 0;
|
addr = 0;
|
||||||
if (align == 0)
|
if (align == 0)
|
||||||
|
@ -746,7 +750,7 @@ static unsigned long __init alloc_down(unsigned long size, unsigned long align,
|
||||||
base = _ALIGN_DOWN(base - 0x100000, align)) {
|
base = _ALIGN_DOWN(base - 0x100000, align)) {
|
||||||
prom_debug(" trying: 0x%x\n\r", base);
|
prom_debug(" trying: 0x%x\n\r", base);
|
||||||
addr = (unsigned long)prom_claim(base, size, 0);
|
addr = (unsigned long)prom_claim(base, size, 0);
|
||||||
if (addr != PROM_ERROR)
|
if (addr != PROM_ERROR && addr != 0)
|
||||||
break;
|
break;
|
||||||
addr = 0;
|
addr = 0;
|
||||||
}
|
}
|
||||||
|
@ -852,9 +856,16 @@ static void __init prom_init_mem(void)
|
||||||
type[0] = 0;
|
type[0] = 0;
|
||||||
prom_getprop(node, "device_type", type, sizeof(type));
|
prom_getprop(node, "device_type", type, sizeof(type));
|
||||||
|
|
||||||
|
if (type[0] == 0) {
|
||||||
|
/*
|
||||||
|
* CHRP Longtrail machines have no device_type
|
||||||
|
* on the memory node, so check the name instead...
|
||||||
|
*/
|
||||||
|
prom_getprop(node, "name", type, sizeof(type));
|
||||||
|
}
|
||||||
if (strcmp(type, RELOC("memory")))
|
if (strcmp(type, RELOC("memory")))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
plen = prom_getprop(node, "reg", RELOC(regbuf), sizeof(regbuf));
|
plen = prom_getprop(node, "reg", RELOC(regbuf), sizeof(regbuf));
|
||||||
if (plen > sizeof(regbuf)) {
|
if (plen > sizeof(regbuf)) {
|
||||||
prom_printf("memory node too large for buffer !\n");
|
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,
|
||||||
unsigned long soff;
|
unsigned long soff;
|
||||||
unsigned char *valp;
|
unsigned char *valp;
|
||||||
static char pname[MAX_PROPERTY_NAME];
|
static char pname[MAX_PROPERTY_NAME];
|
||||||
int l;
|
int l, room;
|
||||||
|
|
||||||
dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end);
|
dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end);
|
||||||
|
|
||||||
/* get the node's full name */
|
/* get the node's full name */
|
||||||
namep = (char *)*mem_start;
|
namep = (char *)*mem_start;
|
||||||
l = call_prom("package-to-path", 3, 1, node,
|
room = *mem_end - *mem_start;
|
||||||
namep, *mem_end - *mem_start);
|
if (room > 255)
|
||||||
|
room = 255;
|
||||||
|
l = call_prom("package-to-path", 3, 1, node, namep, room);
|
||||||
if (l >= 0) {
|
if (l >= 0) {
|
||||||
/* Didn't fit? Get more room. */
|
/* Didn't fit? Get more room. */
|
||||||
if ((l+1) > (*mem_end - *mem_start)) {
|
if (l >= room) {
|
||||||
namep = make_room(mem_start, mem_end, l+1, 1);
|
if (l >= *mem_end - *mem_start)
|
||||||
|
namep = make_room(mem_start, mem_end, l+1, 1);
|
||||||
call_prom("package-to-path", 3, 1, node, namep, l);
|
call_prom("package-to-path", 3, 1, node, namep, l);
|
||||||
}
|
}
|
||||||
namep[l] = '\0';
|
namep[l] = '\0';
|
||||||
|
|
|
@ -29,6 +29,7 @@ claim(unsigned int virt, unsigned int size, unsigned int align)
|
||||||
args.virt = virt;
|
args.virt = virt;
|
||||||
args.size = size;
|
args.size = size;
|
||||||
args.align = align;
|
args.align = align;
|
||||||
|
args.ret = (void *) 0;
|
||||||
(*of_prom_entry)(&args);
|
(*of_prom_entry)(&args);
|
||||||
return args.ret;
|
return args.ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ boot(int a1, int a2, void *prom)
|
||||||
begin_avail = avail_high = avail_ram;
|
begin_avail = avail_high = avail_ram;
|
||||||
end_avail = scratch + sizeof(scratch);
|
end_avail = scratch + sizeof(scratch);
|
||||||
printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len);
|
printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len);
|
||||||
gunzip(dst, 0x400000, im, &len);
|
gunzip(dst, PROG_SIZE - PROG_START, im, &len);
|
||||||
printf("done %u bytes\n\r", len);
|
printf("done %u bytes\n\r", len);
|
||||||
printf("%u bytes of heap consumed, max in use %u\n\r",
|
printf("%u bytes of heap consumed, max in use %u\n\r",
|
||||||
avail_high - begin_avail, heap_max);
|
avail_high - begin_avail, heap_max);
|
||||||
|
|
Loading…
Reference in a new issue