4.3BSD-Tahoe/tmp/autoconf.c

Compare this file to the similar file:
Show the results in this format:

/*
 * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 *
 *	@(#)autoconf.c	7.2 (Berkeley) 5/23/89
 */

/*
 * Setup the system to run on the current machine.
 *
 * Configure() is called at boot time and initializes the vba 
 * device tables and the memory controller monitoring.  Available
 * devices are determined (from possibilities mentioned in ioconf.c),
 * and the drivers are initialized.
 */
#include "param.h"
#include "systm.h"
#include "map.h"
#include "buf.h"
#include "dkstat.h"
#include "vm.h"
#include "conf.h"
#include "dmap.h"
#include "reboot.h"
#include "malloc.h"

#include "pte.h"
#include "mem.h"
#include "mtpr.h"
#include "scb.h"

#include "vba.h"

#include "../tahoevba/vbavar.h"
#include "../tahoevba/vbaparam.h"

/*
 * The following several variables are related to
 * the configuration process, and are used in initializing
 * the machine.
 */
int	dkn;		/* number of iostat dk numbers assigned so far */
int	cold;		/* cold start flag initialized in locore.s */

/*
 * This allocates the space for the per-vba information.
 */
struct	vba_hd vba_hd[NVBA];

/*
 * Determine i/o configuration for a machine.
 */
configure()
{
	register int *ip;
	extern caddr_t Sysbase;

	vbafind(numvba, (caddr_t)&vmem, VMEMmap);
	numvba++;
	/*
	 * Write protect the scb.  It is strange
	 * that this code is here, but this is as soon
	 * as we are done mucking with it, and the
	 * write-enable was done in assembly language
	 * to which we will never return.
	 */
	ip = (int *)&Sysmap[2]; *ip &= ~PG_PROT; *ip |= PG_KR;
	mtpr(TBIS, Sysbase+2*NBPG);
#if GENERIC
	if ((boothowto & RB_ASKNAME) == 0)
		setroot();
	setconf();
#else
	setroot();
#endif
	/*
	 * Configure swap area and related system
	 * parameter based on device(s) used.
	 */
	swapconf();
	cold = 0;
}

/*
 * Make the controllers accessible at physical address phys
 * by mapping kernel ptes starting at pte.
 */
vbaccess(pte, iobase, n)
	register struct pte *pte;
	caddr_t iobase;
	register int n;
{
	register unsigned v = btop(iobase);
	
	do
		*(int *)pte++ = PG_V|PG_KW|v++;
	while (--n > 0);
	mtpr(TBIA, 0);
}

/*
 * Fixctlrmask fixes the masks of the driver ctlr routines
 * which otherwise save r11 and r12 where the interrupt and br
 * level are passed through.
 */
fixctlrmask()
{
	register struct vba_ctlr *vm;
	register struct vba_device *vi;
	register struct vba_driver *vd;
#define	phys(a,b) ((b)(((int)(a))&~0xc0000000))

	vm = phys(vbminit, struct vba_ctlr *);
	for (; vd = phys(vm->um_driver, struct vba_driver *); vm++)
		*phys(vd->ud_probe, short *) &= ~0x1800;
	vi = phys(vbdinit, struct vba_device *);
	for (; vd = phys(vi->ui_driver, struct vba_driver *); vi++)
		*phys(vd->ud_probe, short *) &= ~0x1800;
}

/*
 * Find devices on the VERSAbus.
 * Uses per-driver routine to see who is on the bus
 * and then fills in the tables, with help from a per-driver
 * slave initialization routine.
 */
