static char rcsid[] = "$Header: autoconf.c,v 820.1 86/12/04 19:52:45 root Exp $";
static char sccsid[]="%W% %Y% %Q% %G%";

/************************************************************************
*									*
*				Copyright 1984				*
*			VALID LOGIC SYSTEMS INCORPORATED		*
*									*
*	This listing contains confidential proprietary information	*
*	which is not to be disclosed to unauthorized persons without	*
*	written consent of an officer of Valid Logic Systems 		*
*	Incorporated.							*
*									*
*	The copyright notice appearing above is included to provide	*
*	statutory protection in the event of unauthorized or 		*
*	unintentional public disclosure.				*
*									*
************************************************************************/

/*
 * Setup the system to run on the current machine.
 *
 * Configure() is called at boot time to initialize the multibus
 * device tables.  Available devices are determined (from possibilities
 * mentioned in ioconf.c), and the drivers are initialized.
 */

#include "../machine/pte.h"

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/buf.h"
#include "../h/dk.h"
#include "../h/vm.h"
#include "../h/conf.h"
#include "../h/dmap.h"

#include "../s32/cpu.h"
#include "../s32/trap.h"
#include "../s32dev/mbvar.h"

/*
 * The following several variables are related to
 * the configuration process, and are used in initializing
 * the machine.
 *
 * Cvec is the interrupt auto-vector number set in mbint?() when
 * we probe a controller.  Unlike the Vax, we don't fool around
 * with returning values in registers.
 */
int	cold = 1;	/* if 1, still working on cold-start */
int	dkn;		/* number of iostat dk numbers assigned so far */
int	cvec;		/* vector number from a probe() */

#ifdef	GENERIC
int	generic = 1;	/* 1 ==> Run the GENERIC code */
#endif	GENERIC

/*
 * Determine mass storage and memory configuration for a machine.
 */
configure()
{
	mbconf();
#ifdef	GENERIC
	if (generic)
		setconf();
#endif	GENERIC
	/*
	 * Configure swap area and related system
	 * parameter based on device(s) used.
	 */
	swapconf();
	cold = 0;
	return;
}

/*
 * Find devices on a Multibus.
 * Uses per-driver routine to find interrupt vectors,
 * and then fills in the tables, with help from a per-driver
 * slave initialization routine.
 *
 * This routine assumes that the address in the mbdevice structures
 * is <64k if in Multibus I/O space and >64k if in physical memory space.
 * I/O space addresses for the first 4k are offset by the virtual
 * address of a predefined I/O page map.
 * Memory space addresses are not adjusted.
 */
