xref: /onnv-gate/usr/src/uts/sun4u/io/zuluvm.c (revision 2973:55b674bffad9)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*2973Sgovinda  * Common Development and Distribution License (the "License").
6*2973Sgovinda  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*2973Sgovinda  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * zuluvm module
300Sstevel@tonic-gate  *
310Sstevel@tonic-gate  * Provides services required by the XVR-4000 graphics accelerator (zulu)
320Sstevel@tonic-gate  * that are not provided by the ddi. See PSARC 2002/231.
330Sstevel@tonic-gate  *
340Sstevel@tonic-gate  * Zulu has 2 dma engines with built in MMUs. zuluvm provides TLB miss
350Sstevel@tonic-gate  * interrupt support obtaining virtual to physical address translations
360Sstevel@tonic-gate  * using the XHAT interface PSARC/2003/517.
370Sstevel@tonic-gate  *
380Sstevel@tonic-gate  * The module has 3 components. This file, sun4u/vm/zulu_hat.c, and the
390Sstevel@tonic-gate  * assembly language routines in sun4u/ml/zulu_asm.s and
400Sstevel@tonic-gate  * sun4u/ml/zulu_hat_asm.s.
410Sstevel@tonic-gate  *
420Sstevel@tonic-gate  * The interrupt handler is a data bearing mondo interrupt handled at TL=1
430Sstevel@tonic-gate  * If no translation is found in the zulu hat's tsb, or if the tsb is locked by
440Sstevel@tonic-gate  * C code, the handler posts a soft interrupt which wakes up a parked
450Sstevel@tonic-gate  * thread belonging to zuludaemon(1M).
460Sstevel@tonic-gate  */
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #include <sys/conf.h>
490Sstevel@tonic-gate #include <sys/types.h>
500Sstevel@tonic-gate #include <sys/kmem.h>
510Sstevel@tonic-gate #include <sys/debug.h>
520Sstevel@tonic-gate #include <sys/modctl.h>
530Sstevel@tonic-gate #include <sys/autoconf.h>
540Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
550Sstevel@tonic-gate #include <sys/ddi_subrdefs.h>
560Sstevel@tonic-gate #include <sys/intr.h>
570Sstevel@tonic-gate #include <sys/ddi.h>
580Sstevel@tonic-gate #include <sys/sunndi.h>
590Sstevel@tonic-gate #include <sys/proc.h>
600Sstevel@tonic-gate #include <sys/thread.h>
610Sstevel@tonic-gate #include <sys/machsystm.h>
620Sstevel@tonic-gate #include <sys/ivintr.h>
630Sstevel@tonic-gate #include <sys/tnf_probe.h>
640Sstevel@tonic-gate #include <sys/intreg.h>
650Sstevel@tonic-gate #include <sys/atomic.h>
660Sstevel@tonic-gate #include <vm/as.h>
670Sstevel@tonic-gate #include <vm/seg_enum.h>
680Sstevel@tonic-gate #include <vm/faultcode.h>
690Sstevel@tonic-gate #include <sys/dmv.h>
700Sstevel@tonic-gate #include <sys/zulumod.h>
710Sstevel@tonic-gate #include <sys/zulu_hat.h>
720Sstevel@tonic-gate 
730Sstevel@tonic-gate #define	ZULUVM_GET_PAGE(val) \
740Sstevel@tonic-gate 	(caddr_t)((uintptr_t)(val) & PAGEMASK)
750Sstevel@tonic-gate #define	ZULUVM_GET_AS	curthread->t_procp->p_as
760Sstevel@tonic-gate 
770Sstevel@tonic-gate #define	ZULUVM_LOCK   mutex_enter(&(zdev->dev_lck))
780Sstevel@tonic-gate #define	ZULUVM_UNLOCK mutex_exit(&(zdev->dev_lck))
790Sstevel@tonic-gate 
800Sstevel@tonic-gate #define	ZULUVM_SET_STATE(_z, b, c) \
810Sstevel@tonic-gate 	cas32((uint32_t *)&((_z)->zvm.state), c, b)
820Sstevel@tonic-gate #define	ZULUVM_GET_STATE(_z) \
830Sstevel@tonic-gate 	(_z)->zvm.state
840Sstevel@tonic-gate #define	ZULUVM_SET_IDLE(_z) \
850Sstevel@tonic-gate 	(_z)->zvm.state = ZULUVM_STATE_IDLE;
860Sstevel@tonic-gate 
870Sstevel@tonic-gate #define	ZULUVM_INO_MASK ((1<<INO_SIZE)-1)
880Sstevel@tonic-gate #define	ZULUVM_IGN_MASK ((1<<IGN_SIZE)-1)
890Sstevel@tonic-gate #define	ZULUVM_MONDO(_zdev, _n) \
900Sstevel@tonic-gate 	((ZULUVM_IGN_MASK & _zdev->agentid) << INO_SIZE) | \
910Sstevel@tonic-gate 	(ZULUVM_INO_MASK & (_n))
920Sstevel@tonic-gate 
930Sstevel@tonic-gate static void zuluvm_stop(zuluvm_state_t *, int, char *);
940Sstevel@tonic-gate static zuluvm_proc_t *zuluvm_find_proc(zuluvm_state_t *, struct as *);
950Sstevel@tonic-gate static int zuluvm_proc_release(zuluvm_state_t *zdev, zuluvm_proc_t *proc);
960Sstevel@tonic-gate static int zuluvm_get_intr_props(zuluvm_state_t *zdev, dev_info_t *devi);
970Sstevel@tonic-gate static int zuluvm_driver_attach(zuluvm_state_t *);
980Sstevel@tonic-gate static int zuluvm_driver_detach(zuluvm_state_t *);
990Sstevel@tonic-gate static void zuluvm_retarget_intr(void *arg);
1000Sstevel@tonic-gate static void zuluvm_do_retarget(zuluvm_state_t *zdev);
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate extern const unsigned int _mmu_pageshift;
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate extern int zuluvm_base_pgsize;
1050Sstevel@tonic-gate static int zuluvm_pagesizes[ZULUM_MAX_PG_SIZES + 1];
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate int zuluvm_fast_tlb = 1;
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate zuluvm_state_t *zuluvm_devtab[ZULUVM_MAX_DEV];
1100Sstevel@tonic-gate kmutex_t zuluvm_lck;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate #ifdef DEBUG
1130Sstevel@tonic-gate int zuluvm_debug_state = 0;
1140Sstevel@tonic-gate #endif
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate unsigned long zuluvm_ctx_locked = 0;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate /*
1190Sstevel@tonic-gate  * Module linkage information for the kernel.
1200Sstevel@tonic-gate  */
1210Sstevel@tonic-gate extern struct mod_ops mod_miscops;
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate static struct modlmisc modlmisc = {
1240Sstevel@tonic-gate 	&mod_miscops,
1250Sstevel@tonic-gate 	"sun4u support " ZULUVM_MOD_VERSION
1260Sstevel@tonic-gate };
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate static struct modlinkage modlinkage = {
1290Sstevel@tonic-gate 	MODREV_1,
1300Sstevel@tonic-gate 	(void *)&modlmisc,
1310Sstevel@tonic-gate 	NULL
1320Sstevel@tonic-gate };
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate int
_init(void)1350Sstevel@tonic-gate _init(void)
1360Sstevel@tonic-gate {
1370Sstevel@tonic-gate 	zuluvm_base_pgsize = (_mmu_pageshift - 13) / 3;
1380Sstevel@tonic-gate 	if (zulu_hat_init() != 0) {
1390Sstevel@tonic-gate 		return (ZULUVM_ERROR);
1400Sstevel@tonic-gate 	}
1410Sstevel@tonic-gate 	mutex_init(&zuluvm_lck, NULL, MUTEX_DEFAULT, NULL);
1420Sstevel@tonic-gate 	return (mod_install(&modlinkage));
1430Sstevel@tonic-gate }
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate int
_fini(void)1460Sstevel@tonic-gate _fini(void)
1470Sstevel@tonic-gate {
1480Sstevel@tonic-gate 	mutex_destroy(&zuluvm_lck);
1490Sstevel@tonic-gate 	(void) zulu_hat_destroy();
1500Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
1510Sstevel@tonic-gate }
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1540Sstevel@tonic-gate _info(struct modinfo *modinfop)
1550Sstevel@tonic-gate {
1560Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1570Sstevel@tonic-gate }
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate /*
1600Sstevel@tonic-gate  * currently the kernel driver makes the following assumptions:
1610Sstevel@tonic-gate  * - there is only one TLB miss per zulu device handled at
1620Sstevel@tonic-gate  *   any given time
1630Sstevel@tonic-gate  *   ==> we only need local data storage per device, not per DMA
1640Sstevel@tonic-gate  *   ==> a page fault will block the DMA engine until the fault
1650Sstevel@tonic-gate  *       is resolved
1660Sstevel@tonic-gate  *   ==> a pagefault will not trigger a zulu DMA context switch
1670Sstevel@tonic-gate  *
1680Sstevel@tonic-gate  * If we want to implement asynnchronous zulu page fault, then we
1690Sstevel@tonic-gate  * need to keep track of outstanding faults while zulu DMA runs
1700Sstevel@tonic-gate  * in a different context.
1710Sstevel@tonic-gate  */
1720Sstevel@tonic-gate static int
zuluvm_write_tte(zuluvm_state_t * zdev,void * arg,caddr_t addr,int t_pfn,int t_perm,int t_size,uint64_t tag,int tlbtype,int * size)1730Sstevel@tonic-gate zuluvm_write_tte(zuluvm_state_t *zdev, void *arg, caddr_t addr,
1740Sstevel@tonic-gate     int t_pfn, int t_perm, int t_size, uint64_t tag,
1750Sstevel@tonic-gate     int tlbtype, int *size)
1760Sstevel@tonic-gate {
1770Sstevel@tonic-gate 	int error;
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	(void) addr;
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	ZULUVM_STATS_MISS(zdev, t_size);
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	if (tag == 0) { /* not coming from preload */
1840Sstevel@tonic-gate 		int state = ZULUVM_SET_STATE(zdev, ZULUVM_STATE_WRITE_TTE,
1850Sstevel@tonic-gate 				ZULUVM_STATE_INTR_PENDING);
1860Sstevel@tonic-gate 		if (state != ZULUVM_STATE_INTR_PENDING) {
1870Sstevel@tonic-gate 			zuluvm_stop(zdev, state, "zuluvm_write_tte");
1880Sstevel@tonic-gate 			return (ZULUVM_MISS_CANCELED);
1890Sstevel@tonic-gate 		}
1900Sstevel@tonic-gate 	}
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	if (!(tlbtype & ZULUVM_ITLB_FLAG) &&
1930Sstevel@tonic-gate 	    t_size != zuluvm_base_pgsize &&
1940Sstevel@tonic-gate 	    t_size != ZULU_TTE4M) {
1950Sstevel@tonic-gate 		t_size = zuluvm_base_pgsize;
1960Sstevel@tonic-gate 		TNF_PROBE_2(zuluvm_write_tte_new_pfn, "zuluvm", /* */,
1970Sstevel@tonic-gate 		    tnf_opaque, t_pfn, t_pfn, tnf_int, pagesize, t_size);
1980Sstevel@tonic-gate 	}
1990Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_write_tte, "zuluvm", /* */,
2000Sstevel@tonic-gate 	    tnf_opaque, t_pfn, t_pfn);
2010Sstevel@tonic-gate 	/*
2020Sstevel@tonic-gate 	 * if the caller is zuluvm_preload, then we need to pass
2030Sstevel@tonic-gate 	 * back the page size so it can add the right offset.
2040Sstevel@tonic-gate 	 */
2050Sstevel@tonic-gate 	if (size)
2060Sstevel@tonic-gate 		*size = t_size;
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	error = zulud_write_tte(zdev, arg, t_size, tag, t_pfn,
2090Sstevel@tonic-gate 		    t_perm, tlbtype);
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	return (error);
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate static void
zuluvm_stop(zuluvm_state_t * zdev,int state,char * tag)2150Sstevel@tonic-gate zuluvm_stop(zuluvm_state_t *zdev, int state, char *tag)
2160Sstevel@tonic-gate {
2170Sstevel@tonic-gate 	int ostate = state;
2180Sstevel@tonic-gate 	while (state != ZULUVM_STATE_STOPPED) {
2190Sstevel@tonic-gate 		state = ZULUVM_SET_STATE(zdev,
2200Sstevel@tonic-gate 			    ZULUVM_STATE_STOPPED, state);
2210Sstevel@tonic-gate #ifdef DEBUG
2220Sstevel@tonic-gate 		if (zuluvm_debug_state)
2230Sstevel@tonic-gate 			cmn_err(CE_NOTE, "zuluvm_stop(%s): (loop) state %d\n",
2240Sstevel@tonic-gate 			    tag, state);
2250Sstevel@tonic-gate #endif
2260Sstevel@tonic-gate 	}
2270Sstevel@tonic-gate 	TNF_PROBE_2(zuluvm_stop, "zuluvm", /* */,
2280Sstevel@tonic-gate 	    tnf_string, tag, tag,
2290Sstevel@tonic-gate 	    tnf_int, state, ostate);
2300Sstevel@tonic-gate 	ZULUVM_STATS_CANCEL(zdev);
2310Sstevel@tonic-gate }
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate /*
2340Sstevel@tonic-gate  * Executed with the context of the parked zulu deamon thread,
2350Sstevel@tonic-gate  * uses zulu_hat_load to resolve the miss.
2360Sstevel@tonic-gate  * The tte is loaded and miss done called by the function zuluvm_load_tte
2370Sstevel@tonic-gate  * which is called from zulu_hat
2380Sstevel@tonic-gate  *
2390Sstevel@tonic-gate  * This function is synchronized with the zuluvm_as_free.
2400Sstevel@tonic-gate  * zuluvm_as_free will block until miss servicing is complete.
2410Sstevel@tonic-gate  *
2420Sstevel@tonic-gate  * There is a race condition between as_free and the zulu tlb miss
2430Sstevel@tonic-gate  * soft interrupt:
2440Sstevel@tonic-gate  *	- queue zulu interrupt
2450Sstevel@tonic-gate  *	- process dies, as_free runs
2460Sstevel@tonic-gate  *	- interrupt gets scheduled and runs as_fault on the
2470Sstevel@tonic-gate  *	  already freed as.
2480Sstevel@tonic-gate  * This is solved by keeping track of current zulu dma processes
2490Sstevel@tonic-gate  * and invalidating them in zuluvm_as_free.
2500Sstevel@tonic-gate  */
2510Sstevel@tonic-gate uint_t
zuluvm_tlb_handler(caddr_t data)2520Sstevel@tonic-gate zuluvm_tlb_handler(caddr_t data)
2530Sstevel@tonic-gate {
2540Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)data;
2550Sstevel@tonic-gate 	int	error;
2560Sstevel@tonic-gate 	int	flag = 0;
2570Sstevel@tonic-gate 	int	wait = 0;
2580Sstevel@tonic-gate 	zuluvm_proc_t *proc = NULL;
2590Sstevel@tonic-gate 	struct zulu_hat	*zhat = NULL;
2600Sstevel@tonic-gate 	caddr_t	addr;
2610Sstevel@tonic-gate 	int	tlbtype;
2620Sstevel@tonic-gate 	void	*arg;
2630Sstevel@tonic-gate 	int	state, newstate;
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_tlb_handler_lwp, "zuluvm", /* */,
2660Sstevel@tonic-gate 	    tnf_opaque, lwp, ttolwp(curthread));
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	ZULUVM_LOCK;
2690Sstevel@tonic-gate 	error   = ZULUVM_GET_TLB_ERRCODE(zdev);
2700Sstevel@tonic-gate 	addr    = (caddr_t)ZULUVM_GET_TLB_ADDR(zdev);
2710Sstevel@tonic-gate 	tlbtype = ZULUVM_GET_TLB_TYPE(zdev);
2720Sstevel@tonic-gate 	arg = zdev->zvm.arg;
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	/*
2750Sstevel@tonic-gate 	 * select the correct dma engine and remember the
2760Sstevel@tonic-gate 	 * the as_free synchronization flags.
2770Sstevel@tonic-gate 	 */
2780Sstevel@tonic-gate 	switch (tlbtype) {
2790Sstevel@tonic-gate 	case ZULUVM_ITLB1:
2800Sstevel@tonic-gate 	case ZULUVM_DMA1:
2810Sstevel@tonic-gate 		proc = zdev->zvm.proc1;
2820Sstevel@tonic-gate 		flag |= ZULUVM_DO_INTR1;
2830Sstevel@tonic-gate 		wait |= ZULUVM_WAIT_INTR1;
2840Sstevel@tonic-gate 		break;
2850Sstevel@tonic-gate 	case ZULUVM_ITLB2:
2860Sstevel@tonic-gate 	case ZULUVM_DMA2:
2870Sstevel@tonic-gate 		proc = zdev->zvm.proc2;
2880Sstevel@tonic-gate 		flag |= ZULUVM_DO_INTR2;
2890Sstevel@tonic-gate 		wait |= ZULUVM_WAIT_INTR2;
2900Sstevel@tonic-gate 		break;
2910Sstevel@tonic-gate 	}
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	state = ZULUVM_SET_STATE(zdev, ZULUVM_STATE_INTR_PENDING,
2940Sstevel@tonic-gate 		    ZULUVM_STATE_INTR_QUEUED);
2950Sstevel@tonic-gate 	newstate = ZULUVM_GET_STATE(zdev);
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	TNF_PROBE_2(zuluvm_tlb_handler_state, "zuluvm", /* */,
2980Sstevel@tonic-gate 	    tnf_int, oldstate, state,
2990Sstevel@tonic-gate 	    tnf_int, newstate, newstate);
3000Sstevel@tonic-gate #ifdef DEBUG
3010Sstevel@tonic-gate 	if (zuluvm_debug_state)
3020Sstevel@tonic-gate 		cmn_err(CE_NOTE, "zuluvm_tlb_handler: state %d\n", state);
3030Sstevel@tonic-gate #endif
3040Sstevel@tonic-gate 	if (state != ZULUVM_STATE_INTR_PENDING &&
3050Sstevel@tonic-gate 		state != ZULUVM_STATE_INTR_QUEUED) {
3060Sstevel@tonic-gate 		ZULUVM_UNLOCK;
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 		zuluvm_stop(zdev, state, "softintr1");
3090Sstevel@tonic-gate 		zulud_tlb_done(zdev, arg, tlbtype, ZULUVM_MISS_CANCELED);
3100Sstevel@tonic-gate 		return (1);
3110Sstevel@tonic-gate 	}
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	/*
3140Sstevel@tonic-gate 	 * block the as_free callback in case it comes in
3150Sstevel@tonic-gate 	 */
3160Sstevel@tonic-gate 	zdev->intr_flags |= flag;
3170Sstevel@tonic-gate 	ZULUVM_UNLOCK;
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	mutex_enter(&zdev->proc_lck);
3200Sstevel@tonic-gate 	/*
3210Sstevel@tonic-gate 	 * check if this as is still valid
3220Sstevel@tonic-gate 	 */
3230Sstevel@tonic-gate 	if (proc == NULL || proc->valid == 0 || proc->zhat == NULL) {
3240Sstevel@tonic-gate 		mutex_exit(&zdev->proc_lck);
3250Sstevel@tonic-gate 		/*
3260Sstevel@tonic-gate 		 * we are on our way out, wake up the as_free
3270Sstevel@tonic-gate 		 * callback if it is waiting for us
3280Sstevel@tonic-gate 		 */
3290Sstevel@tonic-gate 		ZULUVM_LOCK;
3300Sstevel@tonic-gate 		zdev->intr_flags &= ~flag;
3310Sstevel@tonic-gate 		if (zdev->intr_flags | wait)
3320Sstevel@tonic-gate 			cv_broadcast(&zdev->intr_wait);
3330Sstevel@tonic-gate 		ZULUVM_UNLOCK;
3340Sstevel@tonic-gate 		state = ZULUVM_SET_STATE(zdev, ZULUVM_STATE_IDLE,
3350Sstevel@tonic-gate 			    ZULUVM_STATE_INTR_PENDING);
3360Sstevel@tonic-gate 		if (state != ZULUVM_STATE_INTR_PENDING) {
3370Sstevel@tonic-gate 			zuluvm_stop(zdev, state, "softintr3");
3380Sstevel@tonic-gate 		}
3390Sstevel@tonic-gate 		zulud_tlb_done(zdev, arg, tlbtype, ZULUVM_NO_HAT);
3400Sstevel@tonic-gate 		return (1);
3410Sstevel@tonic-gate 	}
3420Sstevel@tonic-gate 	zhat = proc->zhat;
3430Sstevel@tonic-gate 	mutex_exit(&zdev->proc_lck);
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_tlb_handler, "zuluvm", /* */,
3460Sstevel@tonic-gate 	    tnf_opaque, addr, addr);
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	switch (error) {
3490Sstevel@tonic-gate 	case ZULUVM_CTX_LOCKED:
3500Sstevel@tonic-gate 		/*
3510Sstevel@tonic-gate 		 * trap handler found that zulu_hat had the lock bit set
3520Sstevel@tonic-gate 		 * rather than block in the fast trap handler, it punts
3530Sstevel@tonic-gate 		 * in this rare instance
3540Sstevel@tonic-gate 		 */
3550Sstevel@tonic-gate 		++zuluvm_ctx_locked;
3560Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_ctx_locked, "zuluvm", /* CSTYLED */,
3570Sstevel@tonic-gate 			tnf_ulong, zuluvm_ctx_locked, zuluvm_ctx_locked);
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 		/*FALLTHROUGH*/
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	case ZULUVM_TTE_DELAY:
3620Sstevel@tonic-gate 		/*
3630Sstevel@tonic-gate 		 * fast tlb handler was skipped, see zuluvm_fast_tlb flag
3640Sstevel@tonic-gate 		 */
3650Sstevel@tonic-gate 		/*FALLTHROUGH*/
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	case ZULUVM_NO_TTE:
3680Sstevel@tonic-gate 		/*
3690Sstevel@tonic-gate 		 * no TSB entry and TTE in the hash
3700Sstevel@tonic-gate 		 */
3710Sstevel@tonic-gate 		mutex_enter(&zdev->load_lck);
3720Sstevel@tonic-gate 		zdev->in_intr = 1;
3730Sstevel@tonic-gate 		error = zulu_hat_load(zhat,  addr,
3740Sstevel@tonic-gate 			(tlbtype == ZULUVM_DMA2) ? S_WRITE : S_READ, NULL);
3750Sstevel@tonic-gate 		zdev->in_intr = 0;
3760Sstevel@tonic-gate 		mutex_exit(&zdev->load_lck);
3770Sstevel@tonic-gate 		if (error) {
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 			error = ZULUVM_NO_MAP;
3800Sstevel@tonic-gate 		} else {
3810Sstevel@tonic-gate 			error = ZULUVM_SUCCESS;
3820Sstevel@tonic-gate 			TNF_PROBE_1(zuluvm_tlb_handler_done, "zuluvm", /* */,
3830Sstevel@tonic-gate 				    tnf_int, error, error);
3840Sstevel@tonic-gate 			return (1);
3850Sstevel@tonic-gate 		}
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	default:
3880Sstevel@tonic-gate 		/*
3890Sstevel@tonic-gate 		 * error case, fall through and tell zulu driver to abort DMA
3900Sstevel@tonic-gate 		 */
3910Sstevel@tonic-gate 		break;
3920Sstevel@tonic-gate 	}
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	if (error != ZULUVM_MISS_CANCELED) {
3950Sstevel@tonic-gate 		state = ZULUVM_SET_STATE(zdev, ZULUVM_STATE_IDLE,
3960Sstevel@tonic-gate 			    ZULUVM_STATE_WRITE_TTE);
3970Sstevel@tonic-gate 		newstate = ZULUVM_GET_STATE(zdev);
3980Sstevel@tonic-gate 		TNF_PROBE_2(zuluvm_tlb_handler_state_done, "zuluvm", /* */,
3990Sstevel@tonic-gate 		    tnf_int, oldstate, state,
4000Sstevel@tonic-gate 		    tnf_int, newstate, newstate);
4010Sstevel@tonic-gate 		if (state != ZULUVM_STATE_WRITE_TTE) {
4020Sstevel@tonic-gate 			zuluvm_stop(zdev, state, "softintr4");
4030Sstevel@tonic-gate 		}
4040Sstevel@tonic-gate 	}
4050Sstevel@tonic-gate 	/*
4060Sstevel@tonic-gate 	 * synchronize with as_free callback
4070Sstevel@tonic-gate 	 * It will set the wait flag, in that case we send
4080Sstevel@tonic-gate 	 * a wake up.
4090Sstevel@tonic-gate 	 */
4100Sstevel@tonic-gate 	ZULUVM_LOCK;
4110Sstevel@tonic-gate 	zdev->intr_flags &= ~flag;
4120Sstevel@tonic-gate 	if (zdev->intr_flags | wait)
4130Sstevel@tonic-gate 		cv_broadcast(&zdev->intr_wait);
4140Sstevel@tonic-gate 	ZULUVM_UNLOCK;
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_tlb_handler_done, "zuluvm", /* */,
4170Sstevel@tonic-gate 	    tnf_int, error, error);
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	zulud_tlb_done(zdev, arg, tlbtype, error);
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	return (1);
4220Sstevel@tonic-gate }
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate void
zuluvm_load_tte(struct zulu_hat * zhat,caddr_t addr,uint64_t pfn,int perm,int size)4260Sstevel@tonic-gate zuluvm_load_tte(struct zulu_hat  *zhat, caddr_t addr, uint64_t pfn,
4270Sstevel@tonic-gate 		int perm, int size)
4280Sstevel@tonic-gate {
4290Sstevel@tonic-gate 	zuluvm_state_t *zdev = zhat->zdev;
4300Sstevel@tonic-gate 	int		tlbtype = ZULUVM_GET_TLB_TYPE(zdev);
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&zdev->load_lck));
4330Sstevel@tonic-gate 	ASSERT(pfn != 0);
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	if (zdev->in_intr) {
4360Sstevel@tonic-gate 		int		error;
4370Sstevel@tonic-gate 		int		flag = 0;
4380Sstevel@tonic-gate 		int		wait = 0;
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 		error = zuluvm_write_tte(zdev, zdev->zvm.arg, addr, pfn,
4410Sstevel@tonic-gate 					perm, size, 0, tlbtype, NULL);
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 		if (error != ZULUVM_MISS_CANCELED) {
4440Sstevel@tonic-gate 			int	state, newstate;
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 			state = ZULUVM_SET_STATE(zdev, ZULUVM_STATE_IDLE,
4470Sstevel@tonic-gate 				    ZULUVM_STATE_WRITE_TTE);
4480Sstevel@tonic-gate 			newstate = ZULUVM_GET_STATE(zdev);
4490Sstevel@tonic-gate 			TNF_PROBE_2(zuluvm_tlb_handler_state_done, "zuluvm",
4500Sstevel@tonic-gate 				    /* */, tnf_int, oldstate, state,
4510Sstevel@tonic-gate 				    tnf_int, newstate, newstate);
4520Sstevel@tonic-gate 			if (state != ZULUVM_STATE_WRITE_TTE) {
4530Sstevel@tonic-gate 				zuluvm_stop(zdev, state, "softintr4");
4540Sstevel@tonic-gate 			}
4550Sstevel@tonic-gate 		}
4560Sstevel@tonic-gate 		/*
4570Sstevel@tonic-gate 		 * synchronize with as_free callback
4580Sstevel@tonic-gate 		 * It will set the wait flag, in that case we send
4590Sstevel@tonic-gate 		 * a wake up.
4600Sstevel@tonic-gate 		 */
4610Sstevel@tonic-gate 		switch (tlbtype) {
4620Sstevel@tonic-gate 		case ZULUVM_ITLB1:
4630Sstevel@tonic-gate 		case ZULUVM_DMA1:
4640Sstevel@tonic-gate 			flag = ZULUVM_DO_INTR1;
4650Sstevel@tonic-gate 			wait = ZULUVM_WAIT_INTR1;
4660Sstevel@tonic-gate 			break;
4670Sstevel@tonic-gate 		case ZULUVM_ITLB2:
4680Sstevel@tonic-gate 		case ZULUVM_DMA2:
4690Sstevel@tonic-gate 			flag = ZULUVM_DO_INTR2;
4700Sstevel@tonic-gate 			wait = ZULUVM_WAIT_INTR2;
4710Sstevel@tonic-gate 			break;
4720Sstevel@tonic-gate 		}
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 		ZULUVM_LOCK;
4750Sstevel@tonic-gate 		zdev->intr_flags &= ~flag;
4760Sstevel@tonic-gate 		if (zdev->intr_flags | wait)
4770Sstevel@tonic-gate 			cv_broadcast(&zdev->intr_wait);
4780Sstevel@tonic-gate 		ZULUVM_UNLOCK;
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 		zulud_tlb_done(zdev, zdev->zvm.arg, tlbtype, error);
4810Sstevel@tonic-gate 	} else {
4820Sstevel@tonic-gate 		(void) zuluvm_write_tte(zdev, zdev->zvm.arg, addr, pfn,
4830Sstevel@tonic-gate 					perm, size, (uint64_t)addr |
4840Sstevel@tonic-gate 					zhat->zulu_ctx, tlbtype, NULL);
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate }
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate /*
4920Sstevel@tonic-gate  * This function provides the faulting thread for zulu page faults
4930Sstevel@tonic-gate  * It is call from the device driver in response to an ioctl issued
4940Sstevel@tonic-gate  * by a zuludaemon thread.
4950Sstevel@tonic-gate  * It sits in cv_wait_sig until it gets woken up by a signal or
4960Sstevel@tonic-gate  * zulu tlb miss soft interrupt.
4970Sstevel@tonic-gate  */
4980Sstevel@tonic-gate int
zuluvm_park(zuluvm_info_t devp)4990Sstevel@tonic-gate zuluvm_park(zuluvm_info_t devp)
5000Sstevel@tonic-gate {
5010Sstevel@tonic-gate 	int rval;
5020Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
5030Sstevel@tonic-gate 	mutex_enter(&zdev->park_lck);
5040Sstevel@tonic-gate 	zdev->parking = 1;
5050Sstevel@tonic-gate 	for (;;) {
5060Sstevel@tonic-gate 		rval = cv_wait_sig(&zdev->park_cv, &zdev->park_lck);
5070Sstevel@tonic-gate 		if (rval == 0)
5080Sstevel@tonic-gate 			break;
5090Sstevel@tonic-gate 		rval = zuluvm_tlb_handler(devp);
5100Sstevel@tonic-gate 	}
5110Sstevel@tonic-gate 	zdev->parking = 0;
5120Sstevel@tonic-gate 	mutex_exit(&zdev->park_lck);
5130Sstevel@tonic-gate 	return (rval);
5140Sstevel@tonic-gate }
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate /*
5170Sstevel@tonic-gate  * zulu soft interrupt handler, just triggers the parked zulu fault
5180Sstevel@tonic-gate  * thread
5190Sstevel@tonic-gate  */
5200Sstevel@tonic-gate /*ARGSUSED*/
5210Sstevel@tonic-gate uint_t
zuluvm_softintr(caddr_t devp,caddr_t arg2)5220Sstevel@tonic-gate zuluvm_softintr(caddr_t devp, caddr_t arg2)
5230Sstevel@tonic-gate {
5240Sstevel@tonic-gate 	int tlbtype;
5250Sstevel@tonic-gate 	void *arg;
5260Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
5270Sstevel@tonic-gate 	mutex_enter(&zdev->park_lck);
5280Sstevel@tonic-gate 	if (zdev->parking) {
5290Sstevel@tonic-gate 		cv_signal(&zdev->park_cv);
5300Sstevel@tonic-gate 		mutex_exit(&zdev->park_lck);
5310Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_fast_intr, "zuluvm", /* */,
5320Sstevel@tonic-gate 		    tnf_opaque, devp, devp);
5330Sstevel@tonic-gate 	} else {
5340Sstevel@tonic-gate 		mutex_exit(&zdev->park_lck);
5350Sstevel@tonic-gate 		cmn_err(CE_NOTE, "zuluvm: no page fault thread\n");
5360Sstevel@tonic-gate 		ZULUVM_LOCK;
5370Sstevel@tonic-gate 		tlbtype = ZULUVM_GET_TLB_TYPE(zdev);
5380Sstevel@tonic-gate 		arg = zdev->zvm.arg;
5390Sstevel@tonic-gate 		ZULUVM_UNLOCK;
5400Sstevel@tonic-gate 		TNF_PROBE_0(zuluvm_fast_intr, "zuluvm", /* */);
5410Sstevel@tonic-gate 		zuluvm_stop(zdev, ZULUVM_STATE_INTR_QUEUED, "fast_intr");
5420Sstevel@tonic-gate 		zulud_tlb_done(zdev, arg, tlbtype, ZULUVM_NO_TTE);
5430Sstevel@tonic-gate 	}
5440Sstevel@tonic-gate 	return (1);
5450Sstevel@tonic-gate }
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate /* ***** public interface for process mapping events (hat layer) ***** */
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate /*
5500Sstevel@tonic-gate  * If the page size matches the Zulu page sizes then just pass
5510Sstevel@tonic-gate  * it thru. If not then emulate the page demap with demaps of
5520Sstevel@tonic-gate  * smaller page size.
5530Sstevel@tonic-gate  */
5540Sstevel@tonic-gate /* ARGSUSED */
5550Sstevel@tonic-gate void
zuluvm_demap_page(void * arg,struct hat * hat_ptr,short ctx,caddr_t vaddr,uint_t size)5560Sstevel@tonic-gate zuluvm_demap_page(void *arg, struct hat *hat_ptr, short ctx,
5570Sstevel@tonic-gate     caddr_t vaddr, uint_t size)
5580Sstevel@tonic-gate {
5590Sstevel@tonic-gate 	void *ddarg;
5600Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)arg;
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	if (arg == NULL)
5630Sstevel@tonic-gate 		return;
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	ZULUVM_STATS_DEMAP_PAGE(zdev);
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	ddarg = zdev->zvm.arg;
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	TNF_PROBE_3(zuluvm_demap_page, "zuluvm", /* */,
5700Sstevel@tonic-gate 	    tnf_opaque, addr, vaddr,
5710Sstevel@tonic-gate 	    tnf_int, size, size,
5720Sstevel@tonic-gate 	    tnf_int, ctx, ctx);
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	if (ddarg != NULL) {
5750Sstevel@tonic-gate 		if (size != zuluvm_base_pgsize &&
5760Sstevel@tonic-gate 		    size != ZULU_TTE4M) {
5770Sstevel@tonic-gate 			int i;
5780Sstevel@tonic-gate 			int cnt = size - zuluvm_base_pgsize;
5790Sstevel@tonic-gate 			cnt = ZULU_HAT_SZ_SHIFT(cnt);
5800Sstevel@tonic-gate 			for (i = 0; i < cnt; i++) {
5810Sstevel@tonic-gate 				uintptr_t addr = (uintptr_t)vaddr |
5820Sstevel@tonic-gate 				    i << ZULU_HAT_BP_SHIFT;
5830Sstevel@tonic-gate 				zulud_demap_page(zdev, ddarg,
5840Sstevel@tonic-gate 						(caddr_t)addr, ctx);
5850Sstevel@tonic-gate 			}
5860Sstevel@tonic-gate 		} else {
5870Sstevel@tonic-gate 			zulud_demap_page(zdev, ddarg, vaddr, ctx);
5880Sstevel@tonic-gate 		}
5890Sstevel@tonic-gate 		TNF_PROBE_0(zuluvm_demap_page_done, "zuluvm", /* */);
5900Sstevel@tonic-gate 	} else {
5910Sstevel@tonic-gate 		TNF_PROBE_0(zuluvm_demap_page_null_ddarg, "zuluvm", /* */);
5920Sstevel@tonic-gate 	}
5930Sstevel@tonic-gate }
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate /*
5960Sstevel@tonic-gate  * An entire context has gone away, just pass it thru
5970Sstevel@tonic-gate  */
5980Sstevel@tonic-gate void
zuluvm_demap_ctx(void * arg,short ctx)5990Sstevel@tonic-gate zuluvm_demap_ctx(void *arg, short ctx)
6000Sstevel@tonic-gate {
6010Sstevel@tonic-gate 	void *ddarg;
6020Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)arg;
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	if (arg == NULL)
6050Sstevel@tonic-gate 		return;
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	ZULUVM_STATS_DEMAP_CTX(zdev);
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_demap_ctx, "zuluvm", /* */,
6100Sstevel@tonic-gate 	    tnf_int, ctx, ctx);
6110Sstevel@tonic-gate 	ddarg = zdev->zvm.arg;
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	if (ddarg != NULL)
6140Sstevel@tonic-gate 		zulud_demap_ctx(zdev, ddarg, ctx);
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate static int
zuluvm_driver_attach(zuluvm_state_t * zdev)6180Sstevel@tonic-gate zuluvm_driver_attach(zuluvm_state_t *zdev)
6190Sstevel@tonic-gate {
6200Sstevel@tonic-gate 	int i;
6210Sstevel@tonic-gate 	mutex_enter(&zuluvm_lck);
6220Sstevel@tonic-gate 	for (i = 0; i < ZULUVM_MAX_DEV; i++) {
6230Sstevel@tonic-gate 		if (zuluvm_devtab[i] == NULL) {
6240Sstevel@tonic-gate 			zuluvm_devtab[i] = zdev;
6250Sstevel@tonic-gate 			ZULUVM_SET_IDLE(zdev);
6260Sstevel@tonic-gate 			break;
6270Sstevel@tonic-gate 		}
6280Sstevel@tonic-gate 	}
6290Sstevel@tonic-gate 	mutex_exit(&zuluvm_lck);
6300Sstevel@tonic-gate 	if (i >= ZULUVM_MAX_DEV)
6310Sstevel@tonic-gate 		return (ZULUVM_ERROR);
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	if (zulu_hat_attach((void *)zdev) != 0) {
6340Sstevel@tonic-gate 		return (ZULUVM_ERROR);
6350Sstevel@tonic-gate 	}
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	mutex_init(&zdev->dev_lck, NULL, MUTEX_DEFAULT, NULL);
6380Sstevel@tonic-gate 	mutex_init(&zdev->load_lck, NULL, MUTEX_DEFAULT, NULL);
6390Sstevel@tonic-gate 	mutex_init(&zdev->proc_lck, NULL, MUTEX_DEFAULT, NULL);
6400Sstevel@tonic-gate 	mutex_init(&zdev->park_lck, NULL, MUTEX_DEFAULT, NULL);
6410Sstevel@tonic-gate 	cv_init(&zdev->park_cv, NULL, CV_DEFAULT, NULL);
6420Sstevel@tonic-gate 	cv_init(&zdev->intr_wait, NULL, CV_DEFAULT, NULL);
6430Sstevel@tonic-gate 	zdev->parking = 0;
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate #ifdef ZULUVM_STATS
6460Sstevel@tonic-gate 	zdev->zvm.cancel	= 0;
6470Sstevel@tonic-gate 	zdev->zvm.pagefault	= 0;
6480Sstevel@tonic-gate 	zdev->zvm.no_mapping	= 0;
6490Sstevel@tonic-gate 	zdev->zvm.preload	= 0;
6500Sstevel@tonic-gate 	zdev->zvm.migrate	= 0;
6510Sstevel@tonic-gate 	zdev->zvm.pagesize	= 0;
6520Sstevel@tonic-gate 	zdev->zvm.tlb_miss[0]	= 0;
6530Sstevel@tonic-gate 	zdev->zvm.tlb_miss[1]	= 0;
6540Sstevel@tonic-gate 	zdev->zvm.tlb_miss[2]	= 0;
6550Sstevel@tonic-gate 	zdev->zvm.tlb_miss[3]	= 0;
6560Sstevel@tonic-gate 	zdev->zvm.itlb1miss	= 0;
6570Sstevel@tonic-gate 	zdev->zvm.dtlb1miss	= 0;
6580Sstevel@tonic-gate 	zdev->zvm.itlb2miss	= 0;
6590Sstevel@tonic-gate 	zdev->zvm.dtlb2miss	= 0;
6600Sstevel@tonic-gate #endif
6610Sstevel@tonic-gate 	zdev->zvm.pfncnt = 0;
6620Sstevel@tonic-gate 	for (i = 0; i < 50; i++)
6630Sstevel@tonic-gate 		zdev->zvm.pfnbuf[i] = 0;
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	zdev->zvm.mmu_pa  	= NULL;
6660Sstevel@tonic-gate 	zdev->zvm.proc1   	= NULL;
6670Sstevel@tonic-gate 	zdev->zvm.proc2   	= NULL;
6680Sstevel@tonic-gate 	zdev->procs = NULL;
6690Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
6700Sstevel@tonic-gate }
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate static int
zuluvm_driver_detach(zuluvm_state_t * zdev)6730Sstevel@tonic-gate zuluvm_driver_detach(zuluvm_state_t *zdev)
6740Sstevel@tonic-gate {
6750Sstevel@tonic-gate 	int i;
6760Sstevel@tonic-gate 	cv_destroy(&zdev->intr_wait);
6770Sstevel@tonic-gate 	cv_destroy(&zdev->park_cv);
6780Sstevel@tonic-gate 	mutex_destroy(&zdev->park_lck);
6790Sstevel@tonic-gate 	mutex_destroy(&zdev->proc_lck);
6800Sstevel@tonic-gate 	mutex_destroy(&zdev->dev_lck);
6810Sstevel@tonic-gate 	mutex_destroy(&zdev->load_lck);
6820Sstevel@tonic-gate 	zdev->dops = NULL;
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	mutex_enter(&zuluvm_lck);
6850Sstevel@tonic-gate 	for (i = 0; i < ZULUVM_MAX_DEV; i++) {
6860Sstevel@tonic-gate 		if (zuluvm_devtab[i] == zdev) {
6870Sstevel@tonic-gate 			zuluvm_devtab[i] = NULL;
6880Sstevel@tonic-gate 			break;
6890Sstevel@tonic-gate 		}
6900Sstevel@tonic-gate 	}
6910Sstevel@tonic-gate 	mutex_exit(&zuluvm_lck);
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	if (zulu_hat_detach((void *)zdev) == 0) {
6940Sstevel@tonic-gate 		return (ZULUVM_SUCCESS);
6950Sstevel@tonic-gate 	} else {
6960Sstevel@tonic-gate 		return (ZULUVM_ERROR);
6970Sstevel@tonic-gate 	}
6980Sstevel@tonic-gate }
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate zulud_ops_t *zuluvm_dops = NULL;
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate /*
7030Sstevel@tonic-gate  * init the zulu kernel driver (variables, locks, etc)
7040Sstevel@tonic-gate  */
7050Sstevel@tonic-gate int
zuluvm_init(zulud_ops_t * ops,int ** pagesizes)7060Sstevel@tonic-gate zuluvm_init(zulud_ops_t *ops, int **pagesizes)
7070Sstevel@tonic-gate {
7080Sstevel@tonic-gate 	int error = ZULUVM_SUCCESS;
7090Sstevel@tonic-gate 	int i;
7100Sstevel@tonic-gate 	int size = zuluvm_base_pgsize; /* MMU_PAGESIZE; */
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	if (ops->version != ZULUVM_INTERFACE_VERSION)
7130Sstevel@tonic-gate 		return (ZULUVM_VERSION_MISMATCH);
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	zuluvm_dops = ops;
7160Sstevel@tonic-gate 	for (i = 0; i < ZULUM_MAX_PG_SIZES && size <= ZULU_TTE4M; i++) {
7170Sstevel@tonic-gate 		zuluvm_pagesizes[i] = size++;
7180Sstevel@tonic-gate 	}
7190Sstevel@tonic-gate 	zuluvm_pagesizes[i] = -1;
7200Sstevel@tonic-gate 	*pagesizes = zuluvm_pagesizes;
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 	return (error);
7230Sstevel@tonic-gate }
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate /*
7260Sstevel@tonic-gate  * cleanup afterwards
7270Sstevel@tonic-gate  */
7280Sstevel@tonic-gate int
zuluvm_fini(void)7290Sstevel@tonic-gate zuluvm_fini(void)
7300Sstevel@tonic-gate {
7310Sstevel@tonic-gate 	zuluvm_dops = NULL;
7320Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
7330Sstevel@tonic-gate }
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate /*
7360Sstevel@tonic-gate  *     allocate a zulu kernel driver instance for this zulu device
7370Sstevel@tonic-gate  */
7380Sstevel@tonic-gate int
zuluvm_alloc_device(dev_info_t * devi,void * arg,zuluvm_info_t * devp,caddr_t mmu,caddr_t imr)7390Sstevel@tonic-gate zuluvm_alloc_device(dev_info_t *devi, void *arg, zuluvm_info_t *devp,
7400Sstevel@tonic-gate     caddr_t mmu, caddr_t imr)
7410Sstevel@tonic-gate {
742*2973Sgovinda 	uint64_t intr_num;
7430Sstevel@tonic-gate 	zuluvm_state_t *zdev;
7440Sstevel@tonic-gate 	int error = ZULUVM_SUCCESS;
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	TNF_PROBE_3(zuluvm_alloc_device, "zuluvm", /* */,
7470Sstevel@tonic-gate 	    tnf_opaque, arg, arg,
7480Sstevel@tonic-gate 	    tnf_opaque, mmu, mmu,
7490Sstevel@tonic-gate 	    tnf_opaque, imr, imr);
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 	zdev = kmem_zalloc(sizeof (zuluvm_state_t), KM_SLEEP);
7520Sstevel@tonic-gate 	zdev->dip = devi;
7530Sstevel@tonic-gate 	zdev->dops = zuluvm_dops;
7540Sstevel@tonic-gate 	error = zuluvm_driver_attach(zdev);
7550Sstevel@tonic-gate 	if (error != ZULUVM_SUCCESS) {
7560Sstevel@tonic-gate 		kmem_free(zdev, sizeof (zuluvm_state_t));
7570Sstevel@tonic-gate 		return (ZULUVM_NO_DEV);
7580Sstevel@tonic-gate 	}
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 	ZULUVM_LOCK;
7610Sstevel@tonic-gate 	error = zuluvm_get_intr_props(zdev, devi);
7620Sstevel@tonic-gate 	if (error != ZULUVM_SUCCESS) {
7630Sstevel@tonic-gate 		ZULUVM_UNLOCK;
7640Sstevel@tonic-gate 		error = zuluvm_driver_detach(zdev);
7650Sstevel@tonic-gate 		if (error != ZULUVM_SUCCESS)
7660Sstevel@tonic-gate 			return (error);
7670Sstevel@tonic-gate 		kmem_free(zdev, sizeof (zuluvm_state_t));
7680Sstevel@tonic-gate 		return (ZULUVM_NO_DEV);
7690Sstevel@tonic-gate 	}
7700Sstevel@tonic-gate 	zdev->zvm.arg = arg;
7710Sstevel@tonic-gate 	zdev->zvm.mmu_pa = (uint64_t)va_to_pa((void *)mmu);
7720Sstevel@tonic-gate 	zdev->imr = (uint64_t *)imr;
7730Sstevel@tonic-gate 	zdev->zvm.dmv_intr = dmv_add_softintr(zuluvm_dmv_tlbmiss_tl1,
7740Sstevel@tonic-gate 	    (void *)zdev);
7750Sstevel@tonic-gate 	zulud_set_itlb_pc(zdev, arg, DMV_MAKE_DMV(zdev->zvm.dmv_intr,
7760Sstevel@tonic-gate 	    (void *)zdev));
7770Sstevel@tonic-gate 	zulud_set_dtlb_pc(zdev, arg, DMV_MAKE_DMV(zdev->zvm.dmv_intr,
7780Sstevel@tonic-gate 	    (void *)zdev));
7790Sstevel@tonic-gate 	intr_dist_add(zuluvm_retarget_intr, (void *)zdev);
7800Sstevel@tonic-gate 	zuluvm_do_retarget(zdev);
781*2973Sgovinda 	intr_num = add_softintr(ZULUVM_PIL, zuluvm_softintr,
782*2973Sgovinda 	    (caddr_t)zdev, SOFTINT_ST);
7830Sstevel@tonic-gate 	zdev->zvm.intr_num = intr_num;
7840Sstevel@tonic-gate 	*devp = (caddr_t)zdev;
7850Sstevel@tonic-gate 	ZULUVM_UNLOCK;
7860Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_alloc_device_done, "zuluvm", /* */,
7870Sstevel@tonic-gate 	    tnf_opaque, devp, *devp);
7880Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
7890Sstevel@tonic-gate }
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate /*
7920Sstevel@tonic-gate  *    free a zulu kernel driver instance
7930Sstevel@tonic-gate  */
7940Sstevel@tonic-gate int
zuluvm_free_device(zuluvm_info_t devp)7950Sstevel@tonic-gate zuluvm_free_device(zuluvm_info_t devp)
7960Sstevel@tonic-gate {
7970Sstevel@tonic-gate 	int error;
7980Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_free_device, "zuluvm", /* */,
8010Sstevel@tonic-gate 	    tnf_opaque, zdev, zdev);
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	if (zdev == NULL)
8040Sstevel@tonic-gate 		return (ZULUVM_NO_DEV);
8050Sstevel@tonic-gate 	ZULUVM_LOCK;
8060Sstevel@tonic-gate 	if (zdev->zvm.arg == NULL) {
8070Sstevel@tonic-gate 		ZULUVM_UNLOCK;
8080Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_free_device_done, "zuluvm", /* */,
8090Sstevel@tonic-gate 		    tnf_int, error, ZULUVM_NO_DEV);
8100Sstevel@tonic-gate 		return (ZULUVM_NO_DEV);
8110Sstevel@tonic-gate 	}
8120Sstevel@tonic-gate 	(void) dmv_rem_intr(zdev->zvm.dmv_intr);
813*2973Sgovinda 	(void) rem_softintr(zdev->zvm.intr_num);
8140Sstevel@tonic-gate 	intr_dist_rem(zuluvm_retarget_intr, (void *)zdev);
8150Sstevel@tonic-gate 	zdev->zvm.arg = NULL;
8160Sstevel@tonic-gate 	ZULUVM_UNLOCK;
8170Sstevel@tonic-gate 	error = zuluvm_driver_detach(zdev);
8180Sstevel@tonic-gate 	if (error != ZULUVM_SUCCESS)
8190Sstevel@tonic-gate 		return (error);
8200Sstevel@tonic-gate 	zdev->dops = NULL;
8210Sstevel@tonic-gate 	kmem_free(zdev, sizeof (zuluvm_state_t));
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	TNF_PROBE_0(zuluvm_free_device_done, "zuluvm", /* */);
8240Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
8250Sstevel@tonic-gate }
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate /*
8280Sstevel@tonic-gate  * find the as in the list of active zulu processes
8290Sstevel@tonic-gate  * The caller has to hold zdev->proc_lck
8300Sstevel@tonic-gate  */
8310Sstevel@tonic-gate static zuluvm_proc_t *
zuluvm_find_proc(zuluvm_state_t * zdev,struct as * asp)8320Sstevel@tonic-gate zuluvm_find_proc(zuluvm_state_t *zdev, struct as *asp)
8330Sstevel@tonic-gate {
8340Sstevel@tonic-gate 	zuluvm_proc_t *p;
8350Sstevel@tonic-gate 	TNF_PROBE_2(zuluvm_find_proc, "zuluvm", /* */,
8360Sstevel@tonic-gate 	    tnf_opaque, zdev, zdev,
8370Sstevel@tonic-gate 	    tnf_opaque, asp, asp);
8380Sstevel@tonic-gate 	for (p = zdev->procs; p != NULL; p = p->next) {
8390Sstevel@tonic-gate 		if (ZULU_HAT2AS(p->zhat) == asp) {
8400Sstevel@tonic-gate 			TNF_PROBE_1(zuluvm_find_proc_done,
8410Sstevel@tonic-gate 			    "zuluvm", /* */, tnf_opaque, proc, p);
8420Sstevel@tonic-gate 			return (p);
8430Sstevel@tonic-gate 		}
8440Sstevel@tonic-gate 	}
8450Sstevel@tonic-gate 	TNF_PROBE_0(zuluvm_find_proc_fail, "zuluvm", /* */);
8460Sstevel@tonic-gate 	return (NULL);
8470Sstevel@tonic-gate }
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate void
zuluvm_as_free(struct as * as,void * arg,uint_t events)8500Sstevel@tonic-gate zuluvm_as_free(struct as *as, void *arg, uint_t events)
8510Sstevel@tonic-gate {
8520Sstevel@tonic-gate 	zuluvm_proc_t *proc = (zuluvm_proc_t *)arg;
8530Sstevel@tonic-gate 	zuluvm_state_t *zdev = proc->zdev;
8540Sstevel@tonic-gate 	int wait = 0;
8550Sstevel@tonic-gate 	int flag = 0;
8560Sstevel@tonic-gate 	int valid;
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	(void) events;
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_as_free, "zuluvm", /* */,
8610Sstevel@tonic-gate 	    tnf_opaque, arg, arg);
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 	(void) as_delete_callback(as, arg);
8640Sstevel@tonic-gate 	/*
8650Sstevel@tonic-gate 	 * if this entry is still valid, then we need to sync
8660Sstevel@tonic-gate 	 * with zuluvm_tlb_handler rountine.
8670Sstevel@tonic-gate 	 */
8680Sstevel@tonic-gate 	mutex_enter(&zdev->proc_lck);
8690Sstevel@tonic-gate 	valid = proc->valid;
8700Sstevel@tonic-gate 	proc->valid = 0;
8710Sstevel@tonic-gate 	mutex_exit(&zdev->proc_lck);
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate 	if (valid) {
8740Sstevel@tonic-gate 		ZULUVM_LOCK;
8750Sstevel@tonic-gate 		if (proc == zdev->zvm.proc1) {
8760Sstevel@tonic-gate 			flag |= ZULUVM_WAIT_INTR1;
8770Sstevel@tonic-gate 			wait |= ZULUVM_DO_INTR1;
8780Sstevel@tonic-gate 		}
8790Sstevel@tonic-gate 		if (proc == zdev->zvm.proc2) {
8800Sstevel@tonic-gate 			flag |= ZULUVM_WAIT_INTR2;
8810Sstevel@tonic-gate 			wait |= ZULUVM_DO_INTR2;
8820Sstevel@tonic-gate 		}
8830Sstevel@tonic-gate 		if (flag) {
8840Sstevel@tonic-gate 			zdev->intr_flags |= flag;
8850Sstevel@tonic-gate 			/*
8860Sstevel@tonic-gate 			 * wait until the tlb miss is resloved
8870Sstevel@tonic-gate 			 */
8880Sstevel@tonic-gate 			while (zdev->intr_flags & wait) {
8890Sstevel@tonic-gate 				cv_wait(&zdev->intr_wait, &zdev->dev_lck);
8900Sstevel@tonic-gate 			}
8910Sstevel@tonic-gate 			zdev->intr_flags &= ~flag;
8920Sstevel@tonic-gate 		}
8930Sstevel@tonic-gate 		ZULUVM_UNLOCK;
8940Sstevel@tonic-gate 	}
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 	if (proc->zhat != NULL) {
8970Sstevel@tonic-gate 		/*
8980Sstevel@tonic-gate 		 * prevent any further tlb miss processing for this hat
8990Sstevel@tonic-gate 		 */
9000Sstevel@tonic-gate 		zulu_hat_terminate(proc->zhat);
9010Sstevel@tonic-gate 	}
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	/*
9040Sstevel@tonic-gate 	 * decrement the ref count and do the appropriate
9050Sstevel@tonic-gate 	 * if it drops to zero.
9060Sstevel@tonic-gate 	 */
9070Sstevel@tonic-gate 	mutex_enter(&zdev->proc_lck);
9080Sstevel@tonic-gate 	(void) zuluvm_proc_release(zdev, proc);
9090Sstevel@tonic-gate 	mutex_exit(&zdev->proc_lck);
9100Sstevel@tonic-gate }
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate /*
9130Sstevel@tonic-gate  *	notify zulu vm driver about a new process going to
9140Sstevel@tonic-gate  *	use zulu DMA. Create a zulu_hat.
9150Sstevel@tonic-gate  */
9160Sstevel@tonic-gate int
zuluvm_dma_add_proc(zuluvm_info_t devp,uint64_t * cookie)9170Sstevel@tonic-gate zuluvm_dma_add_proc(zuluvm_info_t devp, uint64_t *cookie)
9180Sstevel@tonic-gate {
9190Sstevel@tonic-gate 	zuluvm_proc_t *proc;
9200Sstevel@tonic-gate 	int refcnt;
9210Sstevel@tonic-gate 	struct as *asp = ZULUVM_GET_AS;
9220Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_dma_add_proc, "zuluvm", /* */,
9250Sstevel@tonic-gate 	    tnf_opaque, zdev, zdev);
9260Sstevel@tonic-gate 	mutex_enter(&zdev->proc_lck);
9270Sstevel@tonic-gate 	proc = zuluvm_find_proc(zdev, asp);
9280Sstevel@tonic-gate 	if (proc == NULL) {
9290Sstevel@tonic-gate 		proc = kmem_zalloc(sizeof (zuluvm_proc_t), KM_SLEEP);
9300Sstevel@tonic-gate 		proc->zhat = zulu_hat_proc_attach(asp, zdev);
9310Sstevel@tonic-gate 		if (proc->zhat == NULL) {
9320Sstevel@tonic-gate 			mutex_exit(&zdev->proc_lck);
9330Sstevel@tonic-gate 			kmem_free(proc, sizeof (zuluvm_proc_t));
9340Sstevel@tonic-gate 			TNF_PROBE_2(zuluvm_dma_add_proc_done, "zuluvm", /* */,
9350Sstevel@tonic-gate 			    tnf_int, valid, 0,
9360Sstevel@tonic-gate 			    tnf_int, error, ZULUVM_ERROR);
9370Sstevel@tonic-gate 			return (ZULUVM_ERROR);
9380Sstevel@tonic-gate 		}
9390Sstevel@tonic-gate 		proc->zdev = zdev;
9400Sstevel@tonic-gate 		proc->valid = 1;
9410Sstevel@tonic-gate 		proc->refcnt = 1;
9420Sstevel@tonic-gate 		proc->next = zdev->procs;
9430Sstevel@tonic-gate 		if (zdev->procs)
9440Sstevel@tonic-gate 			zdev->procs->prev = proc;
9450Sstevel@tonic-gate 		proc->prev = NULL;
9460Sstevel@tonic-gate 		zdev->procs = proc;
9470Sstevel@tonic-gate 		proc->refcnt++;
9480Sstevel@tonic-gate 		(void) as_add_callback(asp, zuluvm_as_free, proc,
9490Sstevel@tonic-gate 			AS_FREE_EVENT, 0, -1, KM_SLEEP);
9500Sstevel@tonic-gate 	} else {
9510Sstevel@tonic-gate 		if (proc->valid == 0) {
9520Sstevel@tonic-gate 			mutex_exit(&zdev->proc_lck);
9530Sstevel@tonic-gate 			TNF_PROBE_2(zuluvm_dma_add_proc_done, "zuluvm", /* */,
9540Sstevel@tonic-gate 			    tnf_int, valid, 0,
9550Sstevel@tonic-gate 			    tnf_int, error, ZULUVM_ERROR);
9560Sstevel@tonic-gate 			return (ZULUVM_ERROR);
9570Sstevel@tonic-gate 		}
9580Sstevel@tonic-gate 		proc->refcnt++;
9590Sstevel@tonic-gate 	}
9600Sstevel@tonic-gate 	refcnt = proc->refcnt;
9610Sstevel@tonic-gate 	mutex_exit(&zdev->proc_lck);
9620Sstevel@tonic-gate 	*cookie = (uint64_t)proc;
9630Sstevel@tonic-gate 	TNF_PROBE_2(zuluvm_dma_add_proc_done, "zuluvm", /* */,
9640Sstevel@tonic-gate 	    tnf_int, refcnt, refcnt,
9650Sstevel@tonic-gate 	    tnf_int, error, ZULUVM_SUCCESS);
9660Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
9670Sstevel@tonic-gate }
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate void
zuluvm_proc_hold(zuluvm_state_t * zdev,zuluvm_proc_t * proc)9700Sstevel@tonic-gate zuluvm_proc_hold(zuluvm_state_t *zdev, zuluvm_proc_t *proc)
9710Sstevel@tonic-gate {
9720Sstevel@tonic-gate 	mutex_enter(&zdev->proc_lck);
9730Sstevel@tonic-gate 	proc->refcnt++;
9740Sstevel@tonic-gate 	mutex_exit(&zdev->proc_lck);
9750Sstevel@tonic-gate }
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate /*
9780Sstevel@tonic-gate  * decrement ref count and free data if it drops to zero
9790Sstevel@tonic-gate  */
9800Sstevel@tonic-gate static int
zuluvm_proc_release(zuluvm_state_t * zdev,zuluvm_proc_t * proc)9810Sstevel@tonic-gate zuluvm_proc_release(zuluvm_state_t *zdev, zuluvm_proc_t *proc)
9820Sstevel@tonic-gate {
9830Sstevel@tonic-gate 	int refcnt;
9840Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&zdev->proc_lck));
9850Sstevel@tonic-gate 	refcnt = --proc->refcnt;
9860Sstevel@tonic-gate 	TNF_PROBE_3(zuluvm_proc_release, "zuluvm", /* */,
9870Sstevel@tonic-gate 	    tnf_opaque, zdev, zdev,
9880Sstevel@tonic-gate 	    tnf_opaque, proc, proc,
9890Sstevel@tonic-gate 	    tnf_int, refcnt, refcnt);
9900Sstevel@tonic-gate 	if (refcnt == 0) {
9910Sstevel@tonic-gate 		if (proc->next)
9920Sstevel@tonic-gate 			proc->next->prev = proc->prev;
9930Sstevel@tonic-gate 		if (proc->prev)
9940Sstevel@tonic-gate 			proc->prev->next = proc->next;
9950Sstevel@tonic-gate 		else
9960Sstevel@tonic-gate 			zdev->procs = proc->next;
9970Sstevel@tonic-gate 		kmem_free(proc, sizeof (zuluvm_proc_t));
9980Sstevel@tonic-gate 	}
9990Sstevel@tonic-gate 	return (refcnt);
10000Sstevel@tonic-gate }
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate /*
10030Sstevel@tonic-gate  *	this process is not longer using DMA, all entries
10040Sstevel@tonic-gate  * 	have been removed from the TLB.
10050Sstevel@tonic-gate  */
10060Sstevel@tonic-gate int
zuluvm_dma_delete_proc(zuluvm_info_t devp,uint64_t cookie)10070Sstevel@tonic-gate zuluvm_dma_delete_proc(zuluvm_info_t devp, uint64_t cookie)
10080Sstevel@tonic-gate {
10090Sstevel@tonic-gate 	int refcnt;
10100Sstevel@tonic-gate 	zuluvm_proc_t *proc = (zuluvm_proc_t *)cookie;
10110Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 	TNF_PROBE_2(zuluvm_dma_delete_proc, "zuluvm", /* */,
10140Sstevel@tonic-gate 	    tnf_opaque, zdev, zdev,
10150Sstevel@tonic-gate 	    tnf_opaque, cookie, cookie);
10160Sstevel@tonic-gate 	mutex_enter(&zdev->proc_lck);
10170Sstevel@tonic-gate 	if (proc != NULL) {
10180Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_dma_delete_proc, "zuluvm", /* */,
10190Sstevel@tonic-gate 		    tnf_opaque, proc, proc);
10200Sstevel@tonic-gate 		if (proc->zhat != NULL) {
10210Sstevel@tonic-gate 			zulu_hat_proc_detach(proc->zhat);
10220Sstevel@tonic-gate 			proc->zhat = NULL;
10230Sstevel@tonic-gate 		}
10240Sstevel@tonic-gate 		refcnt = zuluvm_proc_release(zdev, proc);
10250Sstevel@tonic-gate 	}
10260Sstevel@tonic-gate 	mutex_exit(&zdev->proc_lck);
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 	TNF_PROBE_2(zuluvm_dma_delete_proc_done, "zuluvm", /* */,
10290Sstevel@tonic-gate 	    tnf_int, refcnt, refcnt,
10300Sstevel@tonic-gate 	    tnf_int, error, ZULUVM_SUCCESS);
10310Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
10320Sstevel@tonic-gate }
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate /*
10350Sstevel@tonic-gate  * barrier sync for device driver
10360Sstevel@tonic-gate  * blocks until zuluvm_tlbmiss_tl1 function is done
10370Sstevel@tonic-gate  */
10380Sstevel@tonic-gate void
zuluvm_fast_tlb_wait(caddr_t devp)10390Sstevel@tonic-gate zuluvm_fast_tlb_wait(caddr_t devp)
10400Sstevel@tonic-gate {
10410Sstevel@tonic-gate 	int state;
10420Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
10430Sstevel@tonic-gate 	int cnt = 0;
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 	do {
10460Sstevel@tonic-gate 		state = ZULUVM_GET_STATE(zdev);
10470Sstevel@tonic-gate 		cnt++;
10480Sstevel@tonic-gate 	} while (state == ZULUVM_STATE_TLB_PENDING);
10490Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_fast_tlb_wait, "zuluvm", /* */,
10500Sstevel@tonic-gate 	    tnf_int, loop_cnt, cnt);
10510Sstevel@tonic-gate }
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate /*
10540Sstevel@tonic-gate  *     setup DMA handling for this handle
10550Sstevel@tonic-gate  */
10560Sstevel@tonic-gate int
zuluvm_dma_alloc_ctx(zuluvm_info_t devp,int dma,short * mmuctx,uint64_t * tsbreg)10570Sstevel@tonic-gate zuluvm_dma_alloc_ctx(zuluvm_info_t devp, int dma, short *mmuctx,
10580Sstevel@tonic-gate     uint64_t *tsbreg)
10590Sstevel@tonic-gate {
10600Sstevel@tonic-gate 	struct as	*asp = ZULUVM_GET_AS;
10610Sstevel@tonic-gate 	int		error = ZULUVM_NO_DEV;
10620Sstevel@tonic-gate 	zuluvm_state_t    *zdev = (zuluvm_state_t *)devp;
10630Sstevel@tonic-gate 	int 		state, newstate;
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 	if (asp == NULL) {
10660Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_dma_alloc_ctx_done, "zuluvm", /* */,
10670Sstevel@tonic-gate 		    tnf_int, error, ZULUVM_NO_HAT);
10680Sstevel@tonic-gate 		return (ZULUVM_NO_HAT);
10690Sstevel@tonic-gate 	}
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	*tsbreg = 0;
10720Sstevel@tonic-gate 	state = ZULUVM_SET_STATE(zdev, ZULUVM_STATE_IDLE,
10730Sstevel@tonic-gate 		    ZULUVM_STATE_STOPPED);
10740Sstevel@tonic-gate 	newstate = ZULUVM_GET_STATE(zdev);
10750Sstevel@tonic-gate 	TNF_PROBE_4(zuluvm_dma_alloc_ctx, "zuluvm", /* */,
10760Sstevel@tonic-gate 	    tnf_opaque, devp, devp,
10770Sstevel@tonic-gate 	    tnf_int, dma, dma,
10780Sstevel@tonic-gate 	    tnf_int, oldstate, state,
10790Sstevel@tonic-gate 	    tnf_int, newstate, newstate);
10800Sstevel@tonic-gate #ifdef DEBUG
10810Sstevel@tonic-gate 	if (zuluvm_debug_state)
10820Sstevel@tonic-gate 		cmn_err(CE_NOTE, "zuluvm_dma_alloc_ctx: state %d\n", state);
10830Sstevel@tonic-gate #endif
10840Sstevel@tonic-gate 	if (state != ZULUVM_STATE_STOPPED && state != ZULUVM_STATE_IDLE) {
10850Sstevel@tonic-gate 		while (state != ZULUVM_STATE_IDLE) {
10860Sstevel@tonic-gate 			state = ZULUVM_SET_STATE(zdev, ZULUVM_STATE_IDLE,
10870Sstevel@tonic-gate 				    ZULUVM_STATE_STOPPED);
10880Sstevel@tonic-gate #ifdef DEBUG
10890Sstevel@tonic-gate 			if (zuluvm_debug_state)
10900Sstevel@tonic-gate 				cmn_err(CE_NOTE, "zuluvm_dma_alloc_ctx: (loop)"
10910Sstevel@tonic-gate 				    " state %d\n", state);
10920Sstevel@tonic-gate #endif
10930Sstevel@tonic-gate 			if (state != ZULUVM_STATE_IDLE)
10940Sstevel@tonic-gate 				delay(1);
10950Sstevel@tonic-gate 		}
10960Sstevel@tonic-gate 	}
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	if (zdev->zvm.arg != NULL) {
10990Sstevel@tonic-gate 		struct zulu_hat *zhat;
11000Sstevel@tonic-gate 		zuluvm_proc_t *proc;
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 		mutex_enter(&zdev->proc_lck);
11030Sstevel@tonic-gate 		proc = zuluvm_find_proc(zdev, asp);
11040Sstevel@tonic-gate 		if (proc != NULL) {
11050Sstevel@tonic-gate 			zhat = proc->zhat;
11060Sstevel@tonic-gate 			proc->refcnt++;
11070Sstevel@tonic-gate 		}
11080Sstevel@tonic-gate 		mutex_exit(&zdev->proc_lck);
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 		switch (dma) {
11110Sstevel@tonic-gate 		case ZULUVM_DMA1:
11120Sstevel@tonic-gate 			ZULUVM_LOCK;
11130Sstevel@tonic-gate 			zdev->zvm.proc1 = proc;
11140Sstevel@tonic-gate 			ZULUVM_UNLOCK;
11150Sstevel@tonic-gate 			error = ZULUVM_SUCCESS;
11160Sstevel@tonic-gate 			break;
11170Sstevel@tonic-gate 		case ZULUVM_DMA2:
11180Sstevel@tonic-gate 			ZULUVM_LOCK;
11190Sstevel@tonic-gate 			zdev->zvm.proc2 = proc;
11200Sstevel@tonic-gate 			ZULUVM_UNLOCK;
11210Sstevel@tonic-gate 			error = ZULUVM_SUCCESS;
11220Sstevel@tonic-gate 			break;
11230Sstevel@tonic-gate 		default:
11240Sstevel@tonic-gate 			mutex_enter(&zdev->proc_lck);
11250Sstevel@tonic-gate 			(void) zuluvm_proc_release(zdev, proc);
11260Sstevel@tonic-gate 			mutex_exit(&zdev->proc_lck);
11270Sstevel@tonic-gate 		}
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate 		if (error == ZULUVM_SUCCESS) {
11300Sstevel@tonic-gate 			zulu_hat_validate_ctx(zhat);
11310Sstevel@tonic-gate 			if (zhat->zulu_ctx >= 0) {
11320Sstevel@tonic-gate 				*mmuctx = zhat->zulu_ctx;
11330Sstevel@tonic-gate 			} else {
11340Sstevel@tonic-gate 				printf("invalid context value: %d\n",
11350Sstevel@tonic-gate 					zhat->zulu_ctx);
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate 				mutex_enter(&zdev->proc_lck);
11380Sstevel@tonic-gate 				(void) zuluvm_proc_release(zdev, proc);
11390Sstevel@tonic-gate 				mutex_exit(&zdev->proc_lck);
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 				error = ZULUVM_ERROR;
11420Sstevel@tonic-gate 			}
11430Sstevel@tonic-gate 		} else {
11440Sstevel@tonic-gate 			error = ZULUVM_ERROR;
11450Sstevel@tonic-gate 		}
11460Sstevel@tonic-gate 	}
11470Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_dma_alloc_ctx_done, "zuluvm", /* */,
11480Sstevel@tonic-gate 	    tnf_int, error, error);
11490Sstevel@tonic-gate 	return (error);
11500Sstevel@tonic-gate }
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate /*
11530Sstevel@tonic-gate  * preload TLB
11540Sstevel@tonic-gate  * this will try to pre-set the zulu tlb, mainly used for dma engine 2,
11550Sstevel@tonic-gate  * video read-back.
11560Sstevel@tonic-gate  */
11570Sstevel@tonic-gate int
zuluvm_dma_preload(zuluvm_info_t devp,int dma,int num,zulud_preload_t * list)11580Sstevel@tonic-gate zuluvm_dma_preload(zuluvm_info_t devp, int dma,
11590Sstevel@tonic-gate 			int num, zulud_preload_t *list)
11600Sstevel@tonic-gate {
11610Sstevel@tonic-gate 	int i;
11620Sstevel@tonic-gate 	int error = ZULUVM_SUCCESS;
11630Sstevel@tonic-gate 	struct zulu_hat *zhat;
11640Sstevel@tonic-gate 	zuluvm_proc_t *proc = NULL;
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
11670Sstevel@tonic-gate 
11680Sstevel@tonic-gate 	TNF_PROBE_4(zuluvm_dma_preload, "zuluvm", /* */,
11690Sstevel@tonic-gate 	    tnf_opaque, devp, devp,
11700Sstevel@tonic-gate 	    tnf_int, dma, dma,
11710Sstevel@tonic-gate 	    tnf_int, num, num,
11720Sstevel@tonic-gate 	    tnf_opaque, list, list);
11730Sstevel@tonic-gate 	ZULUVM_LOCK;
11740Sstevel@tonic-gate 	switch (dma) {
11750Sstevel@tonic-gate 	case ZULUVM_DMA1:
11760Sstevel@tonic-gate 		proc = zdev->zvm.proc1;
11770Sstevel@tonic-gate 		break;
11780Sstevel@tonic-gate 	case ZULUVM_DMA2:
11790Sstevel@tonic-gate 		proc = zdev->zvm.proc2;
11800Sstevel@tonic-gate 		break;
11810Sstevel@tonic-gate 	}
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	mutex_enter(&zdev->proc_lck);
11840Sstevel@tonic-gate 	if (proc == NULL || proc->valid == 0 || proc->zhat == NULL) {
11850Sstevel@tonic-gate 		mutex_exit(&zdev->proc_lck);
11860Sstevel@tonic-gate 		ZULUVM_UNLOCK;
11870Sstevel@tonic-gate 		return (ZULUVM_NO_HAT);
11880Sstevel@tonic-gate 	}
11890Sstevel@tonic-gate 	mutex_exit(&zdev->proc_lck);
11900Sstevel@tonic-gate 
11910Sstevel@tonic-gate 	zhat = proc->zhat;
11920Sstevel@tonic-gate 	/*
11930Sstevel@tonic-gate 	 * need to release this to avoid recursive enter in zuluvm_load_tte
11940Sstevel@tonic-gate 	 * which gets called from zulu_hat_memload()
11950Sstevel@tonic-gate 	 */
11960Sstevel@tonic-gate 	ZULUVM_UNLOCK;
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 	mutex_enter(&zdev->load_lck);
11990Sstevel@tonic-gate 	for (i = 0; i < num; i++) {
12000Sstevel@tonic-gate 		int pg_size;
12010Sstevel@tonic-gate 		int res;
12020Sstevel@tonic-gate 		int first = 1;
12030Sstevel@tonic-gate 		caddr_t addr = ZULUVM_GET_PAGE(list[i].addr);
12040Sstevel@tonic-gate 		int64_t size = (int64_t)list[i].len;
12050Sstevel@tonic-gate 		while (size > 0) {
12060Sstevel@tonic-gate 			if (list[i].tlbtype & ~ZULUVM_DMA_MASK) {
12070Sstevel@tonic-gate 				error = ZULUVM_INVALID_MISS;
12080Sstevel@tonic-gate 				break;
12090Sstevel@tonic-gate 			}
12100Sstevel@tonic-gate 			res = zulu_hat_load(zhat, addr,
12110Sstevel@tonic-gate 			    (list[i].tlbtype == ZULUVM_DMA2) ? S_WRITE : S_READ,
12120Sstevel@tonic-gate 			    &pg_size);
12130Sstevel@tonic-gate 			if ((res != 0) || (pg_size < 0)) {
12140Sstevel@tonic-gate 				error = ZULUVM_NO_MAP;
12150Sstevel@tonic-gate 				break;
12160Sstevel@tonic-gate 			}
12170Sstevel@tonic-gate 			ZULUVM_STATS_PRELOAD(zdev);
12180Sstevel@tonic-gate 			TNF_PROBE_2(zuluvm_dma_preload_addr, "zuluvm", /* */,
12190Sstevel@tonic-gate 			    tnf_opaque, addr, addr,
12200Sstevel@tonic-gate 			    tnf_opaque, size, size);
12210Sstevel@tonic-gate 			if (first) {
12220Sstevel@tonic-gate 				first = 0;
12230Sstevel@tonic-gate 				size -= ZULU_HAT_PGDIFF(list[i].addr,
12240Sstevel@tonic-gate 							pg_size);
12250Sstevel@tonic-gate 			} else {
12260Sstevel@tonic-gate 				size -= ZULU_HAT_PGSZ(pg_size);
12270Sstevel@tonic-gate 			}
12280Sstevel@tonic-gate 			addr += ZULU_HAT_PGSZ(pg_size);
12290Sstevel@tonic-gate 		}
12300Sstevel@tonic-gate 	}
12310Sstevel@tonic-gate 	mutex_exit(&zdev->load_lck);
12320Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_dma_preload_done, "zuluvm", /* */,
12330Sstevel@tonic-gate 	    tnf_int, error, error);
12340Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
12350Sstevel@tonic-gate }
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate /*
12380Sstevel@tonic-gate  * destroy DMA handling for this handle
12390Sstevel@tonic-gate  */
12400Sstevel@tonic-gate int
zuluvm_dma_free_ctx(zuluvm_info_t devp,int dma)12410Sstevel@tonic-gate zuluvm_dma_free_ctx(zuluvm_info_t devp, int dma)
12420Sstevel@tonic-gate {
12430Sstevel@tonic-gate 	int error = ZULUVM_NO_DEV;
12440Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
12450Sstevel@tonic-gate 	int state, newstate;
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 	state = ZULUVM_SET_STATE(zdev, ZULUVM_STATE_STOPPED,
12480Sstevel@tonic-gate 		    ZULUVM_STATE_IDLE);
12490Sstevel@tonic-gate 	newstate = ZULUVM_GET_STATE(zdev);
12500Sstevel@tonic-gate 	TNF_PROBE_4(zuluvm_dma_free_ctx, "zuluvm", /* */,
12510Sstevel@tonic-gate 	    tnf_opaque, devp, devp,
12520Sstevel@tonic-gate 	    tnf_int, dma, dma,
12530Sstevel@tonic-gate 	    tnf_int, oldstate, state,
12540Sstevel@tonic-gate 	    tnf_int, newstate, newstate);
12550Sstevel@tonic-gate #ifdef DEBUG
12560Sstevel@tonic-gate 	if (zuluvm_debug_state)
12570Sstevel@tonic-gate 		cmn_err(CE_NOTE, "zuluvm_dma_free_ctx: state %d\n", state);
12580Sstevel@tonic-gate #endif
12590Sstevel@tonic-gate 	if (state != ZULUVM_STATE_IDLE && state != ZULUVM_STATE_STOPPED) {
12600Sstevel@tonic-gate 		int doit = 1;
12610Sstevel@tonic-gate 		while (doit) {
12620Sstevel@tonic-gate 			switch (state) {
12630Sstevel@tonic-gate 			case ZULUVM_STATE_CANCELED:
12640Sstevel@tonic-gate 			case ZULUVM_STATE_STOPPED:
12650Sstevel@tonic-gate 				doit = 0;
12660Sstevel@tonic-gate 				break;
12670Sstevel@tonic-gate 			case ZULUVM_STATE_IDLE:
12680Sstevel@tonic-gate 				state = ZULUVM_SET_STATE(zdev,
12690Sstevel@tonic-gate 					    ZULUVM_STATE_STOPPED,
12700Sstevel@tonic-gate 					    ZULUVM_STATE_IDLE);
12710Sstevel@tonic-gate 				break;
12720Sstevel@tonic-gate 			default:
12730Sstevel@tonic-gate 				state = ZULUVM_SET_STATE(zdev,
12740Sstevel@tonic-gate 					    ZULUVM_STATE_CANCELED, state);
12750Sstevel@tonic-gate 			}
12760Sstevel@tonic-gate 			TNF_PROBE_1(zuluvm_dma_free_ctx, "zuluvm", /* */,
12770Sstevel@tonic-gate 			    tnf_int, state, state);
12780Sstevel@tonic-gate #ifdef DEBUG
12790Sstevel@tonic-gate 			if (zuluvm_debug_state)
12800Sstevel@tonic-gate 				cmn_err(CE_NOTE, "zuluvm_dma_free_ctx: (loop1)"
12810Sstevel@tonic-gate 				    " state %d\n", state);
12820Sstevel@tonic-gate #endif
12830Sstevel@tonic-gate 		}
12840Sstevel@tonic-gate 	}
12850Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_dma_free_ctx, "zuluvm", /* */,
12860Sstevel@tonic-gate 	    tnf_int, state, state);
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 	error = ZULUVM_SUCCESS;
12890Sstevel@tonic-gate 	while (state != ZULUVM_STATE_STOPPED) {
12900Sstevel@tonic-gate 		state = ZULUVM_GET_STATE(zdev);
12910Sstevel@tonic-gate #ifdef DEBUG
12920Sstevel@tonic-gate 		if (zuluvm_debug_state)
12930Sstevel@tonic-gate 			cmn_err(CE_NOTE, "zuluvm_dma_free: (loop2) state %d\n",
12940Sstevel@tonic-gate 			    state);
12950Sstevel@tonic-gate #endif
12960Sstevel@tonic-gate 		if (state != ZULUVM_STATE_STOPPED)
12970Sstevel@tonic-gate 			delay(1);
12980Sstevel@tonic-gate 	}
12990Sstevel@tonic-gate 	ZULUVM_LOCK;
13000Sstevel@tonic-gate 	if (zdev->zvm.arg != NULL) {
13010Sstevel@tonic-gate 		zuluvm_proc_t *proc = NULL;
13020Sstevel@tonic-gate 		switch (dma) {
13030Sstevel@tonic-gate 		case ZULUVM_DMA1:
13040Sstevel@tonic-gate 			proc = zdev->zvm.proc1;
13050Sstevel@tonic-gate 			zdev->zvm.proc1 = NULL;
13060Sstevel@tonic-gate 			break;
13070Sstevel@tonic-gate 		case ZULUVM_DMA2:
13080Sstevel@tonic-gate 			proc = zdev->zvm.proc2;
13090Sstevel@tonic-gate 			zdev->zvm.proc2 = NULL;
13100Sstevel@tonic-gate 			break;
13110Sstevel@tonic-gate 		default:
13120Sstevel@tonic-gate 			error = ZULUVM_NO_DEV;
13130Sstevel@tonic-gate 		}
13140Sstevel@tonic-gate 		ZULUVM_UNLOCK;
13150Sstevel@tonic-gate 		if (proc) {
13160Sstevel@tonic-gate 			mutex_enter(&zdev->proc_lck);
13170Sstevel@tonic-gate 			(void) zuluvm_proc_release(zdev, proc);
13180Sstevel@tonic-gate 			mutex_exit(&zdev->proc_lck);
13190Sstevel@tonic-gate 		}
13200Sstevel@tonic-gate 	} else {
13210Sstevel@tonic-gate 		ZULUVM_UNLOCK;
13220Sstevel@tonic-gate 		error = ZULUVM_NO_DEV;
13230Sstevel@tonic-gate 	}
13240Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_dma_free_ctx_done, "zuluvm", /* */,
13250Sstevel@tonic-gate 	    tnf_int, error, error);
13260Sstevel@tonic-gate 	return (error);
13270Sstevel@tonic-gate }
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate static void
zuluvm_do_retarget(zuluvm_state_t * zdev)13300Sstevel@tonic-gate zuluvm_do_retarget(zuluvm_state_t *zdev)
13310Sstevel@tonic-gate {
13320Sstevel@tonic-gate 	int i, idx;
13330Sstevel@tonic-gate 	uint_t cpu;
13340Sstevel@tonic-gate 	for (i = 0; i < ZULUVM_MAX_INTR; i++) {
13350Sstevel@tonic-gate 		if (zdev->interrupts[i].ino != -1) {
13360Sstevel@tonic-gate 			cpu = intr_dist_cpuid();
13370Sstevel@tonic-gate 			idx = zdev->interrupts[i].offset;
13380Sstevel@tonic-gate 			if (zdev->imr[idx] & ZULUVM_IMR_V_MASK)
13390Sstevel@tonic-gate 				zdev->imr[idx] = ZULUVM_IMR_V_MASK |
13400Sstevel@tonic-gate 				    (cpu<<ZULUVM_IMR_TARGET_SHIFT);
13410Sstevel@tonic-gate 			else
13420Sstevel@tonic-gate 				zdev->imr[idx] =
13430Sstevel@tonic-gate 				    cpu<<ZULUVM_IMR_TARGET_SHIFT;
13440Sstevel@tonic-gate 		}
13450Sstevel@tonic-gate 	}
13460Sstevel@tonic-gate }
13470Sstevel@tonic-gate 
13480Sstevel@tonic-gate static void
zuluvm_retarget_intr(void * arg)13490Sstevel@tonic-gate zuluvm_retarget_intr(void *arg)
13500Sstevel@tonic-gate {
13510Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)arg;
13520Sstevel@tonic-gate 	ZULUVM_LOCK;
13530Sstevel@tonic-gate 	zuluvm_do_retarget(zdev);
13540Sstevel@tonic-gate 	ZULUVM_UNLOCK;
13550Sstevel@tonic-gate }
13560Sstevel@tonic-gate 
13570Sstevel@tonic-gate int
zuluvm_add_intr(zuluvm_info_t devp,int ino,uint_t (* handler)(caddr_t),caddr_t arg)13580Sstevel@tonic-gate zuluvm_add_intr(zuluvm_info_t devp, int ino,
13590Sstevel@tonic-gate 		uint_t (*handler)(caddr_t), caddr_t arg)
13600Sstevel@tonic-gate {
13610Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
13620Sstevel@tonic-gate 	if (devp == NULL) {
13630Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_add_intr_done, "zuluvm", /* */,
13640Sstevel@tonic-gate 		    tnf_int, error, ZULUVM_NO_DEV);
13650Sstevel@tonic-gate 		return (ZULUVM_NO_DEV);
13660Sstevel@tonic-gate 	}
13670Sstevel@tonic-gate 	if (ddi_add_intr(zdev->dip, ino, NULL, NULL, handler, arg)
13680Sstevel@tonic-gate 		!= DDI_SUCCESS) {
13690Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_add_intr_done, "zuluvm", /* */,
13700Sstevel@tonic-gate 		    tnf_int, error, ZULUVM_ERROR);
13710Sstevel@tonic-gate 		return (ZULUVM_ERROR);
13720Sstevel@tonic-gate 	}
13730Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
13740Sstevel@tonic-gate }
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate int
zuluvm_rem_intr(zuluvm_info_t devp,int ino)13770Sstevel@tonic-gate zuluvm_rem_intr(zuluvm_info_t devp, int ino)
13780Sstevel@tonic-gate {
13790Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
13800Sstevel@tonic-gate 	if (devp == NULL) {
13810Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_rem_intr_done, "zuluvm", /* */,
13820Sstevel@tonic-gate 		    tnf_int, error, ZULUVM_NO_DEV);
13830Sstevel@tonic-gate 		return (ZULUVM_NO_DEV);
13840Sstevel@tonic-gate 	}
13850Sstevel@tonic-gate 	/* remove from distributin list */
13860Sstevel@tonic-gate 	ZULUVM_LOCK;
13870Sstevel@tonic-gate 	zdev->imr[zdev->interrupts[ino].offset] &= ~ZULUVM_IMR_V_MASK;
13880Sstevel@tonic-gate 	ZULUVM_UNLOCK;
13890Sstevel@tonic-gate 	ddi_remove_intr(zdev->dip, ino, NULL);
13900Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
13910Sstevel@tonic-gate }
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate int
zuluvm_enable_intr(zuluvm_info_t devp,int num)13940Sstevel@tonic-gate zuluvm_enable_intr(zuluvm_info_t devp, int num)
13950Sstevel@tonic-gate {
13960Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate 	TNF_PROBE_2(zuluvm_enable_intr, "zuluvm_intr", /* */,
13990Sstevel@tonic-gate 	    tnf_opaque, devp, devp,
14000Sstevel@tonic-gate 	    tnf_int, num, num);
14010Sstevel@tonic-gate 	if (devp == NULL) {
14020Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_enable_intr_done, "zuluvm", /* */,
14030Sstevel@tonic-gate 		    tnf_int, error, ZULUVM_NO_DEV);
14040Sstevel@tonic-gate 		return (ZULUVM_NO_DEV);
14050Sstevel@tonic-gate 	}
14060Sstevel@tonic-gate 	if (num < 0 || num > ZULUVM_IMR_MAX) {
14070Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_enable_intr_done, "zuluvm", /* */,
14080Sstevel@tonic-gate 		    tnf_int, error, ZULUVM_BAD_IDX);
14090Sstevel@tonic-gate 		return (ZULUVM_BAD_IDX);
14100Sstevel@tonic-gate 	}
14110Sstevel@tonic-gate 	ZULUVM_LOCK;
14120Sstevel@tonic-gate 	zdev->imr[num] |= ZULUVM_IMR_V_MASK;
14130Sstevel@tonic-gate 	ZULUVM_UNLOCK;
14140Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_enable_intr_done, "zuluvm_intr", /* */,
14150Sstevel@tonic-gate 	    tnf_int, error, ZULUVM_SUCCESS);
14160Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
14170Sstevel@tonic-gate }
14180Sstevel@tonic-gate 
14190Sstevel@tonic-gate int
zuluvm_disable_intr(zuluvm_info_t devp,int num)14200Sstevel@tonic-gate zuluvm_disable_intr(zuluvm_info_t devp, int num)
14210Sstevel@tonic-gate {
14220Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
14230Sstevel@tonic-gate 
14240Sstevel@tonic-gate 	TNF_PROBE_2(zuluvm_disable_intr, "zuluvm_intr", /* */,
14250Sstevel@tonic-gate 	    tnf_opaque, devp, devp,
14260Sstevel@tonic-gate 	    tnf_int, num, num);
14270Sstevel@tonic-gate 	if (devp == NULL) {
14280Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_disable_intr_done, "zuluvm", /* */,
14290Sstevel@tonic-gate 		    tnf_int, error, ZULUVM_NO_DEV);
14300Sstevel@tonic-gate 		return (ZULUVM_NO_DEV);
14310Sstevel@tonic-gate 	}
14320Sstevel@tonic-gate 	if (num < 0 || num > ZULUVM_IMR_MAX) {
14330Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_disable_intr_done, "zuluvm", /* */,
14340Sstevel@tonic-gate 		    tnf_int, error, ZULUVM_BAD_IDX);
14350Sstevel@tonic-gate 		return (ZULUVM_BAD_IDX);
14360Sstevel@tonic-gate 	}
14370Sstevel@tonic-gate 	ZULUVM_LOCK;
14380Sstevel@tonic-gate 	zdev->imr[num] &= ~ZULUVM_IMR_V_MASK;
14390Sstevel@tonic-gate 	ZULUVM_UNLOCK;
14400Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_disable_intr_done, "zuluvm_intr", /* */,
14410Sstevel@tonic-gate 	    tnf_int, error, ZULUVM_SUCCESS);
14420Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
14430Sstevel@tonic-gate }
14440Sstevel@tonic-gate 
14450Sstevel@tonic-gate static int
zuluvm_get_intr_props(zuluvm_state_t * zdev,dev_info_t * devi)14460Sstevel@tonic-gate zuluvm_get_intr_props(zuluvm_state_t *zdev,
14470Sstevel@tonic-gate 			dev_info_t *devi)
14480Sstevel@tonic-gate {
14490Sstevel@tonic-gate 	int *intr;
14500Sstevel@tonic-gate 	int i;
14510Sstevel@tonic-gate 	uint_t nintr;
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate 	zdev->agentid = ddi_getprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
14540Sstevel@tonic-gate 	    "portid", -1);
14550Sstevel@tonic-gate 	if (zdev->agentid == -1) {
14560Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: no portid property",
14570Sstevel@tonic-gate 		    ddi_get_name(devi),
14580Sstevel@tonic-gate 		    ddi_get_instance(devi));
14590Sstevel@tonic-gate 		return (ZULUVM_ERROR);
14600Sstevel@tonic-gate 	}
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate 	for (i = 0; i < ZULUVM_MAX_INTR; i++) {
14630Sstevel@tonic-gate 		zdev->interrupts[i].offset = 0;
14640Sstevel@tonic-gate 		zdev->interrupts[i].ino = -1;
14650Sstevel@tonic-gate 	}
14660Sstevel@tonic-gate 
14670Sstevel@tonic-gate 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
14680Sstevel@tonic-gate 	    "interrupts", &intr, &nintr) == DDI_PROP_SUCCESS) {
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate 		if (nintr == 0) {
14710Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: no interrupts in property",
14720Sstevel@tonic-gate 			    ddi_get_name(devi),
14730Sstevel@tonic-gate 			    ddi_get_instance(devi));
14740Sstevel@tonic-gate 			ddi_prop_free(intr);
14750Sstevel@tonic-gate 			return (ZULUVM_ERROR);
14760Sstevel@tonic-gate 		}
14770Sstevel@tonic-gate 		if (nintr >= ZULUVM_MAX_INTR) {
14780Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: to many interrupts (%d)",
14790Sstevel@tonic-gate 			    ddi_get_name(devi),
14800Sstevel@tonic-gate 			    ddi_get_instance(devi), nintr);
14810Sstevel@tonic-gate 			ddi_prop_free(intr);
14820Sstevel@tonic-gate 			return (ZULUVM_ERROR);
14830Sstevel@tonic-gate 		}
14840Sstevel@tonic-gate 		for (i = 0; i < nintr; i++) {
14850Sstevel@tonic-gate 			zdev->interrupts[i].offset = intr[i];
14860Sstevel@tonic-gate 			zdev->interrupts[i].ino = i;
14870Sstevel@tonic-gate 		}
14880Sstevel@tonic-gate 		ddi_prop_free(intr);
14890Sstevel@tonic-gate 	} else {
14900Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: no interrupts property",
14910Sstevel@tonic-gate 		    ddi_get_name(devi),
14920Sstevel@tonic-gate 		    ddi_get_instance(devi));
14930Sstevel@tonic-gate 	}
14940Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
14950Sstevel@tonic-gate }
14960Sstevel@tonic-gate 
14970Sstevel@tonic-gate /* *** enf of zulu *** */
1498