Module Name:    src
Committed By:   macallan
Date:           Mon Apr  1 20:14:43 UTC 2013

Modified Files:
        src/sys/arch/powerpc/powerpc: ofw_machdep.c

Log Message:
deal with /memory "reg" property which may contain 64bit addresses on G5


To generate a diff of this commit:
cvs rdiff -u -r1.19 -r1.20 src/sys/arch/powerpc/powerpc/ofw_machdep.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/powerpc/powerpc/ofw_machdep.c
diff -u src/sys/arch/powerpc/powerpc/ofw_machdep.c:1.19 src/sys/arch/powerpc/powerpc/ofw_machdep.c:1.20
--- src/sys/arch/powerpc/powerpc/ofw_machdep.c:1.19	Wed Feb  1 09:54:03 2012
+++ src/sys/arch/powerpc/powerpc/ofw_machdep.c	Mon Apr  1 20:14:42 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: ofw_machdep.c,v 1.19 2012/02/01 09:54:03 matt Exp $	*/
+/*	$NetBSD: ofw_machdep.c,v 1.20 2013/04/01 20:14:42 macallan Exp $	*/
 
 /*
  * Copyright (C) 1996 Wolfgang Solfrank.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ofw_machdep.c,v 1.19 2012/02/01 09:54:03 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ofw_machdep.c,v 1.20 2013/04/01 20:14:42 macallan Exp $");
 
 #include <sys/param.h>
 #include <sys/buf.h>
@@ -50,6 +50,12 @@ __KERNEL_RCSID(0, "$NetBSD: ofw_machdep.
 #include <machine/powerpc.h>
 #include <machine/autoconf.h>
 
+#ifdef DEBUG
+#define DPRINTF aprint_error
+#else
+#define DPRINTF while(0) printf
+#endif
+
 #define	OFMEM_REGIONS	32
 static struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3];
 
@@ -63,74 +69,136 @@ static struct mem_region OFmem[OFMEM_REG
 void
 mem_regions(struct mem_region **memp, struct mem_region **availp)
 {
-	int phandle, i, cnt, regcnt;
-	struct mem_region_avail {
-		paddr_t start;
-		paddr_t size;
-	} OFavail_G5[OFMEM_REGIONS + 3] __attribute((unused));
+	int phandle, i, cnt, regcnt, acells, scells;
+	int numregs;
+	uint32_t regs[OFMEM_REGIONS * 4]; /* 2 values + 2 for 64bit */
+
+	DPRINTF("calling mem_regions\n");
+	/* determine acell size */
+	if ((phandle = OF_finddevice("/")) == -1)
+		goto error;
+	cnt = OF_getprop(phandle, "#address-cells", &acells, sizeof(int));
+	if (cnt <= 0)
+		acells = 1;
 
-	/*
-	 * Get memory.
-	 */
+	/* determine scell size */
+	if ((phandle = OF_finddevice("/")) == -1)
+		goto error;
+	cnt = OF_getprop(phandle, "#size-cells", &scells, sizeof(int));
+	if (cnt <= 0)
+		scells = 1;
+
+	/* Get memory */
 	if ((phandle = OF_finddevice("/memory")) == -1)
 		goto error;
 
-	memset(OFmem, 0, sizeof OFmem);
-	regcnt = OF_getprop(phandle, "reg",
-		OFmem, sizeof OFmem[0] * OFMEM_REGIONS);
+	memset(regs, 0, sizeof(regs));
+	regcnt = OF_getprop(phandle, "reg", regs,
+	    sizeof(regs[0]) * OFMEM_REGIONS * 4);
 	if (regcnt <= 0)
 		goto error;
 
