xref: /onnv-gate/usr/src/uts/sun4u/vm/zulu_hat.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 #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/cmn_err.h>
31*0Sstevel@tonic-gate #include <sys/mman.h>
32*0Sstevel@tonic-gate #include <sys/sunddi.h>
33*0Sstevel@tonic-gate #include <sys/tnf_probe.h>
34*0Sstevel@tonic-gate #include <vm/hat_sfmmu.h>
35*0Sstevel@tonic-gate #include <vm/as.h>
36*0Sstevel@tonic-gate #include <vm/xhat.h>
37*0Sstevel@tonic-gate #include <vm/xhat_sfmmu.h>
38*0Sstevel@tonic-gate #include <sys/zulu_hat.h>
39*0Sstevel@tonic-gate #include <sys/zulumod.h>
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate /*
42*0Sstevel@tonic-gate  * This file contains the implementation of zulu_hat: an XHAT provider
43*0Sstevel@tonic-gate  * to support the MMU for the XVR-4000 graphics accelerator (code name zulu).
44*0Sstevel@tonic-gate  *
45*0Sstevel@tonic-gate  * The zulu hat is linked into the kernel misc module zuluvm.
46*0Sstevel@tonic-gate  * zuluvm provides services that the zulu device driver module requires
47*0Sstevel@tonic-gate  * that are not part of the standard ddi. See PSARC 2002/231.
48*0Sstevel@tonic-gate  *
49*0Sstevel@tonic-gate  * The zulu driver is delivered by the graphics consolidation.
50*0Sstevel@tonic-gate  * zuluvm is in ON workspace.
51*0Sstevel@tonic-gate  *
52*0Sstevel@tonic-gate  * There are two types of interfaces provided by zulu_hat
53*0Sstevel@tonic-gate  *   1.	The set of functions and data structures used by zuluvm to obtain
54*0Sstevel@tonic-gate  * 	tte entries for the zulu MMU and to manage the association between
55*0Sstevel@tonic-gate  *	user process's address spaces and zulu graphics contexts.
56*0Sstevel@tonic-gate  *
57*0Sstevel@tonic-gate  *   2.	The entry points required for an XHAT provider: zulu_hat_ops
58*0Sstevel@tonic-gate  */
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate /*
61*0Sstevel@tonic-gate  * zulu_ctx_tab contains an array of pointers to the zulu_hats.
62*0Sstevel@tonic-gate  *
63*0Sstevel@tonic-gate  * During zulu graphics context switch, the zulu MMU's current context register
64*0Sstevel@tonic-gate  * is set to the index of the process's zulu hat's location in the array
65*0Sstevel@tonic-gate  * zulu_ctx_tab.
66*0Sstevel@tonic-gate  *
67*0Sstevel@tonic-gate  * This allows the TL=1 TLB miss handler to quickly find the zulu hat and
68*0Sstevel@tonic-gate  * lookup a tte in the zulu hat's TSB.
69*0Sstevel@tonic-gate  *
70*0Sstevel@tonic-gate  * To synchronize with the trap handler we use bit zero of
71*0Sstevel@tonic-gate  * the pointer as a lock bit. See the function zulu_ctx_tsb_lock_enter().
72*0Sstevel@tonic-gate  *
73*0Sstevel@tonic-gate  * If the trap handler finds the ctx locked it doesn't wait, it
74*0Sstevel@tonic-gate  * posts a soft interrupt which is handled at TL=0.
75*0Sstevel@tonic-gate  */
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate #define		ZULU_HAT_MAX_CTX 32
78*0Sstevel@tonic-gate struct zulu_hat *zulu_ctx_tab[ZULU_HAT_MAX_CTX];
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate /*
81*0Sstevel@tonic-gate  * To avoid searching through the whole zulu_ctx_tab for a free slot,
82*0Sstevel@tonic-gate  * we maintain the value of zulu_ctx_search_start.
83*0Sstevel@tonic-gate  *
84*0Sstevel@tonic-gate  * This value is a guess as to where a free slot in the context table might be.
85*0Sstevel@tonic-gate  * All slots < zulu_ctx_search_start are definitely occupied.
86*0Sstevel@tonic-gate  */
87*0Sstevel@tonic-gate static int zulu_ctx_search_start = 0;
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate /*
91*0Sstevel@tonic-gate  * this mutex protects the zulu_ctx_tab and zulu_ctx_search_start
92*0Sstevel@tonic-gate  */
93*0Sstevel@tonic-gate static kmutex_t	zulu_ctx_lock;
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate uint64_t	zulu_tsb_hit = 0;	/* assembly code increments this */
97*0Sstevel@tonic-gate static uint64_t	zulu_tsb_miss = 0;
98*0Sstevel@tonic-gate static uint64_t	zulu_as_fault = 0;
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate /*
101*0Sstevel@tonic-gate  * The zulu device has two zulu data mmus.
102*0Sstevel@tonic-gate  * We use the base pagesize for one of them and the and 4M for the other.
103*0Sstevel@tonic-gate  */
104*0Sstevel@tonic-gate extern int zuluvm_base_pgsize;
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate /*
109*0Sstevel@tonic-gate  * call zuluvm to remove translations for a page
110*0Sstevel@tonic-gate  */
111*0Sstevel@tonic-gate static void
zulu_hat_demap_page(struct zulu_hat * zhat,caddr_t vaddr,int size)112*0Sstevel@tonic-gate zulu_hat_demap_page(struct zulu_hat *zhat, caddr_t vaddr, int size)
113*0Sstevel@tonic-gate {
114*0Sstevel@tonic-gate 	if (zhat->zulu_ctx < 0) {
115*0Sstevel@tonic-gate 		/* context has been stolen, so page is already demapped */
116*0Sstevel@tonic-gate 		return;
117*0Sstevel@tonic-gate 	}
118*0Sstevel@tonic-gate 	zuluvm_demap_page(zhat->zdev, NULL, zhat->zulu_ctx, vaddr, size);
119*0Sstevel@tonic-gate }
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate static void
zulu_hat_demap_ctx(void * zdev,int zulu_ctx)122*0Sstevel@tonic-gate zulu_hat_demap_ctx(void *zdev, int zulu_ctx)
123*0Sstevel@tonic-gate {
124*0Sstevel@tonic-gate 	if (zulu_ctx < 0) {
125*0Sstevel@tonic-gate 		/* context has been stolen */
126*0Sstevel@tonic-gate 		return;
127*0Sstevel@tonic-gate 	}
128*0Sstevel@tonic-gate 	zuluvm_demap_ctx(zdev, zulu_ctx);
129*0Sstevel@tonic-gate }
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate /*
133*0Sstevel@tonic-gate  * steal the least recently used context slot.
134*0Sstevel@tonic-gate  */
135*0Sstevel@tonic-gate static int
zulu_hat_steal_ctx()136*0Sstevel@tonic-gate zulu_hat_steal_ctx()
137*0Sstevel@tonic-gate {
138*0Sstevel@tonic-gate 	int		ctx;
139*0Sstevel@tonic-gate 	hrtime_t	delta = INT64_MAX;
140*0Sstevel@tonic-gate 	struct zulu_hat *zhat_oldest = NULL;
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&zulu_ctx_lock));
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 	for (ctx = 0; ctx < ZULU_HAT_MAX_CTX; ctx++) {
145*0Sstevel@tonic-gate 		struct zulu_hat *zhat = ZULU_CTX_GET_HAT(ctx);
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 		/*
148*0Sstevel@tonic-gate 		 * we shouldn't be here unless all slots are occupied
149*0Sstevel@tonic-gate 		 */
150*0Sstevel@tonic-gate 		ASSERT(zhat != NULL);
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 		TNF_PROBE_3(steal_ctx_loop, "zulu_hat", /* CSTYLED */,
153*0Sstevel@tonic-gate 			tnf_int, ctx, ctx,
154*0Sstevel@tonic-gate 			tnf_long, last_used, zhat->last_used,
155*0Sstevel@tonic-gate 			tnf_long, oldest, delta);
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate 		if (zhat->last_used <  delta) {
158*0Sstevel@tonic-gate 			zhat_oldest = zhat;
159*0Sstevel@tonic-gate 			delta  = zhat->last_used;
160*0Sstevel@tonic-gate 		}
161*0Sstevel@tonic-gate 	}
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 	ASSERT(zhat_oldest != NULL);
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	mutex_enter(&zhat_oldest->lock);
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate 	/* Nobody should have the tsb lock bit set here */
168*0Sstevel@tonic-gate 	ASSERT(((uint64_t)zulu_ctx_tab[zhat_oldest->zulu_ctx] & ZULU_CTX_LOCK)
169*0Sstevel@tonic-gate 		== 0);
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 	ctx = zhat_oldest->zulu_ctx;
172*0Sstevel@tonic-gate 	zhat_oldest->zulu_ctx = -1;
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate 	ZULU_CTX_SET_HAT(ctx, NULL);
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate 	zulu_hat_demap_ctx(zhat_oldest->zdev, ctx);
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate 	mutex_exit(&zhat_oldest->lock);
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	TNF_PROBE_1(zulu_hat_steal_ctx, "zulu_hat", /* CSTYLED */,
181*0Sstevel@tonic-gate 		tnf_int, ctx, ctx);
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate 	return (ctx);
184*0Sstevel@tonic-gate }
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate /*
187*0Sstevel@tonic-gate  * find a slot in the context table for a zulu_hat
188*0Sstevel@tonic-gate  */
189*0Sstevel@tonic-gate static void
zulu_hat_ctx_alloc(struct zulu_hat * zhat)190*0Sstevel@tonic-gate zulu_hat_ctx_alloc(struct zulu_hat *zhat)
191*0Sstevel@tonic-gate {
192*0Sstevel@tonic-gate 	int 		ctx;
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 	mutex_enter(&zulu_ctx_lock);
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate 	for (ctx = zulu_ctx_search_start; ctx < ZULU_HAT_MAX_CTX; ctx++) {
197*0Sstevel@tonic-gate 		if (ZULU_CTX_IS_FREE(ctx)) {
198*0Sstevel@tonic-gate 			zulu_ctx_search_start = ctx + 1;
199*0Sstevel@tonic-gate 			break;
200*0Sstevel@tonic-gate 		}
201*0Sstevel@tonic-gate 	}
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 	if (ctx == ZULU_HAT_MAX_CTX) {
204*0Sstevel@tonic-gate 		/* table is full need to steal an entry */
205*0Sstevel@tonic-gate 		zulu_ctx_search_start = ZULU_HAT_MAX_CTX;
206*0Sstevel@tonic-gate 		ctx = zulu_hat_steal_ctx();
207*0Sstevel@tonic-gate 	}
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	mutex_enter(&zhat->lock);
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 	ZULU_CTX_SET_HAT(ctx, zhat);
212*0Sstevel@tonic-gate 	zhat->zulu_ctx = ctx;
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 	mutex_exit(&zhat->lock);
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 	mutex_exit(&zulu_ctx_lock);
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 	TNF_PROBE_2(zulu_hat_ctx_alloc, "zulu_hat", /* CSTYLED */,
219*0Sstevel@tonic-gate 		tnf_opaque, zhat, zhat, tnf_int, ctx, ctx);
220*0Sstevel@tonic-gate }
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate /*
223*0Sstevel@tonic-gate  * zulu_hat_validate_ctx: Called before the graphics context associated
224*0Sstevel@tonic-gate  * with a given zulu hat becomes the current zulu graphics context.
225*0Sstevel@tonic-gate  * Make sure that the hat has a slot in zulu_ctx_tab.
226*0Sstevel@tonic-gate  */
227*0Sstevel@tonic-gate void
zulu_hat_validate_ctx(struct zulu_hat * zhat)228*0Sstevel@tonic-gate zulu_hat_validate_ctx(struct zulu_hat *zhat)
229*0Sstevel@tonic-gate {
230*0Sstevel@tonic-gate 	if (zhat->zulu_ctx < 0)  {
231*0Sstevel@tonic-gate 		zulu_hat_ctx_alloc(zhat);
232*0Sstevel@tonic-gate 	}
233*0Sstevel@tonic-gate 	zhat->last_used = gethrtime();
234*0Sstevel@tonic-gate }
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate static void
zulu_hat_ctx_free(struct zulu_hat * zhat)238*0Sstevel@tonic-gate zulu_hat_ctx_free(struct zulu_hat *zhat)
239*0Sstevel@tonic-gate {
240*0Sstevel@tonic-gate 	TNF_PROBE_1(zulu_hat_ctx_free, "zulu_hat", /* CSTYLED */,
241*0Sstevel@tonic-gate 		tnf_int, ctx, zhat->zulu_ctx);
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 	mutex_enter(&zulu_ctx_lock);
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 	mutex_enter(&zhat->lock);
246*0Sstevel@tonic-gate 	if (zhat->zulu_ctx >= 0) {
247*0Sstevel@tonic-gate 		ZULU_CTX_SET_HAT(zhat->zulu_ctx, NULL);
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 		if (zulu_ctx_search_start > zhat->zulu_ctx) {
250*0Sstevel@tonic-gate 			zulu_ctx_search_start = zhat->zulu_ctx;
251*0Sstevel@tonic-gate 		}
252*0Sstevel@tonic-gate 	}
253*0Sstevel@tonic-gate 	mutex_exit(&zhat->lock);
254*0Sstevel@tonic-gate 	mutex_exit(&zulu_ctx_lock);
255*0Sstevel@tonic-gate }
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate /*
258*0Sstevel@tonic-gate  * Lock the zulu tsb for a given zulu_hat.
259*0Sstevel@tonic-gate  *
260*0Sstevel@tonic-gate  * We're just protecting against the TLB trap handler here. Other operations
261*0Sstevel@tonic-gate  * on the zulu_hat require entering the zhat's lock.
262*0Sstevel@tonic-gate  */
263*0Sstevel@tonic-gate static void
zulu_ctx_tsb_lock_enter(struct zulu_hat * zhat)264*0Sstevel@tonic-gate zulu_ctx_tsb_lock_enter(struct zulu_hat *zhat)
265*0Sstevel@tonic-gate {
266*0Sstevel@tonic-gate 	uint64_t	lck;
267*0Sstevel@tonic-gate 	uint64_t    	*plck;
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&zhat->lock));
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	if (zhat->zulu_ctx < 0) {
272*0Sstevel@tonic-gate 		return;
273*0Sstevel@tonic-gate 	}
274*0Sstevel@tonic-gate 	plck = (uint64_t *)&zulu_ctx_tab[zhat->zulu_ctx];
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate 	for (; ; ) {
277*0Sstevel@tonic-gate 		lck = *plck;
278*0Sstevel@tonic-gate 		if (!(lck & ZULU_CTX_LOCK)) {
279*0Sstevel@tonic-gate 			uint64_t old_lck, new_lck;
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 			new_lck = lck | ZULU_CTX_LOCK;
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 			old_lck = cas64(plck, lck, new_lck);
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 			if (old_lck == lck) {
286*0Sstevel@tonic-gate 				/*
287*0Sstevel@tonic-gate 				 * success
288*0Sstevel@tonic-gate 				 */
289*0Sstevel@tonic-gate 				break;
290*0Sstevel@tonic-gate 			}
291*0Sstevel@tonic-gate 		}
292*0Sstevel@tonic-gate 	}
293*0Sstevel@tonic-gate }
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate static void
zulu_ctx_tsb_lock_exit(struct zulu_hat * zhat)296*0Sstevel@tonic-gate zulu_ctx_tsb_lock_exit(struct zulu_hat *zhat)
297*0Sstevel@tonic-gate {
298*0Sstevel@tonic-gate 	uint64_t	lck;
299*0Sstevel@tonic-gate 	int		zulu_ctx = zhat->zulu_ctx;
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 	if (zulu_ctx < 0) {
302*0Sstevel@tonic-gate 		return;
303*0Sstevel@tonic-gate 	}
304*0Sstevel@tonic-gate 	lck = (uint64_t)zulu_ctx_tab[zulu_ctx];
305*0Sstevel@tonic-gate 	ASSERT(lck & ZULU_CTX_LOCK);
306*0Sstevel@tonic-gate 	lck &= ~ZULU_CTX_LOCK;
307*0Sstevel@tonic-gate 	zulu_ctx_tab[zulu_ctx] = (struct zulu_hat *)lck;
308*0Sstevel@tonic-gate }
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate /*
311*0Sstevel@tonic-gate  * Each zulu hat has a "shadow tree" which is a table of 4MB address regions
312*0Sstevel@tonic-gate  * for which the zhat has mappings.
313*0Sstevel@tonic-gate  *
314*0Sstevel@tonic-gate  * This table is maintained in an avl tree.
315*0Sstevel@tonic-gate  * Nodes in the tree are called shadow blocks (or sblks)
316*0Sstevel@tonic-gate  *
317*0Sstevel@tonic-gate  * This data structure allows unload operations by (address, range) to be
318*0Sstevel@tonic-gate  * much more efficent.
319*0Sstevel@tonic-gate  *
320*0Sstevel@tonic-gate  * We get called a lot for address ranges that have never been supplied
321*0Sstevel@tonic-gate  * to zulu.
322*0Sstevel@tonic-gate  */
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate /*
325*0Sstevel@tonic-gate  * compare the base address of two nodes in the shadow tree
326*0Sstevel@tonic-gate  */
327*0Sstevel@tonic-gate static int
zulu_shadow_tree_compare(const void * a,const void * b)328*0Sstevel@tonic-gate zulu_shadow_tree_compare(const void *a, const void *b)
329*0Sstevel@tonic-gate {
330*0Sstevel@tonic-gate 	struct zulu_shadow_blk *zba = (struct zulu_shadow_blk *)a;
331*0Sstevel@tonic-gate 	struct zulu_shadow_blk *zbb = (struct zulu_shadow_blk *)b;
332*0Sstevel@tonic-gate 	uint64_t		addr_a = zba->ivaddr;
333*0Sstevel@tonic-gate 	uint64_t		addr_b = zbb->ivaddr;
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 	TNF_PROBE_2(zulu_shadow_tree_compare, "zulu_shadow_tree", /* CSTYLED */,
336*0Sstevel@tonic-gate 		tnf_opaque, addr_a, addr_a, tnf_opaque, addr_b, addr_b);
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	if (addr_a < addr_b) {
339*0Sstevel@tonic-gate 		return (-1);
340*0Sstevel@tonic-gate 	} else if (addr_a > addr_b) {
341*0Sstevel@tonic-gate 		return (1);
342*0Sstevel@tonic-gate 	} else {
343*0Sstevel@tonic-gate 		return (0);
344*0Sstevel@tonic-gate 	}
345*0Sstevel@tonic-gate }
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate /*
348*0Sstevel@tonic-gate  * lookup the entry in the shadow tree for a given virtual address
349*0Sstevel@tonic-gate  */
350*0Sstevel@tonic-gate static struct zulu_shadow_blk *
zulu_shadow_tree_lookup(struct zulu_hat * zhat,uint64_t ivaddr,avl_index_t * where)351*0Sstevel@tonic-gate zulu_shadow_tree_lookup(struct zulu_hat *zhat, uint64_t ivaddr,
352*0Sstevel@tonic-gate 	avl_index_t *where)
353*0Sstevel@tonic-gate {
354*0Sstevel@tonic-gate 	struct zulu_shadow_blk proto;
355*0Sstevel@tonic-gate 	struct zulu_shadow_blk *sblk;
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate 	proto.ivaddr = ivaddr & ZULU_SHADOW_BLK_MASK;
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 	/*
360*0Sstevel@tonic-gate 	 * pages typically fault in in order so we cache the last shadow
361*0Sstevel@tonic-gate 	 * block that was referenced so we usually get to reduce calls to
362*0Sstevel@tonic-gate 	 * avl_find.
363*0Sstevel@tonic-gate 	 */
364*0Sstevel@tonic-gate 	if ((zhat->sblk_last != NULL) &&
365*0Sstevel@tonic-gate 		(proto.ivaddr == zhat->sblk_last->ivaddr)) {
366*0Sstevel@tonic-gate 		sblk = zhat->sblk_last;
367*0Sstevel@tonic-gate 	} else {
368*0Sstevel@tonic-gate 		sblk = (struct zulu_shadow_blk *)avl_find(&zhat->shadow_tree,
369*0Sstevel@tonic-gate 								&proto, where);
370*0Sstevel@tonic-gate 		zhat->sblk_last = sblk;
371*0Sstevel@tonic-gate 	}
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 	TNF_PROBE_2(zulu_shadow_tree_lookup, "zulu_shadow_tree", /* CSTYLED */,
374*0Sstevel@tonic-gate 		tnf_opaque, ivaddr, proto.ivaddr,
375*0Sstevel@tonic-gate 		tnf_opaque, where, where ? *where : ~0);
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 	return (sblk);
378*0Sstevel@tonic-gate }
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate /*
381*0Sstevel@tonic-gate  * insert a sblk into the shadow tree for a given zblk.
382*0Sstevel@tonic-gate  * If a sblk already exists, just increment it's refcount.
383*0Sstevel@tonic-gate  */
384*0Sstevel@tonic-gate static void
zulu_shadow_tree_insert(struct zulu_hat * zhat,struct zulu_hat_blk * zblk)385*0Sstevel@tonic-gate zulu_shadow_tree_insert(struct zulu_hat *zhat, struct zulu_hat_blk *zblk)
386*0Sstevel@tonic-gate {
387*0Sstevel@tonic-gate 	avl_index_t		where;
388*0Sstevel@tonic-gate 	struct zulu_shadow_blk 	*sblk  = NULL;
389*0Sstevel@tonic-gate 	uint64_t		ivaddr;
390*0Sstevel@tonic-gate 	uint64_t		end;
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 	ivaddr = zblk->zulu_hat_blk_vaddr & ZULU_SHADOW_BLK_MASK;
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 	end = zblk->zulu_hat_blk_vaddr + ZULU_HAT_PGSZ(zblk->zulu_hat_blk_size);
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 	sblk = zulu_shadow_tree_lookup(zhat, ivaddr, &where);
397*0Sstevel@tonic-gate 	if (sblk != NULL) {
398*0Sstevel@tonic-gate 		sblk->ref_count++;
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate 		end = zblk->zulu_hat_blk_vaddr +
401*0Sstevel@tonic-gate 					ZULU_HAT_PGSZ(zblk->zulu_hat_blk_size);
402*0Sstevel@tonic-gate 		if (zblk->zulu_hat_blk_vaddr < sblk->min_addr) {
403*0Sstevel@tonic-gate 			sblk->min_addr = zblk->zulu_hat_blk_vaddr;
404*0Sstevel@tonic-gate 		}
405*0Sstevel@tonic-gate 		/*
406*0Sstevel@tonic-gate 		 * a blk can set both the minimum and maximum when it
407*0Sstevel@tonic-gate 		 * is the first zblk added to a previously emptied sblk
408*0Sstevel@tonic-gate 		 */
409*0Sstevel@tonic-gate 		if (end > sblk->max_addr) {
410*0Sstevel@tonic-gate 			sblk->max_addr = end;
411*0Sstevel@tonic-gate 		}
412*0Sstevel@tonic-gate 	} else {
413*0Sstevel@tonic-gate 		sblk = kmem_zalloc(sizeof (*sblk), KM_SLEEP);
414*0Sstevel@tonic-gate 		sblk->ref_count = 1;
415*0Sstevel@tonic-gate 		sblk->ivaddr = ivaddr;
416*0Sstevel@tonic-gate 		sblk->min_addr = zblk->zulu_hat_blk_vaddr;
417*0Sstevel@tonic-gate 		sblk->max_addr = end;
418*0Sstevel@tonic-gate 		zhat->sblk_last = sblk;
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 		avl_insert(&zhat->shadow_tree, sblk, where);
421*0Sstevel@tonic-gate 	}
422*0Sstevel@tonic-gate 	zblk->zulu_shadow_blk = sblk;
423*0Sstevel@tonic-gate 	TNF_PROBE_2(zulu_shadow_tree_insert, "zulu_shadow_tree", /* CSTYLED */,
424*0Sstevel@tonic-gate 		tnf_opaque, vaddr, ivaddr,
425*0Sstevel@tonic-gate 		tnf_opaque, ref_count, sblk->ref_count);
426*0Sstevel@tonic-gate }
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate /*
429*0Sstevel@tonic-gate  * decrement the ref_count for the sblk that corresponds to a given zblk.
430*0Sstevel@tonic-gate  * When the ref_count goes to zero remove the sblk from the tree and free it.
431*0Sstevel@tonic-gate  */
432*0Sstevel@tonic-gate 
433*0Sstevel@tonic-gate static void
zulu_shadow_tree_delete(struct zulu_hat * zhat,struct zulu_hat_blk * zblk)434*0Sstevel@tonic-gate zulu_shadow_tree_delete(struct zulu_hat *zhat, struct zulu_hat_blk *zblk)
435*0Sstevel@tonic-gate {
436*0Sstevel@tonic-gate 	struct zulu_shadow_blk 	*sblk;
437*0Sstevel@tonic-gate 
438*0Sstevel@tonic-gate 	ASSERT(zblk->zulu_shadow_blk != NULL);
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate 	sblk = zblk->zulu_shadow_blk;
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 	TNF_PROBE_2(zulu_shadow_tree_delete, "zulu_shadow_tree", /* CSTYLED */,
443*0Sstevel@tonic-gate 		tnf_opaque, vaddr, sblk->ivaddr,
444*0Sstevel@tonic-gate 		tnf_opaque, ref_count, sblk->ref_count-1);
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 	if (--sblk->ref_count == 0) {
447*0Sstevel@tonic-gate 		if (zhat->sblk_last == sblk) {
448*0Sstevel@tonic-gate 			zhat->sblk_last = NULL;
449*0Sstevel@tonic-gate 		}
450*0Sstevel@tonic-gate 		sblk->min_addr = sblk->ivaddr + ZULU_SHADOW_BLK_RANGE;
451*0Sstevel@tonic-gate 		sblk->max_addr = sblk->ivaddr;
452*0Sstevel@tonic-gate 	} else {
453*0Sstevel@tonic-gate 		/*
454*0Sstevel@tonic-gate 		 * Update the high and low water marks for this sblk.
455*0Sstevel@tonic-gate 		 * These are estimates, because we don't know if the previous
456*0Sstevel@tonic-gate 		 * or next region are actually occupied, but we can tell
457*0Sstevel@tonic-gate 		 * whether the previous values have become invalid.
458*0Sstevel@tonic-gate 		 *
459*0Sstevel@tonic-gate 		 * In the most often applied case a segment is being
460*0Sstevel@tonic-gate 		 * unloaded, and the min_addr will be kept up to date as
461*0Sstevel@tonic-gate 		 * the zblks are deleted in order.
462*0Sstevel@tonic-gate 		 */
463*0Sstevel@tonic-gate 		uint64_t end = zblk->zulu_hat_blk_vaddr +
464*0Sstevel@tonic-gate 					ZULU_HAT_PGSZ(zblk->zulu_hat_blk_size);
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate 		if (zblk->zulu_hat_blk_vaddr == sblk->min_addr) {
467*0Sstevel@tonic-gate 			sblk->min_addr = end;
468*0Sstevel@tonic-gate 		}
469*0Sstevel@tonic-gate 		if (end == sblk->max_addr) {
470*0Sstevel@tonic-gate 			sblk->max_addr = zblk->zulu_hat_blk_vaddr;
471*0Sstevel@tonic-gate 		}
472*0Sstevel@tonic-gate 	}
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 	zblk->zulu_shadow_blk = NULL;
475*0Sstevel@tonic-gate }
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate static void
zulu_shadow_tree_destroy(struct zulu_hat * zhat)478*0Sstevel@tonic-gate zulu_shadow_tree_destroy(struct zulu_hat *zhat)
479*0Sstevel@tonic-gate {
480*0Sstevel@tonic-gate 	struct zulu_shadow_blk *sblk;
481*0Sstevel@tonic-gate 	void	*cookie = NULL;
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate 	while ((sblk = (struct zulu_shadow_blk *)avl_destroy_nodes(
484*0Sstevel@tonic-gate 					&zhat->shadow_tree, &cookie)) != NULL) {
485*0Sstevel@tonic-gate 		TNF_PROBE_2(shadow_tree_destroy, "zulu_hat", /* CSTYLED */,
486*0Sstevel@tonic-gate 			tnf_opaque, vaddr, sblk->ivaddr,
487*0Sstevel@tonic-gate 			tnf_opaque, ref_count, sblk->ref_count);
488*0Sstevel@tonic-gate 		kmem_free(sblk, sizeof (*sblk));
489*0Sstevel@tonic-gate 	}
490*0Sstevel@tonic-gate 	avl_destroy(&zhat->shadow_tree);
491*0Sstevel@tonic-gate }
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate /*
494*0Sstevel@tonic-gate  * zulu_hat_insert_map:
495*0Sstevel@tonic-gate  *
496*0Sstevel@tonic-gate  * Add a zulu_hat_blk to the a zhat's mappings list.
497*0Sstevel@tonic-gate  *
498*0Sstevel@tonic-gate  * Several data stuctures are used
499*0Sstevel@tonic-gate  *	tsb: for simple fast lookups by the trap handler
500*0Sstevel@tonic-gate  *	hash table: for efficent lookups by address, range
501*0Sstevel@tonic-gate  *	An shadow tree of 4MB ranges with mappings for unloading big regions.
502*0Sstevel@tonic-gate  */
503*0Sstevel@tonic-gate static void
zulu_hat_insert_map(struct zulu_hat * zhat,struct zulu_hat_blk * zblk)504*0Sstevel@tonic-gate zulu_hat_insert_map(struct zulu_hat *zhat, struct zulu_hat_blk *zblk)
505*0Sstevel@tonic-gate {
506*0Sstevel@tonic-gate 	int tsb_hash;
507*0Sstevel@tonic-gate 
508*0Sstevel@tonic-gate 	tsb_hash = ZULU_TSB_HASH(zblk->zulu_hat_blk_vaddr,
509*0Sstevel@tonic-gate 			    zblk->zulu_hat_blk_size, zhat->zulu_tsb_size);
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 	TNF_PROBE_3(zulu_hat_insert_map, "zulu_hat", /* CSTYLED */,
512*0Sstevel@tonic-gate 		tnf_opaque, zblkp, zblk,
513*0Sstevel@tonic-gate 		tnf_opaque, vaddr, zblk->zulu_hat_blk_vaddr,
514*0Sstevel@tonic-gate 		tnf_opaque, hash, tsb_hash);
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate 	ASSERT(tsb_hash < zhat->zulu_tsb_size);
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 	zulu_shadow_tree_insert(zhat, zblk);
519*0Sstevel@tonic-gate 
520*0Sstevel@tonic-gate 	/*
521*0Sstevel@tonic-gate 	 * The hash table is an array of buckets. Each bucket is the
522*0Sstevel@tonic-gate 	 * head of a linked list of mappings who's address hashess to the bucket
523*0Sstevel@tonic-gate 	 * New entries go to the head of the list.
524*0Sstevel@tonic-gate 	 */
525*0Sstevel@tonic-gate 	zblk->zulu_hash_prev = NULL;
526*0Sstevel@tonic-gate 	zblk->zulu_hash_next = ZULU_MAP_HASH_HEAD(zhat,
527*0Sstevel@tonic-gate 			zblk->zulu_hat_blk_vaddr, zblk->zulu_hat_blk_size);
528*0Sstevel@tonic-gate 	if (zblk->zulu_hash_next) {
529*0Sstevel@tonic-gate 		zblk->zulu_hash_next->zulu_hash_prev = zblk;
530*0Sstevel@tonic-gate 	}
531*0Sstevel@tonic-gate 	ZULU_MAP_HASH_HEAD(zhat, zblk->zulu_hat_blk_vaddr,
532*0Sstevel@tonic-gate 				zblk->zulu_hat_blk_size) = zblk;
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 	zulu_ctx_tsb_lock_enter(zhat);
535*0Sstevel@tonic-gate 	zhat->zulu_tsb[tsb_hash] = zblk->zulu_hat_blk_tte;
536*0Sstevel@tonic-gate 	zulu_ctx_tsb_lock_exit(zhat);
537*0Sstevel@tonic-gate }
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate /*
540*0Sstevel@tonic-gate  * remove a block from a zhat
541*0Sstevel@tonic-gate  */
542*0Sstevel@tonic-gate static void
zulu_hat_remove_map(struct zulu_hat * zhat,struct zulu_hat_blk * zblk)543*0Sstevel@tonic-gate zulu_hat_remove_map(struct zulu_hat *zhat, struct zulu_hat_blk *zblk)
544*0Sstevel@tonic-gate {
545*0Sstevel@tonic-gate 	int tsb_hash = ZULU_TSB_HASH(zblk->zulu_hat_blk_vaddr,
546*0Sstevel@tonic-gate 			    zblk->zulu_hat_blk_size, zhat->zulu_tsb_size);
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate 	TNF_PROBE_2(zulu_hat_remove_map, "zulu_hat", /* CSTYLED */,
549*0Sstevel@tonic-gate 		tnf_opaque, vaddr, zblk->zulu_hat_blk_vaddr,
550*0Sstevel@tonic-gate 		tnf_opaque, hash, tsb_hash);
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate 	ASSERT(tsb_hash < zhat->zulu_tsb_size);
553*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&zhat->lock));
554*0Sstevel@tonic-gate 
555*0Sstevel@tonic-gate 	zulu_shadow_tree_delete(zhat, zblk);
556*0Sstevel@tonic-gate 
557*0Sstevel@tonic-gate 	/*
558*0Sstevel@tonic-gate 	 * first remove zblk from hash table
559*0Sstevel@tonic-gate 	 */
560*0Sstevel@tonic-gate 	if (zblk->zulu_hash_prev) {
561*0Sstevel@tonic-gate 		zblk->zulu_hash_prev->zulu_hash_next = zblk->zulu_hash_next;
562*0Sstevel@tonic-gate 	} else {
563*0Sstevel@tonic-gate 		ZULU_MAP_HASH_HEAD(zhat, zblk->zulu_hat_blk_vaddr,
564*0Sstevel@tonic-gate 			zblk->zulu_hat_blk_size) = NULL;
565*0Sstevel@tonic-gate 	}
566*0Sstevel@tonic-gate 	if (zblk->zulu_hash_next) {
567*0Sstevel@tonic-gate 		zblk->zulu_hash_next->zulu_hash_prev = zblk->zulu_hash_prev;
568*0Sstevel@tonic-gate 	}
569*0Sstevel@tonic-gate 	zblk->zulu_hash_next = NULL;
570*0Sstevel@tonic-gate 	zblk->zulu_hash_prev = NULL;
571*0Sstevel@tonic-gate 
572*0Sstevel@tonic-gate 	/*
573*0Sstevel@tonic-gate 	 * then remove the tsb entry
574*0Sstevel@tonic-gate 	 */
575*0Sstevel@tonic-gate 	zulu_ctx_tsb_lock_enter(zhat);
576*0Sstevel@tonic-gate 	if (zhat->zulu_tsb[tsb_hash].un.zulu_tte_addr ==
577*0Sstevel@tonic-gate 	    zblk->zulu_hat_blk_vaddr) {
578*0Sstevel@tonic-gate 		zhat->zulu_tsb[tsb_hash].zulu_tte_valid = 0;
579*0Sstevel@tonic-gate 	}
580*0Sstevel@tonic-gate 	zulu_ctx_tsb_lock_exit(zhat);
581*0Sstevel@tonic-gate }
582*0Sstevel@tonic-gate 
583*0Sstevel@tonic-gate /*
584*0Sstevel@tonic-gate  * look for a mapping to a given vaddr and page size
585*0Sstevel@tonic-gate  */
586*0Sstevel@tonic-gate static struct zulu_hat_blk *
zulu_lookup_map_bysize(struct zulu_hat * zhat,caddr_t vaddr,int page_sz)587*0Sstevel@tonic-gate zulu_lookup_map_bysize(struct zulu_hat *zhat, caddr_t vaddr, int page_sz)
588*0Sstevel@tonic-gate {
589*0Sstevel@tonic-gate 	struct  	zulu_hat_blk *zblkp;
590*0Sstevel@tonic-gate 	uint64_t	ivaddr = (uint64_t)vaddr;
591*0Sstevel@tonic-gate 	int		blks_checked = 0;
592*0Sstevel@tonic-gate 
593*0Sstevel@tonic-gate 	ASSERT(mutex_owned(&zhat->lock));
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate 	for (zblkp = ZULU_MAP_HASH_HEAD(zhat, ivaddr, page_sz); zblkp != NULL;
596*0Sstevel@tonic-gate 						zblkp = zblkp->zulu_hash_next) {
597*0Sstevel@tonic-gate 		uint64_t	size;
598*0Sstevel@tonic-gate 		uint64_t	iaddr;
599*0Sstevel@tonic-gate 
600*0Sstevel@tonic-gate 		blks_checked++;
601*0Sstevel@tonic-gate 
602*0Sstevel@tonic-gate 		size = ZULU_HAT_PGSZ(zblkp->zulu_hat_blk_size);
603*0Sstevel@tonic-gate 		iaddr = ZULU_VADDR((uint64_t)zblkp->zulu_hat_blk_vaddr);
604*0Sstevel@tonic-gate 
605*0Sstevel@tonic-gate 		if (iaddr <= ivaddr && (iaddr + size) > ivaddr) {
606*0Sstevel@tonic-gate 			int tsb_hash;
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 			tsb_hash = ZULU_TSB_HASH(zblkp->zulu_hat_blk_vaddr,
609*0Sstevel@tonic-gate 				    zblkp->zulu_hat_blk_size,
610*0Sstevel@tonic-gate 				    zhat->zulu_tsb_size);
611*0Sstevel@tonic-gate 			ASSERT(tsb_hash < zhat->zulu_tsb_size);
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate 			zulu_ctx_tsb_lock_enter(zhat);
614*0Sstevel@tonic-gate 			zhat->zulu_tsb[tsb_hash] = zblkp->zulu_hat_blk_tte;
615*0Sstevel@tonic-gate 			zulu_ctx_tsb_lock_exit(zhat);
616*0Sstevel@tonic-gate 			break;
617*0Sstevel@tonic-gate 		}
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 	}
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate 	TNF_PROBE_3(zulu_hat_lookup_map_bysz, "zulu_hat", /* CSTYLED */,
622*0Sstevel@tonic-gate 		tnf_opaque, zblkp, zblkp,
623*0Sstevel@tonic-gate 		tnf_int, blks_checked, blks_checked,
624*0Sstevel@tonic-gate 		tnf_int, page_sz, page_sz);
625*0Sstevel@tonic-gate 
626*0Sstevel@tonic-gate 	return (zblkp);
627*0Sstevel@tonic-gate }
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate /*
630*0Sstevel@tonic-gate  * Lookup a zblk for a given virtual address.
631*0Sstevel@tonic-gate  */
632*0Sstevel@tonic-gate static struct zulu_hat_blk *
zulu_lookup_map(struct zulu_hat * zhat,caddr_t vaddr)633*0Sstevel@tonic-gate zulu_lookup_map(struct zulu_hat *zhat, caddr_t vaddr)
634*0Sstevel@tonic-gate {
635*0Sstevel@tonic-gate 	struct  	zulu_hat_blk *zblkp = NULL;
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate 	/*
638*0Sstevel@tonic-gate 	 * if the hat is using 4M pages, look first for a 4M page
639*0Sstevel@tonic-gate 	 */
640*0Sstevel@tonic-gate 	if (zhat->map4m) {
641*0Sstevel@tonic-gate 		zblkp = zulu_lookup_map_bysize(zhat, vaddr, ZULU_TTE4M);
642*0Sstevel@tonic-gate 		if (zblkp != NULL) {
643*0Sstevel@tonic-gate 			return (zblkp);
644*0Sstevel@tonic-gate 		}
645*0Sstevel@tonic-gate 	}
646*0Sstevel@tonic-gate 	/*
647*0Sstevel@tonic-gate 	 * Otherwise look for a 8k page
648*0Sstevel@tonic-gate 	 * Note: if base pagesize gets increased to 64K remove this test
649*0Sstevel@tonic-gate 	 */
650*0Sstevel@tonic-gate 	if (zhat->map8k) {
651*0Sstevel@tonic-gate 		zblkp = zulu_lookup_map_bysize(zhat, vaddr, ZULU_TTE8K);
652*0Sstevel@tonic-gate 		if (zblkp != NULL) {
653*0Sstevel@tonic-gate 			return (zblkp);
654*0Sstevel@tonic-gate 		}
655*0Sstevel@tonic-gate 	}
656*0Sstevel@tonic-gate 	/*
657*0Sstevel@tonic-gate 	 * only if the page isn't found in the sizes that match the zulu mmus
658*0Sstevel@tonic-gate 	 * look for the inefficient 64K or 512K page sizes
659*0Sstevel@tonic-gate 	 */
660*0Sstevel@tonic-gate 	if (zhat->map64k) {
661*0Sstevel@tonic-gate 		zblkp = zulu_lookup_map_bysize(zhat, vaddr, ZULU_TTE64K);
662*0Sstevel@tonic-gate 		if (zblkp != NULL) {
663*0Sstevel@tonic-gate 			return (zblkp);
664*0Sstevel@tonic-gate 		}
665*0Sstevel@tonic-gate 	}
666*0Sstevel@tonic-gate 	if (zhat->map512k) {
667*0Sstevel@tonic-gate 		zblkp = zulu_lookup_map_bysize(zhat, vaddr, ZULU_TTE512K);
668*0Sstevel@tonic-gate 	}
669*0Sstevel@tonic-gate 
670*0Sstevel@tonic-gate 	return (zblkp);
671*0Sstevel@tonic-gate }
672*0Sstevel@tonic-gate 
673*0Sstevel@tonic-gate /*
674*0Sstevel@tonic-gate  * zulu_hat_load: Load translation for given vaddr
675*0Sstevel@tonic-gate  */
676*0Sstevel@tonic-gate int
zulu_hat_load(struct zulu_hat * zhat,caddr_t vaddr,enum seg_rw rw,int * ppg_size)677*0Sstevel@tonic-gate zulu_hat_load(struct zulu_hat *zhat, caddr_t vaddr,
678*0Sstevel@tonic-gate 		enum seg_rw rw, int *ppg_size)
679*0Sstevel@tonic-gate {
680*0Sstevel@tonic-gate 	faultcode_t 		as_err;
681*0Sstevel@tonic-gate 	struct zulu_hat_blk 	*zblkp;
682*0Sstevel@tonic-gate 	int			rval;
683*0Sstevel@tonic-gate 	uint64_t 		flags_pfn;
684*0Sstevel@tonic-gate 	struct zulu_tte		tte;
685*0Sstevel@tonic-gate 
686*0Sstevel@tonic-gate 	TNF_PROBE_2(zulu_hat_load, "zulu_hat", /* CSTYLED */,
687*0Sstevel@tonic-gate 		tnf_int, zulu_ctx, zhat->zulu_ctx,
688*0Sstevel@tonic-gate 		tnf_opaque, vaddr, vaddr);
689*0Sstevel@tonic-gate 
690*0Sstevel@tonic-gate 	mutex_enter(&zhat->lock);
691*0Sstevel@tonic-gate 	ASSERT(zhat->zulu_ctx >= 0);
692*0Sstevel@tonic-gate 	/*
693*0Sstevel@tonic-gate 	 * lookup in our tsb first
694*0Sstevel@tonic-gate 	 */
695*0Sstevel@tonic-gate 	zulu_ctx_tsb_lock_enter(zhat);
696*0Sstevel@tonic-gate 	flags_pfn = zulu_hat_tsb_lookup_tl0(zhat, vaddr);
697*0Sstevel@tonic-gate 	zulu_ctx_tsb_lock_exit(zhat);
698*0Sstevel@tonic-gate 
699*0Sstevel@tonic-gate 	if (flags_pfn) {
700*0Sstevel@tonic-gate 		uint64_t *p = (uint64_t *)&tte;
701*0Sstevel@tonic-gate 
702*0Sstevel@tonic-gate 		p++; 			/* ignore the tag */
703*0Sstevel@tonic-gate 		*p = flags_pfn;		/* load the flags */
704*0Sstevel@tonic-gate 
705*0Sstevel@tonic-gate 		zuluvm_load_tte(zhat, vaddr, flags_pfn, tte.zulu_tte_perm,
706*0Sstevel@tonic-gate 			tte.zulu_tte_size);
707*0Sstevel@tonic-gate 		if (ppg_size != NULL) {
708*0Sstevel@tonic-gate 			*ppg_size = tte.zulu_tte_size;
709*0Sstevel@tonic-gate 		}
710*0Sstevel@tonic-gate 
711*0Sstevel@tonic-gate 		zulu_tsb_hit++;
712*0Sstevel@tonic-gate 		mutex_exit(&zhat->lock);
713*0Sstevel@tonic-gate 		return (0);
714*0Sstevel@tonic-gate 	}
715*0Sstevel@tonic-gate 
716*0Sstevel@tonic-gate 	zulu_tsb_miss++;
717*0Sstevel@tonic-gate 
718*0Sstevel@tonic-gate 	zblkp = zulu_lookup_map(zhat, vaddr);
719*0Sstevel@tonic-gate 	if (zblkp) {
720*0Sstevel@tonic-gate 		tte = zblkp->zulu_hat_blk_tte;
721*0Sstevel@tonic-gate 		tte.zulu_tte_pfn = ZULU_HAT_ADJ_PFN((&tte), vaddr);
722*0Sstevel@tonic-gate 		zuluvm_load_tte(zhat, vaddr,  tte.zulu_tte_pfn,
723*0Sstevel@tonic-gate 			tte.zulu_tte_perm, tte.zulu_tte_size);
724*0Sstevel@tonic-gate 		if (ppg_size != NULL) {
725*0Sstevel@tonic-gate 			*ppg_size = tte.zulu_tte_size;
726*0Sstevel@tonic-gate 		}
727*0Sstevel@tonic-gate 		mutex_exit(&zhat->lock);
728*0Sstevel@tonic-gate 		return (0);
729*0Sstevel@tonic-gate 	}
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate 	/*
732*0Sstevel@tonic-gate 	 * Set a flag indicating that we're processing a fault.
733*0Sstevel@tonic-gate 	 * See comments in zulu_hat_unload_region.
734*0Sstevel@tonic-gate 	 */
735*0Sstevel@tonic-gate 	zhat->in_fault = 1;
736*0Sstevel@tonic-gate 	mutex_exit(&zhat->lock);
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate 	zulu_as_fault++;
739*0Sstevel@tonic-gate 	TNF_PROBE_0(calling_as_fault, "zulu_hat", /* CSTYLED */);
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate 	as_err = as_fault((struct hat *)zhat, zhat->zulu_xhat.xhat_as,
742*0Sstevel@tonic-gate 			(caddr_t)(ZULU_VADDR((uint64_t)vaddr) & PAGEMASK),
743*0Sstevel@tonic-gate 			PAGESIZE, F_INVAL, rw);
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate 	mutex_enter(&zhat->lock);
746*0Sstevel@tonic-gate 	zhat->in_fault = 0;
747*0Sstevel@tonic-gate 	if (ppg_size != NULL) {
748*0Sstevel@tonic-gate 		/*
749*0Sstevel@tonic-gate 		 * caller wants to know the page size (used by preload)
750*0Sstevel@tonic-gate 		 */
751*0Sstevel@tonic-gate 		zblkp = zulu_lookup_map(zhat, vaddr);
752*0Sstevel@tonic-gate 		if (zblkp != NULL) {
753*0Sstevel@tonic-gate 			*ppg_size = zblkp->zulu_hat_blk_size;
754*0Sstevel@tonic-gate 		} else {
755*0Sstevel@tonic-gate 			*ppg_size = -1;
756*0Sstevel@tonic-gate 		}
757*0Sstevel@tonic-gate 	}
758*0Sstevel@tonic-gate 	mutex_exit(&zhat->lock);
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate 	TNF_PROBE_1(as_fault_returned, "zulu_hat", /* CSTYLED */,
761*0Sstevel@tonic-gate 		tnf_int, as_err, as_err);
762*0Sstevel@tonic-gate 
763*0Sstevel@tonic-gate 	if (as_err != 0) {
764*0Sstevel@tonic-gate 		printf("as_fault returned %d\n", as_err);
765*0Sstevel@tonic-gate 		rval = as_err;
766*0Sstevel@tonic-gate 	} else if (zhat->freed) {
767*0Sstevel@tonic-gate 		rval = -1;
768*0Sstevel@tonic-gate 	} else {
769*0Sstevel@tonic-gate 		rval = 0;
770*0Sstevel@tonic-gate 	}
771*0Sstevel@tonic-gate 
772*0Sstevel@tonic-gate 	return (rval);
773*0Sstevel@tonic-gate }
774*0Sstevel@tonic-gate 
775*0Sstevel@tonic-gate static struct xhat *
zulu_hat_alloc(void * arg)776*0Sstevel@tonic-gate zulu_hat_alloc(void *arg)
777*0Sstevel@tonic-gate {
778*0Sstevel@tonic-gate 	struct zulu_hat *zhat = kmem_zalloc(sizeof (struct zulu_hat), KM_SLEEP);
779*0Sstevel@tonic-gate 
780*0Sstevel@tonic-gate 	(void) arg;
781*0Sstevel@tonic-gate 
782*0Sstevel@tonic-gate 	zulu_hat_ctx_alloc(zhat);
783*0Sstevel@tonic-gate 
784*0Sstevel@tonic-gate 	mutex_init(&zhat->lock, NULL, MUTEX_DEFAULT, NULL);
785*0Sstevel@tonic-gate 
786*0Sstevel@tonic-gate 	zhat->zulu_tsb = kmem_zalloc(ZULU_TSB_SZ, KM_SLEEP);
787*0Sstevel@tonic-gate 	zhat->zulu_tsb_size = ZULU_TSB_NUM;
788*0Sstevel@tonic-gate 	zhat->hash_tbl = kmem_zalloc(ZULU_HASH_TBL_SZ, KM_SLEEP);
789*0Sstevel@tonic-gate 	avl_create(&zhat->shadow_tree, zulu_shadow_tree_compare,
790*0Sstevel@tonic-gate 		sizeof (zhat->shadow_tree), ZULU_SHADOW_BLK_LINK_OFFSET);
791*0Sstevel@tonic-gate 	/*
792*0Sstevel@tonic-gate 	 * The zulu hat has a few opaque data structs embedded in it.
793*0Sstevel@tonic-gate 	 * This tag makes finding the our data easier with a debugger.
794*0Sstevel@tonic-gate 	 */
795*0Sstevel@tonic-gate 	zhat->magic = 0x42;
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate 	zhat->freed = 0;
798*0Sstevel@tonic-gate 	TNF_PROBE_1(zulu_hat_alloc, "zulu_hat", /* CSTYLED */,
799*0Sstevel@tonic-gate 		tnf_int, zulu_ctx, zhat->zulu_ctx);
800*0Sstevel@tonic-gate 	return ((struct xhat *)zhat);
801*0Sstevel@tonic-gate }
802*0Sstevel@tonic-gate 
803*0Sstevel@tonic-gate static void
zulu_hat_free(struct xhat * xhat)804*0Sstevel@tonic-gate zulu_hat_free(struct xhat *xhat)
805*0Sstevel@tonic-gate {
806*0Sstevel@tonic-gate 	struct zulu_hat *zhat = (struct zulu_hat *)xhat;
807*0Sstevel@tonic-gate 
808*0Sstevel@tonic-gate 	TNF_PROBE_1(zulu_hat_free, "zulu_hat", /* CSTYLED */,
809*0Sstevel@tonic-gate 		tnf_int, zulu_ctx, zhat->zulu_ctx);
810*0Sstevel@tonic-gate 
811*0Sstevel@tonic-gate 	zulu_shadow_tree_destroy(zhat);
812*0Sstevel@tonic-gate 	kmem_free(zhat->hash_tbl, ZULU_HASH_TBL_SZ);
813*0Sstevel@tonic-gate 	kmem_free(zhat->zulu_tsb, ZULU_TSB_SZ);
814*0Sstevel@tonic-gate 	mutex_destroy(&zhat->lock);
815*0Sstevel@tonic-gate 	kmem_free(xhat, sizeof (struct zulu_hat));
816*0Sstevel@tonic-gate }
817*0Sstevel@tonic-gate 
818*0Sstevel@tonic-gate static void
zulu_hat_free_start(struct xhat * xhat)819*0Sstevel@tonic-gate zulu_hat_free_start(struct xhat *xhat)
820*0Sstevel@tonic-gate {
821*0Sstevel@tonic-gate 	struct zulu_hat *zhat = (struct zulu_hat *)xhat;
822*0Sstevel@tonic-gate 
823*0Sstevel@tonic-gate 	TNF_PROBE_1(zulu_hat_free_start, "zulu_hat", /* CSTYLED */,
824*0Sstevel@tonic-gate 		tnf_int, zulu_ctx, zhat->zulu_ctx);
825*0Sstevel@tonic-gate 	(void) xhat;
826*0Sstevel@tonic-gate }
827*0Sstevel@tonic-gate 
828*0Sstevel@tonic-gate /*
829*0Sstevel@tonic-gate  * zulu_hat_memload: This is the callback where the vm system gives us our
830*0Sstevel@tonic-gate  * translations
831*0Sstevel@tonic-gate  */
832*0Sstevel@tonic-gate static void
zulu_do_hat_memload(struct xhat * xhat,caddr_t vaddr,struct page * page,uint_t attr,uint_t flags,int use_pszc)833*0Sstevel@tonic-gate zulu_do_hat_memload(struct xhat *xhat, caddr_t vaddr, struct page *page,
834*0Sstevel@tonic-gate     uint_t attr, uint_t flags, int use_pszc)
835*0Sstevel@tonic-gate {
836*0Sstevel@tonic-gate 	void *blk;
837*0Sstevel@tonic-gate 	struct zulu_hat *zhat = (struct zulu_hat *)xhat;
838*0Sstevel@tonic-gate 	struct zulu_hat_blk *zblk;
839*0Sstevel@tonic-gate 	pfn_t pfn;
840*0Sstevel@tonic-gate 
841*0Sstevel@tonic-gate 	TNF_PROBE_4(zulu_hat_memload, "zulu_hat", /* CSTYLED */,
842*0Sstevel@tonic-gate 		tnf_int, zulu_ctx, zhat->zulu_ctx,
843*0Sstevel@tonic-gate 		tnf_opaque, vaddr, vaddr, tnf_opaque, attr, attr,
844*0Sstevel@tonic-gate 		tnf_opaque, flags, flags);
845*0Sstevel@tonic-gate 
846*0Sstevel@tonic-gate 	/*
847*0Sstevel@tonic-gate 	 * keep track of the highest address that this zhat has had
848*0Sstevel@tonic-gate 	 * a mapping for.
849*0Sstevel@tonic-gate 	 * We use this in unload to avoid searching for regions that
850*0Sstevel@tonic-gate 	 * we've never seen.
851*0Sstevel@tonic-gate 	 *
852*0Sstevel@tonic-gate 	 * This is particularly useful avoiding repeated searches for
853*0Sstevel@tonic-gate 	 * for the process's mappings to the zulu hardware. These mappings
854*0Sstevel@tonic-gate 	 * are explicitly unloaded at each graphics context switch..
855*0Sstevel@tonic-gate 	 *
856*0Sstevel@tonic-gate 	 * This takes advantage of the fact that the device addresses
857*0Sstevel@tonic-gate 	 * are always above than the heap where most DMA data is stored.
858*0Sstevel@tonic-gate 	 */
859*0Sstevel@tonic-gate 	if (vaddr > zhat->vaddr_max) {
860*0Sstevel@tonic-gate 		zhat->vaddr_max = vaddr;
861*0Sstevel@tonic-gate 	}
862*0Sstevel@tonic-gate 
863*0Sstevel@tonic-gate 	pfn = xhat_insert_xhatblk(page, xhat, &blk);
864*0Sstevel@tonic-gate 	zblk = (struct zulu_hat_blk *)blk;
865*0Sstevel@tonic-gate 	zblk->zulu_hat_blk_vaddr = (uintptr_t)vaddr;
866*0Sstevel@tonic-gate 	zblk->zulu_hat_blk_pfn = (uint_t)pfn;
867*0Sstevel@tonic-gate 	/*
868*0Sstevel@tonic-gate 	 * The perm bit is actually in the tte which gets copied to the TSB
869*0Sstevel@tonic-gate 	 */
870*0Sstevel@tonic-gate 	zblk->zulu_hat_blk_perm = (attr & PROT_WRITE) ? 1 : 0;
871*0Sstevel@tonic-gate 	zblk->zulu_hat_blk_size = use_pszc ? page->p_szc : 0;
872*0Sstevel@tonic-gate 	zblk->zulu_hat_blk_valid = 1;
873*0Sstevel@tonic-gate 
874*0Sstevel@tonic-gate 	switch (zblk->zulu_hat_blk_size) {
875*0Sstevel@tonic-gate 	case	ZULU_TTE8K:
876*0Sstevel@tonic-gate 		zhat->map8k = 1;
877*0Sstevel@tonic-gate 		break;
878*0Sstevel@tonic-gate 	case	ZULU_TTE64K:
879*0Sstevel@tonic-gate 		zhat->map64k = 1;
880*0Sstevel@tonic-gate 		break;
881*0Sstevel@tonic-gate 	case	ZULU_TTE512K:
882*0Sstevel@tonic-gate 		zhat->map512k = 1;
883*0Sstevel@tonic-gate 		break;
884*0Sstevel@tonic-gate 	case	ZULU_TTE4M:
885*0Sstevel@tonic-gate 		zhat->map4m = 1;
886*0Sstevel@tonic-gate 		break;
887*0Sstevel@tonic-gate 	default:
888*0Sstevel@tonic-gate 		panic("zulu_hat illegal page size\n");
889*0Sstevel@tonic-gate 	}
890*0Sstevel@tonic-gate 
891*0Sstevel@tonic-gate 	mutex_enter(&zhat->lock);
892*0Sstevel@tonic-gate 
893*0Sstevel@tonic-gate 	zulu_hat_insert_map(zhat, zblk);
894*0Sstevel@tonic-gate 	if (!zhat->freed) {
895*0Sstevel@tonic-gate 		zuluvm_load_tte(zhat, vaddr, zblk->zulu_hat_blk_pfn,
896*0Sstevel@tonic-gate 			zblk->zulu_hat_blk_perm, zblk->zulu_hat_blk_size);
897*0Sstevel@tonic-gate 	}
898*0Sstevel@tonic-gate 	zhat->fault_ivaddr_last =
899*0Sstevel@tonic-gate 		ZULU_VADDR((uint64_t)zblk->zulu_hat_blk_vaddr);
900*0Sstevel@tonic-gate 
901*0Sstevel@tonic-gate 	mutex_exit(&zhat->lock);
902*0Sstevel@tonic-gate }
903*0Sstevel@tonic-gate 
904*0Sstevel@tonic-gate static void
zulu_hat_memload(struct xhat * xhat,caddr_t vaddr,struct page * page,uint_t attr,uint_t flags)905*0Sstevel@tonic-gate zulu_hat_memload(struct xhat *xhat, caddr_t vaddr, struct page *page,
906*0Sstevel@tonic-gate     uint_t attr, uint_t flags)
907*0Sstevel@tonic-gate {
908*0Sstevel@tonic-gate 	zulu_do_hat_memload(xhat, vaddr, page, attr, flags, 0);
909*0Sstevel@tonic-gate }
910*0Sstevel@tonic-gate 
911*0Sstevel@tonic-gate static void
zulu_hat_devload(struct xhat * xhat,caddr_t vaddr,size_t size,pfn_t pfn,uint_t attr,int flags)912*0Sstevel@tonic-gate zulu_hat_devload(struct xhat *xhat, caddr_t vaddr, size_t size, pfn_t pfn,
913*0Sstevel@tonic-gate 	uint_t attr, int flags)
914*0Sstevel@tonic-gate {
915*0Sstevel@tonic-gate 	struct page *pp = page_numtopp_nolock(pfn);
916*0Sstevel@tonic-gate 	(void) size;
917*0Sstevel@tonic-gate 	zulu_do_hat_memload(xhat, vaddr, pp, attr, (uint_t)flags, 1);
918*0Sstevel@tonic-gate }
919*0Sstevel@tonic-gate 
920*0Sstevel@tonic-gate static void
zulu_hat_memload_array(struct xhat * xhat,caddr_t addr,size_t len,struct page ** gen_pps,uint_t attr,uint_t flags)921*0Sstevel@tonic-gate zulu_hat_memload_array(struct xhat *xhat, caddr_t addr, size_t len,
922*0Sstevel@tonic-gate     struct page **gen_pps, uint_t attr, uint_t flags)
923*0Sstevel@tonic-gate {
924*0Sstevel@tonic-gate 	struct zulu_hat *zhat = (struct zulu_hat *)xhat;
925*0Sstevel@tonic-gate 
926*0Sstevel@tonic-gate 	TNF_PROBE_3(zulu_hat_memload_array, "zulu_hat", /* CSTYLED */,
927*0Sstevel@tonic-gate 		tnf_int, zulu_ctx, zhat->zulu_ctx,
928*0Sstevel@tonic-gate 		tnf_opaque, addr, addr,
929*0Sstevel@tonic-gate 		tnf_opaque, len, len);
930*0Sstevel@tonic-gate 
931*0Sstevel@tonic-gate 	for (; len > 0; len -= ZULU_HAT_PGSZ((*gen_pps)->p_szc),
932*0Sstevel@tonic-gate 	    gen_pps += ZULU_HAT_NUM_PGS((*gen_pps)->p_szc)) {
933*0Sstevel@tonic-gate 		zulu_do_hat_memload(xhat, addr, *gen_pps, attr, flags, 1);
934*0Sstevel@tonic-gate 
935*0Sstevel@tonic-gate 		addr += ZULU_HAT_PGSZ((*gen_pps)->p_szc);
936*0Sstevel@tonic-gate 	}
937*0Sstevel@tonic-gate }
938*0Sstevel@tonic-gate 
939*0Sstevel@tonic-gate static void
free_zblks(struct zulu_hat_blk * free_list)940*0Sstevel@tonic-gate free_zblks(struct zulu_hat_blk *free_list)
941*0Sstevel@tonic-gate {
942*0Sstevel@tonic-gate 	struct zulu_hat_blk *zblkp;
943*0Sstevel@tonic-gate 	struct zulu_hat_blk *next;
944*0Sstevel@tonic-gate 
945*0Sstevel@tonic-gate 	for (zblkp = free_list; zblkp != NULL; zblkp = next) {
946*0Sstevel@tonic-gate 		next = zblkp->zulu_hash_next;
947*0Sstevel@tonic-gate 		(void) xhat_delete_xhatblk((struct xhat_hme_blk *)zblkp, 0);
948*0Sstevel@tonic-gate 	}
949*0Sstevel@tonic-gate }
950*0Sstevel@tonic-gate 
951*0Sstevel@tonic-gate static void
add_to_free_list(struct zulu_hat_blk ** pfree_list,struct zulu_hat_blk * zblk)952*0Sstevel@tonic-gate add_to_free_list(struct zulu_hat_blk **pfree_list, struct zulu_hat_blk *zblk)
953*0Sstevel@tonic-gate {
954*0Sstevel@tonic-gate 	zblk->zulu_hash_next = *pfree_list;
955*0Sstevel@tonic-gate 	*pfree_list = zblk;
956*0Sstevel@tonic-gate }
957*0Sstevel@tonic-gate 
958*0Sstevel@tonic-gate static void
zulu_hat_unload_region(struct zulu_hat * zhat,uint64_t ivaddr,size_t size,struct zulu_shadow_blk * sblk,struct zulu_hat_blk ** pfree_list)959*0Sstevel@tonic-gate zulu_hat_unload_region(struct zulu_hat *zhat, uint64_t ivaddr, size_t size,
960*0Sstevel@tonic-gate 		struct zulu_shadow_blk *sblk, struct zulu_hat_blk **pfree_list)
961*0Sstevel@tonic-gate {
962*0Sstevel@tonic-gate 	uint64_t	end = ivaddr + size;
963*0Sstevel@tonic-gate 	int		found = 0;
964*0Sstevel@tonic-gate 
965*0Sstevel@tonic-gate 	TNF_PROBE_2(zulu_hat_unload_region, "zulu_hat", /* CSTYLED */,
966*0Sstevel@tonic-gate 		tnf_opaque, vaddr, ivaddr, tnf_opaque, size, size);
967*0Sstevel@tonic-gate 
968*0Sstevel@tonic-gate 	/*
969*0Sstevel@tonic-gate 	 * check address against the low and highwater marks for mappings
970*0Sstevel@tonic-gate 	 * in this sblk
971*0Sstevel@tonic-gate 	 */
972*0Sstevel@tonic-gate 	if (ivaddr < sblk->min_addr) {
973*0Sstevel@tonic-gate 		ivaddr = sblk->min_addr;
974*0Sstevel@tonic-gate 		TNF_PROBE_1(zulu_hat_unload_skip, "zulu_hat", /* CSTYLED */,
975*0Sstevel@tonic-gate 			tnf_opaque, ivaddr, ivaddr);
976*0Sstevel@tonic-gate 	}
977*0Sstevel@tonic-gate 	if (end > sblk->max_addr) {
978*0Sstevel@tonic-gate 		end = sblk->max_addr;
979*0Sstevel@tonic-gate 		TNF_PROBE_1(zulu_hat_unload_reg_skip, "zulu_hat", /* CSTYLED */,
980*0Sstevel@tonic-gate 			tnf_opaque, end, end);
981*0Sstevel@tonic-gate 	}
982*0Sstevel@tonic-gate 	/*
983*0Sstevel@tonic-gate 	 * REMIND: It's not safe to touch the sblk after we enter this loop
984*0Sstevel@tonic-gate 	 * because it may get deleted.
985*0Sstevel@tonic-gate 	 */
986*0Sstevel@tonic-gate 
987*0Sstevel@tonic-gate 	while (ivaddr < end) {
988*0Sstevel@tonic-gate 		uint64_t iaddr;
989*0Sstevel@tonic-gate 		size_t  pg_sz;
990*0Sstevel@tonic-gate 		struct zulu_hat_blk *zblkp;
991*0Sstevel@tonic-gate 
992*0Sstevel@tonic-gate 		zblkp = zulu_lookup_map(zhat, (caddr_t)ivaddr);
993*0Sstevel@tonic-gate 		if (zblkp == NULL) {
994*0Sstevel@tonic-gate 			ivaddr += PAGESIZE;
995*0Sstevel@tonic-gate 			continue;
996*0Sstevel@tonic-gate 		}
997*0Sstevel@tonic-gate 
998*0Sstevel@tonic-gate 		iaddr = ZULU_VADDR((uint64_t)zblkp->zulu_hat_blk_vaddr);
999*0Sstevel@tonic-gate 		pg_sz = ZULU_HAT_PGSZ(zblkp->zulu_hat_blk_size);
1000*0Sstevel@tonic-gate 
1001*0Sstevel@tonic-gate 		found++;
1002*0Sstevel@tonic-gate 
1003*0Sstevel@tonic-gate 		zulu_hat_remove_map(zhat, zblkp);
1004*0Sstevel@tonic-gate 		/*
1005*0Sstevel@tonic-gate 		 * skip demap page if as_free has already been entered
1006*0Sstevel@tonic-gate 		 * zuluvm demapped the context already
1007*0Sstevel@tonic-gate 		 */
1008*0Sstevel@tonic-gate 		if (!zhat->freed) {
1009*0Sstevel@tonic-gate 			if ((zhat->in_fault) &&
1010*0Sstevel@tonic-gate 			    (iaddr == zhat->fault_ivaddr_last)) {
1011*0Sstevel@tonic-gate 				/*
1012*0Sstevel@tonic-gate 				 * We're being called from within as_fault to
1013*0Sstevel@tonic-gate 				 * unload the last translation we loaded.
1014*0Sstevel@tonic-gate 				 *
1015*0Sstevel@tonic-gate 				 * This is probably due to watchpoint handling.
1016*0Sstevel@tonic-gate 				 * Delay the demap for a millisecond
1017*0Sstevel@tonic-gate 				 * to allow zulu to make some progress.
1018*0Sstevel@tonic-gate 				 */
1019*0Sstevel@tonic-gate 				drv_usecwait(1000);
1020*0Sstevel@tonic-gate 				zhat->fault_ivaddr_last = 0;
1021*0Sstevel@tonic-gate 			}
1022*0Sstevel@tonic-gate 			zulu_hat_demap_page(zhat, (caddr_t)iaddr,
1023*0Sstevel@tonic-gate 					zblkp->zulu_hat_blk_size);
1024*0Sstevel@tonic-gate 		}
1025*0Sstevel@tonic-gate 
1026*0Sstevel@tonic-gate 		add_to_free_list(pfree_list, zblkp);
1027*0Sstevel@tonic-gate 
1028*0Sstevel@tonic-gate 		if ((iaddr + pg_sz) >= end) {
1029*0Sstevel@tonic-gate 			break;
1030*0Sstevel@tonic-gate 		}
1031*0Sstevel@tonic-gate 
1032*0Sstevel@tonic-gate 		ivaddr += pg_sz;
1033*0Sstevel@tonic-gate 	}
1034*0Sstevel@tonic-gate 	TNF_PROBE_1(zulu_hat_unload_region_done, "zulu_hat", /* CSTYLED */,
1035*0Sstevel@tonic-gate 		tnf_opaque, found, found);
1036*0Sstevel@tonic-gate }
1037*0Sstevel@tonic-gate 
1038*0Sstevel@tonic-gate static void
zulu_hat_unload(struct xhat * xhat,caddr_t vaddr,size_t size,uint_t flags)1039*0Sstevel@tonic-gate zulu_hat_unload(struct xhat *xhat, caddr_t vaddr, size_t size, uint_t flags)
1040*0Sstevel@tonic-gate {
1041*0Sstevel@tonic-gate 	struct zulu_hat *zhat = (struct zulu_hat *)xhat;
1042*0Sstevel@tonic-gate 	uint64_t	ivaddr;
1043*0Sstevel@tonic-gate 	uint64_t	end;
1044*0Sstevel@tonic-gate 	int		found = 0;
1045*0Sstevel@tonic-gate 	struct zulu_hat_blk *free_list = NULL;
1046*0Sstevel@tonic-gate 
1047*0Sstevel@tonic-gate 	(void) flags;
1048*0Sstevel@tonic-gate 
1049*0Sstevel@tonic-gate 	TNF_PROBE_4(zulu_hat_unload, "zulu_hat", /* CSTYLED */,
1050*0Sstevel@tonic-gate 		tnf_int, zulu_ctx, zhat->zulu_ctx,
1051*0Sstevel@tonic-gate 		tnf_opaque, vaddr, vaddr,
1052*0Sstevel@tonic-gate 		tnf_opaque, vaddr_max, zhat->vaddr_max,
1053*0Sstevel@tonic-gate 		tnf_opaque, size, size);
1054*0Sstevel@tonic-gate 
1055*0Sstevel@tonic-gate 	mutex_enter(&zhat->lock);
1056*0Sstevel@tonic-gate 
1057*0Sstevel@tonic-gate 	/*
1058*0Sstevel@tonic-gate 	 * The following test prevents us from searching for the user's
1059*0Sstevel@tonic-gate 	 * mappings to the zulu device registers. Those mappings get unloaded
1060*0Sstevel@tonic-gate 	 * every time a graphics context switch away from a given context
1061*0Sstevel@tonic-gate 	 * occurs.
1062*0Sstevel@tonic-gate 	 *
1063*0Sstevel@tonic-gate 	 * Since the heap is located at smaller virtual addresses than the
1064*0Sstevel@tonic-gate 	 * registers, this simple test avoids quite a bit of useless work.
1065*0Sstevel@tonic-gate 	 */
1066*0Sstevel@tonic-gate 	if (vaddr > zhat->vaddr_max) {
1067*0Sstevel@tonic-gate 		/*
1068*0Sstevel@tonic-gate 		 * all existing mappings have lower addresses than vaddr
1069*0Sstevel@tonic-gate 		 * no need to search further.
1070*0Sstevel@tonic-gate 		 */
1071*0Sstevel@tonic-gate 		mutex_exit(&zhat->lock);
1072*0Sstevel@tonic-gate 		return;
1073*0Sstevel@tonic-gate 	}
1074*0Sstevel@tonic-gate 
1075*0Sstevel@tonic-gate 	ivaddr = (uint64_t)vaddr;
1076*0Sstevel@tonic-gate 	end = ivaddr + size;
1077*0Sstevel@tonic-gate 
1078*0Sstevel@tonic-gate 	do {
1079*0Sstevel@tonic-gate 		struct zulu_shadow_blk *sblk;
1080*0Sstevel@tonic-gate 
1081*0Sstevel@tonic-gate 		sblk = zulu_shadow_tree_lookup(zhat, ivaddr, NULL);
1082*0Sstevel@tonic-gate 		if (sblk != NULL) {
1083*0Sstevel@tonic-gate 			uint64_t 	sblk_end;
1084*0Sstevel@tonic-gate 			size_t		region_size;
1085*0Sstevel@tonic-gate 
1086*0Sstevel@tonic-gate 			found++;
1087*0Sstevel@tonic-gate 
1088*0Sstevel@tonic-gate 			sblk_end = (ivaddr + ZULU_SHADOW_BLK_RANGE) &
1089*0Sstevel@tonic-gate 					ZULU_SHADOW_BLK_MASK;
1090*0Sstevel@tonic-gate 
1091*0Sstevel@tonic-gate 			if (sblk_end < end) {
1092*0Sstevel@tonic-gate 				region_size = sblk_end - ivaddr;
1093*0Sstevel@tonic-gate 			} else {
1094*0Sstevel@tonic-gate 				region_size = end - ivaddr;
1095*0Sstevel@tonic-gate 			}
1096*0Sstevel@tonic-gate 			zulu_hat_unload_region(zhat, ivaddr, region_size, sblk,
1097*0Sstevel@tonic-gate 				&free_list);
1098*0Sstevel@tonic-gate 
1099*0Sstevel@tonic-gate 		}
1100*0Sstevel@tonic-gate 		ivaddr += ZULU_SHADOW_BLK_RANGE;
1101*0Sstevel@tonic-gate 	} while (ivaddr < end);
1102*0Sstevel@tonic-gate 
1103*0Sstevel@tonic-gate 	mutex_exit(&zhat->lock);
1104*0Sstevel@tonic-gate 
1105*0Sstevel@tonic-gate 	free_zblks(free_list);
1106*0Sstevel@tonic-gate 
1107*0Sstevel@tonic-gate 	TNF_PROBE_1(zulu_hat_unload_done, "zulu_hat", /* CSTYLED */,
1108*0Sstevel@tonic-gate 		tnf_int, found, found);
1109*0Sstevel@tonic-gate }
1110*0Sstevel@tonic-gate 
1111*0Sstevel@tonic-gate static void
zulu_hat_unload_callback(struct xhat * xhat,caddr_t vaddr,size_t size,uint_t flags,hat_callback_t * pcb)1112*0Sstevel@tonic-gate zulu_hat_unload_callback(struct xhat *xhat, caddr_t vaddr, size_t size,
1113*0Sstevel@tonic-gate 	uint_t flags, hat_callback_t *pcb)
1114*0Sstevel@tonic-gate {
1115*0Sstevel@tonic-gate 	(void) size;
1116*0Sstevel@tonic-gate 	(void) pcb;
1117*0Sstevel@tonic-gate 	zulu_hat_unload(xhat, vaddr, size, flags);
1118*0Sstevel@tonic-gate }
1119*0Sstevel@tonic-gate 
1120*0Sstevel@tonic-gate 
1121*0Sstevel@tonic-gate /*
1122*0Sstevel@tonic-gate  * unload one page
1123*0Sstevel@tonic-gate  */
1124*0Sstevel@tonic-gate static int
zulu_hat_pageunload(struct xhat * xhat,struct page * pp,uint_t flags,void * xblk)1125*0Sstevel@tonic-gate zulu_hat_pageunload(struct xhat *xhat, struct page *pp, uint_t flags,
1126*0Sstevel@tonic-gate     void *xblk)
1127*0Sstevel@tonic-gate {
1128*0Sstevel@tonic-gate 	struct zulu_hat_blk *zblk = (struct zulu_hat_blk *)xblk;
1129*0Sstevel@tonic-gate 	struct zulu_hat *zhat = (struct zulu_hat *)xhat;
1130*0Sstevel@tonic-gate 	int	do_delete;
1131*0Sstevel@tonic-gate 
1132*0Sstevel@tonic-gate 	(void) pp;
1133*0Sstevel@tonic-gate 	(void) flags;
1134*0Sstevel@tonic-gate 
1135*0Sstevel@tonic-gate 	TNF_PROBE_3(zulu_hat_pageunload, "zulu_hat", /* CSTYLED */,
1136*0Sstevel@tonic-gate 		tnf_int, zulu_ctx, zhat->zulu_ctx,
1137*0Sstevel@tonic-gate 		tnf_opaque, vaddr, zblk->zulu_hat_blk_vaddr,
1138*0Sstevel@tonic-gate 		tnf_int, pg_size, zblk->zulu_hat_blk_size);
1139*0Sstevel@tonic-gate 
1140*0Sstevel@tonic-gate 	mutex_enter(&zhat->lock);
1141*0Sstevel@tonic-gate 	if (zblk->zulu_shadow_blk != NULL) {
1142*0Sstevel@tonic-gate 
1143*0Sstevel@tonic-gate 		do_delete = 1;
1144*0Sstevel@tonic-gate 
1145*0Sstevel@tonic-gate 		zulu_hat_remove_map(zhat, zblk);
1146*0Sstevel@tonic-gate 
1147*0Sstevel@tonic-gate 		/*
1148*0Sstevel@tonic-gate 		 * now that the entry is removed from the TSB, remove the
1149*0Sstevel@tonic-gate 		 * translation from the zulu hardware.
1150*0Sstevel@tonic-gate 		 *
1151*0Sstevel@tonic-gate 		 * Skip the demap if this as is in the process of being freed.
1152*0Sstevel@tonic-gate 		 * The zuluvm as callback has demapped the whole context.
1153*0Sstevel@tonic-gate 		 */
1154*0Sstevel@tonic-gate 		if (!zhat->freed) {
1155*0Sstevel@tonic-gate 			zulu_hat_demap_page(zhat,
1156*0Sstevel@tonic-gate 			(caddr_t)(zblk->zulu_hat_blk_page << ZULU_HAT_BP_SHIFT),
1157*0Sstevel@tonic-gate 			zblk->zulu_hat_blk_size);
1158*0Sstevel@tonic-gate 		}
1159*0Sstevel@tonic-gate 	} else {
1160*0Sstevel@tonic-gate 		/*
1161*0Sstevel@tonic-gate 		 * This block has already been removed from the zulu_hat,
1162*0Sstevel@tonic-gate 		 * it's on a free list waiting for our thread to release
1163*0Sstevel@tonic-gate 		 * a mutex so it can be freed
1164*0Sstevel@tonic-gate 		 */
1165*0Sstevel@tonic-gate 		do_delete = 0;
1166*0Sstevel@tonic-gate 
1167*0Sstevel@tonic-gate 		TNF_PROBE_0(zulu_hat_pageunload_skip, "zulu_hat",
1168*0Sstevel@tonic-gate 			    /* CSTYLED */);
1169*0Sstevel@tonic-gate 	}
1170*0Sstevel@tonic-gate 	mutex_exit(&zhat->lock);
1171*0Sstevel@tonic-gate 
1172*0Sstevel@tonic-gate 	if (do_delete) {
1173*0Sstevel@tonic-gate 		(void) xhat_delete_xhatblk(xblk, 1);
1174*0Sstevel@tonic-gate 	}
1175*0Sstevel@tonic-gate 
1176*0Sstevel@tonic-gate 	return (0);
1177*0Sstevel@tonic-gate }
1178*0Sstevel@tonic-gate 
1179*0Sstevel@tonic-gate static void
zulu_hat_swapout(struct xhat * xhat)1180*0Sstevel@tonic-gate zulu_hat_swapout(struct xhat *xhat)
1181*0Sstevel@tonic-gate {
1182*0Sstevel@tonic-gate 	struct zulu_hat *zhat = (struct zulu_hat *)xhat;
1183*0Sstevel@tonic-gate 	struct zulu_hat_blk *zblk;
1184*0Sstevel@tonic-gate 	struct zulu_hat_blk *free_list = NULL;
1185*0Sstevel@tonic-gate 	int	i;
1186*0Sstevel@tonic-gate 	int	nblks = 0;
1187*0Sstevel@tonic-gate 
1188*0Sstevel@tonic-gate 	TNF_PROBE_1(zulu_hat_swapout, "zulu_hat", /* CSTYLED */,
1189*0Sstevel@tonic-gate 		tnf_int, zulu_ctx, zhat->zulu_ctx);
1190*0Sstevel@tonic-gate 
1191*0Sstevel@tonic-gate 	mutex_enter(&zhat->lock);
1192*0Sstevel@tonic-gate 
1193*0Sstevel@tonic-gate 	/*
1194*0Sstevel@tonic-gate 	 * real swapout calls are rare so we don't do anything in
1195*0Sstevel@tonic-gate 	 * particular to optimize them.
1196*0Sstevel@tonic-gate 	 *
1197*0Sstevel@tonic-gate 	 * Just loop over all buckets in the hash table and free each
1198*0Sstevel@tonic-gate 	 * zblk.
1199*0Sstevel@tonic-gate 	 */
1200*0Sstevel@tonic-gate 	for (i = 0; i < ZULU_HASH_TBL_NUM; i++) {
1201*0Sstevel@tonic-gate 		struct zulu_hat_blk *next;
1202*0Sstevel@tonic-gate 		for (zblk = zhat->hash_tbl[i]; zblk != NULL; zblk = next) {
1203*0Sstevel@tonic-gate 			next = zblk->zulu_hash_next;
1204*0Sstevel@tonic-gate 			zulu_hat_remove_map(zhat, zblk);
1205*0Sstevel@tonic-gate 			add_to_free_list(&free_list, zblk);
1206*0Sstevel@tonic-gate 			nblks++;
1207*0Sstevel@tonic-gate 		}
1208*0Sstevel@tonic-gate 	}
1209*0Sstevel@tonic-gate 
1210*0Sstevel@tonic-gate 	/*
1211*0Sstevel@tonic-gate 	 * remove all mappings for this context from zulu hardware.
1212*0Sstevel@tonic-gate 	 */
1213*0Sstevel@tonic-gate 	zulu_hat_demap_ctx(zhat->zdev, zhat->zulu_ctx);
1214*0Sstevel@tonic-gate 
1215*0Sstevel@tonic-gate 	mutex_exit(&zhat->lock);
1216*0Sstevel@tonic-gate 
1217*0Sstevel@tonic-gate 	free_zblks(free_list);
1218*0Sstevel@tonic-gate 
1219*0Sstevel@tonic-gate 	TNF_PROBE_1(zulu_hat_swapout_done, "zulu_hat", /* CSTYLED */,
1220*0Sstevel@tonic-gate 		tnf_int, nblks, nblks);
1221*0Sstevel@tonic-gate }
1222*0Sstevel@tonic-gate 
1223*0Sstevel@tonic-gate 
1224*0Sstevel@tonic-gate static void
zulu_hat_unshare(struct xhat * xhat,caddr_t vaddr,size_t size)1225*0Sstevel@tonic-gate zulu_hat_unshare(struct xhat *xhat, caddr_t vaddr, size_t size)
1226*0Sstevel@tonic-gate {
1227*0Sstevel@tonic-gate 	TNF_PROBE_0(zulu_hat_unshare, "zulu_hat", /* CSTYLED */);
1228*0Sstevel@tonic-gate 
1229*0Sstevel@tonic-gate 	zulu_hat_unload(xhat, vaddr, size, 0);
1230*0Sstevel@tonic-gate }
1231*0Sstevel@tonic-gate 
1232*0Sstevel@tonic-gate /*
1233*0Sstevel@tonic-gate  * Functions to manage changes in protections for mappings.
1234*0Sstevel@tonic-gate  *
1235*0Sstevel@tonic-gate  * These are rarely called in normal operation so for now just unload
1236*0Sstevel@tonic-gate  * the region.
1237*0Sstevel@tonic-gate  * If the mapping is still needed, it will fault in later with the new
1238*0Sstevel@tonic-gate  * attrributes.
1239*0Sstevel@tonic-gate  */
1240*0Sstevel@tonic-gate typedef enum {
1241*0Sstevel@tonic-gate 	ZULU_HAT_CHGATTR,
1242*0Sstevel@tonic-gate 	ZULU_HAT_SETATTR,
1243*0Sstevel@tonic-gate 	ZULU_HAT_CLRATTR
1244*0Sstevel@tonic-gate } zulu_hat_prot_op;
1245*0Sstevel@tonic-gate 
1246*0Sstevel@tonic-gate static void
zulu_hat_update_attr(struct xhat * xhat,caddr_t vaddr,size_t size,uint_t flags,zulu_hat_prot_op op)1247*0Sstevel@tonic-gate zulu_hat_update_attr(struct xhat *xhat, caddr_t vaddr, size_t size,
1248*0Sstevel@tonic-gate 	uint_t flags, zulu_hat_prot_op op)
1249*0Sstevel@tonic-gate {
1250*0Sstevel@tonic-gate 	struct zulu_hat *zhat = (struct zulu_hat *)xhat;
1251*0Sstevel@tonic-gate 
1252*0Sstevel@tonic-gate 	TNF_PROBE_5(zulu_hat_changeprot, "zulu_hat", /* CSTYLED */,
1253*0Sstevel@tonic-gate 		tnf_int, ctx, zhat->zulu_ctx,
1254*0Sstevel@tonic-gate 		tnf_opaque, vaddr, vaddr, tnf_opaque, size, size,
1255*0Sstevel@tonic-gate 		tnf_uint, flags, flags, tnf_int, op, op);
1256*0Sstevel@tonic-gate 
1257*0Sstevel@tonic-gate 	zulu_hat_unload(xhat, vaddr, size, 0);
1258*0Sstevel@tonic-gate }
1259*0Sstevel@tonic-gate 
1260*0Sstevel@tonic-gate static void
zulu_hat_chgprot(struct xhat * xhat,caddr_t vaddr,size_t size,uint_t flags)1261*0Sstevel@tonic-gate zulu_hat_chgprot(struct xhat *xhat, caddr_t vaddr, size_t size, uint_t flags)
1262*0Sstevel@tonic-gate {
1263*0Sstevel@tonic-gate 	struct zulu_hat *zhat = (struct zulu_hat *)xhat;
1264*0Sstevel@tonic-gate #ifdef DEBUG
1265*0Sstevel@tonic-gate 	printf("zulu_hat_chgprot: ctx: %d addr: %lx, size: %lx flags: %x\n",
1266*0Sstevel@tonic-gate 		zhat->zulu_ctx, (uint64_t)vaddr, size, flags);
1267*0Sstevel@tonic-gate #endif
1268*0Sstevel@tonic-gate 	zulu_hat_update_attr(xhat, vaddr, size, flags, ZULU_HAT_CHGATTR);
1269*0Sstevel@tonic-gate }
1270*0Sstevel@tonic-gate 
1271*0Sstevel@tonic-gate 
1272*0Sstevel@tonic-gate static void
zulu_hat_setattr(struct xhat * xhat,caddr_t vaddr,size_t size,uint_t flags)1273*0Sstevel@tonic-gate zulu_hat_setattr(struct xhat *xhat, caddr_t vaddr, size_t size, uint_t flags)
1274*0Sstevel@tonic-gate {
1275*0Sstevel@tonic-gate 	struct zulu_hat *zhat = (struct zulu_hat *)xhat;
1276*0Sstevel@tonic-gate #ifdef DEBUG
1277*0Sstevel@tonic-gate 	printf("zulu_hat_setattr: ctx: %d addr: %lx, size: %lx flags: %x\n",
1278*0Sstevel@tonic-gate 		zhat->zulu_ctx, (uint64_t)vaddr, size, flags);
1279*0Sstevel@tonic-gate #endif
1280*0Sstevel@tonic-gate 	zulu_hat_update_attr(xhat, vaddr, size, flags, ZULU_HAT_SETATTR);
1281*0Sstevel@tonic-gate }
1282*0Sstevel@tonic-gate 
1283*0Sstevel@tonic-gate static void
zulu_hat_clrattr(struct xhat * xhat,caddr_t vaddr,size_t size,uint_t flags)1284*0Sstevel@tonic-gate zulu_hat_clrattr(struct xhat *xhat, caddr_t vaddr, size_t size, uint_t flags)
1285*0Sstevel@tonic-gate {
1286*0Sstevel@tonic-gate 	struct zulu_hat *zhat = (struct zulu_hat *)xhat;
1287*0Sstevel@tonic-gate #ifdef DEBUG
1288*0Sstevel@tonic-gate 	printf("zulu_hat_clrattr: ctx: %d addr: %lx, size: %lx flags: %x\n",
1289*0Sstevel@tonic-gate 		zhat->zulu_ctx, (uint64_t)vaddr, size, flags);
1290*0Sstevel@tonic-gate #endif
1291*0Sstevel@tonic-gate 	zulu_hat_update_attr(xhat, vaddr, size, flags, ZULU_HAT_CLRATTR);
1292*0Sstevel@tonic-gate }
1293*0Sstevel@tonic-gate 
1294*0Sstevel@tonic-gate static void
zulu_hat_chgattr(struct xhat * xhat,caddr_t vaddr,size_t size,uint_t flags)1295*0Sstevel@tonic-gate zulu_hat_chgattr(struct xhat *xhat, caddr_t vaddr, size_t size, uint_t flags)
1296*0Sstevel@tonic-gate {
1297*0Sstevel@tonic-gate 	struct zulu_hat *zhat = (struct zulu_hat *)xhat;
1298*0Sstevel@tonic-gate 	TNF_PROBE_3(zulu_hat_chgattr, "zulu_hat", /* CSTYLED */,
1299*0Sstevel@tonic-gate 		tnf_int, ctx, zhat->zulu_ctx,
1300*0Sstevel@tonic-gate 		tnf_opaque, vaddr, vaddr,
1301*0Sstevel@tonic-gate 		tnf_opaque, flags, flags);
1302*0Sstevel@tonic-gate #ifdef DEBUG
1303*0Sstevel@tonic-gate 	printf("zulu_hat_chgattr: ctx: %d addr: %lx, size: %lx flags: %x\n",
1304*0Sstevel@tonic-gate 		zhat->zulu_ctx, (uint64_t)vaddr, size, flags);
1305*0Sstevel@tonic-gate #endif
1306*0Sstevel@tonic-gate 	zulu_hat_update_attr(xhat, vaddr, size, flags, ZULU_HAT_CHGATTR);
1307*0Sstevel@tonic-gate }
1308*0Sstevel@tonic-gate 
1309*0Sstevel@tonic-gate 
1310*0Sstevel@tonic-gate struct xhat_ops zulu_hat_ops = {
1311*0Sstevel@tonic-gate 	zulu_hat_alloc,		/* xhat_alloc */
1312*0Sstevel@tonic-gate 	zulu_hat_free,		/* xhat_free */
1313*0Sstevel@tonic-gate 	zulu_hat_free_start,	/* xhat_free_start */
1314*0Sstevel@tonic-gate 	NULL,			/* xhat_free_end */
1315*0Sstevel@tonic-gate 	NULL,			/* xhat_dup */
1316*0Sstevel@tonic-gate 	NULL,			/* xhat_swapin */
1317*0Sstevel@tonic-gate 	zulu_hat_swapout,	/* xhat_swapout */
1318*0Sstevel@tonic-gate 	zulu_hat_memload,	/* xhat_memload */
1319*0Sstevel@tonic-gate 	zulu_hat_memload_array,	/* xhat_memload_array */
1320*0Sstevel@tonic-gate 	zulu_hat_devload,	/* xhat_devload */
1321*0Sstevel@tonic-gate 	zulu_hat_unload,	/* xhat_unload */
1322*0Sstevel@tonic-gate 	zulu_hat_unload_callback, /* xhat_unload_callback */
1323*0Sstevel@tonic-gate 	zulu_hat_setattr,	/* xhat_setattr */
1324*0Sstevel@tonic-gate 	zulu_hat_clrattr,	/* xhat_clrattr */
1325*0Sstevel@tonic-gate 	zulu_hat_chgattr,	/* xhat_chgattr */
1326*0Sstevel@tonic-gate 	zulu_hat_unshare,	/* xhat_unshare */
1327*0Sstevel@tonic-gate 	zulu_hat_chgprot,	/* xhat_chgprot */
1328*0Sstevel@tonic-gate 	zulu_hat_pageunload,	/* xhat_pageunload */
1329*0Sstevel@tonic-gate };
1330*0Sstevel@tonic-gate 
1331*0Sstevel@tonic-gate xblk_cache_t zulu_xblk_cache = {
1332*0Sstevel@tonic-gate     NULL,
1333*0Sstevel@tonic-gate     NULL,
1334*0Sstevel@tonic-gate     NULL,
1335*0Sstevel@tonic-gate     xhat_xblkcache_reclaim
1336*0Sstevel@tonic-gate };
1337*0Sstevel@tonic-gate 
1338*0Sstevel@tonic-gate xhat_provider_t zulu_hat_provider = {
1339*0Sstevel@tonic-gate 	XHAT_PROVIDER_VERSION,
1340*0Sstevel@tonic-gate 	0,
1341*0Sstevel@tonic-gate 	NULL,
1342*0Sstevel@tonic-gate 	NULL,
1343*0Sstevel@tonic-gate 	"zulu_hat_provider",
1344*0Sstevel@tonic-gate 	&zulu_xblk_cache,
1345*0Sstevel@tonic-gate 	&zulu_hat_ops,
1346*0Sstevel@tonic-gate 	sizeof (struct zulu_hat_blk) + sizeof (struct xhat_hme_blk)
1347*0Sstevel@tonic-gate };
1348*0Sstevel@tonic-gate 
1349*0Sstevel@tonic-gate /*
1350*0Sstevel@tonic-gate  * The following functions are the entry points that zuluvm uses.
1351*0Sstevel@tonic-gate  */
1352*0Sstevel@tonic-gate 
1353*0Sstevel@tonic-gate /*
1354*0Sstevel@tonic-gate  * initialize this module. Called from zuluvm's _init function
1355*0Sstevel@tonic-gate  */
1356*0Sstevel@tonic-gate int
zulu_hat_init()1357*0Sstevel@tonic-gate zulu_hat_init()
1358*0Sstevel@tonic-gate {
1359*0Sstevel@tonic-gate 	int 	c;
1360*0Sstevel@tonic-gate 	int	rval;
1361*0Sstevel@tonic-gate 	mutex_init(&zulu_ctx_lock, NULL, MUTEX_DEFAULT, NULL);
1362*0Sstevel@tonic-gate 
1363*0Sstevel@tonic-gate 	for (c = 0; c < ZULU_HAT_MAX_CTX; c++) {
1364*0Sstevel@tonic-gate 		ZULU_CTX_LOCK_INIT(c);
1365*0Sstevel@tonic-gate 	}
1366*0Sstevel@tonic-gate 	zulu_ctx_search_start = 0;
1367*0Sstevel@tonic-gate 	rval = xhat_provider_register(&zulu_hat_provider);
1368*0Sstevel@tonic-gate 	if (rval != 0) {
1369*0Sstevel@tonic-gate 		mutex_destroy(&zulu_ctx_lock);
1370*0Sstevel@tonic-gate 	}
1371*0Sstevel@tonic-gate 	return (rval);
1372*0Sstevel@tonic-gate }
1373*0Sstevel@tonic-gate 
1374*0Sstevel@tonic-gate /*
1375*0Sstevel@tonic-gate  * un-initialize this module. Called from zuluvm's _fini function
1376*0Sstevel@tonic-gate  */
1377*0Sstevel@tonic-gate int
zulu_hat_destroy()1378*0Sstevel@tonic-gate zulu_hat_destroy()
1379*0Sstevel@tonic-gate {
1380*0Sstevel@tonic-gate 	if (xhat_provider_unregister(&zulu_hat_provider) != 0) {
1381*0Sstevel@tonic-gate 		return (-1);
1382*0Sstevel@tonic-gate 	}
1383*0Sstevel@tonic-gate 	mutex_destroy(&zulu_ctx_lock);
1384*0Sstevel@tonic-gate 	return (0);
1385*0Sstevel@tonic-gate }
1386*0Sstevel@tonic-gate 
1387*0Sstevel@tonic-gate int
zulu_hat_attach(void * arg)1388*0Sstevel@tonic-gate zulu_hat_attach(void *arg)
1389*0Sstevel@tonic-gate {
1390*0Sstevel@tonic-gate 	(void) arg;
1391*0Sstevel@tonic-gate 	return (0);
1392*0Sstevel@tonic-gate }
1393*0Sstevel@tonic-gate 
1394*0Sstevel@tonic-gate int
zulu_hat_detach(void * arg)1395*0Sstevel@tonic-gate zulu_hat_detach(void *arg)
1396*0Sstevel@tonic-gate {
1397*0Sstevel@tonic-gate 	(void) arg;
1398*0Sstevel@tonic-gate 	return (0);
1399*0Sstevel@tonic-gate }
1400*0Sstevel@tonic-gate 
1401*0Sstevel@tonic-gate /*
1402*0Sstevel@tonic-gate  * create a zulu hat for this address space.
1403*0Sstevel@tonic-gate  */
1404*0Sstevel@tonic-gate struct zulu_hat *
zulu_hat_proc_attach(struct as * as,void * zdev)1405*0Sstevel@tonic-gate zulu_hat_proc_attach(struct as *as, void *zdev)
1406*0Sstevel@tonic-gate {
1407*0Sstevel@tonic-gate 	struct zulu_hat *zhat;
1408*0Sstevel@tonic-gate 	int		xhat_rval;
1409*0Sstevel@tonic-gate 
1410*0Sstevel@tonic-gate 	xhat_rval = xhat_attach_xhat(&zulu_hat_provider, as,
1411*0Sstevel@tonic-gate 			(struct xhat **)&zhat, NULL);
1412*0Sstevel@tonic-gate 	if ((xhat_rval == 0) && (zhat != NULL)) {
1413*0Sstevel@tonic-gate 		mutex_enter(&zhat->lock);
1414*0Sstevel@tonic-gate 		ZULU_HAT2AS(zhat) = as;
1415*0Sstevel@tonic-gate 		zhat->zdev = zdev;
1416*0Sstevel@tonic-gate 		mutex_exit(&zhat->lock);
1417*0Sstevel@tonic-gate 	}
1418*0Sstevel@tonic-gate 
1419*0Sstevel@tonic-gate 	TNF_PROBE_3(zulu_hat_proc_attach, "zulu_hat", /* CSTYLED */,
1420*0Sstevel@tonic-gate 		tnf_int, xhat_rval, xhat_rval, tnf_opaque, as, as,
1421*0Sstevel@tonic-gate 		tnf_opaque, zhat, zhat);
1422*0Sstevel@tonic-gate 
1423*0Sstevel@tonic-gate 	return (zhat);
1424*0Sstevel@tonic-gate }
1425*0Sstevel@tonic-gate 
1426*0Sstevel@tonic-gate void
zulu_hat_proc_detach(struct zulu_hat * zhat)1427*0Sstevel@tonic-gate zulu_hat_proc_detach(struct zulu_hat *zhat)
1428*0Sstevel@tonic-gate {
1429*0Sstevel@tonic-gate 	struct  as *as = ZULU_HAT2AS(zhat);
1430*0Sstevel@tonic-gate 
1431*0Sstevel@tonic-gate 	zulu_hat_ctx_free(zhat);
1432*0Sstevel@tonic-gate 
1433*0Sstevel@tonic-gate 	(void) xhat_detach_xhat(&zulu_hat_provider, ZULU_HAT2AS(zhat));
1434*0Sstevel@tonic-gate 
1435*0Sstevel@tonic-gate 	TNF_PROBE_1(zulu_hat_proc_detach, "zulu_hat", /* CSTYLED */,
1436*0Sstevel@tonic-gate 			tnf_opaque, as, as);
1437*0Sstevel@tonic-gate }
1438*0Sstevel@tonic-gate 
1439*0Sstevel@tonic-gate /*
1440*0Sstevel@tonic-gate  * zulu_hat_terminate
1441*0Sstevel@tonic-gate  *
1442*0Sstevel@tonic-gate  * Disables any further TLB miss processing for this hat
1443*0Sstevel@tonic-gate  * Called by zuluvm's as_free callback. The primary purpose of this
1444*0Sstevel@tonic-gate  * function is to cause any pending zulu DMA to abort quickly.
1445*0Sstevel@tonic-gate  */
1446*0Sstevel@tonic-gate void
zulu_hat_terminate(struct zulu_hat * zhat)1447*0Sstevel@tonic-gate zulu_hat_terminate(struct zulu_hat *zhat)
1448*0Sstevel@tonic-gate {
1449*0Sstevel@tonic-gate 	int	ctx = zhat->zulu_ctx;
1450*0Sstevel@tonic-gate 
1451*0Sstevel@tonic-gate 	TNF_PROBE_1(zulu_hat_terminate, "zulu_hat", /* CSTYLED */,
1452*0Sstevel@tonic-gate 		tnf_int, ctx, ctx);
1453*0Sstevel@tonic-gate 
1454*0Sstevel@tonic-gate 	mutex_enter(&zhat->lock);
1455*0Sstevel@tonic-gate 
1456*0Sstevel@tonic-gate 	zhat->freed = 1;
1457*0Sstevel@tonic-gate 
1458*0Sstevel@tonic-gate 	zulu_ctx_tsb_lock_enter(zhat);
1459*0Sstevel@tonic-gate 	/*
1460*0Sstevel@tonic-gate 	 * zap the tsb
1461*0Sstevel@tonic-gate 	 */
1462*0Sstevel@tonic-gate 	bzero(zhat->zulu_tsb, ZULU_TSB_SZ);
1463*0Sstevel@tonic-gate 	zulu_ctx_tsb_lock_exit(zhat);
1464*0Sstevel@tonic-gate 
1465*0Sstevel@tonic-gate 	zulu_hat_demap_ctx(zhat->zdev, zhat->zulu_ctx);
1466*0Sstevel@tonic-gate 
1467*0Sstevel@tonic-gate 	mutex_exit(&zhat->lock);
1468*0Sstevel@tonic-gate 
1469*0Sstevel@tonic-gate 	TNF_PROBE_0(zulu_hat_terminate_done, "zulu_hat", /* CSTYLED */);
1470*0Sstevel@tonic-gate }
1471