1 /* $NetBSD: ofw_machdep.c,v 1.11 2001/08/26 02:47:39 matt Exp $ */ 2 3 /* 4 * Copyright (C) 1996 Wolfgang Solfrank. 5 * Copyright (C) 1996 TooLs GmbH. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by TooLs GmbH. 19 * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 #include <sys/param.h> 34 #include <sys/buf.h> 35 #include <sys/conf.h> 36 #include <sys/device.h> 37 #include <sys/disk.h> 38 #include <sys/disklabel.h> 39 #include <sys/fcntl.h> 40 #include <sys/ioctl.h> 41 #include <sys/malloc.h> 42 #include <sys/stat.h> 43 #include <sys/systm.h> 44 45 #include <dev/ofw/openfirm.h> 46 47 #include <machine/powerpc.h> 48 49 #define OFMEM_REGIONS 32 50 static struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3]; 51 52 /* 53 * This is called during initppc, before the system is really initialized. 54 * It shall provide the total and the available regions of RAM. 55 * Both lists must have a zero-size entry as terminator. 56 * The available regions need not take the kernel into account, but needs 57 * to provide space for two additional entry beyond the terminating one. 58 */ 59 void 60 mem_regions(struct mem_region **memp, struct mem_region **availp) 61 { 62 int phandle, i, cnt; 63 64 /* 65 * Get memory. 66 */ 67 if ((phandle = OF_finddevice("/memory")) == -1) 68 goto error; 69 70 memset(OFmem, 0, sizeof OFmem); 71 cnt = OF_getprop(phandle, "reg", 72 OFmem, sizeof OFmem[0] * OFMEM_REGIONS); 73 if (cnt <= 0) 74 goto error; 75 76 /* Remove zero sized entry in the returned data. */ 77 cnt /= sizeof OFmem[0]; 78 for (i = 0; i < cnt; ) 79 if (OFmem[i].size == 0) { 80 memmove(&OFmem[i], &OFmem[i + 1], 81 (cnt - i) * sizeof OFmem[0]); 82 cnt--; 83 } else 84 i++; 85 86 memset(OFavail, 0, sizeof OFavail); 87 cnt = OF_getprop(phandle, "available", 88 OFavail, sizeof OFavail[0] * OFMEM_REGIONS); 89 if (cnt <= 0) 90 goto error; 91 92 cnt /= sizeof OFavail[0]; 93 for (i = 0; i < cnt; ) 94 if (OFavail[i].size == 0) { 95 memmove(&OFavail[i], &OFavail[i + 1], 96 (cnt - i) * sizeof OFavail[0]); 97 cnt--; 98 } else 99 i++; 100 101 *memp = OFmem; 102 *availp = OFavail; 103 return; 104 105 error: 106 panic("no memory?"); 107 } 108 109 void 110 ppc_exit(void) 111 { 112 OF_exit(); 113 } 114 115 void 116 ppc_boot(char *str) 117 { 118 OF_boot(str); 119 } 120 121 #ifdef __BROKEN_DK_ESTABLISH 122 /* 123 * Establish a list of all available disks to allow specifying the 124 * root/swap/dump dev. 125 */ 126 struct ofb_disk { 127 LIST_ENTRY(ofb_disk) ofb_list; 128 struct disk *ofb_dk; 129 struct device *ofb_dev; 130 int ofb_phandle; 131 int ofb_unit; 132 }; 133 134 #include <machine/autoconf.h> 135 136 static LIST_HEAD(ofb_list, ofb_disk) ofb_head; /* LIST_INIT? XXX */ 137 138 void 139 dk_establish(struct disk *dk, struct device *dev) 140 { 141 struct ofb_disk *od; 142 struct ofbus_softc *ofp = (void *)dev; 143 144 MALLOC(od, struct ofb_disk *, sizeof *od, M_TEMP, M_NOWAIT); 145 if (!od) 146 panic("dk_establish"); 147 od->ofb_dk = dk; 148 od->ofb_dev = dev; 149 od->ofb_phandle = ofp->sc_phandle; 150 if (dev->dv_class == DV_DISK) /* XXX */ 151 od->ofb_unit = ofp->sc_unit; 152 else 153 od->ofb_unit = -1; 154 LIST_INSERT_HEAD(&ofb_head, od, ofb_list); 155 } 156 157 /* 158 * Cleanup the list. 159 */ 160 void 161 dk_cleanup(void) 162 { 163 struct ofb_disk *od, *nd; 164 165 for (od = ofb_head.lh_first; od; od = nd) { 166 nd = od->ofb_list.le_next; 167 LIST_REMOVE(od, ofb_list); 168 FREE(od, M_TEMP); 169 } 170 } 171 172 static void 173 dk_setroot(struct ofb_disk *od, int part) 174 { 175 char type[8]; 176 int maj, unit; 177 struct disklabel *lp; 178 dev_t tmpdev; 179 char *cp; 180 181 if (OF_getprop(od->ofb_phandle, "device_type", type, sizeof type) < 0) 182 panic("OF_getproperty"); 183 184 if (strcmp(type, "block") == 0) { 185 for (maj = 0; maj < nblkdev; maj++) { 186 if (bdevsw[maj].d_strategy == 187 od->ofb_dk->dk_driver->d_strategy) 188 break; 189 } 190 if (maj >= nblkdev) 191 panic("dk_setroot: impossible"); 192 193 /* 194 * Find the unit. 195 */ 196 unit = 0; 197 for (cp = od->ofb_dk->dk_name; *cp; cp++) { 198 if (*cp >= '0' && *cp <= '9') 199 unit = unit * 10 + *cp - '0'; 200 else 201 /* Start anew */ 202 unit = 0; 203 } 204 205 /* 206 * Find a default partition; try partition `a', then 207 * fall back on RAW_PART. 208 */ 209 if (part == -1) { 210 /* 211 * Open the disk to force an update of the in-core 212 * disklabel. Use RAW_PART because all disk 213 * drivers allow RAW_PART to be opened. 214 */ 215 tmpdev = MAKEDISKDEV(maj, unit, RAW_PART); 216 217 if (bdevsw[maj].d_open(tmpdev, FREAD, S_IFBLK, 0)) { 218 /* 219 * Open failed. Device is probably not 220 * configured. setroot() can handle this. 221 */ 222 return; 223 } 224 (void)bdevsw[maj].d_close(tmpdev, FREAD, S_IFBLK, 0); 225 lp = od->ofb_dk->dk_label; 226 227 /* Check for a valid `a' partition. */ 228 if (lp->d_partitions[0].p_size > 0 && 229 lp->d_partitions[0].p_fstype != FS_UNUSED) 230 part = 0; 231 else 232 part = RAW_PART; 233 } 234 booted_device = od->ofb_dev; 235 booted_partition = part; 236 } else if (strcmp(type, "network") == 0) { 237 booted_device = od->ofb_dev; 238 booted_partition = 0; 239 } 240 241 /* "Not found." setroot() will ask for the root device. */ 242 } 243 244 /* 245 * Try to find a disk with the given name. 246 * This allows either the OpenFirmware device name, 247 * or the NetBSD device name, both with optional trailing partition. 248 */ 249 int 250 dk_match(char *name) 251 { 252 struct ofb_disk *od; 253 char *cp; 254 int phandle; 255 int part, unit; 256 int l; 257 258 for (od = ofb_head.lh_first; od; od = od->ofb_list.le_next) { 259 /* 260 * First try the NetBSD name. 261 */ 262 l = strlen(od->ofb_dev->dv_xname); 263 if (!memcmp(name, od->ofb_dev->dv_xname, l)) { 264 if (name[l] == '\0') { 265 /* Default partition, (or none at all) */ 266 dk_setroot(od, -1); 267 return 0; 268 } 269 if (name[l + 1] == '\0') { 270 switch (name[l]) { 271 case '*': 272 /* Default partition */ 273 dk_setroot(od, -1); 274 return 0; 275 default: 276 if (name[l] >= 'a' 277 && name[l] < 'a' + MAXPARTITIONS) { 278 /* specified partition */ 279 dk_setroot(od, name[l] - 'a'); 280 return 0; 281 } 282 break; 283 } 284 } 285 } 286 } 287 /* 288 * Now try the OpenFirmware name 289 */ 290 l = strlen(name); 291 for (cp = name + l; --cp >= name;) 292 if (*cp == '/' || *cp == ':') 293 break; 294 if (cp >= name && *cp == ':') 295 *cp++ = 0; 296 else 297 cp = name + l; 298 part = *cp >= 'a' && *cp < 'a' + MAXPARTITIONS 299 ? *cp - 'a' 300 : -1; 301 while (cp > name && cp[-1] != '@' && cp[-1] != '/') 302 --cp; 303 if (cp > name && cp[-1] == '@') { 304 for (unit = 0; *++cp >= '0' && *cp <= '9';) 305 unit = unit * 10 + *cp - '0'; 306 } else 307 unit = -1; 308 309 if ((phandle = OF_finddevice(name)) != -1) { 310 for (od = ofb_head.lh_first; od; od = od->ofb_list.le_next) { 311 if (phandle == od->ofb_phandle) { 312 /* Check for matching units */ 313 if (od->ofb_dk && 314 unit != -1 && 315 od->ofb_unit != unit) 316 continue; 317 dk_setroot(od, part); 318 return 0; 319 } 320 } 321 } 322 return ENODEV; 323 } 324 #endif /* __BROKEN_DK_ESTABLISH */ 325