autoconf.c revision 1.115
1/* $NetBSD: autoconf.c,v 1.115 2013/12/22 02:21:51 rkujawa Exp $ */ 2 3/* 4 * Copyright (c) 1994 Christian E. Hopps 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Christian E. Hopps. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h> 34__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.115 2013/12/22 02:21:51 rkujawa Exp $"); 35 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/reboot.h> 39#include <sys/conf.h> 40#include <sys/buf.h> 41#include <sys/device.h> 42#include <sys/disklabel.h> 43#include <sys/disk.h> 44#include <sys/proc.h> 45#include <machine/cpu.h> 46#include <amiga/amiga/cfdev.h> 47#include <amiga/amiga/device.h> 48#include <amiga/amiga/custom.h> 49#ifdef DRACO 50#include <amiga/amiga/drcustom.h> 51#endif 52#ifdef P5PB_CONSOLE 53#include <amiga/pci/p5pbvar.h> 54#endif /* P5PB_CONSOLE */ 55 56#include "opt_acafh.h" 57 58static void findroot(void); 59void mbattach(device_t, device_t, void *); 60int mbprint(void *, const char *); 61int mbmatch(device_t, cfdata_t, void *); 62 63#include <sys/kernel.h> 64 65u_long boot_partition; 66 67int amiga_realconfig; 68 69/* 70 * called at boot time, configure all devices on system 71 */ 72void 73cpu_configure(void) 74{ 75 int s; 76#ifdef DEBUG_KERNEL_START 77 int i; 78#endif 79 80 /* 81 * this is the real thing baby (i.e. not console init) 82 */ 83 amiga_realconfig = 1; 84#ifdef DRACO 85 if (is_draco()) { 86 *draco_intena &= ~DRIRQ_GLOBAL; 87 } else 88#endif 89 custom.intena = INTF_INTEN; 90 s = splhigh(); 91 92 if (config_rootfound("mainbus", NULL) == NULL) 93 panic("no mainbus found"); 94 95#ifdef DEBUG_KERNEL_START 96 printf("survived autoconf, going to enable interrupts\n"); 97#endif 98 99#ifdef DRACO 100 if (is_draco()) { 101 *draco_intena |= DRIRQ_GLOBAL; 102 /* softints always enabled */ 103 } else 104#endif 105 { 106 custom.intena = INTF_SETCLR | INTF_INTEN; 107 108 /* also enable hardware aided software interrupts */ 109 custom.intena = INTF_SETCLR | INTF_SOFTINT; 110 } 111#ifdef DEBUG_KERNEL_START 112 for (i=splhigh(); i>=s ;i-=0x100) { 113 splx(i); 114 printf("%d...", (i>>8) & 7); 115 } 116 printf("survived interrupt enable\n"); 117#else 118 splx(s); 119#endif 120#ifdef DEBUG_KERNEL_START 121 printf("survived configure...\n"); 122#endif 123} 124 125void 126cpu_rootconf(void) 127{ 128 findroot(); 129#ifdef DEBUG_KERNEL_START 130 printf("survived findroot()\n"); 131#endif 132 rootconf(); 133} 134 135/*ARGSUSED*/ 136int 137simple_devprint(void *aux, const char *pnp) 138{ 139 return(QUIET); 140} 141 142int 143matchname(const char *fp, const char *sp) 144{ 145 int len; 146 147 len = strlen(fp); 148 if (strlen(sp) != len) 149 return(0); 150 if (memcmp(fp, sp, len) == 0) 151 return(1); 152 return(0); 153} 154 155/* 156 * use config_search_ia to find appropriate device, then call that device 157 * directly with NULL device variable storage. A device can then 158 * always tell the difference betwean the real and console init 159 * by checking for NULL. 160 */ 161int 162amiga_config_found(cfdata_t pcfp, device_t parent, void *aux, cfprint_t pfn) 163{ 164 struct device temp; 165 cfdata_t cf; 166 const struct cfattach *ca; 167 168 if (amiga_realconfig) 169 return(config_found(parent, aux, pfn) != NULL); 170 171 if (parent == NULL) { 172 memset(&temp, 0, sizeof temp); 173 parent = &temp; 174 } 175 176 parent->dv_cfdata = pcfp; 177 parent->dv_cfdriver = config_cfdriver_lookup(pcfp->cf_name); 178 parent->dv_unit = pcfp->cf_unit; 179 180 if ((cf = config_search_ia(NULL, parent, NULL, aux)) != NULL) { 181 ca = config_cfattach_lookup(cf->cf_name, cf->cf_atname); 182 if (ca != NULL) { 183 (*ca->ca_attach)(parent, NULL, aux); 184 parent->dv_cfdata = NULL; 185 return(1); 186 } 187 } 188 parent->dv_cfdata = NULL; 189 return(0); 190} 191 192/* 193 * this function needs to get enough configured to do a console 194 * basically this means start attaching the grfxx's that support 195 * the console. Kinda hacky but it works. 196 */ 197void 198config_console(void) 199{ 200 cfdata_t cf; 201 202 config_init(); 203 204 /* 205 * we need mainbus' cfdata. 206 */ 207 cf = config_rootsearch(NULL, "mainbus", NULL); 208 if (cf == NULL) { 209 panic("no mainbus"); 210 } 211 212 /* 213 * delay clock calibration. 214 */ 215 amiga_config_found(cf, NULL, __UNCONST("clock"), NULL); 216 217 /* 218 * internal grf. 219 */ 220#ifdef DRACO 221 if (!(is_draco())) 222#endif 223 amiga_config_found(cf, NULL, __UNCONST("grfcc"), NULL); 224 225 /* 226 * zbus knows when its not for real and will 227 * only configure the appropriate hardware 228 */ 229 amiga_config_found(cf, NULL, __UNCONST("zbus"), NULL); 230} 231 232/* 233 * mainbus driver 234 */ 235CFATTACH_DECL_NEW(mainbus, 0, 236 mbmatch, mbattach, NULL, NULL); 237 238int 239mbmatch(device_t parent, cfdata_t cf, void *aux) 240{ 241#if 0 /* 242 * XXX is this right? but we need to be found twice 243 * (early console init hack) 244 */ 245 static int mainbus_matched = 0; 246 247 /* Allow only one instance. */ 248 if (mainbus_matched) 249 return (0); 250 251 mainbus_matched = 1; 252#endif 253 return (1); 254} 255 256/* 257 * "find" all the things that should be there. 258 */ 259void 260mbattach(device_t parent, device_t self, void *aux) 261{ 262 printf("\n"); 263 config_found(self, __UNCONST("clock"), simple_devprint); 264 if (is_a3000() || is_a4000()) { 265 config_found(self, __UNCONST("a34kbbc"), simple_devprint); 266 } else 267#ifdef DRACO 268 if (!is_draco()) 269#endif 270 { 271 config_found(self, __UNCONST("a2kbbc"), simple_devprint); 272 } 273#ifdef DRACO 274 if (is_draco()) { 275 config_found(self, __UNCONST("drbbc"), simple_devprint); 276 config_found(self, __UNCONST("kbd"), simple_devprint); 277 config_found(self, __UNCONST("drsc"), simple_devprint); 278 config_found(self, __UNCONST("drsupio"), simple_devprint); 279 } else 280#endif 281 { 282 config_found(self, __UNCONST("ser"), simple_devprint); 283 config_found(self, __UNCONST("par"), simple_devprint); 284 config_found(self, __UNCONST("kbd"), simple_devprint); 285 config_found(self, __UNCONST("ms"), simple_devprint); 286 config_found(self, __UNCONST("grfcc"), simple_devprint); 287 config_found(self, __UNCONST("amidisplaycc"), simple_devprint); 288 config_found(self, __UNCONST("fdc"), simple_devprint); 289 } 290 if (is_a4000() || is_a1200() || is_a600()) 291 config_found(self, __UNCONST("wdc"), simple_devprint); 292 if (is_a4000()) /* Try to configure A4000T SCSI */ 293 config_found(self, __UNCONST("afsc"), simple_devprint); 294 if (is_a3000()) 295 config_found(self, __UNCONST("ahsc"), simple_devprint); 296 if (is_a600() || is_a1200()) 297 config_found(self, __UNCONST("pccard"), simple_devprint); 298 if (is_a1200()) 299 config_found(self, __UNCONST("a1k2cp"), simple_devprint); 300#ifdef DRACO 301 if (!is_draco()) 302#endif 303 config_found(self, __UNCONST("aucc"), simple_devprint); 304 305#ifdef ACA500_SUPPORT 306 config_found(self, __UNCONST("acafh"), simple_devprint); 307#endif 308 309 config_found(self, __UNCONST("zbus"), simple_devprint); 310} 311 312int 313mbprint(void *aux, const char *pnp) 314{ 315 if (pnp) 316 aprint_normal("%s at %s", (char *)aux, pnp); 317 return(UNCONF); 318} 319 320/* 321 * The system will assign the "booted device" indicator (and thus 322 * rootdev if rootspec is wildcarded) to the first partition 'a' 323 * in preference of boot. However, it does walk unit backwards 324 * to remain compatible with the old Amiga method of picking the 325 * last root found. 326 */ 327#include <sys/fcntl.h> /* XXXX and all that uses it */ 328#include <sys/proc.h> /* XXXX and all that uses it */ 329 330#include "fd.h" 331#include "sd.h" 332#include "cd.h" 333#include "wd.h" 334 335#if NFD > 0 336extern struct cfdriver fd_cd; 337extern const struct bdevsw fd_bdevsw; 338#endif 339#if NSD > 0 340extern struct cfdriver sd_cd; 341extern const struct bdevsw sd_bdevsw; 342#endif 343#if NCD > 0 344extern struct cfdriver cd_cd; 345extern const struct bdevsw cd_bdevsw; 346#endif 347#if NWD > 0 348extern struct cfdriver wd_cd; 349extern const struct bdevsw wd_bdevsw; 350#endif 351 352struct cfdriver *genericconf[] = { 353#if NFD > 0 354 &fd_cd, 355#endif 356#if NSD > 0 357 &sd_cd, 358#endif 359#if NWD > 0 360 &wd_cd, 361#endif 362#if NCD > 0 363 &cd_cd, 364#endif 365 NULL, 366}; 367 368void 369findroot(void) 370{ 371 struct disk *dkp; 372 struct partition *pp; 373 device_t *devs; 374 int i, maj, unit; 375 const struct bdevsw *bdp; 376 377#if NSD > 0 378 /* 379 * If we have the boot partition offset (boot_partition), try 380 * to locate the device corresponding to that partition. 381 */ 382#ifdef DEBUG_KERNEL_START 383 printf("Boot partition offset is %ld\n", boot_partition); 384#endif 385 if (boot_partition != 0) { 386 387 for (unit = 0; unit < sd_cd.cd_ndevs; ++unit) { 388#ifdef DEBUG_KERNEL_START 389 printf("probing for sd%d\n", unit); 390#endif 391 if (device_lookup(&sd_cd,unit) == NULL) 392 continue; 393 394 /* 395 * Find the disk corresponding to the current 396 * device. 397 */ 398 devs = sd_cd.cd_devs; 399 if ((dkp = disk_find(device_xname(device_lookup(&sd_cd, unit)))) == NULL) 400 continue; 401 402 if (dkp->dk_driver == NULL || 403 dkp->dk_driver->d_strategy == NULL) 404 continue; 405 bdp = &sd_bdevsw; 406 maj = bdevsw_lookup_major(bdp); 407 if ((*bdp->d_open)(MAKEDISKDEV(maj, unit, RAW_PART), 408 FREAD | FNONBLOCK, 0, curlwp)) 409 continue; 410 (*bdp->d_close)(MAKEDISKDEV(maj, unit, RAW_PART), 411 FREAD | FNONBLOCK, 0, curlwp); 412 pp = &dkp->dk_label->d_partitions[0]; 413 for (i = 0; i < dkp->dk_label->d_npartitions; 414 i++, pp++) { 415#ifdef DEBUG_KERNEL_START 416 printf("sd%d%c type %d offset %d size %d\n", 417 unit, i+'a', pp->p_fstype, 418 pp->p_offset, pp->p_size); 419#endif 420 if (pp->p_size == 0 || 421 (pp->p_fstype != FS_BSDFFS && 422 pp->p_fstype != FS_SWAP)) 423 continue; 424 if (pp->p_offset == boot_partition) { 425 if (booted_device == NULL) { 426 booted_device = devs[unit]; 427 booted_partition = i; 428 } else 429 printf("Ambiguous boot device\n"); 430 } 431 } 432 } 433 } 434 if (booted_device != NULL) 435 return; /* we found the boot device */ 436#endif 437 438 for (i = 0; genericconf[i] != NULL; i++) { 439 for (unit = genericconf[i]->cd_ndevs - 1; unit >= 0; unit--) { 440 if (genericconf[i]->cd_devs[unit] == NULL) 441 continue; 442 443 /* 444 * Find the disk structure corresponding to the 445 * current device. 446 */ 447 devs = (device_t *)genericconf[i]->cd_devs; 448 if ((dkp = disk_find(device_xname(devs[unit]))) == NULL) 449 continue; 450 451 if (dkp->dk_driver == NULL || 452 dkp->dk_driver->d_strategy == NULL) 453 continue; 454 455 bdp = NULL; 456#if NFD > 0 457 if (fd_bdevsw.d_strategy == dkp->dk_driver->d_strategy) 458 bdp = &fd_bdevsw; 459#endif 460#if NSD > 0 461 if (sd_bdevsw.d_strategy == dkp->dk_driver->d_strategy) 462 bdp = &sd_bdevsw; 463#endif 464#if NWD > 0 465 if (wd_bdevsw.d_strategy == dkp->dk_driver->d_strategy) 466 bdp = &wd_bdevsw; 467#endif 468#if NCD > 0 469 if (cd_bdevsw.d_strategy == dkp->dk_driver->d_strategy) 470 bdp = &cd_bdevsw; 471#endif 472#ifdef DIAGNOSTIC 473 if (bdp == NULL) 474 panic("findroot: impossible"); 475#endif 476 maj = bdevsw_lookup_major(bdp); 477 478 /* Open disk; forces read of disklabel. */ 479 if ((*bdp->d_open)(MAKEDISKDEV(maj, 480 unit, 0), FREAD|FNONBLOCK, 0, &lwp0)) 481 continue; 482 (void)(*bdp->d_close)(MAKEDISKDEV(maj, 483 unit, 0), FREAD|FNONBLOCK, 0, &lwp0); 484 485 pp = &dkp->dk_label->d_partitions[0]; 486 if (pp->p_size != 0 && pp->p_fstype == FS_BSDFFS) { 487 booted_device = devs[unit]; 488 booted_partition = 0; 489 return; 490 } 491 } 492 } 493} 494 495/* 496 * Try to determine, of this machine is an A3000, which has a builtin 497 * realtime clock and scsi controller, so that this hardware is only 498 * included as "configured" if this IS an A3000 499 */ 500 501int a3000_flag = 1; /* patchable */ 502#ifdef A4000 503int a4000_flag = 1; /* patchable - default to A4000 */ 504#else 505int a4000_flag = 0; /* patchable */ 506#endif 507 508int 509is_a3000(void) 510{ 511 /* this is a dirty kludge.. but how do you do this RIGHT ? :-) */ 512 extern long boot_fphystart; 513 short sc; 514 515 if ((machineid >> 16) == 3000) 516 return (1); /* It's an A3000 */ 517 if (machineid >> 16) 518 return (0); /* It's not an A3000 */ 519 /* Machine type is unknown, so try to guess it */ 520 /* where is fastram on the A4000 ?? */ 521 /* if fastram is below 0x07000000, assume it's not an A3000 */ 522 if (boot_fphystart < 0x07000000) 523 return(0); 524 /* 525 * OK, fastram starts at or above 0x07000000, check specific 526 * machines 527 */ 528 for (sc = 0; sc < ncfdev; sc++) { 529 switch (cfdev[sc].rom.manid) { 530 case 2026: /* Progressive Peripherals, Inc */ 531 switch (cfdev[sc].rom.prodid) { 532 case 0: /* PPI Mercury - A3000 */ 533 case 1: /* PP&S A3000 '040 */ 534 return(1); 535 case 150: /* PPI Zeus - it's an A2000 */ 536 case 105: /* PP&S A2000 '040 */ 537 case 187: /* PP&S A500 '040 */ 538 return(0); 539 } 540 break; 541 542 case 2112: /* IVS */ 543 switch (cfdev[sc].rom.prodid) { 544 case 242: 545 return(0); /* A2000 accelerator? */ 546 } 547 break; 548 } 549 } 550 return (a3000_flag); /* XXX let flag tell now */ 551} 552 553int 554is_a4000(void) 555{ 556 if ((machineid >> 16) == 4000) 557 return (1); /* It's an A4000 */ 558 if ((machineid >> 16) == 1200) 559 return (0); /* It's an A1200, so not A4000 */ 560#ifdef DRACO 561 if (is_draco()) 562 return (0); 563#endif 564 /* Do I need this any more? */ 565 if ((custom.deniseid & 0xff) == 0xf8) 566 return (1); 567#ifdef DEBUG 568 if (a4000_flag) 569 printf("Denise ID = %04x\n", (unsigned short)custom.deniseid); 570#endif 571 if (machineid >> 16) 572 return (0); /* It's not an A4000 */ 573 return (a4000_flag); /* Machine type not set */ 574} 575 576int 577is_a1200(void) 578{ 579 if ((machineid >> 16) == 1200) 580 return (1); /* It's an A1200 */ 581 return (0); /* Machine type not set */ 582} 583 584int 585is_a600(void) 586{ 587 if ((machineid >> 16) == 600) 588 return (1); /* It's an A600 */ 589 return (0); /* Machine type not set */ 590} 591 592void 593device_register(device_t dev, void *aux) 594{ 595#ifdef P5PB_CONSOLE 596 p5pb_device_register(dev, aux); 597#endif /* P5PB_CONSOLE */ 598} 599