code:
/*	$OpenBSD: autoconf.c,v 1.17 2015/04/25 21:15:08 miod Exp $	*/
/*
 * Copyright (c) 1998 Steve Murphree, Jr.
 * Copyright (c) 1996 Nivas Madhur
 * Copyright (c) 1994 Christian E. Hopps
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Christian E. Hopps.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/reboot.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/disklabel.h>
#include <sys/kernel.h>

#include <machine/asm_macro.h>
#include <machine/autoconf.h>
#include <machine/board.h>
#include <machine/cpu.h>
#include <machine/prom.h>

#ifdef AV530
#include <machine/av530.h>
#endif

#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>

#include <dev/cons.h>

#include "sd.h"
#include "st.h"

/*
 * The following several variables are related to
 * the configuration process, and are used in initializing
 * the machine.
 */

void	dumpconf(void);

int cold = 1;   /* 1 if still booting */

static struct device *bootctrl;		/* boot controller */
static struct device *bootdv;		/* boot device (if found) */
u_int bootdev = 0;			/* set in locore.S, can't be in .bss */
u_int bootunit = 0;			/* set in locore.S, can't be in .bss */
u_int bootlun = 0;			/* set in locore.S, can't be in .bss */
u_int bootpart = 0;			/* set in locore.S, can't be in .bss */
static uint32_t bootdevtype;		/* boot controller SCM name */
static paddr_t bootctrlpaddr;		/* boot controller address */

/*
 * called at boot time, configure all devices on the system.
 */
void
cpu_configure()
{
	printf("bootpath: '%s' dev %u unit %u lun %u\n",
	    bootargs, bootdev, bootunit, bootlun);

	softintr_init();

	if (config_rootfound("mainbus", "mainbus") == 0)
		panic("no mainbus found");

	/* NO PROM CALLS FROM NOW ON */

	cold = 0;

	/*
	 * Turn external interrupts on.
	 */
	set_psr(get_psr() & ~PSR_IND);
	spl0();
}

void
diskconf(void)
{
	printf("boot device: %s\n",
	    (bootdv) ? bootdv->dv_xname : "<unknown>");

	setroot(bootdv, bootpart, RB_USERREQ);
	dumpconf();

}

/*
 * Parse the commandline.
 *
 * This has two goals: first, turn the necessary options into boothowto
 * flags; second, convert the PROM boot device into the matching OpenBSD
 * driver name.
 */

/* skip end of token and whitespace */
static char *stws(char *);
static char *
stws(char *p)
{
	while (*p != ' ' && *p != '\0')
		p++;

	while (*p == ' ')
		p++;

	return (p);
}

/* parse a positive base 10 number */
static u_int strtoi(const char *);
static u_int
strtoi(const char *s)
{
	int c;
	u_int val = 0;

	if (s == NULL || *s == '\0')
		return 0;

	/* skip whitespace */
	do {
		c = *s++;
	} while (c == ' ' || c == '\t');

	for (;;) {
		if (c < '0' || c > '9')
			break;
		val *= 10;
		val += c - '0';
		c = *s++;
	}

	return val;
}

void
cmdline_parse(void)
{
	char *p;

	/*
	 * If the boot commandline has been manually entered, it
	 * may end with a '\r' character.
	 */
	for (p = bootargs; *p != '\0'; p++)
		;
	if (p != bootargs)
		if (*--p == '\r')
			*p = '\0';

	/*
	 * Skip boot device ``foo(ctrl,dev,lun)'' and filename,
	 * i.e. eat everything until whitespace.
	 */
	p = stws(bootargs);
	while (*p != '\0') {
		if (*p++ == '-')
			while (*p != ' ' && *p != '\0')
				switch (*p++) {
				case 'a':
					boothowto |= RB_ASKNAME;
					break;
				case 'b':
					boothowto |= RB_KDB;
					break;
				case 'c':
					boothowto |= RB_CONFIG;
					break;
				case 's':
					boothowto |= RB_SINGLE;
					break;
				}
		p = stws(p);
	}

	/*
	 * Now parse the boot device. We are only interested in the
	 * device type, since the PROM has cracked the controller, unit
	 * and partition numbers for us already, and we do not care about
	 * our own filename...
	 *
	 * However, in the sd() or st() cases, we need to figure out the
	 * SCSI controller name (if not the default one) and address, if
	 * provided.
	 *
	 * Note that we will override bootdev at this point. If no boot
	 * controller number or address was provided, bootdev will be set
	 * to zero anyway.
	 */
	if (memcmp(bootargs, "sd", 2) == 0 ||
	    memcmp(bootargs, "st", 2) == 0) {
		/*
		 * Either
		 *   sd(bootdev,bootunit,bootlun)
		 * or
		 *   sd(ctrl(bootdev,id),bootunit,bootlun)
		 * We already know bootdev, bootunit and bootlun.
		 * All we need here is to figure out the controller type
		 * and address.
		 */
		if (bootargs[7] == '(') {
			bcopy(bootargs + 3, &bootdevtype, sizeof(uint32_t));
			bootdev = strtoi(bootargs + 8);
		}
	} else {
		bcopy(bootargs, &bootdevtype, sizeof(int));
		bootdev = strtoi(bootargs + 5);
	}

	/* fill the holes */
	bootctrlpaddr = platform->get_boot_device(&bootdevtype, bootdev);
}

void
device_register(struct device *dev, void *aux)
{
	struct confargs *ca = (struct confargs *)aux;
	struct cfdriver *cf = dev->dv_cfdata->cf_driver;
	struct device *parent = dev->dv_parent;

	if (bootdv != NULL)
		return;

	if (bootctrl == NULL) {
		if (ca->ca_paddr != bootctrlpaddr)
			return;

		switch (bootdevtype) {
		case SCM_INEN:
		case SCM_DGEN:
			if (strcmp("le", cf->cd_name) == 0 &&
			    strcmp("syscon",
			      parent->dv_cfdata->cf_driver->cd_name) == 0)
				bootctrl = dev;
			break;

		case SCM_INSC:
			if (strcmp("oaic", cf->cd_name) == 0 &&
			    strcmp("syscon",
			      parent->dv_cfdata->cf_driver->cd_name) == 0)
				bootctrl = dev;
			break;

		case SCM_NCSC:
			if (strcmp("oosiop", cf->cd_name) == 0 &&
			    strcmp("syscon",
			      parent->dv_cfdata->cf_driver->cd_name) == 0)
				bootctrl = dev;
			break;
		}

		if (bootctrl != NULL && bootctrl->dv_class == DV_IFNET)
			bootdv = bootctrl;
		return;
	}

	if (memcmp(cf->cd_name, bootargs, 2) == 0 &&
	    (strcmp("sd", cf->cd_name) == 0 ||
	     strcmp("st", cf->cd_name) == 0)) {
		struct scsi_attach_args *saa = aux;
		if (saa->sa_sc_link->target == bootunit &&
		    saa->sa_sc_link->lun == bootlun &&
		    parent->dv_parent == bootctrl)
			bootdv = dev;
	}
}

struct nam2blk nam2blk[] = {
	{ "sd",		4 },
	{ "cd", 	6 },
	{ "rd",		7 },
	{ "vnd",	8 },
	{ NULL,		-1 }
};


code:
/*	$OpenBSD: av400_machdep.c,v 1.28 2015/05/18 04:06:37 miod Exp $	*/
/*
 * Copyright (c) 2006, 2007, Miodrag Vallat.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
/*
 * Copyright (c) 1998, 1999, 2000, 2001 Steve Murphree, Jr.
 * Copyright (c) 1996 Nivas Madhur
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Nivas Madhur.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
/*
 * Copyright (c) 1999 Steve Murphree, Jr.
 * Copyright (c) 1995 Theo de Raadt
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 * Copyright (c) 1995 Nivas Madhur
 * Copyright (c) 1994 Gordon W. Ross
 * Copyright (c) 1993 Adam Glass
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Lawrence Berkeley Laboratory.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)clock.c	8.1 (Berkeley) 6/11/93
 */
/*
 * Mach Operating System
 * Copyright (c) 1993-1991 Carnegie Mellon University
 * Copyright (c) 1991 OMRON Corporation
 * All Rights Reserved.
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/errno.h>

#include <uvm/uvm_extern.h>

#include <machine/asm_macro.h>
#include <machine/board.h>
#include <machine/bus.h>
#include <machine/cmmu.h>
#include <machine/cpu.h>
#include <machine/pmap_table.h>
#include <machine/reg.h>
#include <machine/trap.h>

#include <machine/m88100.h>
#include <machine/m8820x.h>
#include <machine/avcommon.h>
#include <machine/av400.h>
#include <machine/prom.h>

#include <aviion/dev/sysconvar.h>
#include <aviion/dev/vmevar.h>

#ifdef MULTIPROCESSOR0
#include <machine/db_machdep.h>
#endif

u_int	av400_safe_level(u_int, u_int);
void	av400_clock_ipi_handler(struct trapframe *);
void	av400_ipi_handler(struct trapframe *);

const struct pmap_table
av400_ptable[] = {
	{ AV400_PROM,	AV400_PROM_SIZE,	PROT_READ | PROT_WRITE, CACHE_INH },
#if 0	/* mapped by the hardcoded BATC entries */
	{ AV400_UTILITY,AV400_UTILITY_SIZE,	PROT_READ | PROT_WRITE, CACHE_INH },
#endif
	{ 0, (vsize_t)-1, 0, 0 }
};

const struct vme_range vme_av400[] = {
	{ VME_A16,
	  AV400_VME16_START,	AV400_VME16_END,	AV400_VME16_BASE },
	{ VME_A24,
	  AV400_VME24_START,	AV400_VME24_END,	AV400_VME24_BASE },
	{ VME_A32,
	  AV400_VME32_START1,	AV400_VME32_END1,	AV400_VME32_BASE },
	{ VME_A32,
	  AV400_VME32_START2,	AV400_VME32_END2,	AV400_VME32_BASE },
	{ 0 }
};

const struct board board_av400 = {
	av400_bootstrap,
	av400_memsize,
	av400_startup,
	av400_get_boot_device,
	av400_intr,
	cio_init_clocks,
	av400_getipl,
	av400_setipl,
	av400_raiseipl,
#ifdef MULTIPROCESSOR
	NULL,	/* av400_send_ipi, */
	m88100_smp_setup,
#endif
	av400_intsrc,
	av400_exintsrc,
	av400_get_vme_ranges,

	av400_ptable
};

/*
 * The MVME188 interrupt arbiter has 25 orthogonal interrupt sources.
 * On the AViiON machines, there are even more interrupt sources in use,
 * but differences are minimal.
 * We fold this model in the 8-level spl model this port uses, enforcing
 * priorities manually with the interrupt masks.
 */

/*
 * Copy of the interrupt enable register for each CPU.
 * Note that, on the AV400 design, the interrupt enable registers are
 * write-only and read back as 0xffffffff.
 */
u_int32_t av400_int_mask_reg[] = { 0, 0, 0, 0 };

u_int av400_curspl[] = { IPL_HIGH, IPL_HIGH, IPL_HIGH, IPL_HIGH };

#ifdef MULTIPROCESSOR0
/*
 * Interrupts allowed on secondary processors.
 */
#define	SLAVE_MASK	0
#endif

/*
 * Figure out how much memory is available, by asking the PROM.
 */