vbafind(vban, vumem, memmap)
	int vban;
	caddr_t vumem;
	struct pte memmap[];
{
	register int br, cvec;			/* must be r12, r11 */
	register struct vba_device *ui;
	register struct vba_ctlr *um;
	u_short *reg;
	long addr, *ap;
	struct vba_hd *vhp;
	struct vba_driver *udp;
	int i, octlr, (**ivec)();
	caddr_t valloc;
	extern quad catcher[SCB_LASTIV];

#ifdef lint
	br = 0; cvec = 0;
#endif
	vhp = &vba_hd[vban];
	/*
	 * Make the controllers accessible at physical address phys
	 * by mapping kernel ptes starting at pte.
	 */
	vbaccess(memmap, (caddr_t)VBIOBASE, (int)VBIOSIZE);
	printf("vba%d at %x\n", vban, VBIOBASE);
	/*
	 * Setup scb device entries to point into catcher array.
	 */
	for (i = 0; i < SCB_LASTIV; i++)
		scb.scb_devint[i] = (int (*)())((int)&catcher[i]);
	/*
	 * Set last free interrupt vector for devices with
	 * programmable interrupt vectors.  Use is to decrement
	 * this number and use result as interrupt vector.
	 */
	vhp->vh_lastiv = SCB_LASTIV;
	/*
	 * Grab some memory to record the address space we allocate,
	 * so we can be sure not to place two devices at the same address.
	 * Register I/O space is allocated in 256-byte sections,
	 * and memory I/O space is in 4Kb sections.  We record allocations
	 * in 256-byte sections.
	 *
	 * We could use just 1/8 of this (we only want a 1 bit flag) but
	 * we are going to give it back anyway, and that would make the
	 * code here bigger (which we can't give back), so ...
	 */
#define	VSECT(a)	((a) / 0x100)
#define	VSIZE(s)	(((s) + 0xff) / 0x100)
#define	VALLOC(a)	(valloc[VSECT(vboff(a))])
#define	VMAPSIZE	VSIZE(ctob(VBIOSIZE))
	valloc = (caddr_t)malloc((u_long)(VMAPSIZE), M_TEMP, M_NOWAIT);
	if (valloc == (caddr_t)0)
		panic("no mem for vbafind");
	bzero(valloc, VMAPSIZE);