-	/* Remove zero sized entry in the returned data. */
-	regcnt /= sizeof OFmem[0];
-	for (i = 0; i < regcnt; )
-		if (OFmem[i].size == 0) {
-			memmove(&OFmem[i], &OFmem[i + 1],
-				(regcnt - i) * sizeof OFmem[0]);
-			regcnt--;
-		} else
-			i++;
-
-#if defined (PMAC_G5)
-	/* XXXSL: the G5 implementation of OFW is defines the /memory reg/available
-	 * properties differently. Try to fix it up here with minimal damage to the
-	 * rest of the code
- 	 */
-	{
-		int count;
-		memset(OFavail_G5, 0, sizeof OFavail_G5);
-		count = OF_getprop(phandle, "available",
-			OFavail_G5, sizeof OFavail_G5[0] * OFMEM_REGIONS);
-
-		if (count <= 0)
-			goto error;
-
-		count /= sizeof OFavail_G5[0];
-		cnt = count * sizeof(OFavail[0]);
-
-		for (i = 0; i < count; i++ )
-		{
-			OFavail[i].start_hi = 0;
-			OFavail[i].start = OFavail_G5[i].start;
-			OFavail[i].size = OFavail_G5[i].size;
+	/* how many mem regions did we get? */
+	numregs = regcnt / (sizeof(uint32_t)*(acells+scells));
+	DPRINTF("regcnt=%d num=%d acell=%d scell=%d\n",
+	    regcnt, numregs, acells, scells);
+
+	/* move the data into OFmem */
+	memset(OFmem, 0, sizeof(OFmem));
+	for (i=0, cnt=0; i <= numregs; i++) {
+		uint64_t addr, size;
+
+		if (acells > 1)
+			memcpy(&addr, &regs[i * (acells + scells)],
+			    sizeof(int32_t) * acells);
+		else
+			addr = regs[i * (acells + scells)];
+
+		if (scells > 1)
+			memcpy(&size, &regs[i * (acells + scells) + acells],
+			    sizeof(int32_t) * scells);
+		else
+			size = regs[i * (acells + scells) + acells];
+
+		/* skip entry of 0 size */
+		if (size == 0)
+			continue;
+#ifndef _LP64
+		if (addr > 0xFFFFFFFF || size > 0xFFFFFFFF ||
+			(addr + size) > 0xFFFFFFFF) {
+			aprint_error("Base addr of %llx or size of %llx too"
+			    " large for 32 bit OS. Skipping.", addr, size);
+			continue;
 		}
-	}
-#else
-	memset(OFavail, 0, sizeof OFavail);
-	cnt = OF_getprop(phandle, "available",
-		OFavail, sizeof OFavail[0] * OFMEM_REGIONS);
 #endif
-	if (cnt <= 0)
+		OFmem[cnt].start = addr;
+		OFmem[cnt].size = size;
+		aprint_normal("mem region %d start=%llx size=%llx\n",
+		    cnt, addr, size);
+		cnt++;
+	}
+
+	DPRINTF("available\n");
+
+	/* now do the same thing again, for the available counts */
+	memset(regs, 0, sizeof(regs));
+	regcnt = OF_getprop(phandle, "available", regs,
+	    sizeof(regs[0]) * OFMEM_REGIONS * 4);
+	if (regcnt <= 0)
 		goto error;
 
-	cnt /= sizeof OFavail[0];
-	for (i = 0; i < cnt; ) {
-		if (OFavail[i].size == 0) {
-			memmove(&OFavail[i], &OFavail[i + 1],
-				(cnt - i) * sizeof OFavail[0]);
-			cnt--;
-		} else
-			i++;
+	DPRINTF("%08x %08x %08x %08x\n", regs[0], regs[1], regs[2], regs[3]);
+
+	/*
+	 * some(?) G5s have messed up 'available' properties which don't obey
+	 * #address-cells. Try to detect this here.
+	 * XXX this needs a better test
+	 */
+	if (((regcnt >> 2) % (acells + scells)) != 0) {
+		aprint_normal("messed up 'available' property detected\n");
+		acells = 1;
+	}
+	
+	/* how many mem regions did we get? */
+	numregs = regcnt / (sizeof(uint32_t) * (acells + scells));
+	DPRINTF("regcnt=%d num=%d acell=%d scell=%d\n",
+	    regcnt, numregs, acells, scells);
+
+	DPRINTF("to OF_avail\n");
+
+	/* move the data into OFavail */
+	memset(OFavail, 0, sizeof(OFavail));
+	for (i=0, cnt=0; i <= numregs; i++) {
+		uint64_t addr, size;
+
+		DPRINTF("%d\n", i);
+		if (acells > 1)
+			memcpy(&addr, &regs[i * (acells + scells)],
+			    sizeof(int32_t) * acells);
+		else
+			addr = regs[i * (acells + scells)];
+
+		if (scells > 1)
+			memcpy(&size, &regs[i * (acells + scells) + acells],
+			    sizeof(int32_t) * scells);
+		else
+			size = regs[i * (acells + scells) + acells];
+		/* skip entry of 0 size */
+		if (size == 0)
+			continue;
+#ifndef _LP64
+		if (addr > 0xFFFFFFFF || size > 0xFFFFFFFF ||
+			(addr+size) > 0xFFFFFFFF) {
+			aprint_error("Base addr of %llx or size of %llx too"
+			    " large for 32 bit OS. Skipping.", addr, size);
+			continue;
+		}
+#endif
+		OFavail[cnt].start = addr;
+		OFavail[cnt].size = size;
+		aprint_normal("avail region %d start=%llx size=%llx\n",
+		    cnt, addr, size);
+		cnt++;
 	}
 
 	if (strncmp(model_name, "Pegasos", 7) == 0) {

Reply via email to