vaddr_t
av400_memsize()
{
	vaddr_t memsize0, memsize1;

	memsize0 = scm_memsize(0);
	memsize1 = scm_memsize(1);

	/*
	 * What we got is the ``top of memory'', i.e. the largest addressable
	 * word address, ending in 0xffc. Round up to a multiple of a page.
	 */
	memsize0 = round_page(memsize0);
	memsize1 = round_page(memsize1);

	physmem = atop(memsize0);
	return (memsize1);
}

void
av400_startup()
{
}

u_int
av400_bootstrap()
{
	extern const struct cmmu_p cmmu8820x;
	extern u_char hostaddr[6];

	/*
	 * These are the fixed assignments on AV400 designs.
	 */
	cmmu = &cmmu8820x;
	m8820x_cmmu[0].cmmu_regs = (void *)AV400_CMMU_I0;
	m8820x_cmmu[1].cmmu_regs = (void *)AV400_CMMU_D0;
	m8820x_cmmu[2].cmmu_regs = (void *)AV400_CMMU_I1;
	m8820x_cmmu[3].cmmu_regs = (void *)AV400_CMMU_D1;
	m8820x_cmmu[4].cmmu_regs = (void *)AV400_CMMU_I2;
	m8820x_cmmu[5].cmmu_regs = (void *)AV400_CMMU_D2;
	m8820x_cmmu[6].cmmu_regs = (void *)AV400_CMMU_I3;
	m8820x_cmmu[7].cmmu_regs = (void *)AV400_CMMU_D3;

	/* clear and disable all interrupts */
	*(volatile u_int32_t *)AV_IENALL = 0;

	/*
	 * Get all the information we'll need later from the PROM, while
	 * we can still use it.
	 */
	scm_getenaddr(hostaddr);

	/*
	 * Return the delay const value to use (which matches the CPU speed).
	 */
	switch (cputyp) {
	case AVIION_300_310:
	case AVIION_400_4000:
	case AVIION_300C_310C:
	case AVIION_300CD_310CD:
	case AVIION_300D_310D:
	case AVIION_4300_16:
		return 16;
	case AVIION_410_4100:
	case AVIION_4300_20:
		return 20;
	default:
	case AVIION_4300_25:
		return 25;
	}
}

/*
 * Return the address of the boot device, providing the default boot device
 * if none is requested.
 */
paddr_t
av400_get_boot_device(uint32_t *name, u_int unit)
{
	/* default boot device is on-board insc() */
	if (*name == 0)
		*name = SCM_INSC;

	switch (*name) {
	case SCM_INEN:
		if (unit == 0)
			return AV400_LAN;
		break;
	case SCM_INSC:
		if (unit == 0)
			return AV400_SCSI;
		break;
	}

	return 0;
}

/*
 * Return the next ipl >= ``curlevel'' at which we can reenable interrupts
 * while keeping ``mask'' masked.
 */
u_int
av400_safe_level(u_int mask, u_int curlevel)
{
	int i;

#ifdef MULTIPROCESSOR0
	if (mask & AV400_CLOCK_IPI_MASK)
		curlevel = max(IPL_CLOCK, curlevel);
	mask &= ~(AV400_IPI_MASK | AV400_CLOCK_IPI_MASK);
#endif
	for (i = curlevel; i < NIPLS; i++)
		if ((int_mask_val[i] & mask) == 0)
			return i;

	return (NIPLS - 1);
}

u_int
av400_getipl(void)
{
	return av400_curspl[cpu_number()];
}

u_int
av400_setipl(u_int level)
{
	u_int32_t mask, curspl, psr;
	u_int cpu = cpu_number();

	psr = get_psr();
	set_psr(psr | PSR_IND);
	curspl = av400_curspl[cpu];

	mask = int_mask_val[level];
#ifdef MULTIPROCESSOR0
	if (cpu != master_cpu)
		mask &= SLAVE_MASK;
	mask |= AV400_SWI_IPI_MASK(cpu);
	if (level < IPL_CLOCK)
		mask |= AV400_SWI_CLOCK_IPI_MASK(cpu);
#endif

	av400_curspl[cpu] = level;
	*(u_int32_t *)AV_IEN(cpu) = av400_int_mask_reg[cpu] = mask;
	/*
	 * We do not flush the pipeline here, because interrupts are disabled,
	 * and set_psr() will synchronize the pipeline.
	 */
	set_psr(psr);

	return curspl;
}

u_int
av400_raiseipl(u_int level)
{
	u_int32_t mask, curspl, psr;
	u_int cpu = cpu_number();

	psr = get_psr();
	set_psr(psr | PSR_IND);
	curspl = av400_curspl[cpu];
	if (curspl < level) {
		mask = int_mask_val[level];
#ifdef MULTIPROCESSOR0
		if (cpu != master_cpu)
			mask &= SLAVE_MASK;
		mask |= AV400_SWI_IPI_MASK(cpu);
		if (level < IPL_CLOCK)
			mask |= AV400_SWI_CLOCK_IPI_MASK(cpu);
#endif

		av400_curspl[cpu] = level;
		*(u_int32_t *)AV_IEN(cpu) = av400_int_mask_reg[cpu] = mask;
	}
	/*
	 * We do not flush the pipeline here, because interrupts are disabled,
	 * and set_psr() will synchronize the pipeline.
	 */
	set_psr(psr);

	return curspl;
}

#ifdef MULTIPROCESSOR0

void
av400_send_ipi(int ipi, cpuid_t cpu)
{
	struct cpu_info *ci = &m88k_cpus[cpu];
	uint32_t bits = 0;

	if (ci->ci_ipi & ipi)
		return;

	atomic_setbits_int(&ci->ci_ipi, ipi);
	if (ipi & ~(CI_IPI_HARDCLOCK | CI_IPI_STATCLOCK))
		bits |= AV400_SWI_IPI_BIT(cpu);
	if (ipi & (CI_IPI_HARDCLOCK | CI_IPI_STATCLOCK))
		bits |= AV400_SWI_CLOCK_IPI_BIT(cpu);
	*(volatile u_int32_t *)AV400_SETSWI = bits;
}

/*
 * Process inter-processor interrupts.
 */

/*
 * Unmaskable IPIs - those are processed with interrupts disabled,
 * and no lock held.
 */
void
av400_ipi_handler(struct trapframe *eframe)
{
	struct cpu_info *ci = curcpu();
	int ipi = ci->ci_ipi & (CI_IPI_DDB | CI_IPI_NOTIFY);

	*(volatile u_int32_t *)AV400_CLRSWI = AV400_SWI_IPI_BIT(ci->ci_cpuid);
	atomic_clearbits_int(&ci->ci_ipi, ipi);

	if (ipi & CI_IPI_DDB) {
#ifdef DDB
		/*
		 * Another processor has entered DDB. Spin on the ddb lock
		 * until it is done.
		 */
		extern struct __mp_lock ddb_mp_lock;

		__mp_lock(&ddb_mp_lock);
		__mp_unlock(&ddb_mp_lock);

		/*
		 * If ddb is hoping to us, it's our turn to enter ddb now.
		 */
		if (ci->ci_cpuid == ddb_mp_nextcpu)
			Debugger();
#endif
	}
	if (ipi & CI_IPI_NOTIFY) {
		/* nothing to do */
	}
}

/*
 * Maskable IPIs
 */
void
av400_clock_ipi_handler(struct trapframe *eframe)
{
	struct cpu_info *ci = curcpu();
	int ipi = ci->ci_ipi & (CI_IPI_HARDCLOCK | CI_IPI_STATCLOCK);

	/* clear clock ipi interrupt */
	*(volatile u_int32_t *)AV400_CLRSWI =
	    AV400_SWI_CLOCK_IPI_BIT(ci->ci_cpuid);
	atomic_clearbits_int(&ci->ci_ipi, ipi);

	if (ipi & CI_IPI_HARDCLOCK)
		hardclock((struct clockframe *)eframe);
#if 0	/* no separate statclock yet */
	if (ipi & CI_IPI_STATCLOCK)
		statclock((struct clockframe *)eframe);
#endif
}

#endif

/*
 * Provide the interrupt masks for a given logical interrupt source.
 */
u_int32_t
av400_intsrc(int i)
{
	static const u_int32_t intsrc[] = {
		0,
		AV400_IRQ_ABORT,
		AV400_IRQ_ACF,
		AV400_IRQ_SF,
		AV400_IRQ_CIOI,
		AV400_IRQ_DI1,
		AV400_IRQ_DI2,
		AV400_IRQ_ECI,
		0,
		AV400_IRQ_SCI,
		AV400_IRQ_DTC,
		AV400_IRQ_VME1,
		AV400_IRQ_VME2,
		AV400_IRQ_VME3,
		AV400_IRQ_VME4,
		AV400_IRQ_VME5,
		AV400_IRQ_VME6,
		AV400_IRQ_VME7
	};

	return intsrc[i];
}

u_int32_t
av400_exintsrc(int i)
{
	return 0;
}

/*
 * Provide the interrupt source for a given interrupt status bit.
 */
static const u_int av400_obio_vec[32] = {
	0,			/* SWI0 */
	0,			/* SWI1 */
	0,
	0,
	INTSRC_VME(1),		/* VME1 */
	INTSRC_SCSI1,		/* SCI */
	INTSRC_VME(2),		/* VME2 */
	0,
	0,
	0,			/* DVB */
	INTSRC_VME(3),		/* VME3 */
	0,			/* DWP */
	INTSRC_VME(4),		/* VME4 */
	INTSRC_DMA,		/* DTC */
	INTSRC_VME(5),		/* VME5 */
	INTSRC_ETHERNET1,	/* ECI */
	INTSRC_DUART2,		/* DI2 */
	INTSRC_DUART1,		/* DI1 */
	0,			/* PPI */
	INTSRC_VME(6),		/* VME6 */
	INTSRC_SYSFAIL,		/* SF */
	INTSRC_CLOCK,		/* CIOI */
	0,			/* KBD */
	INTSRC_VME(7),		/* VME7 */
	0,			/* PAR */
	0,			/* VID */
	0,			/* ZBUF */
	0,
	0,
	0,			/* ARBTO */
	INTSRC_ACFAIL,		/* ACF */
	INTSRC_ABORT		/* ABORT */
};

/*
 * Device interrupt handler for AV400
 */

#define VME_VECTOR_MASK		0x1ff 	/* mask into VIACK register */
#define VME_BERR_MASK		0x100 	/* timeout during VME IACK cycle */

#define ISR_GET_CURRENT_MASK(cpu) \
	(*(volatile u_int *)AV_IST & av400_int_mask_reg[cpu])

