From 4fea1aeb1949b647515e5dbd8c23ebd8c6838b96 Mon Sep 17 00:00:00 2001 From: Bill Joy Date: Mon, 12 Mar 1990 23:47:40 -0800 Subject: [PATCH] date and time created 90/03/12 15:47:40 by bill SCCS-vsn: sys/i386/i386/autoconf.c 1.1 --- usr/src/sys/i386/i386/autoconf.c | 480 +++++++++++++++++++++++++++++++ 1 file changed, 480 insertions(+) create mode 100644 usr/src/sys/i386/i386/autoconf.c diff --git a/usr/src/sys/i386/i386/autoconf.c b/usr/src/sys/i386/i386/autoconf.c new file mode 100644 index 0000000000..f4cd640ddc --- /dev/null +++ b/usr/src/sys/i386/i386/autoconf.c @@ -0,0 +1,480 @@ +/* autoconf.c 1.13 87/04/02 */ + +/* + * 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 "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, zmemall(); + extern long catcher[SCB_LASTIV*2]; + +#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, 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 (*)())&catcher[i*2]; + /* + * 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. + * + * 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 ... + */ + valloc = zmemall(memall, ctob(VBIOSIZE)); + if (valloc == (caddr_t)0) + panic("no mem for vbafind"); + + /* + * 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[vboff(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[vboff(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; + 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; + } + } + wmemfree(valloc, ctob(VBIOSIZE)); +} + +/* + * 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; + p = &valloc[vboff(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) + panic("vbmapalloc"); + *ppte = &VBmap[vbx]; + *putl = vbcur; + vbx += npf; + vbcur += npf*NBPG; +} + +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) + panic("vbmemalloc"); + *ppte = &VMEMmap1[vbmx]; + *putl = vbmcur; + vbmx += npf; + vbmcur += npf*NBPG; + vbaccess(*ppte, addr, npf); /* map i/o space */ +} + +/* + * 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, adaptor; + dev_t temp, orootdev; + struct swdevt *swp; + + if (boothowto & RB_DFLTROOT || + (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC) + return; + majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK; + if (majdev > sizeof(devname) / sizeof(devname[0])) + return; + adaptor = (bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK; + part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK; + unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK; + /* + * 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_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 +} -- 2.20.1