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