void
av400_intr(struct trapframe *eframe)
{
	u_int cpu = cpu_number();
	u_int32_t cur_mask, ign_mask;
	u_int level, old_spl;
	struct intrhand *intr;
	intrhand_t *list;
	int ret, intbit;
	vaddr_t ivec;
	u_int intsrc, vec;
	int unmasked = 0;
	int warn;
#ifdef DIAGNOSTIC
	static int problems = 0;
#endif

	cur_mask = ISR_GET_CURRENT_MASK(cpu);
	ign_mask = 0;
	old_spl = eframe->tf_mask;

	if (cur_mask == 0) {
		/*
		 * Spurious interrupts - may be caused by debug output clearing
		 * DUART interrupts.
		 */
#ifdef MULTIPROCESSOR0
		if (cpu != master_cpu) {
			if (++problems >= 10) {
				printf("cpu%d: interrupt pin won't clear, "
				    "disabling processor\n", cpu);
				cpu_emergency_disable();
				/* NOTREACHED */
			}
		}
#endif
		flush_pipeline();
		goto out;
	}

	uvmexp.intrs++;

#ifdef MULTIPROCESSOR0
	/*
	 * Handle unmaskable IPIs immediately, so that we can reenable
	 * interrupts before further processing. We rely on the interrupt
	 * mask to make sure that if we get an IPI, it's really for us
	 * and no other processor.
	 */
	if (cur_mask & AV400_IPI_MASK) {
		av400_ipi_handler(eframe);
		cur_mask &= ~AV400_IPI_MASK;
		if (cur_mask == 0)
			goto out;
	}
#endif

	/*
	 * We want to service all interrupts marked in the IST register
	 * They are all valid because the mask would have prevented them
	 * from being generated otherwise.  We will service them in order of
	 * priority.
	 */
	for (;;) {
		cur_mask = ISR_GET_CURRENT_MASK(cpu);
#ifdef MULTIPROCESSOR0
		cur_mask &= ~AV400_IPI_MASK;
#endif
		if ((cur_mask & ~ign_mask) == 0)
			break;

		level = av400_safe_level(cur_mask, old_spl);
		av400_setipl(level);

		if (unmasked == 0) {
			set_psr(get_psr() & ~PSR_IND);
			unmasked = 1;
		}

#ifdef MULTIPROCESSOR0
		/*
		 * Handle pending maskable IPIs first.
		 */
		if (cur_mask & AV400_CLOCK_IPI_MASK) {
			av400_clock_ipi_handler(eframe);
			cur_mask &= ~AV400_CLOCK_IPI_MASK;
			if ((cur_mask & ~ign_mask) == 0)
				break;
		}
#endif

		/* find the first bit set in the current mask */
		warn = 0;
		intbit = ff1(cur_mask);
		intsrc = av400_obio_vec[intbit];

		if (intsrc == 0)
			panic("%s: unexpected interrupt source (bit %d), "
			    "level %d, mask 0x%b",
			    __func__, intbit, level,
			    cur_mask, AV400_IST_STRING);

		if (IS_VME_INTSRC(intsrc)) {
			level = VME_INTSRC_LEVEL(intsrc);
			ivec = AV400_VIRQLV + (level << 2);
			vec = *(volatile u_int32_t *)ivec & VME_VECTOR_MASK;
			if (vec & VME_BERR_MASK) {
				printf("%s: timeout getting VME "
				    "interrupt vector, "
				    "level %d, mask 0x%b\n",
				    __func__, level,
				    cur_mask, AV400_IST_STRING);
				ign_mask |= 1 << intbit;
				continue;
			}
			list = &vmeintr_handlers[vec];
		} else {
			list = &sysconintr_handlers[intsrc];
		}

		if (SLIST_EMPTY(list)) {
			warn = 1;
		} else {
			/*
			 * Walk through all interrupt handlers in the chain
			 * for the given vector, calling each handler in turn,
			 * until some handler returns a value != 0.
			 */
			ret = 0;
			SLIST_FOREACH(intr, list, ih_link) {
#ifdef MULTIPROCESSOR
				if (intr->ih_ipl < IPL_CLOCK)
					__mp_lock(&kernel_lock);
#endif
				if (ISSET(intr->ih_flags, INTR_WANTFRAME))
					ret = (*intr->ih_fn)((void *)eframe);
				else
					ret = (*intr->ih_fn)(intr->ih_arg);
#ifdef MULTIPROCESSOR
				if (intr->ih_ipl < IPL_CLOCK)
					__mp_unlock(&kernel_lock);
#endif
				if (ret != 0) {
					intr->ih_count.ec_count++;
					break;
				}
			}
			if (ret == 0)
				warn = 2;
		}

		if (warn != 0) {
			ign_mask |= 1 << intbit;

			if (IS_VME_INTSRC(intsrc))
				printf("%s: %s VME interrupt, "
				    "level %d, vec 0x%x, mask 0x%b\n",
				    __func__,
				    warn == 1 ? "spurious" : "unclaimed",
				    level, vec,
				    cur_mask, AV400_IST_STRING);
			else
				printf("%s: %s interrupt, "
				    "level %d, bit %d, mask 0x%b\n",
				    __func__,
				    warn == 1 ? "spurious" : "unclaimed",
				    level, intbit, cur_mask, AV400_IST_STRING);
		}
	}

#ifdef DIAGNOSTIC
	if (ign_mask != 0) {
		if (++problems >= 10)
			panic("%s: broken interrupt behaviour", __func__);
	} else
		problems = 0;
#endif

out:
	/*
	 * process any remaining data access exceptions before
	 * returning to assembler
	 */
	if (eframe->tf_dmt0 & DMT_VALID)
		m88100_trap(T_DATAFLT, eframe);

	/*
	 * Disable interrupts before returning to assembler, the spl will
	 * be restored later.
	 */
	set_psr(get_psr() | PSR_IND);
}

const struct vme_range *
av400_get_vme_ranges(void)
{
	/* no VME slots on models 100/200/300 */
	switch (cpuid) {
	case AVIION_300_310:
	case AVIION_300C_310C:
	case AVIION_300CD_310CD:
	case AVIION_300D_310D:
		return NULL;
	default:
		return vme_av400;
	}
}

license: unknown


code:
/*	$OpenBSD: av530_machdep.c,v 1.16 2015/05/18 04:06:37 miod Exp $	*/
/*
 * Copyright (c) 2006, 2007, 2010 Miodrag Vallat.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/errno.h>

#include <uvm/uvm_extern.h>

#include <machine/asm_macro.h>
#include <machine/board.h>
#include <machine/bus.h>
#include <machine/cmmu.h>
#include <machine/cpu.h>
#include <machine/pmap_table.h>
#include <machine/trap.h>

#include <machine/m88100.h>
#include <machine/m8820x.h>
#include <machine/avcommon.h>
#include <machine/av530.h>
#include <machine/prom.h>

#include <aviion/dev/sysconvar.h>
#include <aviion/dev/vmevar.h>

#ifdef MULTIPROCESSOR
#include <machine/db_machdep.h>
#endif

u_int	av530_safe_level(u_int, u_int, u_int);
void	av530_clock_ipi_handler(struct trapframe *);
void	av530_ipi_handler(struct trapframe *);

const struct pmap_table
av530_ptable[] = {
	{ AV530_PROM,	AV530_PROM_SIZE,	PROT_READ | PROT_WRITE, CACHE_INH },
#if 0	/* mapped by the hardcoded BATC entries */
	{ AV530_UTILITY,AV530_UTILITY_SIZE,	PROT_READ | PROT_WRITE, CACHE_INH },
#endif
	{ 0, (vsize_t)-1, 0, 0 }
};

const struct vme_range vme_av530[] = {
	{ VME_A16,
	  AV530_VME16_START,	AV530_VME16_END,	AV530_VME16_BASE },
	{ VME_A24,
	  AV530_VME24_START,	AV530_VME24_END,	AV530_VME24_BASE },
	{ VME_A32,
	  AV530_VME32_START1,	AV530_VME32_END1,	AV530_VME32_BASE },
	{ VME_A32,
	  AV530_VME32_START2,	AV530_VME32_END2,	AV530_VME32_BASE },
	{ 0 }
};

const struct board board_av530 = {
	av530_bootstrap,
	av530_memsize,
	av530_startup,
	av530_get_boot_device,
	av530_intr,
	rtc_init_clocks,
	av530_getipl,
	av530_setipl,
	av530_raiseipl,
#ifdef MULTIPROCESSOR
	av530_send_ipi,
	m88100_smp_setup,
#endif
	av530_intsrc,
	av530_exintsrc,
	av530_get_vme_ranges,

	av530_ptable
};

/*
 * The AViiON 530 machines have two interrupt arbiter for 32 orthognal
 * interrupt sources each.
 * We fold this model in the 8-level spl model this port uses, enforcing
 * priorities manually with the interrupt masks.
 */

/*
 * Copy of the interrupt enable registers for each CPU.
 */
u_int32_t av530_int_mask_reg[] = { 0, 0, 0, 0 };
u_int32_t av530_ext_int_mask_reg[] = { 0, 0, 0, 0 };

u_int av530_curspl[] = { IPL_HIGH, IPL_HIGH, IPL_HIGH, IPL_HIGH };

#ifdef MULTIPROCESSOR
/*
 * Interrupts allowed on secondary processors.
 */
#define	SLAVE_MASK	0
#define	SLAVE_EXMASK	0
#endif

/*
 * Figure out how much memory is available, by asking the PROM.
 */
vaddr_t
av530_memsize()
{
	vaddr_t memsize0, memsize1;

	memsize0 = scm_memsize(0);
	memsize1 = scm_memsize(1);

	/*
	 * What we got is the ``top of memory'', i.e. the largest addressable
	 * word address, ending in 0xffc. Round up to a multiple of a page.
	 */
	memsize0 = round_page(memsize0);
	memsize1 = round_page(memsize1);

	physmem = atop(memsize0);
	return (memsize1);
}

void
av530_startup()
{
}

u_int
av530_bootstrap()
{
	extern const struct cmmu_p cmmu8820x;
	uint32_t whoami;

	/*
	 * Set up CMMU addresses. We need to access the WHOAMI register
	 * early since addresses differ between the 6:1 and 2:1 designs.
	 */
	cmmu = &cmmu8820x;
	whoami = (*(volatile u_int32_t *)AV_WHOAMI & 0xf0) >> 4;
	switch (whoami) {
	default:	/* 2:1 systems */
		m8820x_cmmu[0].cmmu_regs = (void *)AV530_CMMU_I0;
		m8820x_cmmu[1].cmmu_regs = (void *)AV530_CMMU_D0;
		m8820x_cmmu[2].cmmu_regs = (void *)AV530_CMMU_I1;
		m8820x_cmmu[3].cmmu_regs = (void *)AV530_CMMU_D1;
		break;
	case 3:
	case 7:		/* 6:1 systems */
		m8820x_cmmu[0].cmmu_regs = (void *)AV530_CMMU6_I0;
		m8820x_cmmu[1].cmmu_regs = (void *)AV530_CMMU6_D0;
		m8820x_cmmu[2].cmmu_regs = (void *)AV530_CMMU6_I1;
		m8820x_cmmu[3].cmmu_regs = (void *)AV530_CMMU6_D1;
		m8820x_cmmu[4].cmmu_regs = (void *)AV530_CMMU6_I2;
		m8820x_cmmu[6].cmmu_regs = (void *)AV530_CMMU6_I3;

		m8820x_cmmu[8].cmmu_regs = (void *)AV530_CMMU6_I4;
		m8820x_cmmu[9].cmmu_regs = (void *)AV530_CMMU6_D2;
		m8820x_cmmu[10].cmmu_regs = (void *)AV530_CMMU6_I5;
		m8820x_cmmu[11].cmmu_regs = (void *)AV530_CMMU6_D3;
		m8820x_cmmu[12].cmmu_regs = (void *)AV530_CMMU6_I6;
		m8820x_cmmu[14].cmmu_regs = (void *)AV530_CMMU6_I7;
		break;
	}

	/* clear and disable all interrupts */
	*(volatile u_int32_t *)AV_IENALL = 0;
	*(volatile u_int32_t *)AV_EXIENALL = 0;

	/*
	 * Return the delay const value to use (which matches the CPU speed).
	 */
	return 33;
}

