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