1 /* 2 * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)autoconf.c 7.5 (Berkeley) 12/16/90 7 */ 8 9 /* 10 * Setup the system to run on the current machine. 11 * 12 * Configure() is called at boot time and initializes the vba 13 * device tables and the memory controller monitoring. Available 14 * devices are determined (from possibilities mentioned in ioconf.c), 15 * and the drivers are initialized. 16 */ 17 #include "sys/param.h" 18 #include "sys/systm.h" 19 #include "sys/map.h" 20 #include "sys/buf.h" 21 #include "sys/dkstat.h" 22 #include "sys/vm.h" 23 #include "sys/conf.h" 24 #include "sys/dmap.h" 25 #include "sys/reboot.h" 26 #include "sys/malloc.h" 27 28 #include "../include/pte.h" 29 #include "mem.h" 30 #include "../include/mtpr.h" 31 #include "scb.h" 32 33 #include "vba.h" 34 35 #include "../vba/vbavar.h" 36 #include "../vba/vbaparam.h" 37 38 /* 39 * The following several variables are related to 40 * the configuration process, and are used in initializing 41 * the machine. 42 */ 43 int dkn; /* number of iostat dk numbers assigned so far */ 44 int cold; /* cold start flag initialized in locore.s */ 45 46 /* 47 * This allocates the space for the per-vba information. 48 */ 49 struct vba_hd vba_hd[NVBA]; 50 51 /* 52 * Determine i/o configuration for a machine. 53 */ 54 configure() 55 { 56 register int *ip; 57 extern caddr_t Sysbase; 58 59 vbafind(numvba, (caddr_t)vmem, VMEMmap); 60 numvba++; 61 /* 62 * Write protect the scb. It is strange 63 * that this code is here, but this is as soon 64 * as we are done mucking with it, and the 65 * write-enable was done in assembly language 66 * to which we will never return. 67 */ 68 ip = (int *)&Sysmap[2]; *ip &= ~PG_PROT; *ip |= PG_KR; 69 mtpr(TBIS, Sysbase+2*NBPG); 70 #if GENERIC 71 if ((boothowto & RB_ASKNAME) == 0) 72 setroot(); 73 setconf(); 74 #else 75 setroot(); 76 #endif 77 /* 78 * Configure swap area and related system 79 * parameter based on device(s) used. 80 */ 81 swapconf(); 82 cold = 0; 83 } 84 85 /* 86 * Make the controllers accessible at physical address phys 87 * by mapping kernel ptes starting at pte. 88 */ 89 vbaccess(pte, iobase, n) 90 register struct pte *pte; 91 caddr_t iobase; 92 register int n; 93 { 94 register unsigned v = btop(iobase); 95 96 do 97 *(int *)pte++ = PG_V|PG_KW|v++; 98 while (--n > 0); 99 mtpr(TBIA, 0); 100 } 101 102 /* 103 * Fixctlrmask fixes the masks of the driver ctlr routines 104 * which otherwise save r11 and r12 where the interrupt and br 105 * level are passed through. 106 */ 107 fixctlrmask() 108 { 109 register struct vba_ctlr *vm; 110 register struct vba_device *vi; 111 register struct vba_driver *vd; 112 #define phys(a,b) ((b)(((int)(a))&~0xc0000000)) 113 114 vm = phys(vbminit, struct vba_ctlr *); 115 for (; vd = phys(vm->um_driver, struct vba_driver *); vm++) 116 *phys(vd->ud_probe, short *) &= ~0x1800; 117 vi = phys(vbdinit, struct vba_device *); 118 for (; vd = phys(vi->ui_driver, struct vba_driver *); vi++) 119 *phys(vd->ud_probe, short *) &= ~0x1800; 120 } 121 122 /* 123 * Find devices on the VERSAbus. 124 * Uses per-driver routine to see who is on the bus 125 * and then fills in the tables, with help from a per-driver 126 * slave initialization routine. 127 */ 128 vbafind(vban, vumem, memmap) 129 int vban; 130 caddr_t vumem; 131 struct pte memmap[]; 132 { 133 register int br, cvec; /* must be r12, r11 */ 134 register struct vba_device *ui; 135 register struct vba_ctlr *um; 136 u_short *reg; 137 long addr, *ap; 138 struct vba_hd *vhp; 139 struct vba_driver *udp; 140 int i, octlr, (**ivec)(); 141 caddr_t valloc; 142 extern quad catcher[SCB_LASTIV]; 143 144 #ifdef lint 145 br = 0; cvec = 0; 146 #endif 147 vhp = &vba_hd[vban]; 148 /* 149 * Make the controllers accessible at physical address phys 150 * by mapping kernel ptes starting at pte. 151 */ 152 vbaccess(memmap, (caddr_t)VBIOBASE, (int)VBIOSIZE); 153 printf("vba%d at %x\n", vban, VBIOBASE); 154 /* 155 * Setup scb device entries to point into catcher array. 156 */ 157 for (i = 0; i < SCB_LASTIV; i++) 158 scb.scb_devint[i] = (int (*)())((int)&catcher[i]); 159 /* 160 * Set last free interrupt vector for devices with 161 * programmable interrupt vectors. Use is to decrement 162 * this number and use result as interrupt vector. 163 */ 164 vhp->vh_lastiv = SCB_LASTIV; 165 /* 166 * Grab some memory to record the address space we allocate, 167 * so we can be sure not to place two devices at the same address. 168 * Register I/O space is allocated in 256-byte sections, 169 * and memory I/O space is in 4Kb sections. We record allocations 170 * in 256-byte sections. 171 * 172 * We could use just 1/8 of this (we only want a 1 bit flag) but 173 * we are going to give it back anyway, and that would make the 174 * code here bigger (which we can't give back), so ... 175 */ 176 #define VSECT(a) ((a) / 0x100) 177 #define VSIZE(s) (((s) + 0xff) / 0x100) 178 #define VALLOC(a) (valloc[VSECT(vboff(a))]) 179 #define VMAPSIZE VSIZE(ctob(VBIOSIZE)) 180 valloc = (caddr_t)malloc((u_long)(VMAPSIZE), M_TEMP, M_NOWAIT); 181 if (valloc == (caddr_t)0) 182 panic("no mem for vbafind"); 183 bzero(valloc, VMAPSIZE); 184 185 /* 186 * Check each VERSAbus mass storage controller. 187 * For each one which is potentially on this vba, 188 * see if it is really there, and if it is record it and 189 * then go looking for slaves. 190 */ 191 #define vbaddr(off) (u_short *)(vumem + vboff(off)) 192 for (um = vbminit; udp = um->um_driver; um++) { 193 if (um->um_vbanum != vban && um->um_vbanum != '?') 194 continue; 195 /* 196 * Use the particular address specified first, 197 * or if it is given as "0", if there is no device 198 * at that address, try all the standard addresses 199 * in the driver until we find it. 200 */ 201 addr = (long)um->um_addr; 202 for (ap = udp->ud_addr; addr || (addr = *ap++); addr = 0) { 203 if (VBIOMAPPED(addr)) { 204 if (VALLOC(addr)) 205 continue; 206 reg = vbaddr(addr); 207 } else 208 reg = (u_short *)addr; 209 um->um_hd = vhp; 210 cvec = SCB_LASTIV, cold &= ~0x2; 211 i = (*udp->ud_probe)(reg, um); 212 cold |= 0x2; 213 if (i == 0) 214 continue; 215 printf("%s%d at vba%d csr %x ", 216 udp->ud_mname, um->um_ctlr, vban, addr); 217 if (cvec < 0 && vhp->vh_lastiv == cvec) { 218 printf("no space for vector(s)\n"); 219 continue; 220 } 221 if (cvec == SCB_LASTIV) { 222 printf("didn't interrupt\n"); 223 continue; 224 } 225 printf("vec %x, ipl %x\n", cvec, br); 226 csralloc(valloc, addr, i); 227 um->um_alive = 1; 228 um->um_vbanum = vban; 229 um->um_addr = (caddr_t)reg; 230 udp->ud_minfo[um->um_ctlr] = um; 231 for (ivec = um->um_intr; *ivec; ivec++) 232 ((long *)&scb)[cvec++] = (long)*ivec; 233 for (ui = vbdinit; ui->ui_driver; ui++) { 234 if (ui->ui_driver != udp || ui->ui_alive || 235 ui->ui_ctlr != um->um_ctlr && ui->ui_ctlr != '?' || 236 ui->ui_vbanum != vban && ui->ui_vbanum != '?') 237 continue; 238 octlr = ui->ui_ctlr, ui->ui_ctlr = um->um_ctlr; 239 if ((*udp->ud_slave)(ui, reg)) { 240 ui->ui_alive = 1; 241 ui->ui_ctlr = um->um_ctlr; 242 ui->ui_vbanum = vban; 243 ui->ui_addr = (caddr_t)reg; 244 ui->ui_physaddr = (caddr_t)addr; 245 if (ui->ui_dk && dkn < DK_NDRIVE) 246 ui->ui_dk = dkn++; 247 else 248 ui->ui_dk = -1; 249 ui->ui_mi = um; 250 ui->ui_hd = vhp; 251 /* ui_type comes from driver */ 252 udp->ud_dinfo[ui->ui_unit] = ui; 253 printf("%s%d at %s%d slave %d", 254 udp->ud_dname, ui->ui_unit, 255 udp->ud_mname, um->um_ctlr, 256 ui->ui_slave); 257 (*udp->ud_attach)(ui); 258 printf("\n"); 259 } else 260 ui->ui_ctlr = octlr; 261 } 262 break; 263 } 264 } 265 /* 266 * Now look for non-mass storage peripherals. 267 */ 268 for (ui = vbdinit; udp = ui->ui_driver; ui++) { 269 if (ui->ui_vbanum != vban && ui->ui_vbanum != '?' || 270 ui->ui_alive || ui->ui_slave != -1) 271 continue; 272 addr = (long)ui->ui_addr; 273 for (ap = udp->ud_addr; addr || (addr = *ap++); addr = 0) { 274 if (VBIOMAPPED(addr)) { 275 if (VALLOC(addr)) 276 continue; 277 reg = vbaddr(addr); 278 } else 279 reg = (u_short *)addr; 280 ui->ui_hd = vhp; 281 cvec = SCB_LASTIV, cold &= ~0x2; 282 i = (*udp->ud_probe)(reg, ui); 283 cold |= 0x2; 284 if (i == 0) 285 continue; 286 printf("%s%d at vba%d csr %x ", 287 ui->ui_driver->ud_dname, ui->ui_unit, vban, addr); 288 if (ui->ui_intr) { 289 if (cvec < 0 && vhp->vh_lastiv == cvec) { 290 printf("no space for vector(s)\n"); 291 continue; 292 } 293 if (cvec == SCB_LASTIV) { 294 printf("didn't interrupt\n"); 295 continue; 296 } 297 printf("vec %x, ipl %x\n", cvec, br); 298 for (ivec = ui->ui_intr; *ivec; ivec++) 299 ((long *)&scb)[cvec++] = (long)*ivec; 300 } else 301 printf("no interrupts\n"); 302 csralloc(valloc, addr, i); 303 ui->ui_alive = 1; 304 ui->ui_vbanum = vban; 305 if (VBIOMAPPED(addr)) 306 ui->ui_addr = (caddr_t)reg; 307 ui->ui_physaddr = (caddr_t)addr; 308 ui->ui_dk = -1; 309 /* ui_type comes from driver */ 310 udp->ud_dinfo[ui->ui_unit] = ui; 311 (*udp->ud_attach)(ui); 312 break; 313 } 314 } 315 free(valloc, M_TEMP); 316 } 317 318 /* 319 * Mark addresses starting at addr and continuing 320 * size bytes as allocated in the map. 321 * Warn if the new allocation overlaps a previous allocation. 322 */ 323 csralloc(valloc, addr, size) 324 caddr_t valloc; 325 long addr; 326 register int size; 327 { 328 register caddr_t p; 329 int warned = 0; 330 331 if (!VBIOMAPPED(addr)) 332 return; 333 size = VSIZE(size); 334 p = &VALLOC(addr) + size; 335 while (--size >= 0) { 336 if (*--p && !warned) { 337 printf( 338 "WARNING: device registers overlap those for a previous device\n"); 339 warned = 1; 340 } 341 *p = 1; 342 } 343 } 344 345 /* 346 * Tahoe VERSAbus adapator support routines. 347 */ 348 349 caddr_t vbcur = (caddr_t)&vbbase; 350 int vbx = 0; 351 /* 352 * Allocate page tables for mapping intermediate i/o buffers. 353 * Called by device drivers during autoconfigure. 354 */ 355 vbmapalloc(npf, ppte, putl) 356 int npf; 357 struct pte **ppte; 358 caddr_t *putl; 359 { 360 361 if (vbcur + npf*NBPG > (caddr_t)&vbend) 362 return (0); 363 *ppte = &VBmap[vbx]; 364 *putl = vbcur; 365 vbx += npf; 366 vbcur += npf*NBPG; 367 return (1); 368 } 369 370 caddr_t vbmcur = (caddr_t)&vmem1; 371 int vbmx = 0; 372 /* 373 * Allocate page tables and map VERSAbus i/o space. 374 * Called by device drivers during autoconfigure. 375 */ 376 vbmemalloc(npf, addr, ppte, putl) 377 int npf; 378 caddr_t addr; 379 struct pte **ppte; 380 caddr_t *putl; 381 { 382 383 if (vbmcur + npf*NBPG > (caddr_t)&vmemend) 384 return (0); 385 *ppte = &VMEMmap1[vbmx]; 386 *putl = vbmcur; 387 vbmx += npf; 388 vbmcur += npf*NBPG; 389 vbaccess(*ppte, addr, npf); /* map i/o space */ 390 return (1); 391 } 392 393 /* 394 * Configure swap space and related parameters. 395 */ 396 swapconf() 397 { 398 register struct swdevt *swp; 399 register int nblks; 400 401 for (swp = swdevt; swp->sw_dev; swp++) 402 if (bdevsw[major(swp->sw_dev)].d_psize) { 403 nblks = 404 (*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev); 405 if (nblks != -1 && 406 (swp->sw_nblks == 0 || swp->sw_nblks > nblks)) 407 swp->sw_nblks = nblks; 408 } 409 dumpconf(); 410 } 411 412 #define DOSWAP /* change swdevt, argdev, and dumpdev too */ 413 u_long bootdev; /* should be dev_t, but not until 32 bits */ 414 415 static char devname[][2] = { 416 0,0, /* 0 = ud */ 417 'd','k', /* 1 = vd */ 418 0,0, /* 2 = xp */ 419 }; 420 421 #define PARTITIONMASK 0x7 422 #define PARTITIONSHIFT 3 423 424 /* 425 * Attempt to find the device from which we were booted. 426 * If we can do so, and not instructed not to do so, 427 * change rootdev to correspond to the load device. 428 */ 429 setroot() 430 { 431 int majdev, mindev, unit, part, controller, adaptor; 432 dev_t temp, orootdev; 433 struct swdevt *swp; 434 435 if (boothowto & RB_DFLTROOT || 436 (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC) 437 return; 438 majdev = B_TYPE(bootdev); 439 if (majdev >= sizeof(devname) / sizeof(devname[0])) 440 return; 441 adaptor = B_ADAPTOR(bootdev); 442 controller = B_CONTROLLER(bootdev); 443 part = B_PARTITION(bootdev); 444 unit = B_UNIT(bootdev); 445 /* 446 * Search Versabus devices. 447 * 448 * WILL HAVE TO DISTINGUISH VME/VERSABUS SOMETIME 449 */ 450 { 451 register struct vba_device *vbap; 452 453 for (vbap = vbdinit; vbap->ui_driver; vbap++) 454 if (vbap->ui_alive && vbap->ui_slave == unit && 455 vbap->ui_ctlr == controller && 456 vbap->ui_vbanum == adaptor && 457 vbap->ui_driver->ud_dname[0] == devname[majdev][0] && 458 vbap->ui_driver->ud_dname[1] == devname[majdev][1]) 459 break; 460 if (vbap->ui_driver == 0) 461 return; 462 mindev = vbap->ui_unit; 463 } 464 mindev = (mindev << PARTITIONSHIFT) + part; 465 orootdev = rootdev; 466 rootdev = makedev(majdev, mindev); 467 /* 468 * If the original rootdev is the same as the one 469 * just calculated, don't need to adjust the swap configuration. 470 */ 471 if (rootdev == orootdev) 472 return; 473 printf("changing root device to %c%c%d%c\n", 474 devname[majdev][0], devname[majdev][1], 475 mindev >> PARTITIONSHIFT, part + 'a'); 476 #ifdef DOSWAP 477 mindev &= ~PARTITIONMASK; 478 for (swp = swdevt; swp->sw_dev; swp++) { 479 if (majdev == major(swp->sw_dev) && 480 mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) { 481 temp = swdevt[0].sw_dev; 482 swdevt[0].sw_dev = swp->sw_dev; 483 swp->sw_dev = temp; 484 break; 485 } 486 } 487 if (swp->sw_dev == 0) 488 return; 489 /* 490 * If argdev and dumpdev were the same as the old primary swap 491 * device, move them to the new primary swap device. 492 */ 493 if (temp == dumpdev) 494 dumpdev = swdevt[0].sw_dev; 495 if (temp == argdev) 496 argdev = swdevt[0].sw_dev; 497 #endif 498 } 499