/*
 * Return the address of the boot device, providing the default boot device
 * if none is requested.
 */
paddr_t
av530_get_boot_device(uint32_t *name, u_int unit)
{
	/* default boot device is on-board ncsc() */
	if (*name == 0)
		*name = SCM_NCSC;

	switch (*name) {
	case SCM_DGEN:
		switch (unit) {
		case 0:
			return AV530_LAN1;
		case 1:
			return AV530_LAN2;
		}
		break;
	case SCM_NCSC:
		switch (unit) {
		case 0:
			return AV530_SCSI1;
		case 1:
			return AV530_SCSI2;
		}
		break;
	}

	return 0;
}

/*
 * Return the next ipl >= ``curlevel'' at which we can reenable interrupts
 * while keeping ``mask'' and ``exmask'' masked.
 */
u_int
av530_safe_level(u_int mask, u_int exmask, u_int curlevel)
{
	int i;

#ifdef MULTIPROCESSOR
	if (mask & AV530_CLOCK_IPI_MASK)
		curlevel = max(IPL_CLOCK, curlevel);
	mask &= ~(AV530_IPI_MASK | AV530_CLOCK_IPI_MASK);
#endif
	for (i = curlevel; i < NIPLS; i++)
		if ((int_mask_val[i] & mask) == 0 &&
		    (ext_int_mask_val[i] & exmask) == 0)
			return i;

	return (NIPLS - 1);
}

u_int
av530_getipl(void)
{
	return av530_curspl[cpu_number()];
}

u_int
av530_setipl(u_int level)
{
	u_int32_t mask, exmask, curspl, psr;
	u_int cpu = cpu_number();

	psr = get_psr();
	set_psr(psr | PSR_IND);
	curspl = av530_curspl[cpu];

	mask = int_mask_val[level];
	exmask = ext_int_mask_val[level];
#ifdef MULTIPROCESSOR
	if (cpu != master_cpu) {
		mask &= SLAVE_MASK;
		exmask &= SLAVE_EXMASK;
	}
	mask |= AV530_SWI_IPI_MASK(cpu);
	if (level < IPL_CLOCK)
		mask |= AV530_SWI_CLOCK_IPI_MASK(cpu);
#endif

	av530_curspl[cpu] = level;
	*(u_int32_t *)AV_IEN(cpu) = av530_int_mask_reg[cpu] = mask;
	*(u_int32_t *)AV_EXIEN(cpu) = av530_ext_int_mask_reg[cpu] = exmask;
	/*
	 * We do not flush the pipeline here, because interrupts are disabled,
	 * and set_psr() will synchronize the pipeline.
	 */
	set_psr(psr);

	return curspl;
}

u_int
av530_raiseipl(u_int level)
{
	u_int32_t mask, exmask, curspl, psr;
	u_int cpu = cpu_number();

	psr = get_psr();
	set_psr(psr | PSR_IND);
	curspl = av530_curspl[cpu];
	if (curspl < level) {
		mask = int_mask_val[level];
		exmask = ext_int_mask_val[level];
#ifdef MULTIPROCESSOR
		if (cpu != master_cpu) {
			mask &= SLAVE_MASK;
			exmask &= SLAVE_EXMASK;
		}
		mask |= AV530_SWI_IPI_MASK(cpu);
		if (level < IPL_CLOCK)
			mask |= AV530_SWI_CLOCK_IPI_MASK(cpu);
#endif

		av530_curspl[cpu] = level;
		*(u_int32_t *)AV_IEN(cpu) = av530_int_mask_reg[cpu] = mask;
		*(u_int32_t *)AV_EXIEN(cpu) =
		    av530_ext_int_mask_reg[cpu] = exmask;
	}
	/*
	 * We do not flush the pipeline here, because interrupts are disabled,
	 * and set_psr() will synchronize the pipeline.
	 */
	set_psr(psr);

	return curspl;
}

#ifdef MULTIPROCESSOR

void
av530_send_ipi(int ipi, cpuid_t cpu)
{
	struct cpu_info *ci = &m88k_cpus[cpu];
	uint32_t bits = 0;

	if (ci->ci_ipi & ipi)
		return;

	atomic_setbits_int(&ci->ci_ipi, ipi);
	if (ipi & ~(CI_IPI_HARDCLOCK | CI_IPI_STATCLOCK))
		bits |= AV530_SWI_IPI_BIT(cpu);
	if (ipi & (CI_IPI_HARDCLOCK | CI_IPI_STATCLOCK))
		bits |= AV530_SWI_CLOCK_IPI_BIT(cpu);
	*(volatile u_int32_t *)AV530_SETSWI = bits;
}

/*
 * Process inter-processor interrupts.
 */

/*
 * Unmaskable IPIs - those are processed with interrupts disabled,
 * and no lock held.
 */
void
av530_ipi_handler(struct trapframe *eframe)
{
	struct cpu_info *ci = curcpu();
	int ipi = ci->ci_ipi & (CI_IPI_DDB | CI_IPI_NOTIFY);

	*(volatile u_int32_t *)AV530_CLRSWI = AV530_SWI_IPI_BIT(ci->ci_cpuid);
	atomic_clearbits_int(&ci->ci_ipi, ipi);

	if (ipi & CI_IPI_DDB) {
#ifdef DDB
		/*
		 * Another processor has entered DDB. Spin on the ddb lock
		 * until it is done.
		 */
		extern struct __mp_lock ddb_mp_lock;

		__mp_lock(&ddb_mp_lock);
		__mp_unlock(&ddb_mp_lock);

		/*
		 * If ddb is hoping to us, it's our turn to enter ddb now.
		 */
		if (ci->ci_cpuid == ddb_mp_nextcpu)
			Debugger();
#endif
	}
	if (ipi & CI_IPI_NOTIFY) {
		/* nothing to do */
	}
}

/*
 * Maskable IPIs
 */
void
av530_clock_ipi_handler(struct trapframe *eframe)
{
	struct cpu_info *ci = curcpu();
	int ipi = ci->ci_ipi & (CI_IPI_HARDCLOCK | CI_IPI_STATCLOCK);

	/* clear clock ipi interrupt */
	*(volatile u_int32_t *)AV530_CLRSWI =
	    AV530_SWI_CLOCK_IPI_BIT(ci->ci_cpuid);
	atomic_clearbits_int(&ci->ci_ipi, ipi);

	if (ipi & CI_IPI_HARDCLOCK)
		hardclock((struct clockframe *)eframe);
#if 0	/* no separate statclock yet */
	if (ipi & CI_IPI_STATCLOCK)
		statclock((struct clockframe *)eframe);
#endif
}

#endif

/*
 * Provide the interrupt masks for a given logical interrupt source.
 */
u_int32_t
av530_intsrc(int i)
{
	static const u_int32_t intsrc[] = {
		0,
		AV530_IRQ_ABORT,
		AV530_IRQ_ACF,
		AV530_IRQ_SF,
		0,
		AV530_IRQ_DI,
		0,
		0,
		0,
		0,
		0,
		0,
		AV530_IRQ_VME1,
		AV530_IRQ_VME2,
		AV530_IRQ_VME3,
		AV530_IRQ_VME4,
		AV530_IRQ_VME5,
		AV530_IRQ_VME6,
		AV530_IRQ_VME7
	};

	return intsrc[i];
}

u_int32_t
av530_exintsrc(int i)
{
	static const u_int32_t exintsrc[] = {
		0,
		0,
		0,
		0,
		AV530_EXIRQ_PIT0OF,
		0,
		AV530_EXIRQ_DUART2,
		AV530_EXIRQ_LAN0,
		AV530_EXIRQ_LAN1,
		AV530_EXIRQ_SCSI0,
		AV530_EXIRQ_SCSI1,
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0
	};

	return exintsrc[i];
}

/*
 * Provide the interrupt source for a given interrupt status bit.
 */
static const u_int av530_obio_vec[32] = {
	0,			/* SWI0 */
	0,			/* SWI1 */
	0,			/* SWI2 */
	0,			/* SWI3 */
	INTSRC_VME(1),		/* VME1 */
	0,
	INTSRC_VME(2),		/* VME2 */
	0,			/* SIGLPI */
	0,			/* LMI */
	0,
	INTSRC_VME(3),		/* VME3 */
	0,
	INTSRC_VME(4),		/* VME4 */
	0,
	INTSRC_VME(5),		/* VME5 */
	0,
	0,			/* HPI */
	INTSRC_DUART1,		/* DI */
	0,			/* MEM */
	INTSRC_VME(6),		/* VME6 */
	INTSRC_SYSFAIL,		/* SF */
	0,
	0,			/* KBD */
	INTSRC_VME(7),		/* VME7 */
	0,			/* SWI4 */
	0,			/* SWI5 */
	0,			/* SWI6 */
	0,			/* SWI7 */
	0,			/* DTI */
	0,			/* ARBTO */
	INTSRC_ACFAIL,		/* ACF */
	INTSRC_ABORT		/* ABORT */
};
static const u_int av530_obio_exvec[32] = {
	0,
	0,
	0,
	0,
	0,
	0,			/* PDMA */
	0,			/* IOEXP2 */
	0,
	0,			/* IOEXP1 */
	0,
	0,
	0,
	0,			/* VDMA */
	INTSRC_DUART2,		/* DUART2 */
	0,			/* ZBUF */
	0,			/* VIDEO */
	INTSRC_SCSI2,		/* SCSI1 */
	INTSRC_SCSI1,		/* SCSI0 */
	INTSRC_ETHERNET2,	/* LAN1 */
	INTSRC_ETHERNET1,	/* LAN0 */
	0,			/* SCC */
	0,			/* DMA0C */
	0,			/* DMA1C */
	0,			/* DMA2C */
	0,			/* DMA3C */
	0,			/* DMA4C */
	0,
	INTSRC_CLOCK,		/* PIT0OF */
	0,			/* PIT1OF */
	0,			/* PIT2OF */
	0,			/* PIT3OF */
	0			/* RTCOF */
};

/*
 * Device interrupt handler for AV530
 */

#define VME_VECTOR_MASK		0x1ff 	/* mask into VIACK register */
#define VME_BERR_MASK		0x100 	/* timeout during VME IACK cycle */

#define ISR_GET_CURRENT_MASK(cpu) \
	(*(volatile u_int *)AV_IST & av530_int_mask_reg[cpu])
#define EXISR_GET_CURRENT_MASK(cpu) \
	(*(volatile u_int *)AV_EXIST & av530_ext_int_mask_reg[cpu])

