Commit | Line | Data |
---|---|---|
4fea1aeb BJ |
1 | /* autoconf.c 1.13 87/04/02 */ |
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. | |
10 | */ | |
11 | #include "param.h" | |
12 | #include "systm.h" | |
13 | #include "map.h" | |
14 | #include "buf.h" | |
15 | #include "dkstat.h" | |
16 | #include "vm.h" | |
17 | #include "conf.h" | |
18 | #include "dmap.h" | |
19 | #include "reboot.h" | |
20 | ||
21 | #include "pte.h" | |
22 | #include "mem.h" | |
23 | #include "mtpr.h" | |
24 | #include "scb.h" | |
25 | ||
26 | #include "vba.h" | |
27 | ||
28 | #include "../tahoevba/vbavar.h" | |
29 | #include "../tahoevba/vbaparam.h" | |
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 */ | |
37 | int cold; /* cold start flag initialized in locore.s */ | |
38 | ||
39 | /* | |
40 | * This allocates the space for the per-vba information. | |
41 | */ | |
42 | struct vba_hd vba_hd[NVBA]; | |
43 | ||
44 | /* | |
45 | * Determine i/o configuration for a machine. | |
46 | */ | |
47 | configure() | |
48 | { | |
49 | register int *ip; | |
50 | extern caddr_t Sysbase; | |
51 | ||
52 | vbafind(numvba, (caddr_t)&vmem, VMEMmap); | |
53 | numvba++; | |
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; | |
62 | mtpr(TBIS, Sysbase+2*NBPG); | |
63 | #if GENERIC | |
64 | if ((boothowto & RB_ASKNAME) == 0) | |
65 | setroot(); | |
66 | setconf(); | |
67 | #else | |
68 | setroot(); | |
69 | #endif | |
70 | /* | |
71 | * Configure swap area and related system | |
72 | * parameter based on device(s) used. | |
73 | */ | |
74 | swapconf(); | |
75 | cold = 0; | |
76 | } | |
77 | ||
78 | /* | |
79 | * Make the controllers accessible at physical address phys | |
80 | * by mapping kernel ptes starting at pte. | |
81 | */ | |
82 | vbaccess(pte, iobase, n) | |
83 | register struct pte *pte; | |
84 | caddr_t iobase; | |
85 | register int n; | |
86 | { | |
87 | register unsigned v = btop(iobase); | |
88 | ||
89 | do | |
90 | *(int *)pte++ = PG_V|PG_KW|v++; | |
91 | while (--n > 0); | |
92 | mtpr(TBIA, 0); | |
93 | } | |
94 | ||
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 | } | |
114 | ||
115 | /* | |
116 | * Find devices on the VERSAbus. | |
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 | */ | |
121 | vbafind(vban, vumem, memmap) | |
122 | int vban; | |
123 | caddr_t vumem; | |
124 | struct pte memmap[]; | |
125 | { | |
126 | register int br, cvec; /* must be r12, r11 */ | |
127 | register struct vba_device *ui; | |
128 | register struct vba_ctlr *um; | |
129 | u_short *reg; | |
130 | long addr, *ap; | |
131 | struct vba_hd *vhp; | |
132 | struct vba_driver *udp; | |
133 | int i, octlr, (**ivec)(); | |
134 | caddr_t valloc, zmemall(); | |
135 | extern long catcher[SCB_LASTIV*2]; | |
136 | ||
137 | #ifdef lint | |
138 | br = 0; cvec = 0; | |
139 | #endif | |
140 | vhp = &vba_hd[vban]; | |
141 | /* | |
142 | * Make the controllers accessible at physical address phys | |
143 | * by mapping kernel ptes starting at pte. | |
144 | */ | |
145 | vbaccess(memmap, (caddr_t)VBIOBASE, VBIOSIZE); | |
146 | printf("vba%d at %x\n", vban, VBIOBASE); | |
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; | |
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"); | |
169 | ||
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 | */ | |
176 | #define vbaddr(off) (u_short *)(vumem + vboff(off)) | |
177 | for (um = vbminit; udp = um->um_driver; um++) { | |
178 | if (um->um_vbanum != vban && um->um_vbanum != '?') | |
179 | continue; | |
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 | */ | |
186 | addr = (long)um->um_addr; | |
187 | for (ap = udp->ud_addr; addr || (addr = *ap++); addr = 0) { | |
188 | if (VBIOMAPPED(addr)) { | |
189 | if (valloc[vboff(addr)]) | |
190 | continue; | |
191 | reg = vbaddr(addr); | |
192 | } else | |
193 | reg = (u_short *)addr; | |
194 | um->um_hd = vhp; | |
195 | cvec = SCB_LASTIV, cold &= ~0x2; | |
196 | i = (*udp->ud_probe)(reg, um); | |
197 | cold |= 0x2; | |
198 | if (i == 0) | |
199 | continue; | |
200 | printf("%s%d at vba%d csr %x ", | |
201 | udp->ud_mname, um->um_ctlr, vban, addr); | |
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); | |
211 | csralloc(valloc, addr, i); | |
212 | um->um_alive = 1; | |
213 | um->um_vbanum = vban; | |
214 | um->um_addr = (caddr_t)reg; | |
215 | udp->ud_minfo[um->um_ctlr] = um; | |
216 | for (ivec = um->um_intr; *ivec; ivec++) | |
217 | ((long *)&scb)[cvec++] = (long)*ivec; | |
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 != '?' || | |
221 | ui->ui_vbanum != vban && ui->ui_vbanum != '?') | |
222 | continue; | |
223 | octlr = ui->ui_ctlr, ui->ui_ctlr = um->um_ctlr; | |
224 | if ((*udp->ud_slave)(ui, reg)) { | |
225 | ui->ui_alive = 1; | |
226 | ui->ui_ctlr = um->um_ctlr; | |
227 | ui->ui_vbanum = vban; | |
228 | ui->ui_addr = (caddr_t)reg; | |
229 | ui->ui_physaddr = (caddr_t)addr; | |
230 | if (ui->ui_dk && dkn < DK_NDRIVE) | |
231 | ui->ui_dk = dkn++; | |
232 | else | |
233 | ui->ui_dk = -1; | |
234 | ui->ui_mi = um; | |
235 | ui->ui_hd = vhp; | |
236 | /* ui_type comes from driver */ | |
237 | udp->ud_dinfo[ui->ui_unit] = ui; | |
238 | printf("%s%d at %s%d slave %d", | |
239 | udp->ud_dname, ui->ui_unit, | |
240 | udp->ud_mname, um->um_ctlr, | |
241 | ui->ui_slave); | |
242 | (*udp->ud_attach)(ui); | |
243 | printf("\n"); | |
244 | } else | |
245 | ui->ui_ctlr = octlr; | |
246 | } | |
247 | break; | |
248 | } | |
249 | } | |
250 | /* | |
251 | * Now look for non-mass storage peripherals. | |
252 | */ | |
253 | for (ui = vbdinit; udp = ui->ui_driver; ui++) { | |
254 | if (ui->ui_vbanum != vban && ui->ui_vbanum != '?' || | |
255 | ui->ui_alive || ui->ui_slave != -1) | |
256 | continue; | |
257 | addr = (long)ui->ui_addr; | |
258 | for (ap = udp->ud_addr; addr || (addr = *ap++); addr = 0) { | |
259 | if (VBIOMAPPED(addr)) { | |
260 | if (valloc[vboff(addr)]) | |
261 | continue; | |
262 | reg = vbaddr(addr); | |
263 | } else | |
264 | reg = (u_short *)addr; | |
265 | ui->ui_hd = vhp; | |
266 | cvec = SCB_LASTIV, cold &= ~0x2; | |
267 | i = (*udp->ud_probe)(reg, ui); | |
268 | cold |= 0x2; | |
269 | if (i == 0) | |
270 | continue; | |
271 | printf("%s%d at vba%d csr %x ", | |
272 | ui->ui_driver->ud_dname, ui->ui_unit, vban, addr); | |
273 | if (ui->ui_intr) { | |
274 | if (cvec < 0 && vhp->vh_lastiv == cvec) { | |
275 | printf("no space for vector(s)\n"); | |
276 | continue; | |
277 | } | |
278 | if (cvec == SCB_LASTIV) { | |
279 | printf("didn't interrupt\n"); | |
280 | continue; | |
281 | } | |
282 | printf("vec %x, ipl %x\n", cvec, br); | |
283 | for (ivec = ui->ui_intr; *ivec; ivec++) | |
284 | ((long *)&scb)[cvec++] = (long)*ivec; | |
285 | } else | |
286 | printf("no interrupts\n"); | |
287 | csralloc(valloc, addr, i); | |
288 | ui->ui_alive = 1; | |
289 | ui->ui_vbanum = vban; | |
290 | ui->ui_addr = (caddr_t)reg; | |
291 | ui->ui_physaddr = (caddr_t)addr; | |
292 | ui->ui_dk = -1; | |
293 | /* ui_type comes from driver */ | |
294 | udp->ud_dinfo[ui->ui_unit] = ui; | |
295 | (*udp->ud_attach)(ui); | |
296 | break; | |
297 | } | |
298 | } | |
299 | wmemfree(valloc, ctob(VBIOSIZE)); | |
300 | } | |
301 | ||
302 | /* | |
303 | * Mark addresses starting at addr and continuing | |
304 | * size bytes as allocated in the map. | |
305 | * Warn if the new allocation overlaps a previous allocation. | |
306 | */ | |
307 | csralloc(valloc, addr, size) | |
308 | caddr_t valloc; | |
309 | long addr; | |
310 | register int size; | |
311 | { | |
312 | register caddr_t p; | |
313 | int warned = 0; | |
314 | ||
315 | if (!VBIOMAPPED(addr)) | |
316 | return; | |
317 | p = &valloc[vboff(addr+size)]; | |
318 | while (--size >= 0) { | |
319 | if (*--p && !warned) { | |
320 | printf( | |
321 | "WARNING: device registers overlap those for a previous device\n"); | |
322 | warned = 1; | |
323 | } | |
324 | *p = 1; | |
325 | } | |
326 | } | |
327 | ||
328 | /* | |
329 | * Tahoe VERSAbus adapator support routines. | |
330 | */ | |
331 | ||
332 | caddr_t vbcur = (caddr_t)&vbbase; | |
333 | int vbx = 0; | |
334 | /* | |
335 | * Allocate page tables for mapping intermediate i/o buffers. | |
336 | * Called by device drivers during autoconfigure. | |
337 | */ | |
338 | vbmapalloc(npf, ppte, putl) | |
339 | int npf; | |
340 | struct pte **ppte; | |
341 | caddr_t *putl; | |
342 | { | |
343 | ||
344 | if (vbcur + npf*NBPG >= (caddr_t)&vbend) | |
345 | panic("vbmapalloc"); | |
346 | *ppte = &VBmap[vbx]; | |
347 | *putl = vbcur; | |
348 | vbx += npf; | |
349 | vbcur += npf*NBPG; | |
350 | } | |
351 | ||
352 | caddr_t vbmcur = (caddr_t)&vmem1; | |
353 | int vbmx = 0; | |
354 | /* | |
355 | * Allocate page tables and map VERSAbus i/o space. | |
356 | * Called by device drivers during autoconfigure. | |
357 | */ | |
358 | vbmemalloc(npf, addr, ppte, putl) | |
359 | int npf; | |
360 | caddr_t addr; | |
361 | struct pte **ppte; | |
362 | caddr_t *putl; | |
363 | { | |
364 | ||
365 | if (vbmcur + npf*NBPG >= (caddr_t)&vmemend) | |
366 | panic("vbmemalloc"); | |
367 | *ppte = &VMEMmap1[vbmx]; | |
368 | *putl = vbmcur; | |
369 | vbmx += npf; | |
370 | vbmcur += npf*NBPG; | |
371 | vbaccess(*ppte, addr, npf); /* map i/o space */ | |
372 | } | |
373 | ||
374 | /* | |
375 | * Configure swap space and related parameters. | |
376 | */ | |
377 | swapconf() | |
378 | { | |
379 | register struct swdevt *swp; | |
380 | register int nblks; | |
381 | ||
382 | for (swp = swdevt; swp->sw_dev; swp++) | |
383 | if (bdevsw[major(swp->sw_dev)].d_psize) { | |
384 | nblks = | |
385 | (*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev); | |
386 | if (nblks != -1 && | |
387 | (swp->sw_nblks == 0 || swp->sw_nblks > nblks)) | |
388 | swp->sw_nblks = nblks; | |
389 | } | |
390 | if (dumplo == 0 && bdevsw[major(dumpdev)].d_psize) | |
391 | dumplo = (*bdevsw[major(dumpdev)].d_psize)(dumpdev) - physmem; | |
392 | if (dumplo < 0) | |
393 | dumplo = 0; | |
394 | } | |
395 | ||
396 | #define DOSWAP /* change swdevt, argdev, and dumpdev too */ | |
397 | u_long bootdev; /* should be dev_t, but not until 32 bits */ | |
398 | ||
399 | static char devname[][2] = { | |
400 | 0,0, /* 0 = ud */ | |
401 | 'd','k', /* 1 = vd */ | |
402 | 0,0, /* 2 = xp */ | |
403 | }; | |
404 | ||
405 | #define PARTITIONMASK 0x7 | |
406 | #define PARTITIONSHIFT 3 | |
407 | ||
408 | /* | |
409 | * Attempt to find the device from which we were booted. | |
410 | * If we can do so, and not instructed not to do so, | |
411 | * change rootdev to correspond to the load device. | |
412 | */ | |
413 | setroot() | |
414 | { | |
415 | int majdev, mindev, unit, part, adaptor; | |
416 | dev_t temp, orootdev; | |
417 | struct swdevt *swp; | |
418 | ||
419 | if (boothowto & RB_DFLTROOT || | |
420 | (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC) | |
421 | return; | |
422 | majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK; | |
423 | if (majdev > sizeof(devname) / sizeof(devname[0])) | |
424 | return; | |
425 | adaptor = (bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK; | |
426 | part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK; | |
427 | unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK; | |
428 | /* | |
429 | * Search Versabus devices. | |
430 | * | |
431 | * WILL HAVE TO DISTINGUISH VME/VERSABUS SOMETIME | |
432 | */ | |
433 | { | |
434 | register struct vba_device *vbap; | |
435 | ||
436 | for (vbap = vbdinit; vbap->ui_driver; vbap++) | |
437 | if (vbap->ui_alive && vbap->ui_slave == unit && | |
438 | vbap->ui_vbanum == adaptor && | |
439 | vbap->ui_driver->ud_dname[0] == devname[majdev][0] && | |
440 | vbap->ui_driver->ud_dname[1] == devname[majdev][1]) | |
441 | break; | |
442 | if (vbap->ui_driver == 0) | |
443 | return; | |
444 | mindev = vbap->ui_unit; | |
445 | } | |
446 | mindev = (mindev << PARTITIONSHIFT) + part; | |
447 | orootdev = rootdev; | |
448 | rootdev = makedev(majdev, mindev); | |
449 | /* | |
450 | * If the original rootdev is the same as the one | |
451 | * just calculated, don't need to adjust the swap configuration. | |
452 | */ | |
453 | if (rootdev == orootdev) | |
454 | return; | |
455 | printf("changing root device to %c%c%d%c\n", | |
456 | devname[majdev][0], devname[majdev][1], | |
457 | mindev >> PARTITIONSHIFT, part + 'a'); | |
458 | #ifdef DOSWAP | |
459 | mindev &= ~PARTITIONMASK; | |
460 | for (swp = swdevt; swp->sw_dev; swp++) { | |
461 | if (majdev == major(swp->sw_dev) && | |
462 | mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) { | |
463 | temp = swdevt[0].sw_dev; | |
464 | swdevt[0].sw_dev = swp->sw_dev; | |
465 | swp->sw_dev = temp; | |
466 | break; | |
467 | } | |
468 | } | |
469 | if (swp->sw_dev == 0) | |
470 | return; | |
471 | /* | |
472 | * If argdev and dumpdev were the same as the old primary swap | |
473 | * device, move them to the new primary swap device. | |
474 | */ | |
475 | if (temp == dumpdev) | |
476 | dumpdev = swdevt[0].sw_dev; | |
477 | if (temp == argdev) | |
478 | argdev = swdevt[0].sw_dev; | |
479 | #endif | |
480 | } |