Explorar o código

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>
Paul Mackerras %!s(int64=19) %!d(string=hai) anos
pai
achega
c49888203d

+ 28 - 14
arch/powerpc/kernel/prom_init.c

@@ -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,
-		      namep, *mem_end - *mem_start);
+	room = *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)) {
-			namep = make_room(mem_start, mem_end, l+1, 1);
+		if (l >= room) {
+			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';

+ 1 - 0
arch/ppc/boot/of1275/claim.c

@@ -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;
 }
 }

+ 1 - 1
arch/ppc/boot/openfirmware/chrpmain.c

@@ -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);