void
av530_intr(struct trapframe *eframe)
{
	int cpu = cpu_number();
	u_int32_t cur_mask, ign_mask;
	u_int32_t cur_exmask, ign_exmask;
	u_int level, old_spl;
	struct intrhand *intr;
	intrhand_t *list;
	int ret, intbit;
	vaddr_t ivec;
	u_int intsrc, vec;
	int unmasked = 0;
	int warn;
#ifdef DIAGNOSTIC
	static int problems = 0;
#endif

	cur_mask = ISR_GET_CURRENT_MASK(cpu);
	cur_exmask = EXISR_GET_CURRENT_MASK(cpu);
	ign_mask = 0;
	ign_exmask = 0;
	old_spl = eframe->tf_mask;

	if (cur_mask == 0 && cur_exmask == 0) {
		/*
		 * Spurious interrupts - may be caused by debug output clearing
		 * DUART interrupts.
		 */
#ifdef MULTIPROCESSOR
		if (cpu != master_cpu) {
			if (++problems >= 10) {
				printf("cpu%d: interrupt pin won't clear, "
				    "disabling processor\n", cpu);
				cpu_emergency_disable();
				/* NOTREACHED */
			}
		}
#endif
		flush_pipeline();
		goto out;
	}

	uvmexp.intrs++;

#ifdef MULTIPROCESSOR
	/*
	 * Handle unmaskable IPIs immediately, so that we can reenable
	 * interrupts before further processing. We rely on the interrupt
	 * mask to make sure that if we get an IPI, it's really for us
	 * and no other processor.
	 */
	if (cur_mask & AV530_IPI_MASK) {
		av530_ipi_handler(eframe);
		cur_mask &= ~AV530_IPI_MASK;
		if (cur_mask == 0 && cur_exmask == 0)
			goto out;
	}
#endif

	/*
	 * We want to service all interrupts marked in the IST register
	 * They are all valid because the mask would have prevented them
	 * from being generated otherwise.  We will service them in order of
	 * priority.
	 */
	for (;;) {
		cur_mask = ISR_GET_CURRENT_MASK(cpu);
#ifdef MULTIPROCESSOR
		cur_mask &= ~AV530_IPI_MASK;
#endif
		cur_exmask = EXISR_GET_CURRENT_MASK(cpu);
		if ((cur_mask & ~ign_mask) == 0 &&
		    (cur_exmask & ~ign_exmask) == 0)
			break;

		level = av530_safe_level(cur_mask, cur_exmask, old_spl);
		av530_setipl(level);

		if (unmasked == 0) {
			set_psr(get_psr() & ~PSR_IND);
			unmasked = 1;
		}

#ifdef MULTIPROCESSOR
		/*
		 * Handle pending maskable IPIs first.
		 */
		if (cur_mask & AV530_CLOCK_IPI_MASK) {
			av530_clock_ipi_handler(eframe);
			cur_mask &= ~AV530_CLOCK_IPI_MASK;
			if ((cur_mask & ~ign_mask) == 0 &&
			    (cur_exmask & ~ign_exmask) == 0)
				break;
		}
#endif

		/* find the first bit set in the current mask */
		warn = 0;
		if (cur_mask != 0) {
			intbit = ff1(cur_mask);
			intsrc = av530_obio_vec[intbit];

			if (intsrc == 0)
				panic("%s: unexpected interrupt source"
				    " (bit %d), level %d, mask 0x%b",
				    __func__, intbit, level,
				    cur_mask, AV530_IST_STRING);
		} else {
			intbit = ff1(cur_exmask);
			intsrc = av530_obio_exvec[intbit];

			if (intsrc == 0)
				panic("%s: unexpected extended interrupt source"
				    " (bit %d), level %d, mask 0x%b",
				    __func__, intbit, level,
				    cur_exmask, AV530_EXIST_STRING);
		}

		if (IS_VME_INTSRC(intsrc)) {
			level = VME_INTSRC_LEVEL(intsrc);
			ivec = AV530_VIRQLV + (level << 2);
			vec = *(volatile u_int32_t *)ivec & VME_VECTOR_MASK;
			if (vec & VME_BERR_MASK) {
				/* no need to dump exmask for vme intr */
				printf("%s: timeout getting VME "
				    "interrupt vector, "
				    "level %d, mask 0x%b\n",
				    __func__, level,
				    cur_mask, AV530_IST_STRING);
				ign_mask |= 1 << intbit;
				continue;
			}
			list = &vmeintr_handlers[vec];
		} else {
			list = &sysconintr_handlers[intsrc];
		}

		if (SLIST_EMPTY(list)) {
			warn = 1;
		} else {
			/*
			 * Walk through all interrupt handlers in the chain
			 * for the given vector, calling each handler in turn,
			 * until some handler returns a value != 0.
			 */
			ret = 0;
			SLIST_FOREACH(intr, list, ih_link) {
#ifdef MULTIPROCESSOR
				if (intr->ih_ipl < IPL_CLOCK)
					__mp_lock(&kernel_lock);
#endif
				if (ISSET(intr->ih_flags, INTR_WANTFRAME))
					ret = (*intr->ih_fn)((void *)eframe);
				else
					ret = (*intr->ih_fn)(intr->ih_arg);
#ifdef MULTIPROCESSOR
				if (intr->ih_ipl < IPL_CLOCK)
					__mp_unlock(&kernel_lock);
#endif
				if (ret != 0) {
					intr->ih_count.ec_count++;
					break;
				}
			}
			if (ret == 0)
				warn = 2;
		}

		if (warn != 0) {
			if (cur_mask != 0)
				ign_mask |= 1 << intbit;
			else
				ign_exmask |= 1 << intbit;

			if (IS_VME_INTSRC(intsrc))
				printf("%s: %s VME interrupt, "
				    "level %d, vec 0x%x, mask 0x%b\n",
				    __func__,
				    warn == 1 ? "spurious" : "unclaimed",
				    level, vec, cur_mask, AV530_IST_STRING);
			else {
				if (cur_mask != 0)
					printf("%s: %s interrupt, "
					    "level %d, bit %d, mask 0x%b\n",
					    __func__,
					    warn == 1 ?
					      "spurious" : "unclaimed",
					    level, intbit,
					    cur_mask, AV530_IST_STRING);
				else
					printf("%s: %s extended interrupt, "
					    "level %d, bit %d, mask 0x%b\n",
					    __func__,
					    warn == 1 ?
					      "spurious" : "unclaimed",
					    level, intbit,
					    cur_exmask, AV530_EXIST_STRING);
			}
		}
	}

#ifdef DIAGNOSTIC
	if (ign_mask != 0 || ign_exmask != 0) {
		if (++problems >= 10)
			panic("%s: broken interrupt behaviour", __func__);
	} else
		problems = 0;
#endif

out:
	/*
	 * process any remaining data access exceptions before
	 * returning to assembler
	 */
	if (eframe->tf_dmt0 & DMT_VALID)
		m88100_trap(T_DATAFLT, eframe);

	/*
	 * Disable interrupts before returning to assembler, the spl will
	 * be restored later.
	 */
	set_psr(get_psr() | PSR_IND);
}

const struct vme_range *
av530_get_vme_ranges()
{
	return vme_av530;
}


code:
/*      $OpenBSD: bus_dma.c,v 1.10 2014/12/24 22:48:27 miod Exp $	*/
/*      $NetBSD: bus_dma.c,v 1.2 2001/06/10 02:31:25 briggs Exp $        */

/*-
 * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
 * NASA Ames Research Center.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/proc.h>
#include <sys/extent.h>
#include <sys/buf.h>
#include <sys/device.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/file.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/mount.h>

#include <uvm/uvm_extern.h>

#include <machine/bus.h>
#include <machine/cmmu.h>
#include <machine/intr.h>

int     _bus_dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *,
	    bus_size_t, struct proc *, int, paddr_t *, int *, int);

int	_bus_dmamem_alloc_range(bus_dma_tag_t, bus_size_t, bus_size_t,
	    bus_size_t, bus_dma_segment_t *, int, int *, int, paddr_t, paddr_t);

/*
 * Common function for DMA map creation.  May be called by bus-specific
 * DMA map creation functions.
 */
int
bus_dmamap_create(t, size, nsegments, maxsegsz, boundary, flags, dmamp)
        bus_dma_tag_t t;
        bus_size_t size;
        int nsegments;
        bus_size_t maxsegsz;
        bus_size_t boundary;
        int flags;
        bus_dmamap_t *dmamp;
{
        struct m88k_bus_dmamap *map;
        void *mapstore;
        size_t mapsize;

        /*
         * Allocate and initialize the DMA map.  The end of the map
         * is a variable-sized array of segments, so we allocate enough
         * room for them in one shot.
         *
         * Note we don't preserve the WAITOK or NOWAIT flags.  Preservation
         * of ALLOCNOW notifies others that we've reserved these resources,
         * and they are not to be freed.
         *
         * The bus_dmamap_t includes one bus_dma_segment_t, hence
         * the (nsegments - 1).
         */
        mapsize = sizeof(struct m88k_bus_dmamap) +
            (sizeof(bus_dma_segment_t) * (nsegments - 1));
        if ((mapstore = malloc(mapsize, M_DEVBUF, (flags & BUS_DMA_NOWAIT) ?
	    (M_NOWAIT | M_ZERO) : (M_WAITOK | M_ZERO))) == NULL)
                return (ENOMEM);

        map = (struct m88k_bus_dmamap *)mapstore;
        map->_dm_size = size;
        map->_dm_segcnt = nsegments;
        map->_dm_maxsegsz = maxsegsz;
        map->_dm_boundary = boundary;
        map->dm_mapsize = 0;                /* no valid mappings */
        map->dm_nsegs = 0;

        *dmamp = map;
        return (0);
}

/*
 * Common function for DMA map destruction.  May be called by bus-specific
 * DMA map destruction functions.
 */
void
bus_dmamap_destroy(t, map)
        bus_dma_tag_t t;
        bus_dmamap_t map;
{
        size_t mapsize;

        mapsize = sizeof(struct m88k_bus_dmamap) +
            (sizeof(bus_dma_segment_t) * (map->_dm_segcnt - 1));
        free(map, M_DEVBUF, mapsize);
}

/*
 * Utility function to load a linear buffer.  lastaddrp holds state
 * between invocations (for multiple-buffer loads).  segp contains
 * the starting segment on entrance, and the ending segment on exit.
 * first indicates if this is the first invocation of this function.
 */
int
_bus_dmamap_load_buffer(t, map, buf, buflen, p, flags, lastaddrp, segp, first)
        bus_dma_tag_t t;
        bus_dmamap_t map;
        void *buf;
        bus_size_t buflen;
        struct proc *p;
        int flags;
        paddr_t *lastaddrp;
        int *segp;
        int first;
{
        bus_size_t sgsize;
        bus_addr_t curaddr, lastaddr, baddr, bmask;
        vaddr_t vaddr = (vaddr_t)buf;
        int seg;
	pmap_t pmap;

	if (p != NULL)
		pmap = vm_map_pmap(&p->p_vmspace->vm_map);
	else
		pmap = pmap_kernel();

        lastaddr = *lastaddrp;
        bmask = ~(map->_dm_boundary - 1);

        for (seg = *segp; buflen > 0 ; ) {
                /*
                 * Get the physical address for this segment.
                 */
		if (pmap_extract(pmap, vaddr, (paddr_t *)&curaddr) == FALSE)
			return (EINVAL);

                /*
                 * Compute the segment size, and adjust counts.
                 */
                sgsize = PAGE_SIZE - ((u_long)vaddr & PGOFSET);
                if (buflen < sgsize)
                        sgsize = buflen;

                /*
                 * Make sure we don't cross any boundaries.
                 */
                if (map->_dm_boundary > 0) {
                        baddr = (curaddr + map->_dm_boundary) & bmask;
                        if (sgsize > (baddr - curaddr))
                                sgsize = (baddr - curaddr);
                }

                /*
                 * Insert chunk into a segment, coalescing with
                 * the previous segment if possible.
                 */
                if (first) {
                        map->dm_segs[seg].ds_addr = curaddr;
                        map->dm_segs[seg].ds_len = sgsize;
                        first = 0;
                } else {
                        if (curaddr == lastaddr &&
                            (map->dm_segs[seg].ds_len + sgsize) <=
                             map->_dm_maxsegsz &&
                            (map->_dm_boundary == 0 ||
                             (map->dm_segs[seg].ds_addr & bmask) ==
                             (curaddr & bmask)))
                                map->dm_segs[seg].ds_len += sgsize;
                        else {
                                if (++seg >= map->_dm_segcnt)
                                        break;
                                map->dm_segs[seg].ds_addr = curaddr;
                                map->dm_segs[seg].ds_len = sgsize;
                        }
                }

                lastaddr = curaddr + sgsize;
                vaddr += sgsize;
                buflen -= sgsize;
        }

        *segp = seg;
        *lastaddrp = lastaddr;

        /*
         * Did we fit?
         */
        if (buflen != 0)
                return (EFBIG);                /* XXX better return value here? */

        return (0);
}

