/* $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai 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 #include #include #include #include #include #include #include #include #include #include #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, j, cnt*/; /* * Get memory. */ if ((phandle = OF_finddevice("/memory")) == -1 || OF_getprop(phandle, "reg", OFmem, sizeof OFmem[0] * OFMEM_REGIONS) <= 0 || OF_getprop(phandle, "available", OFavail, sizeof OFavail[0] * OFMEM_REGIONS) <= 0) panic("no memory?"); *memp = OFmem; *availp = OFavail; } void ppc_exit() { OF_exit(); } void ppc_boot(str) char *str; { OF_boot(str); } #ifdef __BROKEN_DK_ESTABLISH /* * Establish a list of all available disks to allow specifying the * root/swap/dump dev. */ struct ofb_disk { LIST_ENTRY(ofb_disk) ofb_list; struct disk *ofb_dk; struct device *ofb_dev; int ofb_phandle; int ofb_unit; }; static LIST_HEAD(ofb_list, ofb_disk) ofb_head; /* LIST_INIT? XXX */ void dk_establish(dk, dev) struct disk *dk; struct device *dev; { struct ofb_disk *od; struct ofb_softc *ofp = (void *)dev; MALLOC(od, struct ofb_disk *, sizeof *od, M_TEMP, M_NOWAIT); if (!od) panic("dk_establish"); od->ofb_dk = dk; od->ofb_dev = dev; od->ofb_phandle = ofp->sc_phandle; if (dev->dv_class == DV_DISK) /* XXX */ od->ofb_unit = ofp->sc_unit; else od->ofb_unit = -1; LIST_INSERT_HEAD(&ofb_head, od, ofb_list); } /* * Cleanup the list. */ void dk_cleanup() { struct ofb_disk *od, *nd; for (od = ofb_head.lh_first; od; od = nd) { nd = od->ofb_list.le_next; LIST_REMOVE(od, ofb_list); FREE(od, M_TEMP); } } static void dk_setroot(od, part) struct ofb_disk *od; int part; { char type[8]; int maj, unit; struct disklabel *lp; dev_t tmpdev; char *cp; if (OF_getprop(od->ofb_phandle, "device_type", type, sizeof type) < 0) panic("OF_getproperty"); if (strcmp(type, "block") == 0) { for (maj = 0; maj < nblkdev; maj++) { if (bdevsw[maj].d_strategy == od->ofb_dk->dk_driver->d_strategy) break; } if (maj >= nblkdev) panic("dk_setroot: impossible"); /* * Find the unit. */ unit = 0; for (cp = od->ofb_dk->dk_name; *cp; cp++) { if (*cp >= '0' && *cp <= '9') unit = unit * 10 + *cp - '0'; else /* Start anew */ unit = 0; } /* * Find a default partition; try partition `a', then * fall back on RAW_PART. */ if (part == -1) { /* * Open the disk to force an update of the in-core * disklabel. Use RAW_PART because all disk * drivers allow RAW_PART to be opened. */ tmpdev = MAKEDISKDEV(maj, unit, RAW_PART); if (bdevsw[maj].d_open(tmpdev, FREAD, S_IFBLK, 0)) { /* * Open failed. Device is probably not * configured. setroot() can handle this. */ return; } (void)bdevsw[maj].d_close(tmpdev, FREAD, S_IFBLK, 0); lp = od->ofb_dk->dk_label; /* Check for a valid `a' partition. */ if (lp->d_partitions[0].p_size > 0 && lp->d_partitions[0].p_fstype != FS_UNUSED) part = 0; else part = RAW_PART; } booted_device = od->ofb_dev; booted_partition = part; } else if (strcmp(type, "network") == 0) { booted_device = od->ofb_dev; booted_partition = 0; } /* "Not found." setroot() will ask for the root device. */ } /* * Try to find a disk with the given name. * This allows either the OpenFirmware device name, * or the NetBSD device name, both with optional trailing partition. */ int dk_match(name) char *name; { struct ofb_disk *od; char *cp; int phandle; int part, unit; int l; for (od = ofb_head.lh_first; od; od = od->ofb_list.le_next) { /* * First try the NetBSD name. */ l = strlen(od->ofb_dev->dv_xname); if (!bcmp(name, od->ofb_dev->dv_xname, l)) { if (name[l] == '\0') { /* Default partition, (or none at all) */ dk_setroot(od, -1); return 0; } if (name[l + 1] == '\0') { switch (name[l]) { case '*': /* Default partition */ dk_setroot(od, -1); return 0; default: if (name[l] >= 'a' && name[l] < 'a' + MAXPARTITIONS) { /* specified partition */ dk_setroot(od, name[l] - 'a'); return 0; } break; } } } } /* * Now try the OpenFirmware name */ l = strlen(name); for (cp = name + l; --cp >= name;) if (*cp == '/' || *cp == ':') break; if (cp >= name && *cp == ':') *cp++ = 0; else cp = name + l; part = *cp >= 'a' && *cp < 'a' + MAXPARTITIONS ? *cp - 'a' : -1; while (cp > name && cp[-1] != '@' && cp[-1] != '/') --cp; if (cp > name && cp[-1] == '@') { for (unit = 0; *++cp >= '0' && *cp <= '9';) unit = unit * 10 + *cp - '0'; } else unit = -1; if ((phandle = OF_finddevice(name)) != -1) { for (od = ofb_head.lh_first; od; od = od->ofb_list.le_next) { if (phandle == od->ofb_phandle) { /* Check for matching units */ if (od->ofb_dk && unit != -1 && od->ofb_unit != unit) continue; dk_setroot(od, part); return 0; } } } return ENODEV; } #endif /* __BROKEN_DK_ESTABLISH */