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