/*
 * Common function for loading a DMA map with a linear buffer.  May
 * be called by bus-specific DMA map load functions.
 */
int
bus_dmamap_load(t, map, buf, buflen, p, flags)
        bus_dma_tag_t t;
        bus_dmamap_t map;
        void *buf;
        bus_size_t buflen;
        struct proc *p;
        int flags;
{
        paddr_t lastaddr;
        int seg, error;

        /*
         * Make sure that on error condition we return "no valid mappings".
         */
        map->dm_mapsize = 0;
        map->dm_nsegs = 0;

        if (buflen > map->_dm_size)
                return (EINVAL);

        seg = 0;
        error = _bus_dmamap_load_buffer(t, map, buf, buflen, p, flags,
                &lastaddr, &seg, 1);
        if (error == 0) {
                map->dm_mapsize = buflen;
                map->dm_nsegs = seg + 1;
        }
        return (error);
}

/*
 * Like _bus_dmamap_load(), but for mbufs.
 */
int
bus_dmamap_load_mbuf(t, map, m0, flags)
        bus_dma_tag_t t;
        bus_dmamap_t map;
        struct mbuf *m0;
        int flags;
{
        paddr_t lastaddr;
        int seg, error, first;
        struct mbuf *m;

        /*
         * Make sure that on error condition we return "no valid mappings."
         */
        map->dm_mapsize = 0;
        map->dm_nsegs = 0;

#ifdef DIAGNOSTIC
        if ((m0->m_flags & M_PKTHDR) == 0)
                panic("bus_dmamap_load_mbuf: no packet header");
#endif

        if (m0->m_pkthdr.len > map->_dm_size)
                return (EINVAL);

        first = 1;
        seg = 0;
        error = 0;
        for (m = m0; m != NULL && error == 0; m = m->m_next) {
		if (m->m_len == 0)
			continue;
                error = _bus_dmamap_load_buffer(t, map, m->m_data, m->m_len,
                    NULL, flags, &lastaddr, &seg, first);
                first = 0;
        }
        if (error == 0) {
                map->dm_mapsize = m0->m_pkthdr.len;
                map->dm_nsegs = seg + 1;
        }
        return (error);
}

/*
 * Like _bus_dmamap_load(), but for uios.
 */
int
bus_dmamap_load_uio(t, map, uio, flags)
        bus_dma_tag_t t;
        bus_dmamap_t map;
        struct uio *uio;
        int flags;
{
        paddr_t lastaddr;
        int seg, i, error, first;
        bus_size_t minlen, resid;
        struct proc *p = NULL;
        struct iovec *iov;
        caddr_t addr;

        /*
         * Make sure that on error condition we return "no valid mappings."
         */
        map->dm_mapsize = 0;
        map->dm_nsegs = 0;

        resid = uio->uio_resid;
        iov = uio->uio_iov;

	if (resid > map->_dm_size)
		return (EINVAL);

        if (uio->uio_segflg == UIO_USERSPACE) {
                p = uio->uio_procp;
#ifdef DIAGNOSTIC
                if (p == NULL)
                        panic("bus_dmamap_load_uio: USERSPACE but no proc");
#endif
        }

        first = 1;
        seg = 0;
        error = 0;
        for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0; i++) {
                /*
                 * Now at the first iovec to load.  Load each iovec
                 * until we have exhausted the residual count.
                 */
                minlen = resid < iov[i].iov_len ? resid : iov[i].iov_len;
                addr = (caddr_t)iov[i].iov_base;

                error = _bus_dmamap_load_buffer(t, map, addr, minlen,
                    p, flags, &lastaddr, &seg, first);
                first = 0;

                resid -= minlen;
        }
        if (error == 0) {
                map->dm_mapsize = uio->uio_resid;
                map->dm_nsegs = seg + 1;
        }
        return (error);
}

/*
 * Like bus_dmamap_load(), but for raw memory allocated with
 * bus_dmamem_alloc().
 */
int
bus_dmamap_load_raw(t, map, segs, nsegs, size, flags)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	bus_dma_segment_t *segs;
	int nsegs;
	bus_size_t size;
	int flags;
{
	if (nsegs > map->_dm_segcnt || size > map->_dm_size)
		return (EINVAL);

	/*
	 * Make sure we don't cross any boundaries.
	 */
	if (map->_dm_boundary) {
		bus_addr_t bmask = ~(map->_dm_boundary - 1);
		int i;

		for (i = 0; i < nsegs; i++) {
			if (segs[i].ds_len > map->_dm_maxsegsz)
				return (EINVAL);
			if ((segs[i].ds_addr & bmask) !=
			    ((segs[i].ds_addr + segs[i].ds_len - 1) & bmask))
				return (EINVAL);
		}
	}

	bcopy(segs, map->dm_segs, nsegs * sizeof(*segs));
	map->dm_nsegs = nsegs;
	return (0);
}

/*
 * Common function for unloading a DMA map.  May be called by
 * chipset-specific DMA map unload functions.
 */
void
bus_dmamap_unload(t, map)
        bus_dma_tag_t t;
        bus_dmamap_t map;
{

        /*
         * No resources to free; just mark the mappings as
         * invalid.
         */
        map->dm_mapsize = 0;
        map->dm_nsegs = 0;
}

/*
 * Common function for DMA map synchronization.  May be called
 * by chipset-specific DMA map synchronization functions.
 */

void
bus_dmamap_sync(t, map, offset, len, op)
        bus_dma_tag_t t;
        bus_dmamap_t map;
	bus_addr_t offset;
	bus_size_t len;
	int op;
{
	u_int nsegs;
	bus_dma_segment_t *seg;

	if (op & BUS_DMASYNC_PREREAD)
		op = DMA_CACHE_SYNC_INVAL;
	else if (op & BUS_DMASYNC_PREWRITE)
		op = DMA_CACHE_SYNC;
	else if (op & BUS_DMASYNC_POSTREAD)
		op = DMA_CACHE_INV;
	else
		return;

	nsegs = map->dm_nsegs;
	seg = map->dm_segs;
	while (nsegs != 0 && len != 0) {
		if (offset >= seg->ds_len) {
			offset -= seg->ds_len;
		} else {
			bus_addr_t addr;
			bus_size_t sublen;

			addr = seg->ds_addr + offset;
			sublen = seg->ds_len - offset;
			if (sublen > len)
				sublen = len;

			dma_cachectl(addr, sublen, op);

			offset = 0;
			len -= sublen;
		}
		seg++;
		nsegs--;
	}
}

/*
 * Common function for DMA-safe memory allocation.  May be called
 * by bus-specific DMA memory allocation functions.
 */
int
bus_dmamem_alloc(t, size, alignment, boundary, segs, nsegs, rsegs, flags)
        bus_dma_tag_t t;
        bus_size_t size, alignment, boundary;
        bus_dma_segment_t *segs;
        int nsegs;
        int *rsegs;
        int flags;
{
        return _bus_dmamem_alloc_range(t, size, alignment, boundary, segs,
            nsegs, rsegs, flags, 0, -1);
}

/*
 * Common function for freeing DMA-safe memory.  May be called by
 * bus-specific DMA memory free functions.
 */
void
bus_dmamem_free(t, segs, nsegs)
        bus_dma_tag_t t;
        bus_dma_segment_t *segs;
        int nsegs;
{
        struct vm_page *m;
        bus_addr_t addr;
        struct pglist mlist;
        int curseg;

        /*
         * Build a list of pages to free back to the VM system.
         */
        TAILQ_INIT(&mlist);
        for (curseg = 0; curseg < nsegs; curseg++) {
                for (addr = segs[curseg].ds_addr;
                    addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
                    addr += PAGE_SIZE) {
                        m = PHYS_TO_VM_PAGE(addr);
                        TAILQ_INSERT_TAIL(&mlist, m, pageq);
                }
        }

        uvm_pglistfree(&mlist);
}

/*
 * Common function for mapping DMA-safe memory.  May be called by
 * bus-specific DMA memory map functions.
 */
int
bus_dmamem_map(t, segs, nsegs, size, kvap, flags)
        bus_dma_tag_t t;
        bus_dma_segment_t *segs;
        int nsegs;
        size_t size;
        caddr_t *kvap;
        int flags;
{
        vaddr_t va, sva;
        size_t ssize;
        bus_addr_t addr;
        int curseg, error;
	const struct kmem_dyn_mode *kd;

        size = round_page(size);
	kd = flags & BUS_DMA_NOWAIT ? &kd_trylock : &kd_waitok;
	va = (vaddr_t)km_alloc(size, &kv_any, &kp_none, kd);
        if (va == 0)
                return (ENOMEM);

        *kvap = (caddr_t)va;

	sva = va;
	ssize = size;
        for (curseg = 0; curseg < nsegs; curseg++) {
                for (addr = segs[curseg].ds_addr;
                    addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
                    addr += PAGE_SIZE, va += PAGE_SIZE, size -= PAGE_SIZE) {
                        if (size == 0)
                                panic("bus_dmamem_map: size botch");
                        error = pmap_enter(pmap_kernel(), va, addr,
                            PROT_READ | PROT_WRITE,
			    PROT_READ | PROT_WRITE | PMAP_WIRED | PMAP_CANFAIL);
			if (error) {
				pmap_update(pmap_kernel());
				km_free((void *)sva, ssize, &kv_any, &kp_none);
				return (error);
                        }
			if (flags & BUS_DMA_COHERENT)
				pmap_page_uncache(addr);
                }
        }
	pmap_update(pmap_kernel());

        return (0);
}

/*
 * Common function for unmapping DMA-safe memory.  May be called by
 * bus-specific DMA memory unmapping functions.
 */
void
bus_dmamem_unmap(t, kva, size)
        bus_dma_tag_t t;
        caddr_t kva;
        size_t size;
{

#ifdef DIAGNOSTIC
        if ((u_long)kva & PGOFSET)
                panic("bus_dmamem_unmap");
#endif

	km_free(kva, round_page(size), &kv_any, &kp_none);
}

