deal with /memory "reg" property which may contain 64bit addresses on G5
This commit is contained in:
parent
11c04fdfa0
commit
0ee8b59e60
@ -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.c,v 1.19 2012/02/01 09:54:03 matt Exp $"
|
||||
#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_REGIONS + 1], OFavail[OFMEM_REGIONS + 3];
|
||||
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);
|
||||
|
||||
#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);
|
||||
/* move the data into OFmem */
|
||||
memset(OFmem, 0, sizeof(OFmem));
|
||||
for (i=0, cnt=0; i <= numregs; i++) {
|
||||
uint64_t addr, size;
|
||||
|
||||
if (count <= 0)
|
||||
goto error;
|
||||
if (acells > 1)
|
||||
memcpy(&addr, ®s[i * (acells + scells)],
|
||||
sizeof(int32_t) * acells);
|
||||
else
|
||||
addr = regs[i * (acells + scells)];
|
||||
|
||||
count /= sizeof OFavail_G5[0];
|
||||
cnt = count * sizeof(OFavail[0]);
|
||||
if (scells > 1)
|
||||
memcpy(&size, ®s[i * (acells + scells) + acells],
|
||||
sizeof(int32_t) * scells);
|
||||
else
|
||||
size = regs[i * (acells + scells) + acells];
|
||||
|
||||
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;
|
||||
/* 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, ®s[i * (acells + scells)],
|
||||
sizeof(int32_t) * acells);
|
||||
else
|
||||
addr = regs[i * (acells + scells)];
|
||||
|
||||
if (scells > 1)
|
||||
memcpy(&size, ®s[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) {
|
||||
|
Loading…
Reference in New Issue
Block a user