xref: /original-bsd/sys/tahoe/tahoe/autoconf.c (revision c95cd016)
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.1 (Berkeley) 05/26/88
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 "param.h"
18 #include "systm.h"
19 #include "map.h"
20 #include "buf.h"
21 #include "dkstat.h"
22 #include "vm.h"
23 #include "conf.h"
24 #include "dmap.h"
25 #include "reboot.h"
26 #include "malloc.h"
27 
28 #include "pte.h"
29 #include "mem.h"
30 #include "mtpr.h"
31 #include "scb.h"
32 
33 #include "vba.h"
34 
35 #include "../tahoevba/vbavar.h"
36 #include "../tahoevba/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 		ui->ui_addr = (caddr_t)reg;
306 		ui->ui_physaddr = (caddr_t)addr;
307 		ui->ui_dk = -1;
308 		/* ui_type comes from driver */
309 		udp->ud_dinfo[ui->ui_unit] = ui;
310 		(*udp->ud_attach)(ui);
311 		break;
312 	    }
313 	}
314 	free(valloc, M_TEMP);
315 }
316 
317 /*
318  * Mark addresses starting at addr and continuing
319  * size bytes as allocated in the map.
320  * Warn if the new allocation overlaps a previous allocation.
321  */
322 csralloc(valloc, addr, size)
323 	caddr_t valloc;
324 	long addr;
325 	register int size;
326 {
327 	register caddr_t p;
328 	int warned = 0;
329 
330 	if (!VBIOMAPPED(addr))
331 		return;
332 	size = VSIZE(size);
333 	p = &VALLOC(addr) + size;
334 	while (--size >= 0) {
335 		if (*--p && !warned) {
336 			printf(
337 	"WARNING: device registers overlap those for a previous device\n");
338 			warned = 1;
339 		}
340 		*p = 1;
341 	}
342 }
343 
344 /*
345  * Tahoe VERSAbus adapator support routines.
346  */
347 
348 caddr_t	vbcur = (caddr_t)&vbbase;
349 int	vbx = 0;
350 /*
351  * Allocate page tables for mapping intermediate i/o buffers.
352  * Called by device drivers during autoconfigure.
353  */
354 vbmapalloc(npf, ppte, putl)
355 	int npf;
356 	struct pte **ppte;
357 	caddr_t *putl;
358 {
359 
360 	if (vbcur + npf*NBPG > (caddr_t)&vbend)
361 		return (0);
362 	*ppte = &VBmap[vbx];
363 	*putl = vbcur;
364 	vbx += npf;
365 	vbcur += npf*NBPG;
366 	return (1);
367 }
368 
369 caddr_t	vbmcur = (caddr_t)&vmem1;
370 int	vbmx = 0;
371 /*
372  * Allocate page tables and map VERSAbus i/o space.
373  * Called by device drivers during autoconfigure.
374  */
375 vbmemalloc(npf, addr, ppte, putl)
376 	int npf;
377 	caddr_t addr;
378 	struct pte **ppte;
379 	caddr_t *putl;
380 {
381 
382 	if (vbmcur + npf*NBPG > (caddr_t)&vmemend)
383 		return (0);
384 	*ppte = &VMEMmap1[vbmx];
385 	*putl = vbmcur;
386 	vbmx += npf;
387 	vbmcur += npf*NBPG;
388 	vbaccess(*ppte, addr, npf);		/* map i/o space */
389 	return (1);
390 }
391 
392 /*
393  * Configure swap space and related parameters.
394  */
395 swapconf()
396 {
397 	register struct swdevt *swp;
398 	register int nblks;
399 
400 	for (swp = swdevt; swp->sw_dev; swp++)
401 		if (bdevsw[major(swp->sw_dev)].d_psize) {
402 			nblks =
403 			  (*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev);
404 			if (nblks != -1 &&
405 			    (swp->sw_nblks == 0 || swp->sw_nblks > nblks))
406 				swp->sw_nblks = nblks;
407 		}
408 	if (dumplo == 0 && bdevsw[major(dumpdev)].d_psize)
409 		dumplo = (*bdevsw[major(dumpdev)].d_psize)(dumpdev) - physmem;
410 	if (dumplo < 0)
411 		dumplo = 0;
412 }
413 
414 #define	DOSWAP			/* change swdevt, argdev, and dumpdev too */
415 u_long	bootdev;		/* should be dev_t, but not until 32 bits */
416 
417 static	char devname[][2] = {
418 	0,0,		/* 0 = ud */
419 	'd','k',	/* 1 = vd */
420 	0,0,		/* 2 = xp */
421 };
422 
423 #define	PARTITIONMASK	0x7
424 #define	PARTITIONSHIFT	3
425 
426 /*
427  * Attempt to find the device from which we were booted.
428  * If we can do so, and not instructed not to do so,
429  * change rootdev to correspond to the load device.
430  */
431 setroot()
432 {
433 	int  majdev, mindev, unit, part, controller, adaptor;
434 	dev_t temp, orootdev;
435 	struct swdevt *swp;
436 
437 	if (boothowto & RB_DFLTROOT ||
438 	    (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC)
439 		return;
440 	majdev = B_TYPE(bootdev);
441 	if (majdev >= sizeof(devname) / sizeof(devname[0]))
442 		return;
443 	adaptor = B_ADAPTOR(bootdev);
444 	controller = B_CONTROLLER(bootdev);
445 	part = B_PARTITION(bootdev);
446 	unit = B_UNIT(bootdev);
447 	/*
448 	 * Search Versabus devices.
449 	 *
450 	 * WILL HAVE TO DISTINGUISH VME/VERSABUS SOMETIME
451 	 */
452 	{
453 		register struct vba_device *vbap;
454 
455 		for (vbap = vbdinit; vbap->ui_driver; vbap++)
456 			if (vbap->ui_alive && vbap->ui_slave == unit &&
457 			   vbap->ui_ctlr == controller &&
458 			   vbap->ui_vbanum == adaptor &&
459 			   vbap->ui_driver->ud_dname[0] == devname[majdev][0] &&
460 			   vbap->ui_driver->ud_dname[1] == devname[majdev][1])
461 				break;
462 		if (vbap->ui_driver == 0)
463 			return;
464 		mindev = vbap->ui_unit;
465 	}
466 	mindev = (mindev << PARTITIONSHIFT) + part;
467 	orootdev = rootdev;
468 	rootdev = makedev(majdev, mindev);
469 	/*
470 	 * If the original rootdev is the same as the one
471 	 * just calculated, don't need to adjust the swap configuration.
472 	 */
473 	if (rootdev == orootdev)
474 		return;
475 	printf("changing root device to %c%c%d%c\n",
476 		devname[majdev][0], devname[majdev][1],
477 		mindev >> PARTITIONSHIFT, part + 'a');
478 #ifdef DOSWAP
479 	mindev &= ~PARTITIONMASK;
480 	for (swp = swdevt; swp->sw_dev; swp++) {
481 		if (majdev == major(swp->sw_dev) &&
482 		    mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) {
483 			temp = swdevt[0].sw_dev;
484 			swdevt[0].sw_dev = swp->sw_dev;
485 			swp->sw_dev = temp;
486 			break;
487 		}
488 	}
489 	if (swp->sw_dev == 0)
490 		return;
491 	/*
492 	 * If argdev and dumpdev were the same as the old primary swap
493 	 * device, move them to the new primary swap device.
494 	 */
495 	if (temp == dumpdev)
496 		dumpdev = swdevt[0].sw_dev;
497 	if (temp == argdev)
498 		argdev = swdevt[0].sw_dev;
499 #endif
500 }
501