mbconf()
{
	register struct mb_device *md;
	register struct mb_ctlr *mc;
	register struct mb_vec *mv;
	register struct mb_driver *mdr;
	u_short *ap;
	caddr_t addr;
	caddr_t reg;
	int i, (**ivec)();
	extern label_t *nofault;
	label_t *save_fault, fault;

	for (i = 0; i < MB_NVEC; i++)
		((int (**)()) 0)[T_VEC1 + i] = mbint[i];
	/*
	 * Reset each multibus mass storage CONTROLLER
	 * that has a reset entry in its driver structure.
	 */
	for (mc = mbcinit; mdr = mc->mc_driver; mc++) {
		reg = ((u_long)mc->mc_addr>0xFFFF) ? mc->mc_addr : MBIO_VA+mc->mc_addr;
		if (mdr->mdr_reset)
			(*mdr->mdr_reset)(reg);
	}

	/*
	 * Reset each non-mass storage PERIPHERAL that has
	 * a reset entry in its driver structure.
	 */
	for (md = mbdinit; mdr = md->md_driver; md++) {
		reg = ((u_long)md->md_addr>0xFFFF) ? md->md_addr : MBIO_VA+md->md_addr;
		if (mdr->mdr_reset)
			(*mdr->mdr_reset)(reg);
	}

	/*
	 * Check each multibus mass storage CONTROLLER.
	 * For each one which is potentially on the bus,
	 * see if it is really there, and if it is record it and
	 * then go looking for slaves.
	 */
	for (mc = mbcinit; mdr = mc->mc_driver; mc++) {
		addr = mc->mc_addr;
		/*
		 * use the particular address specified first,
		 * or if it is given as "0", or there is no device
		 * at that address, try all the standard addresses
		 * in the driver til we find it
		 */
	    for (ap = mdr->mdr_addr; addr || (addr = (caddr_t)(*ap++)); addr = 0) {
		reg = ((u_long)addr>0xFFFF) ? addr : MBIO_VA+addr;
		/*
		 * Probe once for each interrupt routine specified.
		 * The driver is responsible for making the device
		 * interrupt properly.
		 */
		for (ivec = mc->mc_intr; *ivec; ivec++) {
			spl0();
			save_fault = nofault;
			if (setjmp(&fault)) {
				/* got bus error, device does not exist */
				nofault = save_fault;
				break;
			}
			cvec = -1;
			nofault = &fault;
			i = (*mdr->mdr_probe)(reg, *ivec, mc->mc_ctlr);
			nofault = save_fault;
			if (i == 0)
				break;
			if (!mc->mc_alive) {
				mc->mc_alive = 1;
				mc->mc_addr = reg;
				mdr->mdr_cinfo[mc->mc_ctlr] = mc;
				printf("%s%d at csr 0x%x",
					mdr->mdr_cname, mc->mc_ctlr, addr);
			}
			printf(", intr 0x%x ", *ivec);
			if (cvec == -1)
				printf("didn't interrupt");
			else {
				mv = mb_vec[cvec];
				for (i = 0; mv[i].mv_func; i++)
					;
				if (i < MB_NDEV) {
					mv[i].mv_func = *ivec;
					mv[i].mv_unit = mc->mc_ctlr;
				} else
					printf("too many devices at ");
				printf("ipl %d", cvec + 1);
			}
		}
		if (mc->mc_alive)
			printf("\n");
		else
			continue;
		for (md = mbdinit; md->md_driver; md++) {
			if (md->md_driver != mdr || md->md_alive ||
			    md->md_ctlr != mc->mc_ctlr && md->md_ctlr != '?')
				continue;
			if ((*mdr->mdr_slave)(md, mc)) {
				md->md_alive = 1;
				md->md_ctlr = mc->mc_ctlr;
				md->md_addr = reg;
				md->md_physaddr = 0;	/* XXX */
				if (md->md_dk && dkn < DK_NDRIVE)
					md->md_dk = dkn++;
				else
					md->md_dk = -1;
				md->md_mi = mc;
				mdr->mdr_dinfo[md->md_unit] = md;
				printf("%s%d at %s%d slave %d\n",
				    mdr->mdr_dname, md->md_unit,
				    mdr->mdr_cname, mc->mc_ctlr, md->md_slave);
				(*mdr->mdr_attach)(md);
			}
		}
		break;
	    }
	}
	/*
	 * Now look for non-mass storage peripherals.
	 */
	for (md = mbdinit; mdr = md->md_driver; md++) {
		if (md->md_alive || md->md_slave != -1)
			continue;
		addr = md->md_addr;
		/*
		 * use the particular address specified first,
		 * or if it is given as "0", of there is no device
		 * at that address, try all the standard addresses
		 * in the driver til we find it
		 */
	    for (ap = mdr->mdr_addr; addr || (addr = (caddr_t)(*ap++)); addr = 0) {
		reg = ((u_long)addr>0xFFFF) ? addr : MBIO_VA+addr;
		/*
		 * Probe once for each interrupt routine specified.
		 * The driver is responsible for making the device
		 * interrupt properly.
		 */
		for (ivec = md->md_intr; *ivec; ivec++) {
			spl0();
			save_fault = nofault;
			if (setjmp(&fault)) {
				/* got bus error, device does not exist */
				nofault = save_fault;
				break;
			}
			cvec = -1;
			nofault = &fault;
			i = (*mdr->mdr_probe)(reg, *ivec, md->md_unit);
			nofault = save_fault;
			if (i == 0)
				break;
			if (!md->md_alive) {
				md->md_alive = 1;
				md->md_addr = reg;
				printf("%s%d at csr 0x%x",
					mdr->mdr_dname, md->md_unit, addr);
			}
			printf(", intr 0x%x ", *ivec);
			if (cvec == -1)
				printf("didn't interrupt");
			else {
				mv = mb_vec[cvec];
				for (i = 0; mv[i].mv_func; i++)
					;
				if (i < MB_NDEV) {
					mv[i].mv_func = *ivec;
					mv[i].mv_unit = md->md_unit;
				} else
					printf("too many devices at ");
				printf("ipl %d", cvec + 1);
			}
		}
		if (md->md_alive)
			printf("\n");
		else
			continue;
		md->md_addr = reg;
		md->md_physaddr = 0;	/* XXX */
		if (md->md_dk && dkn < DK_NDRIVE)
			md->md_dk = dkn++;
		else
			md->md_dk = -1;
		mdr->mdr_dinfo[md->md_unit] = md;
#ifndef	BSDBUGFIX
		(*mdr->mdr_attach)(md);
#else	BSDBUGFIX
		if (mdr->mdr_attach)
			(*mdr->mdr_attach)(md);
#endif	BSDBUGFIX
		break;
	    }
	}
	for (i = 0; i < MB_NVEC; i++)
		if (mb_vec[i][0].mv_func != 0 && mb_vec[i][1].mv_func == 0)
			((int (**)()) 0)[T_VEC1 + i] = mbintx[i];
}

#define	MAXDUMP	(10*2048)
/*
 * 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 (swp->sw_nblks == 0 || swp->sw_nblks > nblks)
			swp->sw_nblks = nblks;
	}
	if (!cold)			/* in case called for mba device */
		return;
	if (dumplo == 0)
		dumplo = swdevt[0].sw_nblks - MAXDUMP;
	if (dumplo < 0)
		dumplo = 0;
	if (dmmin == 0)
		dmmin = DMMIN;
	if (dmmax == 0)
		dmmax = mmu_sizing[normalMmuIndx].mmu_dmmax;
	if (dmtext == 0)
		dmtext = mmu_sizing[normalMmuIndx].mmu_dmtext;
	if (dmtext > dmmax)
		dmtext = dmmax;
}
