1 /* $NetBSD: autoconf.c,v 1.10 2002/10/02 16:02:31 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1996 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Adam Glass, Gordon W. Ross, and Matthew Fredette. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Setup the system to run on the current machine. 41 * 42 * Configure() is called at boot time. Available devices are 43 * determined (from possibilities mentioned in ioconf.c), and 44 * the drivers are initialized. 45 */ 46 47 #include "opt_kgdb.h" 48 49 #include <sys/param.h> 50 #include <sys/systm.h> 51 #include <sys/conf.h> 52 #include <sys/device.h> 53 #include <sys/reboot.h> 54 55 #include "scsibus.h" 56 57 #if NSCSIBUS > 0 58 #include <dev/scsipi/scsi_all.h> 59 #include <dev/scsipi/scsipi_all.h> 60 #include <dev/scsipi/scsiconf.h> 61 #endif /* NSCSIBUS > 0 */ 62 63 #include <machine/autoconf.h> 64 #include <machine/intr.h> 65 #include <machine/promlib.h> 66 67 #ifdef KGDB 68 #include <sys/kgdb.h> 69 #endif 70 71 /* 72 * Do general device autoconfiguration, 73 * then choose root device (etc.) 74 * Called by machdep.c: cpu_startup() 75 */ 76 void 77 cpu_configure() 78 { 79 80 /* 81 * Consider stopping for a debugger before 82 * autoconfiguration. 83 */ 84 if (boothowto & RB_KDB) { 85 #ifdef KGDB 86 /* XXX - Ask on console for kgdb_dev? */ 87 /* Note: this will just return if kgdb_dev==NODEV */ 88 kgdb_connect(1); 89 #else /* KGDB */ 90 /* Either DDB or no debugger (just PROM). */ 91 Debugger(); 92 #endif /* KGDB */ 93 } 94 95 /* 96 * Install handlers for our "soft" interrupts. 97 * There might be a better place to do this? 98 */ 99 softintr_init(); 100 101 /* General device autoconfiguration. */ 102 if (config_rootfound("mainbus", NULL) == NULL) 103 panic("configure: mainbus not found"); 104 105 /* 106 * Now that device autoconfiguration is finished, 107 * we can safely enable interrupts. 108 */ 109 printf("enabling interrupts\n"); 110 (void)spl0(); 111 } 112 113 static int mainbus_match __P((struct device *, struct cfdata *, void *)); 114 static void mainbus_attach __P((struct device *, struct device *, void *)); 115 116 CFATTACH_DECL(mainbus, sizeof(struct device), 117 mainbus_match, mainbus_attach, NULL, NULL); 118 119 /* 120 * Probe for the mainbus; always succeeds. 121 */ 122 static int 123 mainbus_match(parent, cf, aux) 124 struct device *parent; 125 struct cfdata *cf; 126 void *aux; 127 { 128 129 return 1; 130 } 131 132 /* 133 * Do "direct" configuration for the bus types on mainbus. 134 * This controls the order of autoconfig for important things 135 * used early. For example, idprom is used by Ether drivers. 136 */ 137 static void 138 mainbus_attach(parent, self, args) 139 struct device *parent; 140 struct device *self; 141 void *args; 142 { 143 extern struct sun68k_bus_dma_tag mainbus_dma_tag; 144 extern struct sun68k_bus_space_tag mainbus_space_tag; 145 146 struct mainbus_attach_args ma; 147 const char *const *cpp; 148 static const char *const special[] = { 149 /* find these first */ 150 "obio", 151 "obmem", 152 NULL 153 }; 154 155 printf("\n"); 156 157 ma.ma_bustag = &mainbus_space_tag; 158 ma.ma_dmatag = &mainbus_dma_tag; 159 ma.ma_paddr = LOCATOR_FORBIDDEN; 160 ma.ma_pri = LOCATOR_FORBIDDEN; 161 162 /* Find all `early' mainbus buses */ 163 for (cpp = special; *cpp != NULL; cpp++) { 164 ma.ma_name = *cpp; 165 (void)config_found(self, &ma, NULL); 166 } 167 168 /* Find the remaining buses */ 169 ma.ma_name = NULL; 170 (void) config_found(self, &ma, NULL); 171 172 /* Lastly, find the PROM console */ 173 ma.ma_name = "pcons"; 174 (void) config_found(self, &ma, NULL); 175 } 176 177 /* 178 * sun68k_bus_search: 179 * This function is passed to config_search() by the attach function 180 * for each of the "bus" drivers (obio, obmem, mbmem, vme, ...). 181 * The purpose of this function is to copy the "locators" into our 182 * _attach_args structure, so child drivers may use the _attach_args both 183 * as match parameters and as temporary storage for the defaulted 184 * locator values determined in the child_match and preserved for 185 * the child_attach function. If the bus attach functions just 186 * used config_found, then we would not have an opportunity to 187 * setup the _attach_args for each child match and attach call. 188 */ 189 int sun68k_bus_search(parent, cf, aux) 190 struct device *parent; 191 struct cfdata *cf; 192 void *aux; 193 { 194 struct mainbus_attach_args *map = aux; 195 struct mainbus_attach_args ma; 196 197 /* Check whether we're looking for a specifically named device */ 198 if (map->ma_name != NULL && strcmp(map->ma_name, cf->cf_name) != 0) 199 return (0); 200 201 #ifdef DIAGNOSTIC 202 if (cf->cf_fstate == FSTATE_STAR) 203 panic("bus_scan: FSTATE_STAR"); 204 #endif 205 206 /* 207 * Prepare to copy the locators into our _attach_args. 208 */ 209 ma = *map; 210 ma.ma_name = NULL; 211 212 /* 213 * Avoid entries which are missing attach information that 214 * they need, or that have attach information that they 215 * cannot have. The individual bus attach functions tell 216 * us this by initializing the locator fields in the attach 217 * args they provide us. 218 * 219 * At the same time we copy these values into the _attach_args 220 * will pass to the device's match and attach functions. 221 */ 222 #ifdef DIAGNOSTIC 223 #define BAD_LOCATOR(ma_loc, what) panic("sun68k_bus_search: %s %s for: %s%d", \ 224 map-> ma_loc == LOCATOR_REQUIRED ? "missing" : "unexpected", \ 225 what, cf->cf_name, cf->cf_unit) 226 #else 227 #define BAD_LOCATOR(ma_loc, what) return (0) 228 #endif 229 #define CHECK_LOCATOR(ma_loc, cf_loc, what) \ 230 if ((map-> ma_loc == LOCATOR_FORBIDDEN && cf->cf_loc != -1) || \ 231 (map-> ma_loc == LOCATOR_REQUIRED && cf->cf_loc == -1)) \ 232 BAD_LOCATOR( ma_loc, what); \ 233 else \ 234 ma. ma_loc = cf->cf_loc 235 CHECK_LOCATOR(ma_paddr, cf_paddr, "address"); 236 CHECK_LOCATOR(ma_pri, cf_intpri, "ipl"); 237 238 /* 239 * Note that this allows the match function to save 240 * defaulted locators in the _attach_args that will be 241 * preserved for the related attach call. 242 * XXX - This is a hack... 243 */ 244 if (config_match(parent, cf, &ma) > 0) { 245 config_attach(parent, cf, &ma, sun68k_bus_print); 246 } 247 return (0); 248 } 249 250 /* 251 * sun68k_bus_print: 252 * Just print out the final (non-default) locators. 253 * The parent name is non-NULL when there was no match 254 * found by config_found(). 255 */ 256 int 257 sun68k_bus_print(args, name) 258 void *args; 259 const char *name; 260 { 261 struct mainbus_attach_args *ma = args; 262 263 if (name) 264 printf("%s:", name); 265 266 if (ma->ma_paddr != -1) 267 printf(" addr 0x%x", (unsigned int) ma->ma_paddr); 268 if (ma->ma_pri != -1) 269 printf(" ipl %d", ma->ma_pri); 270 271 return(UNCONF); 272 } 273 274 /****************************************************************/ 275 276 /* This takes the args: name, ctlr, unit */ 277 typedef struct device * (*findfunc_t) __P((char *, int, int)); 278 279 static struct device * find_dev_byname __P((char *)); 280 static struct device * net_find __P((char *, int, int)); 281 #if NSCSIBUS > 0 282 static struct device * scsi_find __P((char *, int, int)); 283 #endif /* NSCSIBUS > 0 */ 284 static struct device * xx_find __P((char *, int, int)); 285 286 struct prom_n2f { 287 const char name[4]; 288 findfunc_t func; 289 }; 290 static struct prom_n2f prom_dev_table[] = { 291 { "ie", net_find }, 292 { "ec", net_find }, 293 { "le", net_find }, 294 #if NSCSIBUS > 0 295 { "sd", scsi_find }, 296 #endif /* NSCSIBUS > 0 */ 297 { "xy", xx_find }, 298 { "xd", xx_find }, 299 { "", 0 }, 300 }; 301 302 /* 303 * This converts one hex number to an integer, and returns 304 * an updated string pointer. 305 */ 306 static const char *str2hex __P((const char *, int *)); 307 static const char * 308 str2hex(p, _val) 309 const char *p; 310 int *_val; 311 { 312 int val; 313 int c; 314 315 for(val = 0;; val = (val << 4) + c, p++) { 316 c = *((unsigned char *) p); 317 if (c >= 'a') c-= ('a' + 10); 318 else if (c >= 'A') c -= ('A' + 10); 319 else if (c >= '0') c -= '0'; 320 if (c < 0 || c > 15) break; 321 } 322 *_val = val; 323 return (p); 324 } 325 326 /* 327 * Choose root and swap devices. 328 */ 329 void 330 cpu_rootconf() 331 { 332 struct prom_n2f *nf; 333 struct device *boot_device; 334 int boot_partition; 335 char *devname; 336 findfunc_t find; 337 char promname[4]; 338 char partname[4]; 339 const char *prompath; 340 int prom_ctlr, prom_unit, prom_part; 341 342 /* Get the PROM boot path and take it apart. */ 343 prompath = prom_getbootpath(); 344 if (prompath == NULL) prompath = "zz(0,0,0)"; 345 promname[0] = *(prompath++); 346 promname[1] = *(prompath++); 347 promname[2] = '\0'; 348 prom_ctlr = prom_unit = prom_part = 0; 349 if (*prompath == '(' && 350 *(prompath = str2hex(++prompath, &prom_ctlr)) == ',' && 351 *(prompath = str2hex(++prompath, &prom_unit)) == ',') 352 (void) str2hex(++prompath, &prom_part); 353 354 /* Default to "unknown" */ 355 boot_device = NULL; 356 boot_partition = 0; 357 devname = "<unknown>"; 358 partname[0] = '\0'; 359 find = NULL; 360 361 /* Do we know anything about the PROM boot device? */ 362 for (nf = prom_dev_table; nf->func; nf++) 363 if (!strcmp(nf->name, promname)) { 364 find = nf->func; 365 break; 366 } 367 if (find) 368 boot_device = (*find)(promname, prom_ctlr, prom_unit); 369 if (boot_device) { 370 devname = boot_device->dv_xname; 371 if (boot_device->dv_class == DV_DISK) { 372 boot_partition = prom_part & 7; 373 partname[0] = 'a' + boot_partition; 374 partname[1] = '\0'; 375 } 376 } 377 378 printf("boot device: %s%s\n", devname, partname); 379 setroot(boot_device, boot_partition); 380 } 381 382 /* 383 * Functions to find devices using PROM boot parameters. 384 */ 385 386 /* 387 * Network device: Just use controller number. 388 */ 389 static struct device * 390 net_find(name, ctlr, unit) 391 char *name; 392 int ctlr, unit; 393 { 394 char tname[16]; 395 396 sprintf(tname, "%s%d", name, ctlr); 397 return (find_dev_byname(tname)); 398 } 399 400 #if NSCSIBUS > 0 401 /* 402 * SCSI device: The controller number corresponds to the 403 * scsibus number, and the unit number is (targ*8 + LUN). 404 */ 405 static struct device * 406 scsi_find(name, ctlr, unit) 407 char *name; 408 int ctlr, unit; 409 { 410 struct device *scsibus; 411 struct scsibus_softc *sbsc; 412 struct scsipi_periph *periph; 413 int target, lun; 414 char tname[16]; 415 416 sprintf(tname, "scsibus%d", ctlr); 417 scsibus = find_dev_byname(tname); 418 if (scsibus == NULL) 419 return (NULL); 420 421 /* Compute SCSI target/LUN from PROM unit. */ 422 target = prom_sd_target((unit >> 3) & 7); 423 lun = unit & 7; 424 425 /* Find the device at this target/LUN */ 426 sbsc = (struct scsibus_softc *)scsibus; 427 periph = scsipi_lookup_periph(sbsc->sc_channel, target, lun); 428 if (periph == NULL) 429 return (NULL); 430 431 return (periph->periph_dev); 432 } 433 #endif /* NSCSIBUS > 0 */ 434 435 /* 436 * Xylogics SMD disk: (xy, xd) 437 * Assume wired-in unit numbers for now... 438 */ 439 static struct device * 440 xx_find(name, ctlr, unit) 441 char *name; 442 int ctlr, unit; 443 { 444 int diskunit; 445 char tname[16]; 446 447 diskunit = (ctlr * 2) + unit; 448 sprintf(tname, "%s%d", name, diskunit); 449 return (find_dev_byname(tname)); 450 } 451 452 /* 453 * Given a device name, find its struct device 454 * XXX - Move this to some common file? 455 */ 456 static struct device * 457 find_dev_byname(name) 458 char *name; 459 { 460 struct device *dv; 461 462 for (dv = alldevs.tqh_first; dv != NULL; 463 dv = dv->dv_list.tqe_next) { 464 if (!strcmp(dv->dv_xname, name)) { 465 return(dv); 466 } 467 } 468 return (NULL); 469 } 470