1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/systm.h>
31 #include <sys/sysmacros.h>
32 #include <sys/archsystm.h>
33 #include <sys/vmsystm.h>
34 #include <sys/machparam.h>
35 #include <sys/machsystm.h>
36 #include <vm/vm_dep.h>
37 #include <vm/hat_sfmmu.h>
38 #include <vm/seg_kmem.h>
39 #include <sys/cmn_err.h>
40 #include <sys/debug.h>
41 #include <sys/cpu_module.h>
42 #include <sys/sysmacros.h>
43 #include <sys/panic.h>
44 
45 /*
46  * Note that 'Cheetah PRM' refers to:
47  *   SPARC V9 JPS1 Implementation Supplement: Sun UltraSPARC-III
48  */
49 
50 /* Will be set !NULL for Cheetah+ and derivatives. */
51 extern uchar_t *ctx_pgsz_array;
52 
53 /*
54  * pan_disable_ism_large_pages and pan_disable_large_pages are the Panther-
55  * specific versions of disable_ism_large_pages and disable_large_pages,
56  * and feed back into those two hat variables at hat initialization time,
57  * for Panther-only systems.
58  *
59  * chpjag_disable_ism_large_pages is the Ch/Jaguar-specific version of
60  * disable_ism_large_pages. Ditto for chjag_disable_large_pages.
61  */
62 static int panther_only = 0;
63 
64 static int pan_disable_ism_large_pages = ((1 << TTE64K) |
65 	(1 << TTE512K) | (1 << TTE256M));
66 static int pan_disable_large_pages = (1 << TTE256M);
67 static int pan_disable_auto_large_pages = (1 << TTE4M) | (1 << TTE256M);
68 
69 static int chjag_disable_ism_large_pages = ((1 << TTE64K) |
70 	(1 << TTE512K) | (1 << TTE32M) | (1 << TTE256M));
71 static int chjag_disable_large_pages = ((1 << TTE32M) | (1 << TTE256M));
72 static int chjag_disable_auto_large_pages = ((1 << TTE32M) | (1 << TTE256M));
73 
74 /*
75  * The function returns the USIII-IV mmu-specific values for the
76  * hat's disable_large_pages and disable_ism_large_pages variables.
77  * Currently the hat's disable_large_pages and disable_ism_large_pages
78  * already contain the generic sparc 4 page size info, and the return
79  * values are or'd with those values.
80  */
81 int
82 mmu_large_pages_disabled(uint_t flag)
83 {
84 	int pages_disable = 0;
85 
86 	if (panther_only) {
87 		if (flag == HAT_LOAD) {
88 			pages_disable = pan_disable_large_pages;
89 		} else if (flag == HAT_LOAD_SHARE) {
90 			pages_disable = pan_disable_ism_large_pages;
91 		} else if (flag == HAT_LOAD_AUTOLPG) {
92 			pages_disable = pan_disable_auto_large_pages;
93 		}
94 	} else {
95 		if (flag == HAT_LOAD) {
96 			pages_disable = chjag_disable_large_pages;
97 		} else if (flag == HAT_LOAD_SHARE) {
98 			pages_disable = chjag_disable_ism_large_pages;
99 		} else if (flag == HAT_LOAD_AUTOLPG) {
100 			pages_disable = chjag_disable_auto_large_pages;
101 		}
102 	}
103 	return (pages_disable);
104 }
105 
106 #if defined(CPU_IMP_DUAL_PAGESIZE)
107 /*
108  * If a platform is running with only Ch+ or Jaguar, and then someone DR's
109  * in a Panther board, the Panther mmu will not like it if one of the already
110  * running threads is context switched to the Panther and tries to program
111  * a 512K or 4M page into the T512_1. So make these platforms pay the price
112  * and follow the Panther DTLB restrictions by default. :)
113  * The mmu_init_mmu_page_sizes code below takes care of heterogeneous
114  * platforms that don't support DR, like daktari.
115  *
116  * The effect of these restrictions is to limit the allowable values in
117  * sfmmu_pgsz[0] and sfmmu_pgsz[1], since these hat variables are used in
118  * mmu_set_ctx_page_sizes to set up the values in the ctx_pgsz_array that
119  * are used at context switch time. The value in sfmmu_pgsz[0] is used in
120  * P_pgsz0 and sfmmu_pgsz[1] is used in P_pgsz1, as per Figure F-1-1
121  * IMMU and DMMU Primary Context Register in the Panther Implementation
122  * Supplement and Table 15-21 DMMU Primary Context Register in the
123  * Cheetah+ Delta PRM.
124  */
125 #ifdef MIXEDCPU_DR_SUPPORTED
126 int panther_dtlb_restrictions = 1;
127 #else
128 int panther_dtlb_restrictions = 0;
129 #endif /* MIXEDCPU_DR_SUPPORTED */
130 
131 /*
132  * init_mmu_page_sizes is set to one after the bootup time initialization
133  * via mmu_init_mmu_page_sizes, to indicate that mmu_page_sizes has a
134  * valid value.
135  */
136 int init_mmu_page_sizes = 0;
137 
138 /*
139  * mmu_init_large_pages is called with the desired ism_pagesize parameter,
140  * for Panther-only systems. It may be called from set_platform_defaults,
141  * if some value other than 32M is desired, for Panther-only systems.
142  * mmu_ism_pagesize is the tunable.  If it has a bad value, then only warn,
143  * since it would be bad form to panic due
144  * to a user typo.
145  *
146  * The function re-initializes the pan_disable_ism_large_pages and
147  * pan_disable_large_pages variables, which are closely related.
148  * Aka, if 32M is the desired [D]ISM page sizes, then 256M cannot be allowed
149  * for non-ISM large page usage, or DTLB conflict will occur. Please see the
150  * Panther PRM for additional DTLB technical info.
151  */
152 void
153 mmu_init_large_pages(size_t ism_pagesize)
154 {
155 	if (ctx_pgsz_array == NULL) {	/* disable_dual_pgsz flag */
156 		pan_disable_ism_large_pages = ((1 << TTE64K) |
157 			(1 << TTE512K) | (1 << TTE32M) | (1 << TTE256M));
158 		pan_disable_large_pages = ((1 << TTE32M) | (1 << TTE256M));
159 		auto_lpg_maxszc = TTE4M;
160 		return;
161 	}
162 
163 	switch (ism_pagesize) {
164 	case MMU_PAGESIZE4M:
165 		pan_disable_ism_large_pages = ((1 << TTE64K) |
166 			(1 << TTE512K) | (1 << TTE32M) | (1 << TTE256M));
167 		pan_disable_large_pages = (1 << TTE256M);
168 		pan_disable_auto_large_pages = (1 << TTE32M) | (1 << TTE256M);
169 		auto_lpg_maxszc = TTE4M;
170 		break;
171 	case MMU_PAGESIZE32M:
172 		pan_disable_ism_large_pages = ((1 << TTE64K) |
173 			(1 << TTE512K) | (1 << TTE256M));
174 		pan_disable_large_pages = (1 << TTE256M);
175 		pan_disable_auto_large_pages = (1 << TTE4M) | (1 << TTE256M);
176 		auto_lpg_maxszc = TTE32M;
177 		break;
178 	case MMU_PAGESIZE256M:
179 		pan_disable_ism_large_pages = ((1 << TTE64K) |
180 			(1 << TTE512K) | (1 << TTE32M));
181 		pan_disable_large_pages = (1 << TTE32M);
182 		pan_disable_auto_large_pages = (1 << TTE4M) | (1 << TTE32M);
183 		auto_lpg_maxszc = TTE256M;
184 		break;
185 	default:
186 		cmn_err(CE_WARN, "Unrecognized mmu_ism_pagesize value 0x%lx",
187 			ism_pagesize);
188 		break;
189 	}
190 }
191 
192 /*
193  * Re-initialize mmu_page_sizes and friends, for Panther mmu support.
194  * Called during very early bootup from check_cpus_set().
195  * Can be called to verify that mmu_page_sizes are set up correctly.
196  * Note that ncpus is not initialized at this point in the bootup sequence.
197  */
198 int
199 mmu_init_mmu_page_sizes(int cinfo)
200 {
201 	int npanther = cinfo;
202 
203 	if (!init_mmu_page_sizes) {
204 		if (npanther == ncpunode) {
205 			mmu_page_sizes = MMU_PAGE_SIZES;
206 			mmu_hashcnt = MAX_HASHCNT;
207 			mmu_ism_pagesize = MMU_PAGESIZE32M;
208 			mmu_exported_pagesize_mask = (1 << TTE8K) |
209 			    (1 << TTE64K) | (1 << TTE512K) | (1 << TTE4M) |
210 			    (1 << TTE32M) | (1 << TTE256M);
211 			panther_dtlb_restrictions = 1;
212 			panther_only = 1;
213 			auto_lpg_maxszc = TTE32M;
214 		} else if (npanther > 0) {
215 			panther_dtlb_restrictions = 1;
216 		}
217 		init_mmu_page_sizes = 1;
218 		return (0);
219 	}
220 	return (1);
221 }
222 
223 
224 /* Cheetah+ and later worst case DTLB parameters */
225 #ifndef	LOCKED_DTLB_ENTRIES
226 #define	LOCKED_DTLB_ENTRIES	5	/* 2 user TSBs, 2 nucleus, + OBP */
227 #endif
228 #define	TOTAL_DTLB_ENTRIES	16
229 #define	AVAIL_32M_ENTRIES	0
230 #define	AVAIL_256M_ENTRIES	0
231 #define	AVAIL_DTLB_ENTRIES	(TOTAL_DTLB_ENTRIES - LOCKED_DTLB_ENTRIES)
232 static uint64_t ttecnt_threshold[MMU_PAGE_SIZES] = {
233 	AVAIL_DTLB_ENTRIES, AVAIL_DTLB_ENTRIES,
234 	AVAIL_DTLB_ENTRIES, AVAIL_DTLB_ENTRIES,
235 	AVAIL_32M_ENTRIES, AVAIL_256M_ENTRIES };
236 
237 /*ARGSUSED*/
238 uint_t
239 mmu_preferred_pgsz(struct hat *hat, caddr_t addr, size_t len)
240 {
241 	sfmmu_t *sfmmup = (sfmmu_t *)hat;
242 	uint_t pgsz0, pgsz1;
243 	uint_t szc, maxszc = mmu_page_sizes - 1;
244 	size_t pgsz;
245 	extern int disable_large_pages;
246 
247 	pgsz0 = (uint_t)sfmmup->sfmmu_pgsz[0];
248 	pgsz1 = (uint_t)sfmmup->sfmmu_pgsz[1];
249 
250 	/*
251 	 * If either of the TLBs are reprogrammed, choose
252 	 * the largest mapping size as the preferred size,
253 	 * if it fits the size and alignment constraints.
254 	 * Else return the largest mapping size that fits,
255 	 * if neither TLB is reprogrammed.
256 	 */
257 	if (pgsz0 > TTE8K || pgsz1 > TTE8K) {
258 		if (pgsz1 > pgsz0) {	/* First try pgsz1 */
259 			pgsz = hw_page_array[pgsz1].hp_size;
260 			if ((len >= pgsz) && IS_P2ALIGNED(addr, pgsz))
261 				return (pgsz1);
262 		}
263 		if (pgsz0 > TTE8K) {	/* Then try pgsz0, if !TTE8K */
264 			pgsz = hw_page_array[pgsz0].hp_size;
265 			if ((len >= pgsz) && IS_P2ALIGNED(addr, pgsz))
266 				return (pgsz0);
267 		}
268 	} else { /* Otherwise pick best fit if neither TLB is reprogrammed. */
269 		for (szc = maxszc; szc > TTE8K; szc--) {
270 			if (disable_large_pages & (1 << szc))
271 				continue;
272 
273 			pgsz = hw_page_array[szc].hp_size;
274 			if ((len >= pgsz) && IS_P2ALIGNED(addr, pgsz))
275 				return (szc);
276 		}
277 	}
278 	return (TTE8K);
279 }
280 
281 /*
282  * The purpose of this code is to indirectly reorganize the sfmmu_pgsz array
283  * in order to handle the Panther mmu DTLB requirements. Panther only supports
284  * the 32M/256M pages in the T512_1 and not in the T16, so the Panther cpu
285  * can only support one of the two largest page sizes at a time (efficiently).
286  * Panther only supports 512K and 4M pages in the T512_0, and 32M/256M pages
287  * in the T512_1.  So check the sfmmu flags and ttecnt before enabling
288  * the T512_1 for 32M or 256M page sizes, and make sure that 512K and 4M
289  * requests go to the T512_0.
290  *
291  * The tmp_pgsz array comes into this routine in sorted order, as it is
292  * sorted from largest to smallest #pages per pagesize in use by the hat code,
293  * and leaves with the Panther mmu DTLB requirements satisfied. Note that
294  * when the array leaves this function it may not contain all of the page
295  * size codes that it had coming into the function.
296  *
297  * Note that for DISM the flag can be set but the ttecnt can be 0, if we
298  * didn't fault any pages in. This allows the t512_1 to be reprogrammed,
299  * because the T16 does not support the two giant page sizes. ouch.
300  */
301 void
302 mmu_fixup_large_pages(struct hat *hat, uint64_t *ttecnt, uint8_t *tmp_pgsz)
303 {
304 	uint_t pgsz0 = tmp_pgsz[0];
305 	uint_t pgsz1 = tmp_pgsz[1];
306 	uint_t spgsz;
307 
308 	/*
309 	 * Don't program 2nd dtlb for kernel and ism hat
310 	 */
311 	ASSERT(hat->sfmmu_ismhat == NULL);
312 	ASSERT(hat != ksfmmup);
313 	ASSERT(ctx_pgsz_array != NULL);
314 
315 	ASSERT((!SFMMU_FLAGS_ISSET(hat, HAT_32M_FLAG)) ||
316 		(!SFMMU_FLAGS_ISSET(hat, HAT_256M_FLAG)));
317 
318 	if ((SFMMU_FLAGS_ISSET(hat, HAT_32M_FLAG)) || (ttecnt[TTE32M] != 0)) {
319 		spgsz = pgsz1;
320 		pgsz1 = TTE32M;
321 		if (pgsz0 == TTE32M)
322 			pgsz0 = spgsz;
323 	} else if ((SFMMU_FLAGS_ISSET(hat, HAT_256M_FLAG)) ||
324 	    (ttecnt[TTE256M] != 0)) {
325 		spgsz = pgsz1;
326 		pgsz1 = TTE256M;
327 		if (pgsz0 == TTE256M)
328 			pgsz0 = spgsz;
329 	} else if ((pgsz1 == TTE512K) || (pgsz1 == TTE4M)) {
330 		if ((pgsz0 != TTE512K) && (pgsz0 != TTE4M)) {
331 			spgsz = pgsz0;
332 			pgsz0 = pgsz1;
333 			pgsz1 = spgsz;
334 		} else {
335 			pgsz1 = page_szc(MMU_PAGESIZE);
336 		}
337 	}
338 	/*
339 	 * This implements PAGESIZE programming of the T8s
340 	 * if large TTE counts don't exceed the thresholds.
341 	 */
342 	if (ttecnt[pgsz0] < ttecnt_threshold[pgsz0])
343 		pgsz0 = page_szc(MMU_PAGESIZE);
344 	if (ttecnt[pgsz1] < ttecnt_threshold[pgsz1])
345 		pgsz1 = page_szc(MMU_PAGESIZE);
346 	tmp_pgsz[0] = pgsz0;
347 	tmp_pgsz[1] = pgsz1;
348 }
349 
350 /*
351  * Function to set up the page size values used to reprogram the DTLBs,
352  * when page sizes used by a process change significantly.
353  */
354 void
355 mmu_setup_page_sizes(struct hat *hat, uint64_t *ttecnt, uint8_t *tmp_pgsz)
356 {
357 	uint_t pgsz0, pgsz1;
358 
359 	/*
360 	 * Don't program 2nd dtlb for kernel and ism hat
361 	 */
362 	ASSERT(hat->sfmmu_ismhat == NULL);
363 	ASSERT(hat != ksfmmup);
364 
365 	if (ctx_pgsz_array == NULL)	/* disable_dual_pgsz flag */
366 		return;
367 
368 	/*
369 	 * hat->sfmmu_pgsz[] is an array whose elements
370 	 * contain a sorted order of page sizes.  Element
371 	 * 0 is the most commonly used page size, followed
372 	 * by element 1, and so on.
373 	 *
374 	 * ttecnt[] is an array of per-page-size page counts
375 	 * mapped into the process.
376 	 *
377 	 * If the HAT's choice for page sizes is unsuitable,
378 	 * we can override it here.  The new values written
379 	 * to the array will be handed back to us later to
380 	 * do the actual programming of the TLB hardware.
381 	 *
382 	 * The policy we use for programming the dual T8s on
383 	 * Cheetah+ and beyond is as follows:
384 	 *
385 	 *   We have two programmable TLBs, so we look at
386 	 *   the two most common page sizes in the array, which
387 	 *   have already been computed for us by the HAT.
388 	 *   If the TTE count of either of a preferred page size
389 	 *   exceeds the number of unlocked T16 entries,
390 	 *   we reprogram one of the T8s to that page size
391 	 *   to avoid thrashing in the T16.  Else we program
392 	 *   that T8 to the base page size.  Note that we do
393 	 *   not force either T8 to be the base page size if a
394 	 *   process is using more than two page sizes.  Policy
395 	 *   decisions about which page sizes are best to use are
396 	 *   left to the upper layers.
397 	 *
398 	 *   Note that for Panther, 4M and 512K pages need to be
399 	 *   programmed into T512_0, and 32M and 256M into T512_1,
400 	 *   so we don't want to go through the MIN/MAX code.
401 	 *   For partial-Panther systems, we still want to make sure
402 	 *   that 4M and 512K page sizes NEVER get into the T512_1.
403 	 *   Since the DTLB flags are not set up on a per-cpu basis,
404 	 *   Panther rules must be applied for mixed Panther/Cheetah+/
405 	 *   Jaguar configurations.
406 	 */
407 	if (panther_dtlb_restrictions) {
408 		if ((tmp_pgsz[1] == TTE512K) || (tmp_pgsz[1] == TTE4M)) {
409 			if ((tmp_pgsz[0] != TTE512K) &&
410 			    (tmp_pgsz[0] != TTE4M)) {
411 				pgsz1 = tmp_pgsz[0];
412 				pgsz0 = tmp_pgsz[1];
413 			} else {
414 				pgsz0 = tmp_pgsz[0];
415 				pgsz1 = page_szc(MMU_PAGESIZE);
416 			}
417 		} else {
418 			pgsz0 = tmp_pgsz[0];
419 			pgsz1 = tmp_pgsz[1];
420 		}
421 	} else {
422 		pgsz0 = MIN(tmp_pgsz[0], tmp_pgsz[1]);
423 		pgsz1 = MAX(tmp_pgsz[0], tmp_pgsz[1]);
424 	}
425 
426 	/*
427 	 * This implements PAGESIZE programming of the T8s
428 	 * if large TTE counts don't exceed the thresholds.
429 	 */
430 	if (ttecnt[pgsz0] < ttecnt_threshold[pgsz0])
431 		pgsz0 = page_szc(MMU_PAGESIZE);
432 	if (ttecnt[pgsz1] < ttecnt_threshold[pgsz1])
433 		pgsz1 = page_szc(MMU_PAGESIZE);
434 	tmp_pgsz[0] = pgsz0;
435 	tmp_pgsz[1] = pgsz1;
436 }
437 
438 /*
439  * The HAT calls this function when an MMU context is allocated so that we
440  * can reprogram the large TLBs appropriately for the new process using
441  * the context.
442  *
443  * The caller must hold the HAT lock.
444  */
445 void
446 mmu_set_ctx_page_sizes(struct hat *hat)
447 {
448 	uint_t pgsz0, pgsz1;
449 	uint_t new_cext;
450 
451 	ASSERT(sfmmu_hat_lock_held(hat));
452 	ASSERT(hat != ksfmmup);
453 
454 	if (ctx_pgsz_array == NULL)	/* disable_dual_pgsz flag */
455 		return;
456 
457 	/*
458 	 * If supported, reprogram the TLBs to a larger pagesize.
459 	 */
460 	pgsz0 = hat->sfmmu_pgsz[0];
461 	pgsz1 = hat->sfmmu_pgsz[1];
462 	ASSERT(pgsz0 < mmu_page_sizes);
463 	ASSERT(pgsz1 < mmu_page_sizes);
464 #ifdef DEBUG
465 	if (panther_dtlb_restrictions) {
466 		ASSERT(pgsz1 != TTE512K);
467 		ASSERT(pgsz1 != TTE4M);
468 	}
469 	if (panther_only) {
470 		ASSERT(pgsz0 != TTE32M);
471 		ASSERT(pgsz0 != TTE256M);
472 	}
473 #endif /* DEBUG */
474 	new_cext = TAGACCEXT_MKSZPAIR(pgsz1, pgsz0);
475 	if (hat->sfmmu_cext != new_cext) {
476 		hat->sfmmu_cext = new_cext;
477 	}
478 	ctx_pgsz_array[hat->sfmmu_cnum] = hat->sfmmu_cext;
479 	/*
480 	 * sfmmu_setctx_sec() will take care of the
481 	 * rest of the chores reprogramming the ctx_pgsz_array
482 	 * page size values into the DTLBs.
483 	 */
484 }
485 
486 /*
487  * This function assumes that there are either four or six supported page
488  * sizes and at most two programmable TLBs, so we need to decide which
489  * page sizes are most important and then adjust the TLB page sizes
490  * accordingly (if supported).
491  *
492  * If these assumptions change, this function will need to be
493  * updated to support whatever the new limits are.
494  */
495 void
496 mmu_check_page_sizes(sfmmu_t *sfmmup, uint64_t *ttecnt)
497 {
498 	uint64_t sortcnt[MMU_PAGE_SIZES];
499 	uint8_t tmp_pgsz[MMU_PAGE_SIZES];
500 	uint8_t i, j, max;
501 	uint16_t oldval, newval;
502 
503 	/*
504 	 * We only consider reprogramming the TLBs if one or more of
505 	 * the two most used page sizes changes and we're using
506 	 * large pages in this process, except for Panther 32M/256M pages,
507 	 * which the Panther T16 does not support.
508 	 */
509 	if (sfmmup->sfmmu_flags & HAT_LGPG_FLAGS) {
510 		/* Sort page sizes. */
511 		for (i = 0; i < mmu_page_sizes; i++) {
512 			sortcnt[i] = ttecnt[i];
513 		}
514 		for (j = 0; j < mmu_page_sizes; j++) {
515 			for (i = mmu_page_sizes - 1, max = 0; i > 0; i--) {
516 				if (sortcnt[i] > sortcnt[max])
517 					max = i;
518 			}
519 			tmp_pgsz[j] = max;
520 			sortcnt[max] = 0;
521 		}
522 
523 		/*
524 		 * Handle Panther page dtlb calcs separately. The check
525 		 * for actual or potential 32M/256M pages must occur
526 		 * every time due to lack of T16 support for them.
527 		 * The sort works fine for Ch+/Jag, but Panther has
528 		 * pagesize restrictions for both DTLBs.
529 		 */
530 		oldval = sfmmup->sfmmu_pgsz[0] << 8 | sfmmup->sfmmu_pgsz[1];
531 
532 		if (panther_only) {
533 			mmu_fixup_large_pages(sfmmup, ttecnt, tmp_pgsz);
534 		} else {
535 			/* Check 2 largest values after the sort. */
536 			mmu_setup_page_sizes(sfmmup, ttecnt, tmp_pgsz);
537 		}
538 		newval = tmp_pgsz[0] << 8 | tmp_pgsz[1];
539 		if (newval != oldval) {
540 			sfmmu_steal_context(sfmmup, tmp_pgsz);
541 		}
542 	}
543 }
544 
545 #endif	/* CPU_IMP_DUAL_PAGESIZE */
546 
547 struct heap_lp_page_size {
548 	int    impl;
549 	uint_t tte;
550 	int    use_dt512;
551 };
552 
553 struct heap_lp_page_size heap_lp_pgsz[] = {
554 
555 	{CHEETAH_IMPL, TTE8K, 0},		/* default */
556 	{CHEETAH_IMPL, TTE64K, 0},
557 	{CHEETAH_IMPL, TTE4M, 0},
558 
559 	{ CHEETAH_PLUS_IMPL, TTE4M,  1 },	/* default */
560 	{ CHEETAH_PLUS_IMPL, TTE4M,  0 },
561 	{ CHEETAH_PLUS_IMPL, TTE64K, 1 },
562 	{ CHEETAH_PLUS_IMPL, TTE64K, 0 },
563 	{ CHEETAH_PLUS_IMPL, TTE8K,  0 },
564 
565 	{ JALAPENO_IMPL, TTE4M,  1 },		/* default */
566 	{ JALAPENO_IMPL, TTE4M,  0 },
567 	{ JALAPENO_IMPL, TTE64K, 1 },
568 	{ JALAPENO_IMPL, TTE64K, 0 },
569 	{ JALAPENO_IMPL, TTE8K,  0 },
570 
571 	{ JAGUAR_IMPL, TTE4M, 1 },		/* default */
572 	{ JAGUAR_IMPL, TTE4M, 0 },
573 	{ JAGUAR_IMPL, TTE64K, 1 },
574 	{ JAGUAR_IMPL, TTE64K, 0 },
575 	{ JAGUAR_IMPL, TTE8K, 0 },
576 
577 	{ SERRANO_IMPL, TTE4M,  1 },		/* default */
578 	{ SERRANO_IMPL, TTE4M,  0 },
579 	{ SERRANO_IMPL, TTE64K, 1 },
580 	{ SERRANO_IMPL, TTE64K, 0 },
581 	{ SERRANO_IMPL, TTE8K,  0 },
582 
583 	{ PANTHER_IMPL, TTE4M, 1 },		/* default */
584 	{ PANTHER_IMPL, TTE4M, 0 },
585 	{ PANTHER_IMPL, TTE64K, 1 },
586 	{ PANTHER_IMPL, TTE64K, 0 },
587 	{ PANTHER_IMPL, TTE8K, 0 }
588 };
589 
590 int	heaplp_use_dt512 = -1;
591 
592 void
593 mmu_init_kernel_pgsz(struct hat *hat)
594 {
595 	uint_t tte = page_szc(segkmem_lpsize);
596 	uchar_t new_cext_primary, new_cext_nucleus;
597 
598 	if (heaplp_use_dt512 == 0 || tte > TTE4M) {
599 		/* do not reprogram dt512 tlb */
600 		tte = TTE8K;
601 	}
602 
603 	new_cext_nucleus = TAGACCEXT_MKSZPAIR(tte, TTE8K);
604 	new_cext_primary = TAGACCEXT_MKSZPAIR(TTE8K, tte);
605 
606 	if (ctx_pgsz_array)
607 		ctx_pgsz_array[KCONTEXT] = new_cext_primary;
608 	hat->sfmmu_cext = new_cext_primary;
609 	kcontextreg = ((uint64_t)new_cext_nucleus << CTXREG_NEXT_SHIFT) |
610 		((uint64_t)new_cext_primary << CTXREG_EXT_SHIFT);
611 	mmu_init_kcontext();
612 }
613 
614 size_t
615 mmu_get_kernel_lpsize(size_t lpsize)
616 {
617 	struct heap_lp_page_size *p_lpgsz, *pend_lpgsz;
618 	int impl = cpunodes[getprocessorid()].implementation;
619 	uint_t tte = TTE8K;
620 
621 	pend_lpgsz = (struct heap_lp_page_size *)
622 	    ((char *)heap_lp_pgsz + sizeof (heap_lp_pgsz));
623 
624 	/* search for a valid segkmem_lpsize */
625 	for (p_lpgsz = heap_lp_pgsz; p_lpgsz < pend_lpgsz; p_lpgsz++) {
626 		if (impl != p_lpgsz->impl)
627 			continue;
628 
629 		if (lpsize == 0) {
630 			/*
631 			 * no setting for segkmem_lpsize in /etc/system
632 			 * use default from the table
633 			 */
634 			tte = p_lpgsz->tte;
635 			heaplp_use_dt512 = p_lpgsz->use_dt512;
636 			break;
637 		}
638 
639 		if (lpsize == TTEBYTES(p_lpgsz->tte) &&
640 		    (heaplp_use_dt512 == -1 ||
641 			heaplp_use_dt512 == p_lpgsz->use_dt512)) {
642 
643 			tte = p_lpgsz->tte;
644 			heaplp_use_dt512 = p_lpgsz->use_dt512;
645 
646 			/* found a match */
647 			break;
648 		}
649 	}
650 
651 	if (p_lpgsz == pend_lpgsz) {
652 		/* nothing found: disable large page kernel heap */
653 		tte = TTE8K;
654 		heaplp_use_dt512 = 0;
655 	}
656 
657 	lpsize = TTEBYTES(tte);
658 
659 	return (lpsize);
660 }
661