/*
 * Common function for mmap(2)'ing DMA-safe memory.  May be called by
 * bus-specific DMA mmap(2)'ing functions.
 */
paddr_t
bus_dmamem_mmap(t, segs, nsegs, off, prot, flags)
        bus_dma_tag_t t;
        bus_dma_segment_t *segs;
        int nsegs;
        off_t off;
        int prot, flags;
{
        int i;

        for (i = 0; i < nsegs; i++) {
#ifdef DIAGNOSTIC
                if (off & PGOFSET)
                        panic("bus_dmamem_mmap: offset unaligned");
                if (segs[i].ds_addr & PGOFSET)
                        panic("bus_dmamem_mmap: segment unaligned");
                if (segs[i].ds_len & PGOFSET)
                        panic("bus_dmamem_mmap: segment size not multiple"
                            " of page size");
#endif
                if (off >= segs[i].ds_len) {
                        off -= segs[i].ds_len;
                        continue;
                }

                return (segs[i].ds_addr + off);
        }

        /* Page not found. */
        return (-1);
}

/*
 * Allocate physical memory from the given physical address range.
 * Called by DMA-safe memory allocation methods.
 */
int
_bus_dmamem_alloc_range(t, size, alignment, boundary, segs, nsegs, rsegs,
    flags, low, high)
        bus_dma_tag_t t;
        bus_size_t size, alignment, boundary;
        bus_dma_segment_t *segs;
        int nsegs;
        int *rsegs;
        int flags;
        paddr_t low;
        paddr_t high;
{
        paddr_t curaddr, lastaddr;
        struct vm_page *m;
        struct pglist mlist;
        int curseg, error, plaflag;

        /* Always round the size. */
        size = round_page(size);

        /*
         * Allocate pages from the VM system.
         */
	plaflag = flags & BUS_DMA_NOWAIT ? UVM_PLA_NOWAIT : UVM_PLA_WAITOK;
	if (flags & BUS_DMA_ZERO)
		plaflag |= UVM_PLA_ZERO;

        TAILQ_INIT(&mlist);
        error = uvm_pglistalloc(size, low, high, alignment, boundary,
            &mlist, nsegs, plaflag);
        if (error)
                return (error);

        /*
         * Compute the location, size, and number of segments actually
         * returned by the VM code.
         */
        m = TAILQ_FIRST(&mlist);
        curseg = 0;
        lastaddr = segs[curseg].ds_addr = VM_PAGE_TO_PHYS(m);
        segs[curseg].ds_len = PAGE_SIZE;
	m = TAILQ_NEXT(m, pageq);

	for (; m != NULL; m = TAILQ_NEXT(m, pageq)) {
                curaddr = VM_PAGE_TO_PHYS(m);
#ifdef DIAGNOSTIC
                if (curaddr < low || curaddr >= high) {
                        panic("_bus_dmamem_alloc_range: uvm_pglistalloc "
			    "returned non-sensical address 0x%lx\n", curaddr);
                }
#endif
                if (curaddr == (lastaddr + PAGE_SIZE))
                        segs[curseg].ds_len += PAGE_SIZE;
                else {
                        curseg++;
                        segs[curseg].ds_addr = curaddr;
                        segs[curseg].ds_len = PAGE_SIZE;
                }
                lastaddr = curaddr;
        }

        *rsegs = curseg + 1;

        return (0);
}


code:
/*	$OpenBSD: bus_space.c,v 1.1 2010/04/20 22:53:20 miod Exp $ */

/*
 * Copyright (c) 2001-2003 Opsycon AB  (www.opsycon.se / www.opsycon.com)
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

/*
 * Simple generic bus access primitives, for memory mapped space without
 * any access restriction or endianness conversion required.
 */

#include <sys/param.h>
#include <sys/systm.h>

#include <machine/bus.h>

uint8_t
generic_space_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
{
	return *(volatile uint8_t *)(h + o);
}

uint16_t
generic_space_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
{
	return *(volatile uint16_t *)(h + o);
}

uint32_t
generic_space_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
{
	return *(volatile uint32_t *)(h + o);
}

void
generic_space_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
    uint8_t v)
{
	*(volatile uint8_t *)(h + o) = v;
}

void
generic_space_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
    uint16_t v)
{
	*(volatile uint16_t *)(h + o) = v;
}

void
generic_space_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
    uint32_t v)
{
	*(volatile uint32_t *)(h + o) = v;
}

void
generic_space_read_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
    uint8_t *buf, bus_size_t len)
{
	volatile uint16_t *addr = (volatile uint16_t *)(h + o);
	len >>= 1;
	while (len-- != 0) {
		*(uint16_t *)buf = *addr;
		buf += 2;
	}
}

void
generic_space_write_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
    const uint8_t *buf, bus_size_t len)
{
	volatile uint16_t *addr = (volatile uint16_t *)(h + o);
	len >>= 1;
	while (len-- != 0) {
		*addr = *(uint16_t *)buf;
		buf += 2;
	}
}

void
generic_space_read_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
    uint8_t *buf, bus_size_t len)
{
	volatile uint32_t *addr = (volatile uint32_t *)(h + o);
	len >>= 2;
	while (len-- != 0) {
		*(uint32_t *)buf = *addr;
		buf += 4;
	}
}

void
generic_space_write_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
    const uint8_t *buf, bus_size_t len)
{
	volatile uint32_t *addr = (volatile uint32_t *)(h + o);
	len >>= 2;
	while (len-- != 0) {
		*addr = *(uint32_t *)buf;
		buf += 4;
	}
}


code:
/*	$OpenBSD: cio_clock.c,v 1.3 2010/04/24 18:46:51 miod Exp $	*/
/*
 * Copyright (c) 2006, 2007, 2009 Miodrag Vallat.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
/*
 * Copyright (c) 1998, 1999, 2000, 2001 Steve Murphree, Jr.
 * Copyright (c) 1996 Nivas Madhur
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Nivas Madhur.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
/*
 * Copyright (c) 1999 Steve Murphree, Jr.
 * Copyright (c) 1995 Theo de Raadt
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 * Copyright (c) 1995 Nivas Madhur
 * Copyright (c) 1994 Gordon W. Ross
 * Copyright (c) 1993 Adam Glass
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Lawrence Berkeley Laboratory.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)clock.c	8.1 (Berkeley) 6/11/93
 */
/*
 * Mach Operating System
 * Copyright (c) 1993-1991 Carnegie Mellon University
 * Copyright (c) 1991 OMRON Corporation
 * All Rights Reserved.
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/errno.h>
#include <sys/mutex.h>
#include <sys/timetc.h>

#include <uvm/uvm_extern.h>

#include <machine/asm_macro.h>
#include <machine/board.h>
#include <machine/avcommon.h>

#include <aviion/dev/sysconvar.h>
#include <dev/ic/z8536reg.h>

/*
 * Z8536 (CIO) Clock routines
 */

void	cio_clock_init(u_int);
u_int	read_cio(int);
void	write_cio(int, u_int);

struct intrhand	cio_clock_ih;

int	cio_clockintr(void *);
int	cio_calibrateintr(void *);
u_int	cio_get_timecount(struct timecounter *);

volatile int cio_calibrate_phase = 0;
extern u_int aviion_delay_const;

uint32_t	cio_step;
uint32_t	cio_refcnt;
uint32_t	cio_lastcnt;

struct mutex cio_mutex = MUTEX_INITIALIZER(IPL_CLOCK);

struct timecounter cio_timecounter = {
	.tc_get_timecount = cio_get_timecount,
	.tc_counter_mask = 0xffffffff,
	.tc_name = "cio",
	.tc_quality = 0
};

/*
 * Notes on the AV400 clock usage:
 *
 * Unlike the MVME188 design, we only have access to three counter/timers
 * in the Zilog Z8536 (since we can not receive the DUART timer interrupts).
 *
 * Clock is run on a Z8536 counter, kept in counter mode and retriggered
 * every interrupt (when using the Z8536 in timer mode, it _seems_ that it
 * resets at 0xffff instead of the initial count value...)
 *
 * It should be possible to run statclock on the Z8536 counter #2, but
 * this would make interrupt handling more tricky, in the case both
 * counters interrupt at the same time...
 */

void
cio_init_clocks(void)
{
	u_int iter, divisor;
	u_int32_t psr;

	psr = get_psr();
	set_psr(psr | PSR_IND);

#ifdef DIAGNOSTIC
	if (1000000 % hz) {
		printf("cannot get %d Hz clock; using 100 Hz\n", hz);
		hz = 100;
	}
#endif
	tick = 1000000 / hz;

	cio_clock_init(tick);

	profhz = stathz = 0;

	/*
	 * Calibrate delay const.
	 */
	cio_clock_ih.ih_fn = cio_calibrateintr;
	cio_clock_ih.ih_arg = 0;
	cio_clock_ih.ih_flags = INTR_WANTFRAME;
	cio_clock_ih.ih_ipl = IPL_CLOCK;
	sysconintr_establish(INTSRC_CLOCK, &cio_clock_ih, "clock");

	aviion_delay_const = 1;
	set_psr(psr);
	while (cio_calibrate_phase == 0)
		;

	iter = 0;
	while (cio_calibrate_phase == 1) {
		delay(10000);
		iter++;
	}

	divisor = 1000000 / 10000;
	aviion_delay_const = (iter * hz + divisor - 1) / divisor;

	set_psr(psr | PSR_IND);

	sysconintr_disestablish(INTSRC_CLOCK, &cio_clock_ih);
	cio_clock_ih.ih_fn = cio_clockintr;
	sysconintr_establish(INTSRC_CLOCK, &cio_clock_ih, "clock");

	set_psr(psr);

	tc_init(&cio_timecounter);
}

int
cio_calibrateintr(void *eframe)
{
	/* no need to grab the mutex, only one processor is running for now */
	/* ack the interrupt */
	write_cio(ZCIO_CT1CS, ZCIO_CTCS_GCB | ZCIO_CTCS_C_IP);

	cio_calibrate_phase++;

	return (1);
}

int
cio_clockintr(void *eframe)
{
	mtx_enter(&cio_mutex);
	/* ack the interrupt */
	write_cio(ZCIO_CT1CS, ZCIO_CTCS_GCB | ZCIO_CTCS_C_IP);
	cio_refcnt += cio_step;
	mtx_leave(&cio_mutex);

	hardclock(eframe);

#ifdef MULTIPROCESSOR
	/*
	 * Send an IPI to all other processors, so they can get their
	 * own ticks.
	 */
	m88k_broadcast_ipi(CI_IPI_HARDCLOCK);
#endif

	return (1);
}

/* Write CIO register */
void
write_cio(int reg, u_int val)
{
	volatile int i;
	volatile u_int32_t * cio_ctrl = (volatile u_int32_t *)CIO_CTRL;

	i = *cio_ctrl;				/* goto state 1 */
	*cio_ctrl = 0;				/* take CIO out of RESET */
	i = *cio_ctrl;				/* reset CIO state machine */

	*cio_ctrl = (reg & 0xff);		/* select register */
	*cio_ctrl = (val & 0xff);		/* write the value */
}

/* Read CIO register */
u_int
read_cio(int reg)
{
	int c;
	volatile int i;
	volatile u_int32_t * cio_ctrl = (volatile u_int32_t *)CIO_CTRL;

	/* select register */
	*cio_ctrl = (reg & 0xff);
	/* delay for a short time to allow 8536 to settle */
	for (i = 0; i < 100; i++)
		;
	/* read the value */
	c = *cio_ctrl;
	return (c & 0xff);
}

