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