Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/powerpc/powerpc deal with /memory "reg" property wh...



details:   https://anonhg.NetBSD.org/src/rev/659414fb29ea
branches:  trunk
changeset: 785838:659414fb29ea
user:      macallan <macallan%NetBSD.org@localhost>
date:      Mon Apr 01 20:14:42 2013 +0000

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

diffstat:

 sys/arch/powerpc/powerpc/ofw_machdep.c |  184 ++++++++++++++++++++++----------
 1 files changed, 126 insertions(+), 58 deletions(-)

diffs (224 lines):

diff -r 6fa5934ba16e -r 659414fb29ea sys/arch/powerpc/powerpc/ofw_machdep.c
--- a/sys/arch/powerpc/powerpc/ofw_machdep.c    Mon Apr 01 16:37:22 2013 +0000
+++ b/sys/arch/powerpc/powerpc/ofw_machdep.c    Mon Apr 01 20:14:42 2013 +0000
@@ -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 @@
 #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 @@
 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 */
 
-       /*
-        * Get memory.
-        */
+       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;
+
+       /* 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++;
+       /* 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];
 
-#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;
+               /* 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
+               OFmem[cnt].start = addr;
+               OFmem[cnt].size = size;
+               aprint_normal("mem region %d start=%llx size=%llx\n",
+                   cnt, addr, size);
+               cnt++;
+       }
 
-               count /= sizeof OFavail_G5[0];
-               cnt = count * sizeof(OFavail[0]);
+       DPRINTF("available\n");
 
-               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;
-               }
-       }
-#else
-       memset(OFavail, 0, sizeof OFavail);
-       cnt = OF_getprop(phandle, "available",
-               OFavail, sizeof OFavail[0] * OFMEM_REGIONS);
-#endif
-       if (cnt <= 0)
+       /* 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) {



Home | Main Index | Thread Index | Old Index