NetBSD-5.0.2/sys/arch/powerpc/powerpc/ofw_machdep.c
/* $NetBSD: ofw_machdep.c,v 1.18 2008/03/27 18:01:08 phx Exp $ */
/*
* Copyright (C) 1996 Wolfgang Solfrank.
* Copyright (C) 1996 TooLs GmbH.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by TooLs GmbH.
* 4. The name of TooLs GmbH may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ofw_machdep.c,v 1.18 2008/03/27 18:01:08 phx Exp $");
#include <sys/param.h>
#include <sys/buf.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/disk.h>
#include <sys/disklabel.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/stat.h>
#include <sys/systm.h>
#include <dev/ofw/openfirm.h>
#include <machine/powerpc.h>
#include <machine/autoconf.h>
#define OFMEM_REGIONS 32
static struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3];
/*
* This is called during initppc, before the system is really initialized.
* It shall provide the total and the available regions of RAM.
* Both lists must have a zero-size entry as terminator.
* The available regions need not take the kernel into account, but needs
* to provide space for two additional entry beyond the terminating one.
*/
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));
/*
* 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);
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;
}
}
#else
memset(OFavail, 0, sizeof OFavail);
cnt = OF_getprop(phandle, "available",
OFavail, sizeof OFavail[0] * OFMEM_REGIONS);
#endif
if (cnt <= 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++;
}
if (strncmp(model_name, "Pegasos", 7) == 0) {
/*
* Some versions of SmartFirmware, only recognize the first
* 256MB segment as available. Work around it and add an
* extra entry to OFavail[] to account for this.
*/
#define AVAIL_THRESH (0x10000000-1)
if (((OFavail[cnt-1].start + OFavail[cnt-1].size +
AVAIL_THRESH) & ~AVAIL_THRESH) <
(OFmem[regcnt-1].start + OFmem[regcnt-1].size)) {
OFavail[cnt].start =
(OFavail[cnt-1].start + OFavail[cnt-1].size +
AVAIL_THRESH) & ~AVAIL_THRESH;
OFavail[cnt].size =
OFmem[regcnt-1].size - OFavail[cnt].start;
aprint_normal("WARNING: add memory segment %lx - %lx,"
"\nWARNING: which was not recognized by "
"the Firmware.\n",
(unsigned long)OFavail[cnt].start,
(unsigned long)OFavail[cnt].start +
OFavail[cnt].size);
cnt++;
}
}
*memp = OFmem;
*availp = OFavail;
return;
error:
#if defined (MAMBO)
printf("no memory, assuming 512MB\n");
OFmem[0].start = 0x0;
OFmem[0].size = 0x20000000;
OFavail[0].start = 0x3000;
OFavail[0].size = 0x20000000 - 0x3000;
*memp = OFmem;
*availp = OFavail;
#else
panic("no memory?");
#endif
return;
}
void
ppc_exit(void)
{
OF_exit();
}
void
ppc_boot(char *str)
{
OF_boot(str);
}