NetBSD-5.0.2/sys/arch/powerpc/powerpc/ofw_machdep.c

Compare this file to the similar file:
Show the results in this format:

/*	$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);
}