	/*
	 * Check each VERSAbus mass storage controller.
	 * For each one which is potentially on this vba,
	 * see if it is really there, and if it is record it and
	 * then go looking for slaves.
	 */
#define	vbaddr(off)	(u_short *)(vumem + vboff(off))
	for (um = vbminit; udp = um->um_driver; um++) {
		if (um->um_vbanum != vban && um->um_vbanum != '?')
			continue;
		/*
		 * Use the particular address specified first,
		 * or if it is given as "0", if there is no device
		 * at that address, try all the standard addresses
		 * in the driver until we find it.
		 */
		addr = (long)um->um_addr;
	    for (ap = udp->ud_addr; addr || (addr = *ap++); addr = 0) {
		if (VBIOMAPPED(addr)) {
			if (VALLOC(addr))
				continue;
			reg = vbaddr(addr);
		} else
			reg = (u_short *)addr;
		um->um_hd = vhp;
		cvec = SCB_LASTIV, cold &= ~0x2;
		i = (*udp->ud_probe)(reg, um);
		cold |= 0x2;
		if (i == 0)
			continue;
		printf("%s%d at vba%d csr %x ",
		    udp->ud_mname, um->um_ctlr, vban, addr);
		if (cvec < 0 && vhp->vh_lastiv == cvec) {
			printf("no space for vector(s)\n");
			continue;
		}
		if (cvec == SCB_LASTIV) {
			printf("didn't interrupt\n");
			continue;
		}
		printf("vec %x, ipl %x\n", cvec, br);
		csralloc(valloc, addr, i);
		um->um_alive = 1;
		um->um_vbanum = vban;
		um->um_addr = (caddr_t)reg;
		udp->ud_minfo[um->um_ctlr] = um;
		for (ivec = um->um_intr; *ivec; ivec++)
			((long *)&scb)[cvec++] = (long)*ivec;
		for (ui = vbdinit; ui->ui_driver; ui++) {
			if (ui->ui_driver != udp || ui->ui_alive ||
			    ui->ui_ctlr != um->um_ctlr && ui->ui_ctlr != '?' ||
			    ui->ui_vbanum != vban && ui->ui_vbanum != '?')
				continue;
			octlr = ui->ui_ctlr, ui->ui_ctlr = um->um_ctlr;
			if ((*udp->ud_slave)(ui, reg)) {
				ui->ui_alive = 1;
				ui->ui_ctlr = um->um_ctlr;
				ui->ui_vbanum = vban;
				ui->ui_addr = (caddr_t)reg;
				ui->ui_physaddr = (caddr_t)addr;
				if (ui->ui_dk && dkn < DK_NDRIVE)
					ui->ui_dk = dkn++;
				else
					ui->ui_dk = -1;
				ui->ui_mi = um;
				ui->ui_hd = vhp;
				/* ui_type comes from driver */
				udp->ud_dinfo[ui->ui_unit] = ui;
				printf("%s%d at %s%d slave %d",
				    udp->ud_dname, ui->ui_unit,
				    udp->ud_mname, um->um_ctlr,
				    ui->ui_slave);
				(*udp->ud_attach)(ui);
				printf("\n");
			} else
				ui->ui_ctlr = octlr;
		}
		break;
	    }
	}
	/*
	 * Now look for non-mass storage peripherals.
	 */
	for (ui = vbdinit; udp = ui->ui_driver; ui++) {
		if (ui->ui_vbanum != vban && ui->ui_vbanum != '?' ||
		    ui->ui_alive || ui->ui_slave != -1)
			continue;
		addr = (long)ui->ui_addr;
	    for (ap = udp->ud_addr; addr || (addr = *ap++); addr = 0) {
		if (VBIOMAPPED(addr)) {
			if (VALLOC(addr))
				continue;
			reg = vbaddr(addr);
		} else
			reg = (u_short *)addr;
		ui->ui_hd = vhp;
		cvec = SCB_LASTIV, cold &= ~0x2;
		i = (*udp->ud_probe)(reg, ui);
		cold |= 0x2;
		if (i == 0)
			continue;
		printf("%s%d at vba%d csr %x ",
		    ui->ui_driver->ud_dname, ui->ui_unit, vban, addr);
		if (ui->ui_intr) {
			if (cvec < 0 && vhp->vh_lastiv == cvec) {
				printf("no space for vector(s)\n");
				continue;
			}
			if (cvec == SCB_LASTIV) {
				printf("didn't interrupt\n");
				continue;
			}
			printf("vec %x, ipl %x\n", cvec, br);
			for (ivec = ui->ui_intr; *ivec; ivec++)
				((long *)&scb)[cvec++] = (long)*ivec;
		} else
			printf("no interrupts\n");
		csralloc(valloc, addr, i);
		ui->ui_alive = 1;
		ui->ui_vbanum = vban;
		if (VBIOMAPPED(addr))
			ui->ui_addr = (caddr_t)reg;
		ui->ui_physaddr = (caddr_t)addr;
		ui->ui_dk = -1;
		/* ui_type comes from driver */
		udp->ud_dinfo[ui->ui_unit] = ui;
		(*udp->ud_attach)(ui);
		break;
	    }
	}
	free(valloc, M_TEMP);
}

/*
 * Mark addresses starting at addr and continuing
 * size bytes as allocated in the map.
 * Warn if the new allocation overlaps a previous allocation.
 */
csralloc(valloc, addr, size)
	caddr_t valloc;
	long addr;
	register int size;
{
	register caddr_t p;
	int warned = 0;

	if (!VBIOMAPPED(addr))
		return;
	size = VSIZE(size);
	p = &VALLOC(addr) + size;
	while (--size >= 0) {
		if (*--p && !warned) {
			printf(
	"WARNING: device registers overlap those for a previous device\n");
			warned = 1;
		}
		*p = 1;
	}
}

/*
 * Tahoe VERSAbus adapator support routines.
 */

caddr_t	vbcur = (caddr_t)&vbbase;
int	vbx = 0;
/*
 * Allocate page tables for mapping intermediate i/o buffers.
 * Called by device drivers during autoconfigure.
 */
vbmapalloc(npf, ppte, putl)
	int npf;
	struct pte **ppte;
	caddr_t *putl;
{

	if (vbcur + npf*NBPG > (caddr_t)&vbend)
		return (0);
	*ppte = &VBmap[vbx];
	*putl = vbcur;
	vbx += npf;
	vbcur += npf*NBPG;
	return (1);
}

caddr_t	vbmcur = (caddr_t)&vmem1;
int	vbmx = 0;
/*
 * Allocate page tables and map VERSAbus i/o space.
 * Called by device drivers during autoconfigure.
 */