/*
 * Initialize the CTC (8536)
 * Only the counter/timers are used - the IO ports are un-comitted.
 */
void
cio_clock_init(u_int period)
{
	volatile int i;

	/* Start by forcing chip into known state */
	read_cio(ZCIO_MIC);
	write_cio(ZCIO_MIC, ZCIO_MIC_RESET);	/* Reset the CTC */
	for (i = 0; i < 1000; i++)	 	/* Loop to delay */
		;

	/* Clear reset and start init seq. */
	write_cio(ZCIO_MIC, 0x00);

	/* Wait for chip to come ready */
	while ((read_cio(ZCIO_MIC) & ZCIO_MIC_RJA) == 0)
		;

	/* Initialize the 8536 for real */
	write_cio(ZCIO_MIC,
	    ZCIO_MIC_MIE /* | ZCIO_MIC_NV */ | ZCIO_MIC_RJA | ZCIO_MIC_DLC);
	write_cio(ZCIO_CT1MD, ZCIO_CTMD_CSC);	/* Continuous count */
	write_cio(ZCIO_PBDIR, 0xff);		/* set port B to input */

	period <<= 1;	/* CT#1 runs at PCLK/2, hence 2MHz */
	write_cio(ZCIO_CT1TCM, period >> 8);
	write_cio(ZCIO_CT1TCL, period);
	/* enable counter #1 */
	write_cio(ZCIO_MCC, ZCIO_MCC_CT1E | ZCIO_MCC_PBE);
	write_cio(ZCIO_CT1CS, ZCIO_CTCS_GCB | ZCIO_CTCS_TCB | ZCIO_CTCS_S_IE);

	cio_step = period;
	cio_timecounter.tc_frequency = (uint64_t)cio_step * hz;
}

u_int
cio_get_timecount(struct timecounter *tc)
{
	u_int cmsb, clsb, counter, curcnt;

	/*
	 * The CIO counter is free running, but by setting the
	 * RCC bit in its control register, we can read a frozen
	 * value of the counter.
	 * The counter will automatically unfreeze after reading
	 * its LSB.
	 */

	mtx_enter(&cio_mutex);
	write_cio(ZCIO_CT1CS, ZCIO_CTCS_GCB | ZCIO_CTCS_RCC);
	cmsb = read_cio(ZCIO_CT1CCM);
	clsb = read_cio(ZCIO_CT1CCL);
	curcnt = cio_refcnt;

	counter = (cmsb << 8) | clsb;
#if 0	/* this will never happen unless the period itself is 65536 */
	if (counter == 0)
		counter = 65536;
#endif

	/*
	 * The counter counts down from its initialization value to 1.
	 */
	counter = cio_step - counter;

	curcnt += counter;
	if (curcnt < cio_lastcnt)
		curcnt += cio_step;

	cio_lastcnt = curcnt;
	mtx_leave(&cio_mutex);
	return curcnt;
}


code:
/*	$OpenBSD: conf.c,v 1.19 2014/10/09 04:10:03 tedu Exp $	*/

/*-
 * Copyright (c) 1991 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *      @(#)conf.c	7.9 (Berkeley) 5/28/91
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
#include <sys/vnode.h>

#include <machine/conf.h>

#include "bpfilter.h"
#include "cd.h"
#include "ch.h"
#include "dart.h"
#include "ksyms.h"
#include "nvram.h"
#include "pf.h"
#include "bio.h"
#include "pty.h"
#include "rd.h"
#include "sd.h"
#include "st.h"
#include "systrace.h"
#include "tun.h"
#include "uk.h"
#include "vme.h"
#include "vnd.h"
#include "vscsi.h"
#include "pppx.h"
#include "fuse.h"

struct bdevsw	bdevsw[] =
{
	bdev_notdef(),			/* 0 */
	bdev_notdef(),			/* 1 */
	bdev_notdef(),			/* 2 */
	bdev_swap_init(1,sw),		/* 3: swap pseudo-device */
	bdev_disk_init(NSD,sd),		/* 4: SCSI disk */
	bdev_tape_init(NST,st),		/* 5: SCSI tape */
	bdev_disk_init(NCD,cd),		/* 6: SCSI CD-ROM */
	bdev_disk_init(NRD,rd),		/* 7: ramdisk */
	bdev_disk_init(NVND,vnd),	/* 8: vnode disk driver */
	bdev_notdef(),			/* 9: was: concatenated disk driver */
	bdev_notdef(),			/* 10 */
	bdev_notdef(),			/* 11 */
	bdev_notdef(),			/* 12 */
	bdev_notdef(),			/* 13 */
	bdev_notdef(),			/* 14 */
	bdev_notdef(),			/* 15 */
	bdev_notdef(),			/* 16 */
	bdev_notdef(),			/* 17 */
	bdev_notdef(),			/* 18 */
};
int	nblkdev = nitems(bdevsw);

struct cdevsw	cdevsw[] =
{
	cdev_cn_init(1,cn),		/* 0: virtual console */
	cdev_ctty_init(1,ctty),		/* 1: controlling terminal */
	cdev_mm_init(1,mm),		/* 2: /dev/{null,mem,kmem,...} */
	cdev_notdef(),			/* 3 was /dev/drum */
	cdev_tty_init(NPTY,pts),	/* 4: pseudo-tty slave */
	cdev_ptc_init(NPTY,ptc),	/* 5: pseudo-tty master */
	cdev_log_init(1,log),		/* 6: /dev/klog */
	cdev_notdef(),			/* 7 */
	cdev_disk_init(NSD,sd),		/* 8: SCSI disk */
	cdev_disk_init(NCD,cd),		/* 9: SCSI CD-ROM */
	cdev_mm_init(NNVRAM,nvram),	/* 10: /dev/nvramX */
	cdev_notdef(),			/* 11: */
	cdev_tty_init(NDART,dart),	/* 12: on-board serial (tty[ab]) */
	cdev_notdef(),			/* 13 */
	cdev_notdef(),			/* 14 */
	cdev_notdef(),			/* 15 */
	cdev_notdef(),			/* 16 */
	cdev_notdef(),			/* 17: was: concatenated disk */
	cdev_disk_init(NRD,rd),		/* 18: ramdisk disk */
	cdev_disk_init(NVND,vnd),	/* 19: vnode disk */
	cdev_tape_init(NST,st),		/* 20: SCSI tape */
	cdev_fd_init(1,filedesc),	/* 21: file descriptor pseudo-dev */
	cdev_bpf_init(NBPFILTER,bpf),	/* 22: berkeley packet filter */
	cdev_tun_init(NTUN,tun),	/* 23: network tunnel */
	cdev_notdef(),			/* 24 was LKM */
	cdev_notdef(),			/* 25 */
	cdev_notdef(),			/* 26: XD disk */
	cdev_notdef(),			/* 27 */
	cdev_notdef(),			/* 28: lp */
	cdev_notdef(),			/* 29: lptwo */
	cdev_mm_init(NVME,vme),		/* 30: /dev/vme* */
	cdev_notdef(),			/* 31: old /dev/vmelX */
	cdev_notdef(),			/* 32: old /dev/vmesX */
	cdev_notdef(),			/* 33 */
	cdev_notdef(),			/* 34 */
	cdev_notdef(),			/* 35 */
	cdev_notdef(),			/* 36 */
	cdev_notdef(),			/* 37 */
	cdev_notdef(),			/* 38 */
	cdev_pf_init(NPF,pf),		/* 39: packet filter */
	cdev_random_init(1,random),	/* 40: random data source */
	cdev_uk_init(NUK,uk),		/* 41 */
	cdev_notdef(),			/* 42 */
	cdev_ksyms_init(NKSYMS,ksyms),	/* 43: Kernel symbols device */
	cdev_ch_init(NCH,ch),		/* 44: SCSI autochanger */
	cdev_fuse_init(NFUSE,fuse),	/* 45: fuse */
	cdev_notdef(),			/* 46 */
	cdev_notdef(),			/* 47 */
	cdev_notdef(),			/* 48 */
	cdev_bio_init(NBIO,bio),	/* 49: ioctl tunnel */
	cdev_systrace_init(NSYSTRACE,systrace),	/* 50 system call tracing */
	cdev_notdef(),			/* 51 */
	cdev_ptm_init(NPTY,ptm),	/* 52: pseudo-tty ptm device */
	cdev_vscsi_init(NVSCSI,vscsi),	/* 53: vscsi */
	cdev_disk_init(1,diskmap),	/* 54: disk mapper */
	cdev_pppx_init(NPPPX,pppx),	/* 55: pppx */
};
int	nchrdev = nitems(cdevsw);

int	mem_no = 2;	/* major device number of memory special file */

/*
 * Swapdev is a fake device implemented
 * in sw.c used only internally to get to swstrategy.
 * It cannot be provided to the users, because the
 * swstrategy routine munches the b_dev and b_blkno entries
 * before calling the appropriate driver.  This would horribly
 * confuse, e.g. the hashing routines. Instead, /dev/drum is
 * provided as a character (raw) device.
 */
dev_t	swapdev = makedev(3, 0);

/*
 * Returns true if dev is /dev/mem or /dev/kmem.
 */
int
iskmemdev(dev)
	dev_t dev;
{

	return (major(dev) == mem_no && minor(dev) < 2);
}

/*
 * Returns true if dev is /dev/zero.
 */
int
iszerodev(dev)
	dev_t dev;
{

	return (major(dev) == mem_no && minor(dev) == 12);
}

dev_t
getnulldev()
{
	return makedev(mem_no, 2);
}

int chrtoblktbl[] = {
	/*VCHR*/	/*VBLK*/
	/*  0 */	NODEV,
	/*  1 */	NODEV,
	/*  2 */	NODEV,
	/*  3 */	NODEV,
	/*  4 */	NODEV,
	/*  5 */	NODEV,
	/*  6 */	NODEV,
	/*  7 */	NODEV,
	/*  8 */	4,	/* sd */
	/*  9 */	6,	/* cd */
	/* 10 */	NODEV,
	/* 11 */	NODEV,
	/* 12 */	NODEV,
	/* 13 */	NODEV,
	/* 14 */	NODEV,
	/* 15 */	NODEV,
	/* 16 */	NODEV,
	/* 17 */	NODEV,
	/* 18 */	7,	/* rd */
	/* 19 */	8,	/* vnd */
	/* 20 */	5,	/* st */
};
int nchrtoblktbl = nitems(chrtoblktbl);

#include <dev/cons.h>

#define dartcnpollc	nullcnpollc
cons_decl(dart);

struct	consdev constab[] = {
#if NDART > 0
	cons_init(dart),
#endif
	{ 0 },
};


code:
/*	$OpenBSD: db_machdep.c,v 1.1.1.1 2006/05/09 18:08:53 miod Exp $	*/
/*
 * Mach Operating System
 * Copyright (c) 1993-1991 Carnegie Mellon University
 * Copyright (c) 1991 OMRON Corporation
 * All Rights Reserved.
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */

/*
 * aviion-specific interface to ddb debugger
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>

#include <machine/cpu.h>
#include <machine/db_machdep.h>

void
m88k_db_prom_cmd(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	doboot();
}