date and time created 90/04/24 12:59:50 by william
[unix-history] / usr / src / sys / i386 / i386 / autoconf.c
CommitLineData
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 */
36int dkn; /* number of iostat dk numbers assigned so far */
37int cold; /* cold start flag initialized in locore.s */
38
39/*
40 * This allocates the space for the per-vba information.
41 */
42struct vba_hd vba_hd[NVBA];
43
44/*
45 * Determine i/o configuration for a machine.
46 */
47configure()
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 */
82vbaccess(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 */
100fixctlrmask()
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 */
121vbafind(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 */
307csralloc(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
332caddr_t vbcur = (caddr_t)&vbbase;
333int vbx = 0;
334/*
335 * Allocate page tables for mapping intermediate i/o buffers.
336 * Called by device drivers during autoconfigure.
337 */
338vbmapalloc(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
352caddr_t vbmcur = (caddr_t)&vmem1;
353int vbmx = 0;
354/*
355 * Allocate page tables and map VERSAbus i/o space.
356 * Called by device drivers during autoconfigure.
357 */
358vbmemalloc(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 */
377swapconf()
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 */
397u_long bootdev; /* should be dev_t, but not until 32 bits */
398
399static 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 */
413setroot()
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}