vbmemalloc(npf, addr, ppte, putl)
	int npf;
	caddr_t addr;
	struct pte **ppte;
	caddr_t *putl;
{

	if (vbmcur + npf*NBPG > (caddr_t)&vmemend)
		return (0);
	*ppte = &VMEMmap1[vbmx];
	*putl = vbmcur;
	vbmx += npf;
	vbmcur += npf*NBPG;
	vbaccess(*ppte, addr, npf);		/* map i/o space */
	return (1);
}

/*
 * Configure swap space and related parameters.
 */
swapconf()
{
	register struct swdevt *swp;
	register int nblks;

	for (swp = swdevt; swp->sw_dev; swp++)
		if (bdevsw[major(swp->sw_dev)].d_psize) {
			nblks =
			  (*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev);
			if (nblks != -1 &&
			    (swp->sw_nblks == 0 || swp->sw_nblks > nblks))
				swp->sw_nblks = nblks;
		}
	if (dumplo == 0 && bdevsw[major(dumpdev)].d_psize)
		dumplo = (*bdevsw[major(dumpdev)].d_psize)(dumpdev) - physmem;
	if (dumplo < 0)
		dumplo = 0;
}

#define	DOSWAP			/* change swdevt, argdev, and dumpdev too */
u_long	bootdev;		/* should be dev_t, but not until 32 bits */

static	char devname[][2] = {
	0,0,		/* 0 = ud */
	'd','k',	/* 1 = vd */
	0,0,		/* 2 = xp */
};

#define	PARTITIONMASK	0x7
#define	PARTITIONSHIFT	3

/*
 * Attempt to find the device from which we were booted.
 * If we can do so, and not instructed not to do so,
 * change rootdev to correspond to the load device.
 */
setroot()
{
	int  majdev, mindev, unit, part, controller, adaptor;
	dev_t temp, orootdev;
	struct swdevt *swp;

	if (boothowto & RB_DFLTROOT ||
	    (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC)
		return;
	majdev = B_TYPE(bootdev);
	if (majdev >= sizeof(devname) / sizeof(devname[0]))
		return;
	adaptor = B_ADAPTOR(bootdev);
	controller = B_CONTROLLER(bootdev);
	part = B_PARTITION(bootdev);
	unit = B_UNIT(bootdev);
	/*
	 * Search Versabus devices.
	 *
	 * WILL HAVE TO DISTINGUISH VME/VERSABUS SOMETIME
	 */
	{
		register struct vba_device *vbap;

		for (vbap = vbdinit; vbap->ui_driver; vbap++)
			if (vbap->ui_alive && vbap->ui_slave == unit &&
			   vbap->ui_ctlr == controller &&
			   vbap->ui_vbanum == adaptor &&
			   vbap->ui_driver->ud_dname[0] == devname[majdev][0] &&
			   vbap->ui_driver->ud_dname[1] == devname[majdev][1])
				break;
		if (vbap->ui_driver == 0)
			return;
		mindev = vbap->ui_unit;
	}
	mindev = (mindev << PARTITIONSHIFT) + part;
	orootdev = rootdev;
	rootdev = makedev(majdev, mindev);
	/*
	 * If the original rootdev is the same as the one
	 * just calculated, don't need to adjust the swap configuration.
	 */
	if (rootdev == orootdev)
		return;
	printf("changing root device to %c%c%d%c\n",
		devname[majdev][0], devname[majdev][1],
		mindev >> PARTITIONSHIFT, part + 'a');
#ifdef DOSWAP
	mindev &= ~PARTITIONMASK;
	for (swp = swdevt; swp->sw_dev; swp++) {
		if (majdev == major(swp->sw_dev) &&
		    mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) {
			temp = swdevt[0].sw_dev;
			swdevt[0].sw_dev = swp->sw_dev;
			swp->sw_dev = temp;
			break;
		}
	}
	if (swp->sw_dev == 0)
		return;
	/*
	 * If argdev and dumpdev were the same as the old primary swap
	 * device, move them to the new primary swap device.
	 */
	if (temp == dumpdev)
		dumpdev = swdevt[0].sw_dev;
	if (temp == argdev)
		argdev = swdevt[0].sw_dev;
#endif
}