xref: /onnv-gate/usr/src/uts/sun4u/io/zuluvm.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * zuluvm module
31*0Sstevel@tonic-gate  *
32*0Sstevel@tonic-gate  * Provides services required by the XVR-4000 graphics accelerator (zulu)
33*0Sstevel@tonic-gate  * that are not provided by the ddi. See PSARC 2002/231.
34*0Sstevel@tonic-gate  *
35*0Sstevel@tonic-gate  * Zulu has 2 dma engines with built in MMUs. zuluvm provides TLB miss
36*0Sstevel@tonic-gate  * interrupt support obtaining virtual to physical address translations
37*0Sstevel@tonic-gate  * using the XHAT interface PSARC/2003/517.
38*0Sstevel@tonic-gate  *
39*0Sstevel@tonic-gate  * The module has 3 components. This file, sun4u/vm/zulu_hat.c, and the
40*0Sstevel@tonic-gate  * assembly language routines in sun4u/ml/zulu_asm.s and
41*0Sstevel@tonic-gate  * sun4u/ml/zulu_hat_asm.s.
42*0Sstevel@tonic-gate  *
43*0Sstevel@tonic-gate  * The interrupt handler is a data bearing mondo interrupt handled at TL=1
44*0Sstevel@tonic-gate  * If no translation is found in the zulu hat's tsb, or if the tsb is locked by
45*0Sstevel@tonic-gate  * C code, the handler posts a soft interrupt which wakes up a parked
46*0Sstevel@tonic-gate  * thread belonging to zuludaemon(1M).
47*0Sstevel@tonic-gate  */
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate #include <sys/conf.h>
50*0Sstevel@tonic-gate #include <sys/types.h>
51*0Sstevel@tonic-gate #include <sys/kmem.h>
52*0Sstevel@tonic-gate #include <sys/debug.h>
53*0Sstevel@tonic-gate #include <sys/modctl.h>
54*0Sstevel@tonic-gate #include <sys/autoconf.h>
55*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
56*0Sstevel@tonic-gate #include <sys/ddi_subrdefs.h>
57*0Sstevel@tonic-gate #include <sys/intr.h>
58*0Sstevel@tonic-gate #include <sys/ddi.h>
59*0Sstevel@tonic-gate #include <sys/sunndi.h>
60*0Sstevel@tonic-gate #include <sys/proc.h>
61*0Sstevel@tonic-gate #include <sys/thread.h>
62*0Sstevel@tonic-gate #include <sys/machsystm.h>
63*0Sstevel@tonic-gate #include <sys/ivintr.h>
64*0Sstevel@tonic-gate #include <sys/tnf_probe.h>
65*0Sstevel@tonic-gate #include <sys/intreg.h>
66*0Sstevel@tonic-gate #include <sys/atomic.h>
67*0Sstevel@tonic-gate #include <vm/as.h>
68*0Sstevel@tonic-gate #include <vm/seg_enum.h>
69*0Sstevel@tonic-gate #include <vm/faultcode.h>
70*0Sstevel@tonic-gate #include <sys/dmv.h>
71*0Sstevel@tonic-gate #include <sys/zulumod.h>
72*0Sstevel@tonic-gate #include <sys/zulu_hat.h>
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate #define	ZULUVM_GET_PAGE(val) \
75*0Sstevel@tonic-gate 	(caddr_t)((uintptr_t)(val) & PAGEMASK)
76*0Sstevel@tonic-gate #define	ZULUVM_GET_AS	curthread->t_procp->p_as
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate #define	ZULUVM_LOCK   mutex_enter(&(zdev->dev_lck))
79*0Sstevel@tonic-gate #define	ZULUVM_UNLOCK mutex_exit(&(zdev->dev_lck))
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate #define	ZULUVM_SET_STATE(_z, b, c) \
82*0Sstevel@tonic-gate 	cas32((uint32_t *)&((_z)->zvm.state), c, b)
83*0Sstevel@tonic-gate #define	ZULUVM_GET_STATE(_z) \
84*0Sstevel@tonic-gate 	(_z)->zvm.state
85*0Sstevel@tonic-gate #define	ZULUVM_SET_IDLE(_z) \
86*0Sstevel@tonic-gate 	(_z)->zvm.state = ZULUVM_STATE_IDLE;
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate #define	ZULUVM_INO_MASK ((1<<INO_SIZE)-1)
89*0Sstevel@tonic-gate #define	ZULUVM_IGN_MASK ((1<<IGN_SIZE)-1)
90*0Sstevel@tonic-gate #define	ZULUVM_MONDO(_zdev, _n) \
91*0Sstevel@tonic-gate 	((ZULUVM_IGN_MASK & _zdev->agentid) << INO_SIZE) | \
92*0Sstevel@tonic-gate 	(ZULUVM_INO_MASK & (_n))
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate static void zuluvm_stop(zuluvm_state_t *, int, char *);
95*0Sstevel@tonic-gate static zuluvm_proc_t *zuluvm_find_proc(zuluvm_state_t *, struct as *);
96*0Sstevel@tonic-gate static int zuluvm_proc_release(zuluvm_state_t *zdev, zuluvm_proc_t *proc);
97*0Sstevel@tonic-gate static int zuluvm_get_intr_props(zuluvm_state_t *zdev, dev_info_t *devi);
98*0Sstevel@tonic-gate static int zuluvm_driver_attach(zuluvm_state_t *);
99*0Sstevel@tonic-gate static int zuluvm_driver_detach(zuluvm_state_t *);
100*0Sstevel@tonic-gate static void zuluvm_retarget_intr(void *arg);
101*0Sstevel@tonic-gate static void zuluvm_do_retarget(zuluvm_state_t *zdev);
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate extern const unsigned int _mmu_pageshift;
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate extern int zuluvm_base_pgsize;
106*0Sstevel@tonic-gate static int zuluvm_pagesizes[ZULUM_MAX_PG_SIZES + 1];
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate int zuluvm_fast_tlb = 1;
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate zuluvm_state_t *zuluvm_devtab[ZULUVM_MAX_DEV];
111*0Sstevel@tonic-gate kmutex_t zuluvm_lck;
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate #ifdef DEBUG
114*0Sstevel@tonic-gate int zuluvm_debug_state = 0;
115*0Sstevel@tonic-gate #endif
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate unsigned long zuluvm_ctx_locked = 0;
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate /*
120*0Sstevel@tonic-gate  * Module linkage information for the kernel.
121*0Sstevel@tonic-gate  */
122*0Sstevel@tonic-gate extern struct mod_ops mod_miscops;
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate static struct modlmisc modlmisc = {
125*0Sstevel@tonic-gate 	&mod_miscops,
126*0Sstevel@tonic-gate 	"sun4u support " ZULUVM_MOD_VERSION
127*0Sstevel@tonic-gate };
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
130*0Sstevel@tonic-gate 	MODREV_1,
131*0Sstevel@tonic-gate 	(void *)&modlmisc,
132*0Sstevel@tonic-gate 	NULL
133*0Sstevel@tonic-gate };
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate int
136*0Sstevel@tonic-gate _init(void)
137*0Sstevel@tonic-gate {
138*0Sstevel@tonic-gate 	zuluvm_base_pgsize = (_mmu_pageshift - 13) / 3;
139*0Sstevel@tonic-gate 	if (zulu_hat_init() != 0) {
140*0Sstevel@tonic-gate 		return (ZULUVM_ERROR);
141*0Sstevel@tonic-gate 	}
142*0Sstevel@tonic-gate 	mutex_init(&zuluvm_lck, NULL, MUTEX_DEFAULT, NULL);
143*0Sstevel@tonic-gate 	return (mod_install(&modlinkage));
144*0Sstevel@tonic-gate }
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate int
147*0Sstevel@tonic-gate _fini(void)
148*0Sstevel@tonic-gate {
149*0Sstevel@tonic-gate 	mutex_destroy(&zuluvm_lck);
150*0Sstevel@tonic-gate 	(void) zulu_hat_destroy();
151*0Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
152*0Sstevel@tonic-gate }
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate int
155*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
156*0Sstevel@tonic-gate {
157*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
158*0Sstevel@tonic-gate }
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate /*
161*0Sstevel@tonic-gate  * currently the kernel driver makes the following assumptions:
162*0Sstevel@tonic-gate  * - there is only one TLB miss per zulu device handled at
163*0Sstevel@tonic-gate  *   any given time
164*0Sstevel@tonic-gate  *   ==> we only need local data storage per device, not per DMA
165*0Sstevel@tonic-gate  *   ==> a page fault will block the DMA engine until the fault
166*0Sstevel@tonic-gate  *       is resolved
167*0Sstevel@tonic-gate  *   ==> a pagefault will not trigger a zulu DMA context switch
168*0Sstevel@tonic-gate  *
169*0Sstevel@tonic-gate  * If we want to implement asynnchronous zulu page fault, then we
170*0Sstevel@tonic-gate  * need to keep track of outstanding faults while zulu DMA runs
171*0Sstevel@tonic-gate  * in a different context.
172*0Sstevel@tonic-gate  */
173*0Sstevel@tonic-gate static int
174*0Sstevel@tonic-gate zuluvm_write_tte(zuluvm_state_t *zdev, void *arg, caddr_t addr,
175*0Sstevel@tonic-gate     int t_pfn, int t_perm, int t_size, uint64_t tag,
176*0Sstevel@tonic-gate     int tlbtype, int *size)
177*0Sstevel@tonic-gate {
178*0Sstevel@tonic-gate 	int error;
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	(void) addr;
181*0Sstevel@tonic-gate 
182*0Sstevel@tonic-gate 	ZULUVM_STATS_MISS(zdev, t_size);
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 	if (tag == 0) { /* not coming from preload */
185*0Sstevel@tonic-gate 		int state = ZULUVM_SET_STATE(zdev, ZULUVM_STATE_WRITE_TTE,
186*0Sstevel@tonic-gate 				ZULUVM_STATE_INTR_PENDING);
187*0Sstevel@tonic-gate 		if (state != ZULUVM_STATE_INTR_PENDING) {
188*0Sstevel@tonic-gate 			zuluvm_stop(zdev, state, "zuluvm_write_tte");
189*0Sstevel@tonic-gate 			return (ZULUVM_MISS_CANCELED);
190*0Sstevel@tonic-gate 		}
191*0Sstevel@tonic-gate 	}
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	if (!(tlbtype & ZULUVM_ITLB_FLAG) &&
194*0Sstevel@tonic-gate 	    t_size != zuluvm_base_pgsize &&
195*0Sstevel@tonic-gate 	    t_size != ZULU_TTE4M) {
196*0Sstevel@tonic-gate 		t_size = zuluvm_base_pgsize;
197*0Sstevel@tonic-gate 		TNF_PROBE_2(zuluvm_write_tte_new_pfn, "zuluvm", /* */,
198*0Sstevel@tonic-gate 		    tnf_opaque, t_pfn, t_pfn, tnf_int, pagesize, t_size);
199*0Sstevel@tonic-gate 	}
200*0Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_write_tte, "zuluvm", /* */,
201*0Sstevel@tonic-gate 	    tnf_opaque, t_pfn, t_pfn);
202*0Sstevel@tonic-gate 	/*
203*0Sstevel@tonic-gate 	 * if the caller is zuluvm_preload, then we need to pass
204*0Sstevel@tonic-gate 	 * back the page size so it can add the right offset.
205*0Sstevel@tonic-gate 	 */
206*0Sstevel@tonic-gate 	if (size)
207*0Sstevel@tonic-gate 		*size = t_size;
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	error = zulud_write_tte(zdev, arg, t_size, tag, t_pfn,
210*0Sstevel@tonic-gate 		    t_perm, tlbtype);
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	return (error);
213*0Sstevel@tonic-gate }
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate static void
216*0Sstevel@tonic-gate zuluvm_stop(zuluvm_state_t *zdev, int state, char *tag)
217*0Sstevel@tonic-gate {
218*0Sstevel@tonic-gate 	int ostate = state;
219*0Sstevel@tonic-gate 	while (state != ZULUVM_STATE_STOPPED) {
220*0Sstevel@tonic-gate 		state = ZULUVM_SET_STATE(zdev,
221*0Sstevel@tonic-gate 			    ZULUVM_STATE_STOPPED, state);
222*0Sstevel@tonic-gate #ifdef DEBUG
223*0Sstevel@tonic-gate 		if (zuluvm_debug_state)
224*0Sstevel@tonic-gate 			cmn_err(CE_NOTE, "zuluvm_stop(%s): (loop) state %d\n",
225*0Sstevel@tonic-gate 			    tag, state);
226*0Sstevel@tonic-gate #endif
227*0Sstevel@tonic-gate 	}
228*0Sstevel@tonic-gate 	TNF_PROBE_2(zuluvm_stop, "zuluvm", /* */,
229*0Sstevel@tonic-gate 	    tnf_string, tag, tag,
230*0Sstevel@tonic-gate 	    tnf_int, state, ostate);
231*0Sstevel@tonic-gate 	ZULUVM_STATS_CANCEL(zdev);
232*0Sstevel@tonic-gate }
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate /*
235*0Sstevel@tonic-gate  * Executed with the context of the parked zulu deamon thread,
236*0Sstevel@tonic-gate  * uses zulu_hat_load to resolve the miss.
237*0Sstevel@tonic-gate  * The tte is loaded and miss done called by the function zuluvm_load_tte
238*0Sstevel@tonic-gate  * which is called from zulu_hat
239*0Sstevel@tonic-gate  *
240*0Sstevel@tonic-gate  * This function is synchronized with the zuluvm_as_free.
241*0Sstevel@tonic-gate  * zuluvm_as_free will block until miss servicing is complete.
242*0Sstevel@tonic-gate  *
243*0Sstevel@tonic-gate  * There is a race condition between as_free and the zulu tlb miss
244*0Sstevel@tonic-gate  * soft interrupt:
245*0Sstevel@tonic-gate  *	- queue zulu interrupt
246*0Sstevel@tonic-gate  *	- process dies, as_free runs
247*0Sstevel@tonic-gate  *	- interrupt gets scheduled and runs as_fault on the
248*0Sstevel@tonic-gate  *	  already freed as.
249*0Sstevel@tonic-gate  * This is solved by keeping track of current zulu dma processes
250*0Sstevel@tonic-gate  * and invalidating them in zuluvm_as_free.
251*0Sstevel@tonic-gate  */
252*0Sstevel@tonic-gate uint_t
253*0Sstevel@tonic-gate zuluvm_tlb_handler(caddr_t data)
254*0Sstevel@tonic-gate {
255*0Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)data;
256*0Sstevel@tonic-gate 	int	error;
257*0Sstevel@tonic-gate 	int	flag = 0;
258*0Sstevel@tonic-gate 	int	wait = 0;
259*0Sstevel@tonic-gate 	zuluvm_proc_t *proc = NULL;
260*0Sstevel@tonic-gate 	struct zulu_hat	*zhat = NULL;
261*0Sstevel@tonic-gate 	caddr_t	addr;
262*0Sstevel@tonic-gate 	int	tlbtype;
263*0Sstevel@tonic-gate 	void	*arg;
264*0Sstevel@tonic-gate 	int	state, newstate;
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_tlb_handler_lwp, "zuluvm", /* */,
267*0Sstevel@tonic-gate 	    tnf_opaque, lwp, ttolwp(curthread));
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate 	ZULUVM_LOCK;
270*0Sstevel@tonic-gate 	error   = ZULUVM_GET_TLB_ERRCODE(zdev);
271*0Sstevel@tonic-gate 	addr    = (caddr_t)ZULUVM_GET_TLB_ADDR(zdev);
272*0Sstevel@tonic-gate 	tlbtype = ZULUVM_GET_TLB_TYPE(zdev);
273*0Sstevel@tonic-gate 	arg = zdev->zvm.arg;
274*0Sstevel@tonic-gate 
275*0Sstevel@tonic-gate 	/*
276*0Sstevel@tonic-gate 	 * select the correct dma engine and remember the
277*0Sstevel@tonic-gate 	 * the as_free synchronization flags.
278*0Sstevel@tonic-gate 	 */
279*0Sstevel@tonic-gate 	switch (tlbtype) {
280*0Sstevel@tonic-gate 	case ZULUVM_ITLB1:
281*0Sstevel@tonic-gate 	case ZULUVM_DMA1:
282*0Sstevel@tonic-gate 		proc = zdev->zvm.proc1;
283*0Sstevel@tonic-gate 		flag |= ZULUVM_DO_INTR1;
284*0Sstevel@tonic-gate 		wait |= ZULUVM_WAIT_INTR1;
285*0Sstevel@tonic-gate 		break;
286*0Sstevel@tonic-gate 	case ZULUVM_ITLB2:
287*0Sstevel@tonic-gate 	case ZULUVM_DMA2:
288*0Sstevel@tonic-gate 		proc = zdev->zvm.proc2;
289*0Sstevel@tonic-gate 		flag |= ZULUVM_DO_INTR2;
290*0Sstevel@tonic-gate 		wait |= ZULUVM_WAIT_INTR2;
291*0Sstevel@tonic-gate 		break;
292*0Sstevel@tonic-gate 	}
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	state = ZULUVM_SET_STATE(zdev, ZULUVM_STATE_INTR_PENDING,
295*0Sstevel@tonic-gate 		    ZULUVM_STATE_INTR_QUEUED);
296*0Sstevel@tonic-gate 	newstate = ZULUVM_GET_STATE(zdev);
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	TNF_PROBE_2(zuluvm_tlb_handler_state, "zuluvm", /* */,
299*0Sstevel@tonic-gate 	    tnf_int, oldstate, state,
300*0Sstevel@tonic-gate 	    tnf_int, newstate, newstate);
301*0Sstevel@tonic-gate #ifdef DEBUG
302*0Sstevel@tonic-gate 	if (zuluvm_debug_state)
303*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "zuluvm_tlb_handler: state %d\n", state);
304*0Sstevel@tonic-gate #endif
305*0Sstevel@tonic-gate 	if (state != ZULUVM_STATE_INTR_PENDING &&
306*0Sstevel@tonic-gate 		state != ZULUVM_STATE_INTR_QUEUED) {
307*0Sstevel@tonic-gate 		ZULUVM_UNLOCK;
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 		zuluvm_stop(zdev, state, "softintr1");
310*0Sstevel@tonic-gate 		zulud_tlb_done(zdev, arg, tlbtype, ZULUVM_MISS_CANCELED);
311*0Sstevel@tonic-gate 		return (1);
312*0Sstevel@tonic-gate 	}
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate 	/*
315*0Sstevel@tonic-gate 	 * block the as_free callback in case it comes in
316*0Sstevel@tonic-gate 	 */
317*0Sstevel@tonic-gate 	zdev->intr_flags |= flag;
318*0Sstevel@tonic-gate 	ZULUVM_UNLOCK;
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate 	mutex_enter(&zdev->proc_lck);
321*0Sstevel@tonic-gate 	/*
322*0Sstevel@tonic-gate 	 * check if this as is still valid
323*0Sstevel@tonic-gate 	 */
324*0Sstevel@tonic-gate 	if (proc == NULL || proc->valid == 0 || proc->zhat == NULL) {
325*0Sstevel@tonic-gate 		mutex_exit(&zdev->proc_lck);
326*0Sstevel@tonic-gate 		/*
327*0Sstevel@tonic-gate 		 * we are on our way out, wake up the as_free
328*0Sstevel@tonic-gate 		 * callback if it is waiting for us
329*0Sstevel@tonic-gate 		 */
330*0Sstevel@tonic-gate 		ZULUVM_LOCK;
331*0Sstevel@tonic-gate 		zdev->intr_flags &= ~flag;
332*0Sstevel@tonic-gate 		if (zdev->intr_flags | wait)
333*0Sstevel@tonic-gate 			cv_broadcast(&zdev->intr_wait);
334*0Sstevel@tonic-gate 		ZULUVM_UNLOCK;
335*0Sstevel@tonic-gate 		state = ZULUVM_SET_STATE(zdev, ZULUVM_STATE_IDLE,
336*0Sstevel@tonic-gate 			    ZULUVM_STATE_INTR_PENDING);
337*0Sstevel@tonic-gate 		if (state != ZULUVM_STATE_INTR_PENDING) {
338*0Sstevel@tonic-gate 			zuluvm_stop(zdev, state, "softintr3");
339*0Sstevel@tonic-gate 		}
340*0Sstevel@tonic-gate 		zulud_tlb_done(zdev, arg, tlbtype, ZULUVM_NO_HAT);
341*0Sstevel@tonic-gate 		return (1);
342*0Sstevel@tonic-gate 	}
343*0Sstevel@tonic-gate 	zhat = proc->zhat;
344*0Sstevel@tonic-gate 	mutex_exit(&zdev->proc_lck);
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_tlb_handler, "zuluvm", /* */,
347*0Sstevel@tonic-gate 	    tnf_opaque, addr, addr);
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	switch (error) {
350*0Sstevel@tonic-gate 	case ZULUVM_CTX_LOCKED:
351*0Sstevel@tonic-gate 		/*
352*0Sstevel@tonic-gate 		 * trap handler found that zulu_hat had the lock bit set
353*0Sstevel@tonic-gate 		 * rather than block in the fast trap handler, it punts
354*0Sstevel@tonic-gate 		 * in this rare instance
355*0Sstevel@tonic-gate 		 */
356*0Sstevel@tonic-gate 		++zuluvm_ctx_locked;
357*0Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_ctx_locked, "zuluvm", /* CSTYLED */,
358*0Sstevel@tonic-gate 			tnf_ulong, zuluvm_ctx_locked, zuluvm_ctx_locked);
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 		/*FALLTHROUGH*/
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 	case ZULUVM_TTE_DELAY:
363*0Sstevel@tonic-gate 		/*
364*0Sstevel@tonic-gate 		 * fast tlb handler was skipped, see zuluvm_fast_tlb flag
365*0Sstevel@tonic-gate 		 */
366*0Sstevel@tonic-gate 		/*FALLTHROUGH*/
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 	case ZULUVM_NO_TTE:
369*0Sstevel@tonic-gate 		/*
370*0Sstevel@tonic-gate 		 * no TSB entry and TTE in the hash
371*0Sstevel@tonic-gate 		 */
372*0Sstevel@tonic-gate 		mutex_enter(&zdev->load_lck);
373*0Sstevel@tonic-gate 		zdev->in_intr = 1;
374*0Sstevel@tonic-gate 		error = zulu_hat_load(zhat,  addr,
375*0Sstevel@tonic-gate 			(tlbtype == ZULUVM_DMA2) ? S_WRITE : S_READ, NULL);
376*0Sstevel@tonic-gate 		zdev->in_intr = 0;
377*0Sstevel@tonic-gate 		mutex_exit(&zdev->load_lck);
378*0Sstevel@tonic-gate 		if (error) {
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 			error = ZULUVM_NO_MAP;
381*0Sstevel@tonic-gate 		} else {
382*0Sstevel@tonic-gate 			error = ZULUVM_SUCCESS;
383*0Sstevel@tonic-gate 			TNF_PROBE_1(zuluvm_tlb_handler_done, "zuluvm", /* */,
384*0Sstevel@tonic-gate 				    tnf_int, error, error);
385*0Sstevel@tonic-gate 			return (1);
386*0Sstevel@tonic-gate 		}
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 	default:
389*0Sstevel@tonic-gate 		/*
390*0Sstevel@tonic-gate 		 * error case, fall through and tell zulu driver to abort DMA
391*0Sstevel@tonic-gate 		 */
392*0Sstevel@tonic-gate 		break;
393*0Sstevel@tonic-gate 	}
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 	if (error != ZULUVM_MISS_CANCELED) {
396*0Sstevel@tonic-gate 		state = ZULUVM_SET_STATE(zdev, ZULUVM_STATE_IDLE,
397*0Sstevel@tonic-gate 			    ZULUVM_STATE_WRITE_TTE);
398*0Sstevel@tonic-gate 		newstate = ZULUVM_GET_STATE(zdev);
399*0Sstevel@tonic-gate 		TNF_PROBE_2(zuluvm_tlb_handler_state_done, "zuluvm", /* */,
400*0Sstevel@tonic-gate 		    tnf_int, oldstate, state,
401*0Sstevel@tonic-gate 		    tnf_int, newstate, newstate);
402*0Sstevel@tonic-gate 		if (state != ZULUVM_STATE_WRITE_TTE) {
403*0Sstevel@tonic-gate 			zuluvm_stop(zdev, state, "softintr4");
404*0Sstevel@tonic-gate 		}
405*0Sstevel@tonic-gate 	}
406*0Sstevel@tonic-gate 	/*
407*0Sstevel@tonic-gate 	 * synchronize with as_free callback
408*0Sstevel@tonic-gate 	 * It will set the wait flag, in that case we send
409*0Sstevel@tonic-gate 	 * a wake up.
410*0Sstevel@tonic-gate 	 */
411*0Sstevel@tonic-gate 	ZULUVM_LOCK;
412*0Sstevel@tonic-gate 	zdev->intr_flags &= ~flag;
413*0Sstevel@tonic-gate 	if (zdev->intr_flags | wait)
414*0Sstevel@tonic-gate 		cv_broadcast(&zdev->intr_wait);
415*0Sstevel@tonic-gate 	ZULUVM_UNLOCK;
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_tlb_handler_done, "zuluvm", /* */,
418*0Sstevel@tonic-gate 	    tnf_int, error, error);
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 	zulud_tlb_done(zdev, arg, tlbtype, error);
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 	return (1);
423*0Sstevel@tonic-gate }
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate void
427*0Sstevel@tonic-gate zuluvm_load_tte(struct zulu_hat  *zhat, caddr_t addr, uint64_t pfn,
428*0Sstevel@tonic-gate 		int perm, int size)
429*0Sstevel@tonic-gate {
430*0Sstevel@tonic-gate 	zuluvm_state_t *zdev = zhat->zdev;
431*0Sstevel@tonic-gate 	int		tlbtype = ZULUVM_GET_TLB_TYPE(zdev);
432*0Sstevel@tonic-gate 
433*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&zdev->load_lck));
434*0Sstevel@tonic-gate 	ASSERT(pfn != 0);
435*0Sstevel@tonic-gate 
436*0Sstevel@tonic-gate 	if (zdev->in_intr) {
437*0Sstevel@tonic-gate 		int		error;
438*0Sstevel@tonic-gate 		int		flag = 0;
439*0Sstevel@tonic-gate 		int		wait = 0;
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 		error = zuluvm_write_tte(zdev, zdev->zvm.arg, addr, pfn,
442*0Sstevel@tonic-gate 					perm, size, 0, tlbtype, NULL);
443*0Sstevel@tonic-gate 
444*0Sstevel@tonic-gate 		if (error != ZULUVM_MISS_CANCELED) {
445*0Sstevel@tonic-gate 			int	state, newstate;
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 			state = ZULUVM_SET_STATE(zdev, ZULUVM_STATE_IDLE,
448*0Sstevel@tonic-gate 				    ZULUVM_STATE_WRITE_TTE);
449*0Sstevel@tonic-gate 			newstate = ZULUVM_GET_STATE(zdev);
450*0Sstevel@tonic-gate 			TNF_PROBE_2(zuluvm_tlb_handler_state_done, "zuluvm",
451*0Sstevel@tonic-gate 				    /* */, tnf_int, oldstate, state,
452*0Sstevel@tonic-gate 				    tnf_int, newstate, newstate);
453*0Sstevel@tonic-gate 			if (state != ZULUVM_STATE_WRITE_TTE) {
454*0Sstevel@tonic-gate 				zuluvm_stop(zdev, state, "softintr4");
455*0Sstevel@tonic-gate 			}
456*0Sstevel@tonic-gate 		}
457*0Sstevel@tonic-gate 		/*
458*0Sstevel@tonic-gate 		 * synchronize with as_free callback
459*0Sstevel@tonic-gate 		 * It will set the wait flag, in that case we send
460*0Sstevel@tonic-gate 		 * a wake up.
461*0Sstevel@tonic-gate 		 */
462*0Sstevel@tonic-gate 		switch (tlbtype) {
463*0Sstevel@tonic-gate 		case ZULUVM_ITLB1:
464*0Sstevel@tonic-gate 		case ZULUVM_DMA1:
465*0Sstevel@tonic-gate 			flag = ZULUVM_DO_INTR1;
466*0Sstevel@tonic-gate 			wait = ZULUVM_WAIT_INTR1;
467*0Sstevel@tonic-gate 			break;
468*0Sstevel@tonic-gate 		case ZULUVM_ITLB2:
469*0Sstevel@tonic-gate 		case ZULUVM_DMA2:
470*0Sstevel@tonic-gate 			flag = ZULUVM_DO_INTR2;
471*0Sstevel@tonic-gate 			wait = ZULUVM_WAIT_INTR2;
472*0Sstevel@tonic-gate 			break;
473*0Sstevel@tonic-gate 		}
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate 		ZULUVM_LOCK;
476*0Sstevel@tonic-gate 		zdev->intr_flags &= ~flag;
477*0Sstevel@tonic-gate 		if (zdev->intr_flags | wait)
478*0Sstevel@tonic-gate 			cv_broadcast(&zdev->intr_wait);
479*0Sstevel@tonic-gate 		ZULUVM_UNLOCK;
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate 		zulud_tlb_done(zdev, zdev->zvm.arg, tlbtype, error);
482*0Sstevel@tonic-gate 	} else {
483*0Sstevel@tonic-gate 		(void) zuluvm_write_tte(zdev, zdev->zvm.arg, addr, pfn,
484*0Sstevel@tonic-gate 					perm, size, (uint64_t)addr |
485*0Sstevel@tonic-gate 					zhat->zulu_ctx, tlbtype, NULL);
486*0Sstevel@tonic-gate 	}
487*0Sstevel@tonic-gate }
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate 
492*0Sstevel@tonic-gate /*
493*0Sstevel@tonic-gate  * This function provides the faulting thread for zulu page faults
494*0Sstevel@tonic-gate  * It is call from the device driver in response to an ioctl issued
495*0Sstevel@tonic-gate  * by a zuludaemon thread.
496*0Sstevel@tonic-gate  * It sits in cv_wait_sig until it gets woken up by a signal or
497*0Sstevel@tonic-gate  * zulu tlb miss soft interrupt.
498*0Sstevel@tonic-gate  */
499*0Sstevel@tonic-gate int
500*0Sstevel@tonic-gate zuluvm_park(zuluvm_info_t devp)
501*0Sstevel@tonic-gate {
502*0Sstevel@tonic-gate 	int rval;
503*0Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
504*0Sstevel@tonic-gate 	mutex_enter(&zdev->park_lck);
505*0Sstevel@tonic-gate 	zdev->parking = 1;
506*0Sstevel@tonic-gate 	for (;;) {
507*0Sstevel@tonic-gate 		rval = cv_wait_sig(&zdev->park_cv, &zdev->park_lck);
508*0Sstevel@tonic-gate 		if (rval == 0)
509*0Sstevel@tonic-gate 			break;
510*0Sstevel@tonic-gate 		rval = zuluvm_tlb_handler(devp);
511*0Sstevel@tonic-gate 	}
512*0Sstevel@tonic-gate 	zdev->parking = 0;
513*0Sstevel@tonic-gate 	mutex_exit(&zdev->park_lck);
514*0Sstevel@tonic-gate 	return (rval);
515*0Sstevel@tonic-gate }
516*0Sstevel@tonic-gate 
517*0Sstevel@tonic-gate /*
518*0Sstevel@tonic-gate  * zulu soft interrupt handler, just triggers the parked zulu fault
519*0Sstevel@tonic-gate  * thread
520*0Sstevel@tonic-gate  */
521*0Sstevel@tonic-gate /*ARGSUSED*/
522*0Sstevel@tonic-gate uint_t
523*0Sstevel@tonic-gate zuluvm_softintr(caddr_t devp, caddr_t arg2)
524*0Sstevel@tonic-gate {
525*0Sstevel@tonic-gate 	int tlbtype;
526*0Sstevel@tonic-gate 	void *arg;
527*0Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
528*0Sstevel@tonic-gate 	mutex_enter(&zdev->park_lck);
529*0Sstevel@tonic-gate 	if (zdev->parking) {
530*0Sstevel@tonic-gate 		cv_signal(&zdev->park_cv);
531*0Sstevel@tonic-gate 		mutex_exit(&zdev->park_lck);
532*0Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_fast_intr, "zuluvm", /* */,
533*0Sstevel@tonic-gate 		    tnf_opaque, devp, devp);
534*0Sstevel@tonic-gate 	} else {
535*0Sstevel@tonic-gate 		mutex_exit(&zdev->park_lck);
536*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "zuluvm: no page fault thread\n");
537*0Sstevel@tonic-gate 		ZULUVM_LOCK;
538*0Sstevel@tonic-gate 		tlbtype = ZULUVM_GET_TLB_TYPE(zdev);
539*0Sstevel@tonic-gate 		arg = zdev->zvm.arg;
540*0Sstevel@tonic-gate 		ZULUVM_UNLOCK;
541*0Sstevel@tonic-gate 		TNF_PROBE_0(zuluvm_fast_intr, "zuluvm", /* */);
542*0Sstevel@tonic-gate 		zuluvm_stop(zdev, ZULUVM_STATE_INTR_QUEUED, "fast_intr");
543*0Sstevel@tonic-gate 		zulud_tlb_done(zdev, arg, tlbtype, ZULUVM_NO_TTE);
544*0Sstevel@tonic-gate 	}
545*0Sstevel@tonic-gate 	return (1);
546*0Sstevel@tonic-gate }
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate /* ***** public interface for process mapping events (hat layer) ***** */
549*0Sstevel@tonic-gate 
550*0Sstevel@tonic-gate /*
551*0Sstevel@tonic-gate  * If the page size matches the Zulu page sizes then just pass
552*0Sstevel@tonic-gate  * it thru. If not then emulate the page demap with demaps of
553*0Sstevel@tonic-gate  * smaller page size.
554*0Sstevel@tonic-gate  */
555*0Sstevel@tonic-gate /* ARGSUSED */
556*0Sstevel@tonic-gate void
557*0Sstevel@tonic-gate zuluvm_demap_page(void *arg, struct hat *hat_ptr, short ctx,
558*0Sstevel@tonic-gate     caddr_t vaddr, uint_t size)
559*0Sstevel@tonic-gate {
560*0Sstevel@tonic-gate 	void *ddarg;
561*0Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)arg;
562*0Sstevel@tonic-gate 
563*0Sstevel@tonic-gate 	if (arg == NULL)
564*0Sstevel@tonic-gate 		return;
565*0Sstevel@tonic-gate 
566*0Sstevel@tonic-gate 	ZULUVM_STATS_DEMAP_PAGE(zdev);
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate 	ddarg = zdev->zvm.arg;
569*0Sstevel@tonic-gate 
570*0Sstevel@tonic-gate 	TNF_PROBE_3(zuluvm_demap_page, "zuluvm", /* */,
571*0Sstevel@tonic-gate 	    tnf_opaque, addr, vaddr,
572*0Sstevel@tonic-gate 	    tnf_int, size, size,
573*0Sstevel@tonic-gate 	    tnf_int, ctx, ctx);
574*0Sstevel@tonic-gate 
575*0Sstevel@tonic-gate 	if (ddarg != NULL) {
576*0Sstevel@tonic-gate 		if (size != zuluvm_base_pgsize &&
577*0Sstevel@tonic-gate 		    size != ZULU_TTE4M) {
578*0Sstevel@tonic-gate 			int i;
579*0Sstevel@tonic-gate 			int cnt = size - zuluvm_base_pgsize;
580*0Sstevel@tonic-gate 			cnt = ZULU_HAT_SZ_SHIFT(cnt);
581*0Sstevel@tonic-gate 			for (i = 0; i < cnt; i++) {
582*0Sstevel@tonic-gate 				uintptr_t addr = (uintptr_t)vaddr |
583*0Sstevel@tonic-gate 				    i << ZULU_HAT_BP_SHIFT;
584*0Sstevel@tonic-gate 				zulud_demap_page(zdev, ddarg,
585*0Sstevel@tonic-gate 						(caddr_t)addr, ctx);
586*0Sstevel@tonic-gate 			}
587*0Sstevel@tonic-gate 		} else {
588*0Sstevel@tonic-gate 			zulud_demap_page(zdev, ddarg, vaddr, ctx);
589*0Sstevel@tonic-gate 		}
590*0Sstevel@tonic-gate 		TNF_PROBE_0(zuluvm_demap_page_done, "zuluvm", /* */);
591*0Sstevel@tonic-gate 	} else {
592*0Sstevel@tonic-gate 		TNF_PROBE_0(zuluvm_demap_page_null_ddarg, "zuluvm", /* */);
593*0Sstevel@tonic-gate 	}
594*0Sstevel@tonic-gate }
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate /*
597*0Sstevel@tonic-gate  * An entire context has gone away, just pass it thru
598*0Sstevel@tonic-gate  */
599*0Sstevel@tonic-gate void
600*0Sstevel@tonic-gate zuluvm_demap_ctx(void *arg, short ctx)
601*0Sstevel@tonic-gate {
602*0Sstevel@tonic-gate 	void *ddarg;
603*0Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)arg;
604*0Sstevel@tonic-gate 
605*0Sstevel@tonic-gate 	if (arg == NULL)
606*0Sstevel@tonic-gate 		return;
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 	ZULUVM_STATS_DEMAP_CTX(zdev);
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_demap_ctx, "zuluvm", /* */,
611*0Sstevel@tonic-gate 	    tnf_int, ctx, ctx);
612*0Sstevel@tonic-gate 	ddarg = zdev->zvm.arg;
613*0Sstevel@tonic-gate 
614*0Sstevel@tonic-gate 	if (ddarg != NULL)
615*0Sstevel@tonic-gate 		zulud_demap_ctx(zdev, ddarg, ctx);
616*0Sstevel@tonic-gate }
617*0Sstevel@tonic-gate 
618*0Sstevel@tonic-gate static int
619*0Sstevel@tonic-gate zuluvm_driver_attach(zuluvm_state_t *zdev)
620*0Sstevel@tonic-gate {
621*0Sstevel@tonic-gate 	int i;
622*0Sstevel@tonic-gate 	mutex_enter(&zuluvm_lck);
623*0Sstevel@tonic-gate 	for (i = 0; i < ZULUVM_MAX_DEV; i++) {
624*0Sstevel@tonic-gate 		if (zuluvm_devtab[i] == NULL) {
625*0Sstevel@tonic-gate 			zuluvm_devtab[i] = zdev;
626*0Sstevel@tonic-gate 			ZULUVM_SET_IDLE(zdev);
627*0Sstevel@tonic-gate 			break;
628*0Sstevel@tonic-gate 		}
629*0Sstevel@tonic-gate 	}
630*0Sstevel@tonic-gate 	mutex_exit(&zuluvm_lck);
631*0Sstevel@tonic-gate 	if (i >= ZULUVM_MAX_DEV)
632*0Sstevel@tonic-gate 		return (ZULUVM_ERROR);
633*0Sstevel@tonic-gate 
634*0Sstevel@tonic-gate 	if (zulu_hat_attach((void *)zdev) != 0) {
635*0Sstevel@tonic-gate 		return (ZULUVM_ERROR);
636*0Sstevel@tonic-gate 	}
637*0Sstevel@tonic-gate 
638*0Sstevel@tonic-gate 	mutex_init(&zdev->dev_lck, NULL, MUTEX_DEFAULT, NULL);
639*0Sstevel@tonic-gate 	mutex_init(&zdev->load_lck, NULL, MUTEX_DEFAULT, NULL);
640*0Sstevel@tonic-gate 	mutex_init(&zdev->proc_lck, NULL, MUTEX_DEFAULT, NULL);
641*0Sstevel@tonic-gate 	mutex_init(&zdev->park_lck, NULL, MUTEX_DEFAULT, NULL);
642*0Sstevel@tonic-gate 	cv_init(&zdev->park_cv, NULL, CV_DEFAULT, NULL);
643*0Sstevel@tonic-gate 	cv_init(&zdev->intr_wait, NULL, CV_DEFAULT, NULL);
644*0Sstevel@tonic-gate 	zdev->parking = 0;
645*0Sstevel@tonic-gate 
646*0Sstevel@tonic-gate #ifdef ZULUVM_STATS
647*0Sstevel@tonic-gate 	zdev->zvm.cancel	= 0;
648*0Sstevel@tonic-gate 	zdev->zvm.pagefault	= 0;
649*0Sstevel@tonic-gate 	zdev->zvm.no_mapping	= 0;
650*0Sstevel@tonic-gate 	zdev->zvm.preload	= 0;
651*0Sstevel@tonic-gate 	zdev->zvm.migrate	= 0;
652*0Sstevel@tonic-gate 	zdev->zvm.pagesize	= 0;
653*0Sstevel@tonic-gate 	zdev->zvm.tlb_miss[0]	= 0;
654*0Sstevel@tonic-gate 	zdev->zvm.tlb_miss[1]	= 0;
655*0Sstevel@tonic-gate 	zdev->zvm.tlb_miss[2]	= 0;
656*0Sstevel@tonic-gate 	zdev->zvm.tlb_miss[3]	= 0;
657*0Sstevel@tonic-gate 	zdev->zvm.itlb1miss	= 0;
658*0Sstevel@tonic-gate 	zdev->zvm.dtlb1miss	= 0;
659*0Sstevel@tonic-gate 	zdev->zvm.itlb2miss	= 0;
660*0Sstevel@tonic-gate 	zdev->zvm.dtlb2miss	= 0;
661*0Sstevel@tonic-gate #endif
662*0Sstevel@tonic-gate 	zdev->zvm.pfncnt = 0;
663*0Sstevel@tonic-gate 	for (i = 0; i < 50; i++)
664*0Sstevel@tonic-gate 		zdev->zvm.pfnbuf[i] = 0;
665*0Sstevel@tonic-gate 
666*0Sstevel@tonic-gate 	zdev->zvm.mmu_pa  	= NULL;
667*0Sstevel@tonic-gate 	zdev->zvm.proc1   	= NULL;
668*0Sstevel@tonic-gate 	zdev->zvm.proc2   	= NULL;
669*0Sstevel@tonic-gate 	zdev->procs = NULL;
670*0Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
671*0Sstevel@tonic-gate }
672*0Sstevel@tonic-gate 
673*0Sstevel@tonic-gate static int
674*0Sstevel@tonic-gate zuluvm_driver_detach(zuluvm_state_t *zdev)
675*0Sstevel@tonic-gate {
676*0Sstevel@tonic-gate 	int i;
677*0Sstevel@tonic-gate 	cv_destroy(&zdev->intr_wait);
678*0Sstevel@tonic-gate 	cv_destroy(&zdev->park_cv);
679*0Sstevel@tonic-gate 	mutex_destroy(&zdev->park_lck);
680*0Sstevel@tonic-gate 	mutex_destroy(&zdev->proc_lck);
681*0Sstevel@tonic-gate 	mutex_destroy(&zdev->dev_lck);
682*0Sstevel@tonic-gate 	mutex_destroy(&zdev->load_lck);
683*0Sstevel@tonic-gate 	zdev->dops = NULL;
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 	mutex_enter(&zuluvm_lck);
686*0Sstevel@tonic-gate 	for (i = 0; i < ZULUVM_MAX_DEV; i++) {
687*0Sstevel@tonic-gate 		if (zuluvm_devtab[i] == zdev) {
688*0Sstevel@tonic-gate 			zuluvm_devtab[i] = NULL;
689*0Sstevel@tonic-gate 			break;
690*0Sstevel@tonic-gate 		}
691*0Sstevel@tonic-gate 	}
692*0Sstevel@tonic-gate 	mutex_exit(&zuluvm_lck);
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate 	if (zulu_hat_detach((void *)zdev) == 0) {
695*0Sstevel@tonic-gate 		return (ZULUVM_SUCCESS);
696*0Sstevel@tonic-gate 	} else {
697*0Sstevel@tonic-gate 		return (ZULUVM_ERROR);
698*0Sstevel@tonic-gate 	}
699*0Sstevel@tonic-gate }
700*0Sstevel@tonic-gate 
701*0Sstevel@tonic-gate zulud_ops_t *zuluvm_dops = NULL;
702*0Sstevel@tonic-gate 
703*0Sstevel@tonic-gate /*
704*0Sstevel@tonic-gate  * init the zulu kernel driver (variables, locks, etc)
705*0Sstevel@tonic-gate  */
706*0Sstevel@tonic-gate int
707*0Sstevel@tonic-gate zuluvm_init(zulud_ops_t *ops, int **pagesizes)
708*0Sstevel@tonic-gate {
709*0Sstevel@tonic-gate 	int error = ZULUVM_SUCCESS;
710*0Sstevel@tonic-gate 	int i;
711*0Sstevel@tonic-gate 	int size = zuluvm_base_pgsize; /* MMU_PAGESIZE; */
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate 	if (ops->version != ZULUVM_INTERFACE_VERSION)
714*0Sstevel@tonic-gate 		return (ZULUVM_VERSION_MISMATCH);
715*0Sstevel@tonic-gate 
716*0Sstevel@tonic-gate 	zuluvm_dops = ops;
717*0Sstevel@tonic-gate 	for (i = 0; i < ZULUM_MAX_PG_SIZES && size <= ZULU_TTE4M; i++) {
718*0Sstevel@tonic-gate 		zuluvm_pagesizes[i] = size++;
719*0Sstevel@tonic-gate 	}
720*0Sstevel@tonic-gate 	zuluvm_pagesizes[i] = -1;
721*0Sstevel@tonic-gate 	*pagesizes = zuluvm_pagesizes;
722*0Sstevel@tonic-gate 
723*0Sstevel@tonic-gate 	return (error);
724*0Sstevel@tonic-gate }
725*0Sstevel@tonic-gate 
726*0Sstevel@tonic-gate /*
727*0Sstevel@tonic-gate  * cleanup afterwards
728*0Sstevel@tonic-gate  */
729*0Sstevel@tonic-gate int
730*0Sstevel@tonic-gate zuluvm_fini(void)
731*0Sstevel@tonic-gate {
732*0Sstevel@tonic-gate 	zuluvm_dops = NULL;
733*0Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
734*0Sstevel@tonic-gate }
735*0Sstevel@tonic-gate 
736*0Sstevel@tonic-gate /*
737*0Sstevel@tonic-gate  *     allocate a zulu kernel driver instance for this zulu device
738*0Sstevel@tonic-gate  */
739*0Sstevel@tonic-gate int
740*0Sstevel@tonic-gate zuluvm_alloc_device(dev_info_t *devi, void *arg, zuluvm_info_t *devp,
741*0Sstevel@tonic-gate     caddr_t mmu, caddr_t imr)
742*0Sstevel@tonic-gate {
743*0Sstevel@tonic-gate 	uint_t intr_num;
744*0Sstevel@tonic-gate 	zuluvm_state_t *zdev;
745*0Sstevel@tonic-gate 	int error = ZULUVM_SUCCESS;
746*0Sstevel@tonic-gate 
747*0Sstevel@tonic-gate 	TNF_PROBE_3(zuluvm_alloc_device, "zuluvm", /* */,
748*0Sstevel@tonic-gate 	    tnf_opaque, arg, arg,
749*0Sstevel@tonic-gate 	    tnf_opaque, mmu, mmu,
750*0Sstevel@tonic-gate 	    tnf_opaque, imr, imr);
751*0Sstevel@tonic-gate 
752*0Sstevel@tonic-gate 	zdev = kmem_zalloc(sizeof (zuluvm_state_t), KM_SLEEP);
753*0Sstevel@tonic-gate 	zdev->dip = devi;
754*0Sstevel@tonic-gate 	zdev->dops = zuluvm_dops;
755*0Sstevel@tonic-gate 	error = zuluvm_driver_attach(zdev);
756*0Sstevel@tonic-gate 	if (error != ZULUVM_SUCCESS) {
757*0Sstevel@tonic-gate 		kmem_free(zdev, sizeof (zuluvm_state_t));
758*0Sstevel@tonic-gate 		return (ZULUVM_NO_DEV);
759*0Sstevel@tonic-gate 	}
760*0Sstevel@tonic-gate 
761*0Sstevel@tonic-gate 	ZULUVM_LOCK;
762*0Sstevel@tonic-gate 	error = zuluvm_get_intr_props(zdev, devi);
763*0Sstevel@tonic-gate 	if (error != ZULUVM_SUCCESS) {
764*0Sstevel@tonic-gate 		ZULUVM_UNLOCK;
765*0Sstevel@tonic-gate 		error = zuluvm_driver_detach(zdev);
766*0Sstevel@tonic-gate 		if (error != ZULUVM_SUCCESS)
767*0Sstevel@tonic-gate 			return (error);
768*0Sstevel@tonic-gate 		kmem_free(zdev, sizeof (zuluvm_state_t));
769*0Sstevel@tonic-gate 		return (ZULUVM_NO_DEV);
770*0Sstevel@tonic-gate 	}
771*0Sstevel@tonic-gate 	zdev->zvm.arg = arg;
772*0Sstevel@tonic-gate 	zdev->zvm.mmu_pa = (uint64_t)va_to_pa((void *)mmu);
773*0Sstevel@tonic-gate 	zdev->imr = (uint64_t *)imr;
774*0Sstevel@tonic-gate 	zdev->zvm.dmv_intr = dmv_add_softintr(zuluvm_dmv_tlbmiss_tl1,
775*0Sstevel@tonic-gate 	    (void *)zdev);
776*0Sstevel@tonic-gate 	zulud_set_itlb_pc(zdev, arg, DMV_MAKE_DMV(zdev->zvm.dmv_intr,
777*0Sstevel@tonic-gate 	    (void *)zdev));
778*0Sstevel@tonic-gate 	zulud_set_dtlb_pc(zdev, arg, DMV_MAKE_DMV(zdev->zvm.dmv_intr,
779*0Sstevel@tonic-gate 	    (void *)zdev));
780*0Sstevel@tonic-gate 	intr_dist_add(zuluvm_retarget_intr, (void *)zdev);
781*0Sstevel@tonic-gate 	zuluvm_do_retarget(zdev);
782*0Sstevel@tonic-gate 	intr_num = add_softintr(ZULUVM_PIL, zuluvm_softintr, (caddr_t)zdev);
783*0Sstevel@tonic-gate 	zdev->zvm.intr_num = intr_num;
784*0Sstevel@tonic-gate 	*devp = (caddr_t)zdev;
785*0Sstevel@tonic-gate 	ZULUVM_UNLOCK;
786*0Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_alloc_device_done, "zuluvm", /* */,
787*0Sstevel@tonic-gate 	    tnf_opaque, devp, *devp);
788*0Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
789*0Sstevel@tonic-gate }
790*0Sstevel@tonic-gate 
791*0Sstevel@tonic-gate /*
792*0Sstevel@tonic-gate  *    free a zulu kernel driver instance
793*0Sstevel@tonic-gate  */
794*0Sstevel@tonic-gate int
795*0Sstevel@tonic-gate zuluvm_free_device(zuluvm_info_t devp)
796*0Sstevel@tonic-gate {
797*0Sstevel@tonic-gate 	int error;
798*0Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
799*0Sstevel@tonic-gate 
800*0Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_free_device, "zuluvm", /* */,
801*0Sstevel@tonic-gate 	    tnf_opaque, zdev, zdev);
802*0Sstevel@tonic-gate 
803*0Sstevel@tonic-gate 	if (zdev == NULL)
804*0Sstevel@tonic-gate 		return (ZULUVM_NO_DEV);
805*0Sstevel@tonic-gate 	ZULUVM_LOCK;
806*0Sstevel@tonic-gate 	if (zdev->zvm.arg == NULL) {
807*0Sstevel@tonic-gate 		ZULUVM_UNLOCK;
808*0Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_free_device_done, "zuluvm", /* */,
809*0Sstevel@tonic-gate 		    tnf_int, error, ZULUVM_NO_DEV);
810*0Sstevel@tonic-gate 		return (ZULUVM_NO_DEV);
811*0Sstevel@tonic-gate 	}
812*0Sstevel@tonic-gate 	(void) dmv_rem_intr(zdev->zvm.dmv_intr);
813*0Sstevel@tonic-gate 	rem_softintr(zdev->zvm.intr_num);
814*0Sstevel@tonic-gate 	intr_dist_rem(zuluvm_retarget_intr, (void *)zdev);
815*0Sstevel@tonic-gate 	zdev->zvm.arg = NULL;
816*0Sstevel@tonic-gate 	ZULUVM_UNLOCK;
817*0Sstevel@tonic-gate 	error = zuluvm_driver_detach(zdev);
818*0Sstevel@tonic-gate 	if (error != ZULUVM_SUCCESS)
819*0Sstevel@tonic-gate 		return (error);
820*0Sstevel@tonic-gate 	zdev->dops = NULL;
821*0Sstevel@tonic-gate 	kmem_free(zdev, sizeof (zuluvm_state_t));
822*0Sstevel@tonic-gate 
823*0Sstevel@tonic-gate 	TNF_PROBE_0(zuluvm_free_device_done, "zuluvm", /* */);
824*0Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
825*0Sstevel@tonic-gate }
826*0Sstevel@tonic-gate 
827*0Sstevel@tonic-gate /*
828*0Sstevel@tonic-gate  * find the as in the list of active zulu processes
829*0Sstevel@tonic-gate  * The caller has to hold zdev->proc_lck
830*0Sstevel@tonic-gate  */
831*0Sstevel@tonic-gate static zuluvm_proc_t *
832*0Sstevel@tonic-gate zuluvm_find_proc(zuluvm_state_t *zdev, struct as *asp)
833*0Sstevel@tonic-gate {
834*0Sstevel@tonic-gate 	zuluvm_proc_t *p;
835*0Sstevel@tonic-gate 	TNF_PROBE_2(zuluvm_find_proc, "zuluvm", /* */,
836*0Sstevel@tonic-gate 	    tnf_opaque, zdev, zdev,
837*0Sstevel@tonic-gate 	    tnf_opaque, asp, asp);
838*0Sstevel@tonic-gate 	for (p = zdev->procs; p != NULL; p = p->next) {
839*0Sstevel@tonic-gate 		if (ZULU_HAT2AS(p->zhat) == asp) {
840*0Sstevel@tonic-gate 			TNF_PROBE_1(zuluvm_find_proc_done,
841*0Sstevel@tonic-gate 			    "zuluvm", /* */, tnf_opaque, proc, p);
842*0Sstevel@tonic-gate 			return (p);
843*0Sstevel@tonic-gate 		}
844*0Sstevel@tonic-gate 	}
845*0Sstevel@tonic-gate 	TNF_PROBE_0(zuluvm_find_proc_fail, "zuluvm", /* */);
846*0Sstevel@tonic-gate 	return (NULL);
847*0Sstevel@tonic-gate }
848*0Sstevel@tonic-gate 
849*0Sstevel@tonic-gate void
850*0Sstevel@tonic-gate zuluvm_as_free(struct as *as, void *arg, uint_t events)
851*0Sstevel@tonic-gate {
852*0Sstevel@tonic-gate 	zuluvm_proc_t *proc = (zuluvm_proc_t *)arg;
853*0Sstevel@tonic-gate 	zuluvm_state_t *zdev = proc->zdev;
854*0Sstevel@tonic-gate 	int wait = 0;
855*0Sstevel@tonic-gate 	int flag = 0;
856*0Sstevel@tonic-gate 	int valid;
857*0Sstevel@tonic-gate 
858*0Sstevel@tonic-gate 	(void) events;
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_as_free, "zuluvm", /* */,
861*0Sstevel@tonic-gate 	    tnf_opaque, arg, arg);
862*0Sstevel@tonic-gate 
863*0Sstevel@tonic-gate 	(void) as_delete_callback(as, arg);
864*0Sstevel@tonic-gate 	/*
865*0Sstevel@tonic-gate 	 * if this entry is still valid, then we need to sync
866*0Sstevel@tonic-gate 	 * with zuluvm_tlb_handler rountine.
867*0Sstevel@tonic-gate 	 */
868*0Sstevel@tonic-gate 	mutex_enter(&zdev->proc_lck);
869*0Sstevel@tonic-gate 	valid = proc->valid;
870*0Sstevel@tonic-gate 	proc->valid = 0;
871*0Sstevel@tonic-gate 	mutex_exit(&zdev->proc_lck);
872*0Sstevel@tonic-gate 
873*0Sstevel@tonic-gate 	if (valid) {
874*0Sstevel@tonic-gate 		ZULUVM_LOCK;
875*0Sstevel@tonic-gate 		if (proc == zdev->zvm.proc1) {
876*0Sstevel@tonic-gate 			flag |= ZULUVM_WAIT_INTR1;
877*0Sstevel@tonic-gate 			wait |= ZULUVM_DO_INTR1;
878*0Sstevel@tonic-gate 		}
879*0Sstevel@tonic-gate 		if (proc == zdev->zvm.proc2) {
880*0Sstevel@tonic-gate 			flag |= ZULUVM_WAIT_INTR2;
881*0Sstevel@tonic-gate 			wait |= ZULUVM_DO_INTR2;
882*0Sstevel@tonic-gate 		}
883*0Sstevel@tonic-gate 		if (flag) {
884*0Sstevel@tonic-gate 			zdev->intr_flags |= flag;
885*0Sstevel@tonic-gate 			/*
886*0Sstevel@tonic-gate 			 * wait until the tlb miss is resloved
887*0Sstevel@tonic-gate 			 */
888*0Sstevel@tonic-gate 			while (zdev->intr_flags & wait) {
889*0Sstevel@tonic-gate 				cv_wait(&zdev->intr_wait, &zdev->dev_lck);
890*0Sstevel@tonic-gate 			}
891*0Sstevel@tonic-gate 			zdev->intr_flags &= ~flag;
892*0Sstevel@tonic-gate 		}
893*0Sstevel@tonic-gate 		ZULUVM_UNLOCK;
894*0Sstevel@tonic-gate 	}
895*0Sstevel@tonic-gate 
896*0Sstevel@tonic-gate 	if (proc->zhat != NULL) {
897*0Sstevel@tonic-gate 		/*
898*0Sstevel@tonic-gate 		 * prevent any further tlb miss processing for this hat
899*0Sstevel@tonic-gate 		 */
900*0Sstevel@tonic-gate 		zulu_hat_terminate(proc->zhat);
901*0Sstevel@tonic-gate 	}
902*0Sstevel@tonic-gate 
903*0Sstevel@tonic-gate 	/*
904*0Sstevel@tonic-gate 	 * decrement the ref count and do the appropriate
905*0Sstevel@tonic-gate 	 * if it drops to zero.
906*0Sstevel@tonic-gate 	 */
907*0Sstevel@tonic-gate 	mutex_enter(&zdev->proc_lck);
908*0Sstevel@tonic-gate 	(void) zuluvm_proc_release(zdev, proc);
909*0Sstevel@tonic-gate 	mutex_exit(&zdev->proc_lck);
910*0Sstevel@tonic-gate }
911*0Sstevel@tonic-gate 
912*0Sstevel@tonic-gate /*
913*0Sstevel@tonic-gate  *	notify zulu vm driver about a new process going to
914*0Sstevel@tonic-gate  *	use zulu DMA. Create a zulu_hat.
915*0Sstevel@tonic-gate  */
916*0Sstevel@tonic-gate int
917*0Sstevel@tonic-gate zuluvm_dma_add_proc(zuluvm_info_t devp, uint64_t *cookie)
918*0Sstevel@tonic-gate {
919*0Sstevel@tonic-gate 	zuluvm_proc_t *proc;
920*0Sstevel@tonic-gate 	int refcnt;
921*0Sstevel@tonic-gate 	struct as *asp = ZULUVM_GET_AS;
922*0Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
923*0Sstevel@tonic-gate 
924*0Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_dma_add_proc, "zuluvm", /* */,
925*0Sstevel@tonic-gate 	    tnf_opaque, zdev, zdev);
926*0Sstevel@tonic-gate 	mutex_enter(&zdev->proc_lck);
927*0Sstevel@tonic-gate 	proc = zuluvm_find_proc(zdev, asp);
928*0Sstevel@tonic-gate 	if (proc == NULL) {
929*0Sstevel@tonic-gate 		proc = kmem_zalloc(sizeof (zuluvm_proc_t), KM_SLEEP);
930*0Sstevel@tonic-gate 		proc->zhat = zulu_hat_proc_attach(asp, zdev);
931*0Sstevel@tonic-gate 		if (proc->zhat == NULL) {
932*0Sstevel@tonic-gate 			mutex_exit(&zdev->proc_lck);
933*0Sstevel@tonic-gate 			kmem_free(proc, sizeof (zuluvm_proc_t));
934*0Sstevel@tonic-gate 			TNF_PROBE_2(zuluvm_dma_add_proc_done, "zuluvm", /* */,
935*0Sstevel@tonic-gate 			    tnf_int, valid, 0,
936*0Sstevel@tonic-gate 			    tnf_int, error, ZULUVM_ERROR);
937*0Sstevel@tonic-gate 			return (ZULUVM_ERROR);
938*0Sstevel@tonic-gate 		}
939*0Sstevel@tonic-gate 		proc->zdev = zdev;
940*0Sstevel@tonic-gate 		proc->valid = 1;
941*0Sstevel@tonic-gate 		proc->refcnt = 1;
942*0Sstevel@tonic-gate 		proc->next = zdev->procs;
943*0Sstevel@tonic-gate 		if (zdev->procs)
944*0Sstevel@tonic-gate 			zdev->procs->prev = proc;
945*0Sstevel@tonic-gate 		proc->prev = NULL;
946*0Sstevel@tonic-gate 		zdev->procs = proc;
947*0Sstevel@tonic-gate 		proc->refcnt++;
948*0Sstevel@tonic-gate 		(void) as_add_callback(asp, zuluvm_as_free, proc,
949*0Sstevel@tonic-gate 			AS_FREE_EVENT, 0, -1, KM_SLEEP);
950*0Sstevel@tonic-gate 	} else {
951*0Sstevel@tonic-gate 		if (proc->valid == 0) {
952*0Sstevel@tonic-gate 			mutex_exit(&zdev->proc_lck);
953*0Sstevel@tonic-gate 			TNF_PROBE_2(zuluvm_dma_add_proc_done, "zuluvm", /* */,
954*0Sstevel@tonic-gate 			    tnf_int, valid, 0,
955*0Sstevel@tonic-gate 			    tnf_int, error, ZULUVM_ERROR);
956*0Sstevel@tonic-gate 			return (ZULUVM_ERROR);
957*0Sstevel@tonic-gate 		}
958*0Sstevel@tonic-gate 		proc->refcnt++;
959*0Sstevel@tonic-gate 	}
960*0Sstevel@tonic-gate 	refcnt = proc->refcnt;
961*0Sstevel@tonic-gate 	mutex_exit(&zdev->proc_lck);
962*0Sstevel@tonic-gate 	*cookie = (uint64_t)proc;
963*0Sstevel@tonic-gate 	TNF_PROBE_2(zuluvm_dma_add_proc_done, "zuluvm", /* */,
964*0Sstevel@tonic-gate 	    tnf_int, refcnt, refcnt,
965*0Sstevel@tonic-gate 	    tnf_int, error, ZULUVM_SUCCESS);
966*0Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
967*0Sstevel@tonic-gate }
968*0Sstevel@tonic-gate 
969*0Sstevel@tonic-gate void
970*0Sstevel@tonic-gate zuluvm_proc_hold(zuluvm_state_t *zdev, zuluvm_proc_t *proc)
971*0Sstevel@tonic-gate {
972*0Sstevel@tonic-gate 	mutex_enter(&zdev->proc_lck);
973*0Sstevel@tonic-gate 	proc->refcnt++;
974*0Sstevel@tonic-gate 	mutex_exit(&zdev->proc_lck);
975*0Sstevel@tonic-gate }
976*0Sstevel@tonic-gate 
977*0Sstevel@tonic-gate /*
978*0Sstevel@tonic-gate  * decrement ref count and free data if it drops to zero
979*0Sstevel@tonic-gate  */
980*0Sstevel@tonic-gate static int
981*0Sstevel@tonic-gate zuluvm_proc_release(zuluvm_state_t *zdev, zuluvm_proc_t *proc)
982*0Sstevel@tonic-gate {
983*0Sstevel@tonic-gate 	int refcnt;
984*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&zdev->proc_lck));
985*0Sstevel@tonic-gate 	refcnt = --proc->refcnt;
986*0Sstevel@tonic-gate 	TNF_PROBE_3(zuluvm_proc_release, "zuluvm", /* */,
987*0Sstevel@tonic-gate 	    tnf_opaque, zdev, zdev,
988*0Sstevel@tonic-gate 	    tnf_opaque, proc, proc,
989*0Sstevel@tonic-gate 	    tnf_int, refcnt, refcnt);
990*0Sstevel@tonic-gate 	if (refcnt == 0) {
991*0Sstevel@tonic-gate 		if (proc->next)
992*0Sstevel@tonic-gate 			proc->next->prev = proc->prev;
993*0Sstevel@tonic-gate 		if (proc->prev)
994*0Sstevel@tonic-gate 			proc->prev->next = proc->next;
995*0Sstevel@tonic-gate 		else
996*0Sstevel@tonic-gate 			zdev->procs = proc->next;
997*0Sstevel@tonic-gate 		kmem_free(proc, sizeof (zuluvm_proc_t));
998*0Sstevel@tonic-gate 	}
999*0Sstevel@tonic-gate 	return (refcnt);
1000*0Sstevel@tonic-gate }
1001*0Sstevel@tonic-gate 
1002*0Sstevel@tonic-gate /*
1003*0Sstevel@tonic-gate  *	this process is not longer using DMA, all entries
1004*0Sstevel@tonic-gate  * 	have been removed from the TLB.
1005*0Sstevel@tonic-gate  */
1006*0Sstevel@tonic-gate int
1007*0Sstevel@tonic-gate zuluvm_dma_delete_proc(zuluvm_info_t devp, uint64_t cookie)
1008*0Sstevel@tonic-gate {
1009*0Sstevel@tonic-gate 	int refcnt;
1010*0Sstevel@tonic-gate 	zuluvm_proc_t *proc = (zuluvm_proc_t *)cookie;
1011*0Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
1012*0Sstevel@tonic-gate 
1013*0Sstevel@tonic-gate 	TNF_PROBE_2(zuluvm_dma_delete_proc, "zuluvm", /* */,
1014*0Sstevel@tonic-gate 	    tnf_opaque, zdev, zdev,
1015*0Sstevel@tonic-gate 	    tnf_opaque, cookie, cookie);
1016*0Sstevel@tonic-gate 	mutex_enter(&zdev->proc_lck);
1017*0Sstevel@tonic-gate 	if (proc != NULL) {
1018*0Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_dma_delete_proc, "zuluvm", /* */,
1019*0Sstevel@tonic-gate 		    tnf_opaque, proc, proc);
1020*0Sstevel@tonic-gate 		if (proc->zhat != NULL) {
1021*0Sstevel@tonic-gate 			zulu_hat_proc_detach(proc->zhat);
1022*0Sstevel@tonic-gate 			proc->zhat = NULL;
1023*0Sstevel@tonic-gate 		}
1024*0Sstevel@tonic-gate 		refcnt = zuluvm_proc_release(zdev, proc);
1025*0Sstevel@tonic-gate 	}
1026*0Sstevel@tonic-gate 	mutex_exit(&zdev->proc_lck);
1027*0Sstevel@tonic-gate 
1028*0Sstevel@tonic-gate 	TNF_PROBE_2(zuluvm_dma_delete_proc_done, "zuluvm", /* */,
1029*0Sstevel@tonic-gate 	    tnf_int, refcnt, refcnt,
1030*0Sstevel@tonic-gate 	    tnf_int, error, ZULUVM_SUCCESS);
1031*0Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
1032*0Sstevel@tonic-gate }
1033*0Sstevel@tonic-gate 
1034*0Sstevel@tonic-gate /*
1035*0Sstevel@tonic-gate  * barrier sync for device driver
1036*0Sstevel@tonic-gate  * blocks until zuluvm_tlbmiss_tl1 function is done
1037*0Sstevel@tonic-gate  */
1038*0Sstevel@tonic-gate void
1039*0Sstevel@tonic-gate zuluvm_fast_tlb_wait(caddr_t devp)
1040*0Sstevel@tonic-gate {
1041*0Sstevel@tonic-gate 	int state;
1042*0Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
1043*0Sstevel@tonic-gate 	int cnt = 0;
1044*0Sstevel@tonic-gate 
1045*0Sstevel@tonic-gate 	do {
1046*0Sstevel@tonic-gate 		state = ZULUVM_GET_STATE(zdev);
1047*0Sstevel@tonic-gate 		cnt++;
1048*0Sstevel@tonic-gate 	} while (state == ZULUVM_STATE_TLB_PENDING);
1049*0Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_fast_tlb_wait, "zuluvm", /* */,
1050*0Sstevel@tonic-gate 	    tnf_int, loop_cnt, cnt);
1051*0Sstevel@tonic-gate }
1052*0Sstevel@tonic-gate 
1053*0Sstevel@tonic-gate /*
1054*0Sstevel@tonic-gate  *     setup DMA handling for this handle
1055*0Sstevel@tonic-gate  */
1056*0Sstevel@tonic-gate int
1057*0Sstevel@tonic-gate zuluvm_dma_alloc_ctx(zuluvm_info_t devp, int dma, short *mmuctx,
1058*0Sstevel@tonic-gate     uint64_t *tsbreg)
1059*0Sstevel@tonic-gate {
1060*0Sstevel@tonic-gate 	struct as	*asp = ZULUVM_GET_AS;
1061*0Sstevel@tonic-gate 	int		error = ZULUVM_NO_DEV;
1062*0Sstevel@tonic-gate 	zuluvm_state_t    *zdev = (zuluvm_state_t *)devp;
1063*0Sstevel@tonic-gate 	int 		state, newstate;
1064*0Sstevel@tonic-gate 
1065*0Sstevel@tonic-gate 	if (asp == NULL) {
1066*0Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_dma_alloc_ctx_done, "zuluvm", /* */,
1067*0Sstevel@tonic-gate 		    tnf_int, error, ZULUVM_NO_HAT);
1068*0Sstevel@tonic-gate 		return (ZULUVM_NO_HAT);
1069*0Sstevel@tonic-gate 	}
1070*0Sstevel@tonic-gate 
1071*0Sstevel@tonic-gate 	*tsbreg = 0;
1072*0Sstevel@tonic-gate 	state = ZULUVM_SET_STATE(zdev, ZULUVM_STATE_IDLE,
1073*0Sstevel@tonic-gate 		    ZULUVM_STATE_STOPPED);
1074*0Sstevel@tonic-gate 	newstate = ZULUVM_GET_STATE(zdev);
1075*0Sstevel@tonic-gate 	TNF_PROBE_4(zuluvm_dma_alloc_ctx, "zuluvm", /* */,
1076*0Sstevel@tonic-gate 	    tnf_opaque, devp, devp,
1077*0Sstevel@tonic-gate 	    tnf_int, dma, dma,
1078*0Sstevel@tonic-gate 	    tnf_int, oldstate, state,
1079*0Sstevel@tonic-gate 	    tnf_int, newstate, newstate);
1080*0Sstevel@tonic-gate #ifdef DEBUG
1081*0Sstevel@tonic-gate 	if (zuluvm_debug_state)
1082*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "zuluvm_dma_alloc_ctx: state %d\n", state);
1083*0Sstevel@tonic-gate #endif
1084*0Sstevel@tonic-gate 	if (state != ZULUVM_STATE_STOPPED && state != ZULUVM_STATE_IDLE) {
1085*0Sstevel@tonic-gate 		while (state != ZULUVM_STATE_IDLE) {
1086*0Sstevel@tonic-gate 			state = ZULUVM_SET_STATE(zdev, ZULUVM_STATE_IDLE,
1087*0Sstevel@tonic-gate 				    ZULUVM_STATE_STOPPED);
1088*0Sstevel@tonic-gate #ifdef DEBUG
1089*0Sstevel@tonic-gate 			if (zuluvm_debug_state)
1090*0Sstevel@tonic-gate 				cmn_err(CE_NOTE, "zuluvm_dma_alloc_ctx: (loop)"
1091*0Sstevel@tonic-gate 				    " state %d\n", state);
1092*0Sstevel@tonic-gate #endif
1093*0Sstevel@tonic-gate 			if (state != ZULUVM_STATE_IDLE)
1094*0Sstevel@tonic-gate 				delay(1);
1095*0Sstevel@tonic-gate 		}
1096*0Sstevel@tonic-gate 	}
1097*0Sstevel@tonic-gate 
1098*0Sstevel@tonic-gate 	if (zdev->zvm.arg != NULL) {
1099*0Sstevel@tonic-gate 		struct zulu_hat *zhat;
1100*0Sstevel@tonic-gate 		zuluvm_proc_t *proc;
1101*0Sstevel@tonic-gate 
1102*0Sstevel@tonic-gate 		mutex_enter(&zdev->proc_lck);
1103*0Sstevel@tonic-gate 		proc = zuluvm_find_proc(zdev, asp);
1104*0Sstevel@tonic-gate 		if (proc != NULL) {
1105*0Sstevel@tonic-gate 			zhat = proc->zhat;
1106*0Sstevel@tonic-gate 			proc->refcnt++;
1107*0Sstevel@tonic-gate 		}
1108*0Sstevel@tonic-gate 		mutex_exit(&zdev->proc_lck);
1109*0Sstevel@tonic-gate 
1110*0Sstevel@tonic-gate 		switch (dma) {
1111*0Sstevel@tonic-gate 		case ZULUVM_DMA1:
1112*0Sstevel@tonic-gate 			ZULUVM_LOCK;
1113*0Sstevel@tonic-gate 			zdev->zvm.proc1 = proc;
1114*0Sstevel@tonic-gate 			ZULUVM_UNLOCK;
1115*0Sstevel@tonic-gate 			error = ZULUVM_SUCCESS;
1116*0Sstevel@tonic-gate 			break;
1117*0Sstevel@tonic-gate 		case ZULUVM_DMA2:
1118*0Sstevel@tonic-gate 			ZULUVM_LOCK;
1119*0Sstevel@tonic-gate 			zdev->zvm.proc2 = proc;
1120*0Sstevel@tonic-gate 			ZULUVM_UNLOCK;
1121*0Sstevel@tonic-gate 			error = ZULUVM_SUCCESS;
1122*0Sstevel@tonic-gate 			break;
1123*0Sstevel@tonic-gate 		default:
1124*0Sstevel@tonic-gate 			mutex_enter(&zdev->proc_lck);
1125*0Sstevel@tonic-gate 			(void) zuluvm_proc_release(zdev, proc);
1126*0Sstevel@tonic-gate 			mutex_exit(&zdev->proc_lck);
1127*0Sstevel@tonic-gate 		}
1128*0Sstevel@tonic-gate 
1129*0Sstevel@tonic-gate 		if (error == ZULUVM_SUCCESS) {
1130*0Sstevel@tonic-gate 			zulu_hat_validate_ctx(zhat);
1131*0Sstevel@tonic-gate 			if (zhat->zulu_ctx >= 0) {
1132*0Sstevel@tonic-gate 				*mmuctx = zhat->zulu_ctx;
1133*0Sstevel@tonic-gate 			} else {
1134*0Sstevel@tonic-gate 				printf("invalid context value: %d\n",
1135*0Sstevel@tonic-gate 					zhat->zulu_ctx);
1136*0Sstevel@tonic-gate 
1137*0Sstevel@tonic-gate 				mutex_enter(&zdev->proc_lck);
1138*0Sstevel@tonic-gate 				(void) zuluvm_proc_release(zdev, proc);
1139*0Sstevel@tonic-gate 				mutex_exit(&zdev->proc_lck);
1140*0Sstevel@tonic-gate 
1141*0Sstevel@tonic-gate 				error = ZULUVM_ERROR;
1142*0Sstevel@tonic-gate 			}
1143*0Sstevel@tonic-gate 		} else {
1144*0Sstevel@tonic-gate 			error = ZULUVM_ERROR;
1145*0Sstevel@tonic-gate 		}
1146*0Sstevel@tonic-gate 	}
1147*0Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_dma_alloc_ctx_done, "zuluvm", /* */,
1148*0Sstevel@tonic-gate 	    tnf_int, error, error);
1149*0Sstevel@tonic-gate 	return (error);
1150*0Sstevel@tonic-gate }
1151*0Sstevel@tonic-gate 
1152*0Sstevel@tonic-gate /*
1153*0Sstevel@tonic-gate  * preload TLB
1154*0Sstevel@tonic-gate  * this will try to pre-set the zulu tlb, mainly used for dma engine 2,
1155*0Sstevel@tonic-gate  * video read-back.
1156*0Sstevel@tonic-gate  */
1157*0Sstevel@tonic-gate int
1158*0Sstevel@tonic-gate zuluvm_dma_preload(zuluvm_info_t devp, int dma,
1159*0Sstevel@tonic-gate 			int num, zulud_preload_t *list)
1160*0Sstevel@tonic-gate {
1161*0Sstevel@tonic-gate 	int i;
1162*0Sstevel@tonic-gate 	int error = ZULUVM_SUCCESS;
1163*0Sstevel@tonic-gate 	struct zulu_hat *zhat;
1164*0Sstevel@tonic-gate 	zuluvm_proc_t *proc = NULL;
1165*0Sstevel@tonic-gate 
1166*0Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
1167*0Sstevel@tonic-gate 
1168*0Sstevel@tonic-gate 	TNF_PROBE_4(zuluvm_dma_preload, "zuluvm", /* */,
1169*0Sstevel@tonic-gate 	    tnf_opaque, devp, devp,
1170*0Sstevel@tonic-gate 	    tnf_int, dma, dma,
1171*0Sstevel@tonic-gate 	    tnf_int, num, num,
1172*0Sstevel@tonic-gate 	    tnf_opaque, list, list);
1173*0Sstevel@tonic-gate 	ZULUVM_LOCK;
1174*0Sstevel@tonic-gate 	switch (dma) {
1175*0Sstevel@tonic-gate 	case ZULUVM_DMA1:
1176*0Sstevel@tonic-gate 		proc = zdev->zvm.proc1;
1177*0Sstevel@tonic-gate 		break;
1178*0Sstevel@tonic-gate 	case ZULUVM_DMA2:
1179*0Sstevel@tonic-gate 		proc = zdev->zvm.proc2;
1180*0Sstevel@tonic-gate 		break;
1181*0Sstevel@tonic-gate 	}
1182*0Sstevel@tonic-gate 
1183*0Sstevel@tonic-gate 	mutex_enter(&zdev->proc_lck);
1184*0Sstevel@tonic-gate 	if (proc == NULL || proc->valid == 0 || proc->zhat == NULL) {
1185*0Sstevel@tonic-gate 		mutex_exit(&zdev->proc_lck);
1186*0Sstevel@tonic-gate 		ZULUVM_UNLOCK;
1187*0Sstevel@tonic-gate 		return (ZULUVM_NO_HAT);
1188*0Sstevel@tonic-gate 	}
1189*0Sstevel@tonic-gate 	mutex_exit(&zdev->proc_lck);
1190*0Sstevel@tonic-gate 
1191*0Sstevel@tonic-gate 	zhat = proc->zhat;
1192*0Sstevel@tonic-gate 	/*
1193*0Sstevel@tonic-gate 	 * need to release this to avoid recursive enter in zuluvm_load_tte
1194*0Sstevel@tonic-gate 	 * which gets called from zulu_hat_memload()
1195*0Sstevel@tonic-gate 	 */
1196*0Sstevel@tonic-gate 	ZULUVM_UNLOCK;
1197*0Sstevel@tonic-gate 
1198*0Sstevel@tonic-gate 	mutex_enter(&zdev->load_lck);
1199*0Sstevel@tonic-gate 	for (i = 0; i < num; i++) {
1200*0Sstevel@tonic-gate 		int pg_size;
1201*0Sstevel@tonic-gate 		int res;
1202*0Sstevel@tonic-gate 		int first = 1;
1203*0Sstevel@tonic-gate 		caddr_t addr = ZULUVM_GET_PAGE(list[i].addr);
1204*0Sstevel@tonic-gate 		int64_t size = (int64_t)list[i].len;
1205*0Sstevel@tonic-gate 		while (size > 0) {
1206*0Sstevel@tonic-gate 			if (list[i].tlbtype & ~ZULUVM_DMA_MASK) {
1207*0Sstevel@tonic-gate 				error = ZULUVM_INVALID_MISS;
1208*0Sstevel@tonic-gate 				break;
1209*0Sstevel@tonic-gate 			}
1210*0Sstevel@tonic-gate 			res = zulu_hat_load(zhat, addr,
1211*0Sstevel@tonic-gate 			    (list[i].tlbtype == ZULUVM_DMA2) ? S_WRITE : S_READ,
1212*0Sstevel@tonic-gate 			    &pg_size);
1213*0Sstevel@tonic-gate 			if ((res != 0) || (pg_size < 0)) {
1214*0Sstevel@tonic-gate 				error = ZULUVM_NO_MAP;
1215*0Sstevel@tonic-gate 				break;
1216*0Sstevel@tonic-gate 			}
1217*0Sstevel@tonic-gate 			ZULUVM_STATS_PRELOAD(zdev);
1218*0Sstevel@tonic-gate 			TNF_PROBE_2(zuluvm_dma_preload_addr, "zuluvm", /* */,
1219*0Sstevel@tonic-gate 			    tnf_opaque, addr, addr,
1220*0Sstevel@tonic-gate 			    tnf_opaque, size, size);
1221*0Sstevel@tonic-gate 			if (first) {
1222*0Sstevel@tonic-gate 				first = 0;
1223*0Sstevel@tonic-gate 				size -= ZULU_HAT_PGDIFF(list[i].addr,
1224*0Sstevel@tonic-gate 							pg_size);
1225*0Sstevel@tonic-gate 			} else {
1226*0Sstevel@tonic-gate 				size -= ZULU_HAT_PGSZ(pg_size);
1227*0Sstevel@tonic-gate 			}
1228*0Sstevel@tonic-gate 			addr += ZULU_HAT_PGSZ(pg_size);
1229*0Sstevel@tonic-gate 		}
1230*0Sstevel@tonic-gate 	}
1231*0Sstevel@tonic-gate 	mutex_exit(&zdev->load_lck);
1232*0Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_dma_preload_done, "zuluvm", /* */,
1233*0Sstevel@tonic-gate 	    tnf_int, error, error);
1234*0Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
1235*0Sstevel@tonic-gate }
1236*0Sstevel@tonic-gate 
1237*0Sstevel@tonic-gate /*
1238*0Sstevel@tonic-gate  * destroy DMA handling for this handle
1239*0Sstevel@tonic-gate  */
1240*0Sstevel@tonic-gate int
1241*0Sstevel@tonic-gate zuluvm_dma_free_ctx(zuluvm_info_t devp, int dma)
1242*0Sstevel@tonic-gate {
1243*0Sstevel@tonic-gate 	int error = ZULUVM_NO_DEV;
1244*0Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
1245*0Sstevel@tonic-gate 	int state, newstate;
1246*0Sstevel@tonic-gate 
1247*0Sstevel@tonic-gate 	state = ZULUVM_SET_STATE(zdev, ZULUVM_STATE_STOPPED,
1248*0Sstevel@tonic-gate 		    ZULUVM_STATE_IDLE);
1249*0Sstevel@tonic-gate 	newstate = ZULUVM_GET_STATE(zdev);
1250*0Sstevel@tonic-gate 	TNF_PROBE_4(zuluvm_dma_free_ctx, "zuluvm", /* */,
1251*0Sstevel@tonic-gate 	    tnf_opaque, devp, devp,
1252*0Sstevel@tonic-gate 	    tnf_int, dma, dma,
1253*0Sstevel@tonic-gate 	    tnf_int, oldstate, state,
1254*0Sstevel@tonic-gate 	    tnf_int, newstate, newstate);
1255*0Sstevel@tonic-gate #ifdef DEBUG
1256*0Sstevel@tonic-gate 	if (zuluvm_debug_state)
1257*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "zuluvm_dma_free_ctx: state %d\n", state);
1258*0Sstevel@tonic-gate #endif
1259*0Sstevel@tonic-gate 	if (state != ZULUVM_STATE_IDLE && state != ZULUVM_STATE_STOPPED) {
1260*0Sstevel@tonic-gate 		int doit = 1;
1261*0Sstevel@tonic-gate 		while (doit) {
1262*0Sstevel@tonic-gate 			switch (state) {
1263*0Sstevel@tonic-gate 			case ZULUVM_STATE_CANCELED:
1264*0Sstevel@tonic-gate 			case ZULUVM_STATE_STOPPED:
1265*0Sstevel@tonic-gate 				doit = 0;
1266*0Sstevel@tonic-gate 				break;
1267*0Sstevel@tonic-gate 			case ZULUVM_STATE_IDLE:
1268*0Sstevel@tonic-gate 				state = ZULUVM_SET_STATE(zdev,
1269*0Sstevel@tonic-gate 					    ZULUVM_STATE_STOPPED,
1270*0Sstevel@tonic-gate 					    ZULUVM_STATE_IDLE);
1271*0Sstevel@tonic-gate 				break;
1272*0Sstevel@tonic-gate 			default:
1273*0Sstevel@tonic-gate 				state = ZULUVM_SET_STATE(zdev,
1274*0Sstevel@tonic-gate 					    ZULUVM_STATE_CANCELED, state);
1275*0Sstevel@tonic-gate 			}
1276*0Sstevel@tonic-gate 			TNF_PROBE_1(zuluvm_dma_free_ctx, "zuluvm", /* */,
1277*0Sstevel@tonic-gate 			    tnf_int, state, state);
1278*0Sstevel@tonic-gate #ifdef DEBUG
1279*0Sstevel@tonic-gate 			if (zuluvm_debug_state)
1280*0Sstevel@tonic-gate 				cmn_err(CE_NOTE, "zuluvm_dma_free_ctx: (loop1)"
1281*0Sstevel@tonic-gate 				    " state %d\n", state);
1282*0Sstevel@tonic-gate #endif
1283*0Sstevel@tonic-gate 		}
1284*0Sstevel@tonic-gate 	}
1285*0Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_dma_free_ctx, "zuluvm", /* */,
1286*0Sstevel@tonic-gate 	    tnf_int, state, state);
1287*0Sstevel@tonic-gate 
1288*0Sstevel@tonic-gate 	error = ZULUVM_SUCCESS;
1289*0Sstevel@tonic-gate 	while (state != ZULUVM_STATE_STOPPED) {
1290*0Sstevel@tonic-gate 		state = ZULUVM_GET_STATE(zdev);
1291*0Sstevel@tonic-gate #ifdef DEBUG
1292*0Sstevel@tonic-gate 		if (zuluvm_debug_state)
1293*0Sstevel@tonic-gate 			cmn_err(CE_NOTE, "zuluvm_dma_free: (loop2) state %d\n",
1294*0Sstevel@tonic-gate 			    state);
1295*0Sstevel@tonic-gate #endif
1296*0Sstevel@tonic-gate 		if (state != ZULUVM_STATE_STOPPED)
1297*0Sstevel@tonic-gate 			delay(1);
1298*0Sstevel@tonic-gate 	}
1299*0Sstevel@tonic-gate 	ZULUVM_LOCK;
1300*0Sstevel@tonic-gate 	if (zdev->zvm.arg != NULL) {
1301*0Sstevel@tonic-gate 		zuluvm_proc_t *proc = NULL;
1302*0Sstevel@tonic-gate 		switch (dma) {
1303*0Sstevel@tonic-gate 		case ZULUVM_DMA1:
1304*0Sstevel@tonic-gate 			proc = zdev->zvm.proc1;
1305*0Sstevel@tonic-gate 			zdev->zvm.proc1 = NULL;
1306*0Sstevel@tonic-gate 			break;
1307*0Sstevel@tonic-gate 		case ZULUVM_DMA2:
1308*0Sstevel@tonic-gate 			proc = zdev->zvm.proc2;
1309*0Sstevel@tonic-gate 			zdev->zvm.proc2 = NULL;
1310*0Sstevel@tonic-gate 			break;
1311*0Sstevel@tonic-gate 		default:
1312*0Sstevel@tonic-gate 			error = ZULUVM_NO_DEV;
1313*0Sstevel@tonic-gate 		}
1314*0Sstevel@tonic-gate 		ZULUVM_UNLOCK;
1315*0Sstevel@tonic-gate 		if (proc) {
1316*0Sstevel@tonic-gate 			mutex_enter(&zdev->proc_lck);
1317*0Sstevel@tonic-gate 			(void) zuluvm_proc_release(zdev, proc);
1318*0Sstevel@tonic-gate 			mutex_exit(&zdev->proc_lck);
1319*0Sstevel@tonic-gate 		}
1320*0Sstevel@tonic-gate 	} else {
1321*0Sstevel@tonic-gate 		ZULUVM_UNLOCK;
1322*0Sstevel@tonic-gate 		error = ZULUVM_NO_DEV;
1323*0Sstevel@tonic-gate 	}
1324*0Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_dma_free_ctx_done, "zuluvm", /* */,
1325*0Sstevel@tonic-gate 	    tnf_int, error, error);
1326*0Sstevel@tonic-gate 	return (error);
1327*0Sstevel@tonic-gate }
1328*0Sstevel@tonic-gate 
1329*0Sstevel@tonic-gate static void
1330*0Sstevel@tonic-gate zuluvm_do_retarget(zuluvm_state_t *zdev)
1331*0Sstevel@tonic-gate {
1332*0Sstevel@tonic-gate 	int i, idx;
1333*0Sstevel@tonic-gate 	uint_t cpu;
1334*0Sstevel@tonic-gate 	for (i = 0; i < ZULUVM_MAX_INTR; i++) {
1335*0Sstevel@tonic-gate 		if (zdev->interrupts[i].ino != -1) {
1336*0Sstevel@tonic-gate 			cpu = intr_dist_cpuid();
1337*0Sstevel@tonic-gate 			idx = zdev->interrupts[i].offset;
1338*0Sstevel@tonic-gate 			if (zdev->imr[idx] & ZULUVM_IMR_V_MASK)
1339*0Sstevel@tonic-gate 				zdev->imr[idx] = ZULUVM_IMR_V_MASK |
1340*0Sstevel@tonic-gate 				    (cpu<<ZULUVM_IMR_TARGET_SHIFT);
1341*0Sstevel@tonic-gate 			else
1342*0Sstevel@tonic-gate 				zdev->imr[idx] =
1343*0Sstevel@tonic-gate 				    cpu<<ZULUVM_IMR_TARGET_SHIFT;
1344*0Sstevel@tonic-gate 		}
1345*0Sstevel@tonic-gate 	}
1346*0Sstevel@tonic-gate }
1347*0Sstevel@tonic-gate 
1348*0Sstevel@tonic-gate static void
1349*0Sstevel@tonic-gate zuluvm_retarget_intr(void *arg)
1350*0Sstevel@tonic-gate {
1351*0Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)arg;
1352*0Sstevel@tonic-gate 	ZULUVM_LOCK;
1353*0Sstevel@tonic-gate 	zuluvm_do_retarget(zdev);
1354*0Sstevel@tonic-gate 	ZULUVM_UNLOCK;
1355*0Sstevel@tonic-gate }
1356*0Sstevel@tonic-gate 
1357*0Sstevel@tonic-gate int
1358*0Sstevel@tonic-gate zuluvm_add_intr(zuluvm_info_t devp, int ino,
1359*0Sstevel@tonic-gate 		uint_t (*handler)(caddr_t), caddr_t arg)
1360*0Sstevel@tonic-gate {
1361*0Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
1362*0Sstevel@tonic-gate 	if (devp == NULL) {
1363*0Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_add_intr_done, "zuluvm", /* */,
1364*0Sstevel@tonic-gate 		    tnf_int, error, ZULUVM_NO_DEV);
1365*0Sstevel@tonic-gate 		return (ZULUVM_NO_DEV);
1366*0Sstevel@tonic-gate 	}
1367*0Sstevel@tonic-gate 	if (ddi_add_intr(zdev->dip, ino, NULL, NULL, handler, arg)
1368*0Sstevel@tonic-gate 		!= DDI_SUCCESS) {
1369*0Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_add_intr_done, "zuluvm", /* */,
1370*0Sstevel@tonic-gate 		    tnf_int, error, ZULUVM_ERROR);
1371*0Sstevel@tonic-gate 		return (ZULUVM_ERROR);
1372*0Sstevel@tonic-gate 	}
1373*0Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
1374*0Sstevel@tonic-gate }
1375*0Sstevel@tonic-gate 
1376*0Sstevel@tonic-gate int
1377*0Sstevel@tonic-gate zuluvm_rem_intr(zuluvm_info_t devp, int ino)
1378*0Sstevel@tonic-gate {
1379*0Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
1380*0Sstevel@tonic-gate 	if (devp == NULL) {
1381*0Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_rem_intr_done, "zuluvm", /* */,
1382*0Sstevel@tonic-gate 		    tnf_int, error, ZULUVM_NO_DEV);
1383*0Sstevel@tonic-gate 		return (ZULUVM_NO_DEV);
1384*0Sstevel@tonic-gate 	}
1385*0Sstevel@tonic-gate 	/* remove from distributin list */
1386*0Sstevel@tonic-gate 	ZULUVM_LOCK;
1387*0Sstevel@tonic-gate 	zdev->imr[zdev->interrupts[ino].offset] &= ~ZULUVM_IMR_V_MASK;
1388*0Sstevel@tonic-gate 	ZULUVM_UNLOCK;
1389*0Sstevel@tonic-gate 	ddi_remove_intr(zdev->dip, ino, NULL);
1390*0Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
1391*0Sstevel@tonic-gate }
1392*0Sstevel@tonic-gate 
1393*0Sstevel@tonic-gate int
1394*0Sstevel@tonic-gate zuluvm_enable_intr(zuluvm_info_t devp, int num)
1395*0Sstevel@tonic-gate {
1396*0Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
1397*0Sstevel@tonic-gate 
1398*0Sstevel@tonic-gate 	TNF_PROBE_2(zuluvm_enable_intr, "zuluvm_intr", /* */,
1399*0Sstevel@tonic-gate 	    tnf_opaque, devp, devp,
1400*0Sstevel@tonic-gate 	    tnf_int, num, num);
1401*0Sstevel@tonic-gate 	if (devp == NULL) {
1402*0Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_enable_intr_done, "zuluvm", /* */,
1403*0Sstevel@tonic-gate 		    tnf_int, error, ZULUVM_NO_DEV);
1404*0Sstevel@tonic-gate 		return (ZULUVM_NO_DEV);
1405*0Sstevel@tonic-gate 	}
1406*0Sstevel@tonic-gate 	if (num < 0 || num > ZULUVM_IMR_MAX) {
1407*0Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_enable_intr_done, "zuluvm", /* */,
1408*0Sstevel@tonic-gate 		    tnf_int, error, ZULUVM_BAD_IDX);
1409*0Sstevel@tonic-gate 		return (ZULUVM_BAD_IDX);
1410*0Sstevel@tonic-gate 	}
1411*0Sstevel@tonic-gate 	ZULUVM_LOCK;
1412*0Sstevel@tonic-gate 	zdev->imr[num] |= ZULUVM_IMR_V_MASK;
1413*0Sstevel@tonic-gate 	ZULUVM_UNLOCK;
1414*0Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_enable_intr_done, "zuluvm_intr", /* */,
1415*0Sstevel@tonic-gate 	    tnf_int, error, ZULUVM_SUCCESS);
1416*0Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
1417*0Sstevel@tonic-gate }
1418*0Sstevel@tonic-gate 
1419*0Sstevel@tonic-gate int
1420*0Sstevel@tonic-gate zuluvm_disable_intr(zuluvm_info_t devp, int num)
1421*0Sstevel@tonic-gate {
1422*0Sstevel@tonic-gate 	zuluvm_state_t *zdev = (zuluvm_state_t *)devp;
1423*0Sstevel@tonic-gate 
1424*0Sstevel@tonic-gate 	TNF_PROBE_2(zuluvm_disable_intr, "zuluvm_intr", /* */,
1425*0Sstevel@tonic-gate 	    tnf_opaque, devp, devp,
1426*0Sstevel@tonic-gate 	    tnf_int, num, num);
1427*0Sstevel@tonic-gate 	if (devp == NULL) {
1428*0Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_disable_intr_done, "zuluvm", /* */,
1429*0Sstevel@tonic-gate 		    tnf_int, error, ZULUVM_NO_DEV);
1430*0Sstevel@tonic-gate 		return (ZULUVM_NO_DEV);
1431*0Sstevel@tonic-gate 	}
1432*0Sstevel@tonic-gate 	if (num < 0 || num > ZULUVM_IMR_MAX) {
1433*0Sstevel@tonic-gate 		TNF_PROBE_1(zuluvm_disable_intr_done, "zuluvm", /* */,
1434*0Sstevel@tonic-gate 		    tnf_int, error, ZULUVM_BAD_IDX);
1435*0Sstevel@tonic-gate 		return (ZULUVM_BAD_IDX);
1436*0Sstevel@tonic-gate 	}
1437*0Sstevel@tonic-gate 	ZULUVM_LOCK;
1438*0Sstevel@tonic-gate 	zdev->imr[num] &= ~ZULUVM_IMR_V_MASK;
1439*0Sstevel@tonic-gate 	ZULUVM_UNLOCK;
1440*0Sstevel@tonic-gate 	TNF_PROBE_1(zuluvm_disable_intr_done, "zuluvm_intr", /* */,
1441*0Sstevel@tonic-gate 	    tnf_int, error, ZULUVM_SUCCESS);
1442*0Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
1443*0Sstevel@tonic-gate }
1444*0Sstevel@tonic-gate 
1445*0Sstevel@tonic-gate static int
1446*0Sstevel@tonic-gate zuluvm_get_intr_props(zuluvm_state_t *zdev,
1447*0Sstevel@tonic-gate 			dev_info_t *devi)
1448*0Sstevel@tonic-gate {
1449*0Sstevel@tonic-gate 	int *intr;
1450*0Sstevel@tonic-gate 	int i;
1451*0Sstevel@tonic-gate 	uint_t nintr;
1452*0Sstevel@tonic-gate 
1453*0Sstevel@tonic-gate 	zdev->agentid = ddi_getprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
1454*0Sstevel@tonic-gate 	    "portid", -1);
1455*0Sstevel@tonic-gate 	if (zdev->agentid == -1) {
1456*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: no portid property",
1457*0Sstevel@tonic-gate 		    ddi_get_name(devi),
1458*0Sstevel@tonic-gate 		    ddi_get_instance(devi));
1459*0Sstevel@tonic-gate 		return (ZULUVM_ERROR);
1460*0Sstevel@tonic-gate 	}
1461*0Sstevel@tonic-gate 
1462*0Sstevel@tonic-gate 	for (i = 0; i < ZULUVM_MAX_INTR; i++) {
1463*0Sstevel@tonic-gate 		zdev->interrupts[i].offset = 0;
1464*0Sstevel@tonic-gate 		zdev->interrupts[i].ino = -1;
1465*0Sstevel@tonic-gate 	}
1466*0Sstevel@tonic-gate 
1467*0Sstevel@tonic-gate 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
1468*0Sstevel@tonic-gate 	    "interrupts", &intr, &nintr) == DDI_PROP_SUCCESS) {
1469*0Sstevel@tonic-gate 
1470*0Sstevel@tonic-gate 		if (nintr == 0) {
1471*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: no interrupts in property",
1472*0Sstevel@tonic-gate 			    ddi_get_name(devi),
1473*0Sstevel@tonic-gate 			    ddi_get_instance(devi));
1474*0Sstevel@tonic-gate 			ddi_prop_free(intr);
1475*0Sstevel@tonic-gate 			return (ZULUVM_ERROR);
1476*0Sstevel@tonic-gate 		}
1477*0Sstevel@tonic-gate 		if (nintr >= ZULUVM_MAX_INTR) {
1478*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: to many interrupts (%d)",
1479*0Sstevel@tonic-gate 			    ddi_get_name(devi),
1480*0Sstevel@tonic-gate 			    ddi_get_instance(devi), nintr);
1481*0Sstevel@tonic-gate 			ddi_prop_free(intr);
1482*0Sstevel@tonic-gate 			return (ZULUVM_ERROR);
1483*0Sstevel@tonic-gate 		}
1484*0Sstevel@tonic-gate 		for (i = 0; i < nintr; i++) {
1485*0Sstevel@tonic-gate 			zdev->interrupts[i].offset = intr[i];
1486*0Sstevel@tonic-gate 			zdev->interrupts[i].ino = i;
1487*0Sstevel@tonic-gate 		}
1488*0Sstevel@tonic-gate 		ddi_prop_free(intr);
1489*0Sstevel@tonic-gate 	} else {
1490*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: no interrupts property",
1491*0Sstevel@tonic-gate 		    ddi_get_name(devi),
1492*0Sstevel@tonic-gate 		    ddi_get_instance(devi));
1493*0Sstevel@tonic-gate 	}
1494*0Sstevel@tonic-gate 	return (ZULUVM_SUCCESS);
1495*0Sstevel@tonic-gate }
1496*0Sstevel@tonic-gate 
1497*0Sstevel@tonic-gate /* *** enf of zulu *** */
1498