Home | History | Annotate | Line # | Download | only in powerpc
      1 /*	$NetBSD: pmap_subr.c,v 1.30 2020/07/06 10:31:24 rin Exp $	*/
      2 /*-
      3  * Copyright (c) 2001 The NetBSD Foundation, Inc.
      4  * All rights reserved.
      5  *
      6  * This code is derived from software contributed to The NetBSD Foundation
      7  * by Matt Thomas <matt (at) 3am-software.com> of Allegro Networks, Inc.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     20  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     28  * POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include <sys/cdefs.h>
     32 __KERNEL_RCSID(0, "$NetBSD: pmap_subr.c,v 1.30 2020/07/06 10:31:24 rin Exp $");
     33 
     34 #ifdef _KERNEL_OPT
     35 #include "opt_altivec.h"
     36 #include "opt_multiprocessor.h"
     37 #include "opt_pmap.h"
     38 #include "opt_ppcarch.h"
     39 #endif
     40 
     41 #include <sys/param.h>
     42 #include <sys/proc.h>
     43 #include <sys/sched.h>
     44 #include <sys/device.h>
     45 #include <sys/systm.h>
     46 
     47 #include <uvm/uvm.h>
     48 
     49 #if defined (PPC_OEA) || defined (PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
     50 #include <powerpc/oea/vmparam.h>
     51 #ifdef ALTIVEC
     52 #include <powerpc/altivec.h>
     53 #endif
     54 #endif
     55 #include <powerpc/psl.h>
     56 
     57 #define	MFMSR()		mfmsr()
     58 #define	MTMSR(psl)	__asm volatile("sync; mtmsr %0; isync" :: "r"(psl))
     59 
     60 #ifdef PMAPCOUNTERS
     61 #define	PMAPCOUNT(ev)	((pmap_evcnt_ ## ev).ev_count++)
     62 #define	PMAPCOUNT2(ev)	((ev).ev_count++)
     63 
     64 struct evcnt pmap_evcnt_zeroed_pages =
     65     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap",
     66 	"pages zeroed");
     67 struct evcnt pmap_evcnt_copied_pages =
     68     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap",
     69 	"pages copied");
     70 struct evcnt pmap_evcnt_idlezeroed_pages =
     71     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap",
     72 	"pages idle zeroed");
     73 
     74 EVCNT_ATTACH_STATIC(pmap_evcnt_zeroed_pages);
     75 EVCNT_ATTACH_STATIC(pmap_evcnt_copied_pages);
     76 EVCNT_ATTACH_STATIC(pmap_evcnt_idlezeroed_pages);
     77 
     78 #if defined (PPC_OEA) || defined (PPC_OEA64_BRIDGE)
     79 
     80 struct evcnt pmap_evcnt_mappings =
     81     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
     82 	    "pmap", "pages mapped");
     83 struct evcnt pmap_evcnt_unmappings =
     84     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, &pmap_evcnt_mappings,
     85 	    "pmap", "pages unmapped");
     86 
     87 struct evcnt pmap_evcnt_kernel_mappings =
     88     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
     89 	    "pmap", "kernel pages mapped");
     90 struct evcnt pmap_evcnt_kernel_unmappings =
     91     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, &pmap_evcnt_kernel_mappings,
     92 	    "pmap", "kernel pages unmapped");
     93 
     94 struct evcnt pmap_evcnt_mappings_replaced =
     95     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
     96 	    "pmap", "page mappings replaced");
     97 
     98 struct evcnt pmap_evcnt_exec_mappings =
     99     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, &pmap_evcnt_mappings,
    100 	    "pmap", "exec pages mapped");
    101 struct evcnt pmap_evcnt_exec_cached =
    102     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, &pmap_evcnt_mappings,
    103 	    "pmap", "exec pages cached");
    104 
    105 struct evcnt pmap_evcnt_exec_synced =
    106     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, &pmap_evcnt_exec_mappings,
    107 	    "pmap", "exec pages synced");
    108 struct evcnt pmap_evcnt_exec_synced_clear_modify =
    109     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, &pmap_evcnt_exec_mappings,
    110 	    "pmap", "exec pages synced (CM)");
    111 struct evcnt pmap_evcnt_exec_synced_pvo_remove =
    112     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, &pmap_evcnt_exec_mappings,
    113 	    "pmap", "exec pages synced (PR)");
    114 
    115 struct evcnt pmap_evcnt_exec_uncached_page_protect =
    116     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, &pmap_evcnt_exec_mappings,
    117 	    "pmap", "exec pages uncached (PP)");
    118 struct evcnt pmap_evcnt_exec_uncached_clear_modify =
    119     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, &pmap_evcnt_exec_mappings,
    120 	    "pmap", "exec pages uncached (CM)");
    121 struct evcnt pmap_evcnt_exec_uncached_zero_page =
    122     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, &pmap_evcnt_exec_mappings,
    123 	    "pmap", "exec pages uncached (ZP)");
    124 struct evcnt pmap_evcnt_exec_uncached_copy_page =
    125     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, &pmap_evcnt_exec_mappings,
    126 	    "pmap", "exec pages uncached (CP)");
    127 struct evcnt pmap_evcnt_exec_uncached_pvo_remove =
    128     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, &pmap_evcnt_exec_mappings,
    129 	    "pmap", "exec pages uncached (PR)");
    130 
    131 struct evcnt pmap_evcnt_updates =
    132     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    133 	    "pmap", "updates");
    134 struct evcnt pmap_evcnt_collects =
    135     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    136 	    "pmap", "collects");
    137 struct evcnt pmap_evcnt_copies =
    138     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    139 	    "pmap", "copies");
    140 
    141 struct evcnt pmap_evcnt_ptes_spilled =
    142     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    143 	    "pmap", "ptes spilled from overflow");
    144 struct evcnt pmap_evcnt_ptes_unspilled =
    145     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    146 	    "pmap", "ptes not spilled");
    147 struct evcnt pmap_evcnt_ptes_evicted =
    148     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    149 	    "pmap", "ptes evicted");
    150 
    151 struct evcnt pmap_evcnt_ptes_primary[8] = {
    152     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    153 	    "pmap", "ptes added at primary[0]"),
    154     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    155 	    "pmap", "ptes added at primary[1]"),
    156     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    157 	    "pmap", "ptes added at primary[2]"),
    158     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    159 	    "pmap", "ptes added at primary[3]"),
    160 
    161     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    162 	    "pmap", "ptes added at primary[4]"),
    163     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    164 	    "pmap", "ptes added at primary[5]"),
    165     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    166 	    "pmap", "ptes added at primary[6]"),
    167     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    168 	    "pmap", "ptes added at primary[7]"),
    169 };
    170 struct evcnt pmap_evcnt_ptes_secondary[8] = {
    171     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    172 	    "pmap", "ptes added at secondary[0]"),
    173     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    174 	    "pmap", "ptes added at secondary[1]"),
    175     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    176 	    "pmap", "ptes added at secondary[2]"),
    177     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    178 	    "pmap", "ptes added at secondary[3]"),
    179 
    180     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    181 	    "pmap", "ptes added at secondary[4]"),
    182     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    183 	    "pmap", "ptes added at secondary[5]"),
    184     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    185 	    "pmap", "ptes added at secondary[6]"),
    186     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    187 	    "pmap", "ptes added at secondary[7]"),
    188 };
    189 struct evcnt pmap_evcnt_ptes_removed =
    190     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    191 	    "pmap", "ptes removed");
    192 struct evcnt pmap_evcnt_ptes_changed =
    193     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    194 	    "pmap", "ptes changed");
    195 struct evcnt pmap_evcnt_pvos_reclaimed =
    196     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    197 	    "pmap", "pvos reclaimed");
    198 struct evcnt pmap_evcnt_pvos_failed =
    199     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
    200 	    "pmap", "pvo allocation failures");
    201 
    202 EVCNT_ATTACH_STATIC(pmap_evcnt_mappings);
    203 EVCNT_ATTACH_STATIC(pmap_evcnt_mappings_replaced);
    204 EVCNT_ATTACH_STATIC(pmap_evcnt_unmappings);
    205 
    206 EVCNT_ATTACH_STATIC(pmap_evcnt_kernel_mappings);
    207 EVCNT_ATTACH_STATIC(pmap_evcnt_kernel_unmappings);
    208 
    209 EVCNT_ATTACH_STATIC(pmap_evcnt_exec_mappings);
    210 EVCNT_ATTACH_STATIC(pmap_evcnt_exec_cached);
    211 EVCNT_ATTACH_STATIC(pmap_evcnt_exec_synced);
    212 EVCNT_ATTACH_STATIC(pmap_evcnt_exec_synced_clear_modify);
    213 EVCNT_ATTACH_STATIC(pmap_evcnt_exec_synced_pvo_remove);
    214 
    215 EVCNT_ATTACH_STATIC(pmap_evcnt_exec_uncached_page_protect);
    216 EVCNT_ATTACH_STATIC(pmap_evcnt_exec_uncached_clear_modify);
    217 EVCNT_ATTACH_STATIC(pmap_evcnt_exec_uncached_zero_page);
    218 EVCNT_ATTACH_STATIC(pmap_evcnt_exec_uncached_copy_page);
    219 EVCNT_ATTACH_STATIC(pmap_evcnt_exec_uncached_pvo_remove);
    220 
    221 EVCNT_ATTACH_STATIC(pmap_evcnt_updates);
    222 EVCNT_ATTACH_STATIC(pmap_evcnt_collects);
    223 EVCNT_ATTACH_STATIC(pmap_evcnt_copies);
    224 
    225 EVCNT_ATTACH_STATIC(pmap_evcnt_ptes_spilled);
    226 EVCNT_ATTACH_STATIC(pmap_evcnt_ptes_unspilled);
    227 EVCNT_ATTACH_STATIC(pmap_evcnt_ptes_evicted);
    228 EVCNT_ATTACH_STATIC(pmap_evcnt_ptes_removed);
    229 EVCNT_ATTACH_STATIC(pmap_evcnt_ptes_changed);
    230 
    231 EVCNT_ATTACH_STATIC2(pmap_evcnt_ptes_primary, 0);
    232 EVCNT_ATTACH_STATIC2(pmap_evcnt_ptes_primary, 1);
    233 EVCNT_ATTACH_STATIC2(pmap_evcnt_ptes_primary, 2);
    234 EVCNT_ATTACH_STATIC2(pmap_evcnt_ptes_primary, 3);
    235 EVCNT_ATTACH_STATIC2(pmap_evcnt_ptes_primary, 4);
    236 EVCNT_ATTACH_STATIC2(pmap_evcnt_ptes_primary, 5);
    237 EVCNT_ATTACH_STATIC2(pmap_evcnt_ptes_primary, 6);
    238 EVCNT_ATTACH_STATIC2(pmap_evcnt_ptes_primary, 7);
    239 EVCNT_ATTACH_STATIC2(pmap_evcnt_ptes_secondary, 0);
    240 EVCNT_ATTACH_STATIC2(pmap_evcnt_ptes_secondary, 1);
    241 EVCNT_ATTACH_STATIC2(pmap_evcnt_ptes_secondary, 2);
    242 EVCNT_ATTACH_STATIC2(pmap_evcnt_ptes_secondary, 3);
    243 EVCNT_ATTACH_STATIC2(pmap_evcnt_ptes_secondary, 4);
    244 EVCNT_ATTACH_STATIC2(pmap_evcnt_ptes_secondary, 5);
    245 EVCNT_ATTACH_STATIC2(pmap_evcnt_ptes_secondary, 6);
    246 EVCNT_ATTACH_STATIC2(pmap_evcnt_ptes_secondary, 7);
    247 
    248 EVCNT_ATTACH_STATIC(pmap_evcnt_pvos_reclaimed);
    249 EVCNT_ATTACH_STATIC(pmap_evcnt_pvos_failed);
    250 #endif /* PPC_OEA || PPC_OEA64_BRIDGE */
    251 #else
    252 #define	PMAPCOUNT(ev)	((void) 0)
    253 #define	PMAPCOUNT2(ev)	((void) 0)
    254 #endif /* PMAPCOUNTERS */
    255 
    256 /*
    257  * This file uses a sick & twisted method to deal with the common pmap
    258  * operations of zero'ing, copying, and syncing the page with the
    259  * instruction cache.
    260  *
    261  * When a PowerPC CPU takes an exception (interrupt or trap), that
    262  * exception is handled with the MMU off.  The handler has to explicitly
    263  * renable the MMU before continuing.  The state of the MMU will be restored
    264  * when the exception is returned from.
    265  *
    266  * Therefore if we disable the MMU we know that doesn't affect any exception.
    267  * So it's safe for us to disable the MMU so we can deal with physical
    268  * addresses without having to map any pages via a BAT or into a page table.
    269  *
    270  * It's also safe to do regardless of IPL.
    271  *
    272  * However while relocation is off, we MUST not access the kernel stack in
    273  * any manner since it will probably no longer be mapped.  This mean no
    274  * calls while relocation is off.  The AltiVEC routines need to handle the
    275  * MSR fiddling themselves so they can save things on the stack.
    276  */
    277 
    278 /*
    279  * Fill the given physical page with zeroes.
    280  */
    281 void
    282 pmap_zero_page(paddr_t pa)
    283 {
    284 	size_t linewidth;
    285 	register_t msr = 0; /* XXX: gcc */
    286 
    287 #if defined(PPC_OEA) || defined (PPC_OEA64_BRIDGE)
    288 	{
    289 		/*
    290 		 * If we are zeroing this page, we must clear the EXEC-ness
    291 		 * of this page since the page contents will have changed.
    292 		 */
    293 		struct vm_page *pg = PHYS_TO_VM_PAGE(pa);
    294 		struct vm_page_md * const md = VM_PAGE_TO_MD(pg);
    295 		KDASSERT(pg != NULL);
    296 		KDASSERT(LIST_EMPTY(&md->mdpg_pvoh));
    297 #ifdef PMAPCOUNTERS
    298 		if (md->mdpg_attrs & PTE_EXEC) {
    299 			PMAPCOUNT(exec_uncached_zero_page);
    300 		}
    301 #endif
    302 		md->mdpg_attrs &= ~PTE_EXEC;
    303 	}
    304 #endif
    305 
    306 	PMAPCOUNT(zeroed_pages);
    307 
    308 #ifdef ALTIVEC
    309 	if (pmap_use_altivec) {
    310 		vzeropage(pa);
    311 		return;
    312 	}
    313 #endif
    314 
    315 	/*
    316 	 * Turn off data relocation (DMMU off).
    317 	 */
    318 #if defined (PPC_OEA) || defined (PPC_OEA64_BRIDGE)
    319 	if (pa >= SEGMENT_LENGTH) {
    320 #endif
    321 		msr = MFMSR();
    322 		MTMSR(msr & ~PSL_DR);
    323 #if defined (PPC_OEA) || defined (PPC_OEA64_BRIDGE)
    324 	}
    325 #endif
    326 
    327 	/*
    328 	 * Zero the page.  Since DR is off, the address is assumed to
    329 	 * valid but we know that UVM will never pass a uncacheable page.
    330 	 * Don't use dcbz if we don't know the cache width.
    331 	 */
    332 	if ((linewidth = curcpu()->ci_ci.dcache_line_size) == 0) {
    333 		long *dp = (long *)pa;
    334 		long * const ep = dp + PAGE_SIZE/sizeof(dp[0]);
    335 		do {
    336 			dp[0] = 0; dp[1] = 0; dp[2] = 0; dp[3] = 0;
    337 			dp[4] = 0; dp[5] = 0; dp[6] = 0; dp[7] = 0;
    338 		} while ((dp += 8) < ep);
    339 	} else {
    340 		size_t i = 0;
    341 		do {
    342 			__asm ("dcbz %0,%1" :: "b"(pa), "r"(i)); i += linewidth;
    343 			__asm ("dcbz %0,%1" :: "b"(pa), "r"(i)); i += linewidth;
    344 		} while (i < PAGE_SIZE);
    345 	}
    346 
    347 	/*
    348 	 * Restore data relocation (DMMU on).
    349 	 */
    350 #if defined (PPC_OEA) || defined (PPC_OEA64_BRIDGE)
    351 	if (pa >= SEGMENT_LENGTH)
    352 #endif
    353 		MTMSR(msr);
    354 }
    355 
    356 /*
    357  * Copy the given physical source page to its destination.
    358  */
    359 void
    360 pmap_copy_page(paddr_t src, paddr_t dst)
    361 {
    362 	const register_t *sp;
    363 	register_t *dp;
    364 	register_t msr;
    365 	size_t i;
    366 
    367 #if defined(PPC_OEA) || defined (PPC_OEA64_BRIDGE)
    368 	{
    369 		/*
    370 		 * If we are copying to the destination page, we must clear
    371 		 * the EXEC-ness of this page since the page contents have
    372 		 * changed.
    373 		 */
    374 		struct vm_page *pg = PHYS_TO_VM_PAGE(dst);
    375 		struct vm_page_md * const md = VM_PAGE_TO_MD(pg);
    376 		KDASSERT(pg != NULL);
    377 		KDASSERT(LIST_EMPTY(&md->mdpg_pvoh));
    378 #ifdef PMAPCOUNTERS
    379 		if (md->mdpg_attrs & PTE_EXEC) {
    380 			PMAPCOUNT(exec_uncached_copy_page);
    381 		}
    382 #endif
    383 		md->mdpg_attrs &= ~PTE_EXEC;
    384 	}
    385 #endif
    386 
    387 	PMAPCOUNT(copied_pages);
    388 
    389 #ifdef ALTIVEC
    390 	if (pmap_use_altivec) {
    391 		vcopypage(dst, src);
    392 		return;
    393 	}
    394 #endif
    395 
    396 #if defined (PPC_OEA) || defined (PPC_OEA64_BRIDGE)
    397 	if (src < SEGMENT_LENGTH && dst < SEGMENT_LENGTH) {
    398 		/*
    399 		 * Copy the page (memcpy is optimized, right? :)
    400 		 */
    401 		memcpy((void *) dst, (void *) src, PAGE_SIZE);
    402 		return;
    403 	}
    404 #endif
    405 
    406 	/*
    407 	 * Turn off data relocation (DMMU off).
    408 	 */
    409 	msr = MFMSR();
    410 	MTMSR(msr & ~PSL_DR);
    411 
    412 	/*
    413 	 * Copy the page.  Don't use memcpy as we can't refer to the
    414 	 * kernel stack at this point.
    415 	 */
    416 	sp = (const register_t *) src;
    417 	dp = (register_t *) dst;
    418 	for (i = 0; i < PAGE_SIZE/sizeof(dp[0]); i += 8, dp += 8, sp += 8) {
    419 		dp[0] = sp[0]; dp[1] = sp[1]; dp[2] = sp[2]; dp[3] = sp[3];
    420 		dp[4] = sp[4]; dp[5] = sp[5]; dp[6] = sp[6]; dp[7] = sp[7];
    421 	}
    422 
    423 	/*
    424 	 * Restore data relocation (DMMU on).
    425 	 */
    426 	MTMSR(msr);
    427 }
    428 
    429 void
    430 pmap_syncicache(paddr_t pa, psize_t len)
    431 {
    432 
    433 /*
    434  * XXX
    435  * disabling the MULTIPROCESSOR case because:
    436  * - _syncicache() takes a virtual addresses
    437  * - this causes crashes on G5
    438  */
    439 #ifdef MULTIPROCESSOR__
    440 	__syncicache((void *)pa, len);
    441 #else
    442 	const size_t linewidth = curcpu()->ci_ci.icache_line_size;
    443 	register_t msr;
    444 	size_t i;
    445 
    446 #if defined (PPC_OEA) || defined (PPC_OEA64_BRIDGE)
    447 	if (pa + len <= SEGMENT_LENGTH) {
    448 		__syncicache((void *)pa, len);
    449 		return;
    450 	}
    451 #endif
    452 
    453 	/*
    454 	 * Turn off instruction and data relocation (MMU off).
    455 	 */
    456 	msr = MFMSR();
    457 	MTMSR(msr & ~(PSL_IR|PSL_DR));
    458 
    459 	/*
    460 	 * Make sure to start on a cache boundary.
    461 	 */
    462 	len += pa - (pa & ~linewidth);
    463 	pa &= ~linewidth;
    464 
    465 	/*
    466 	 * Write out the data cache
    467 	 */
    468 	i = 0;
    469 	do {
    470 		__asm ("dcbst %0,%1" :: "b"(pa), "r"(i)); i += linewidth;
    471 	} while (i < len);
    472 
    473 	/*
    474 	 * Wait for it to finish
    475 	 */
    476 	__asm volatile("sync");
    477 
    478 	/*
    479 	 * Now invalidate the instruction cache.
    480 	 */
    481 	i = 0;
    482 	do {
    483 		__asm ("icbi %0,%1" :: "b"(pa), "r"(i)); i += linewidth;
    484 	} while (i < len);
    485 
    486 	/*
    487 	 * Restore relocation (MMU on).  (this will do the required
    488 	 * sync and isync).
    489 	 */
    490 	MTMSR(msr);
    491 #endif	/* !MULTIPROCESSOR */
    492 }
    493 
    494 bool
    495 pmap_pageidlezero(paddr_t pa)
    496 {
    497 	register_t msr;
    498 	register_t *dp = (register_t *) pa;
    499 	struct cpu_info * const ci = curcpu();
    500 	bool rv = true;
    501 	int i;
    502 
    503 #if defined(PPC_OEA) || defined (PPC_OEA64_BRIDGE)
    504 	if (pa < SEGMENT_LENGTH) {
    505 		for (i = 0; i < PAGE_SIZE / sizeof(dp[0]); i++) {
    506 			if (ci->ci_want_resched)
    507 				return false;
    508 			*dp++ = 0;
    509 		}
    510 		PMAPCOUNT(idlezeroed_pages);
    511 		return true;
    512 	}
    513 #endif
    514 
    515 	/*
    516 	 * Turn off instruction and data relocation (MMU off).
    517 	 */
    518 	msr = MFMSR();
    519 	MTMSR(msr & ~(PSL_IR|PSL_DR));
    520 
    521 	/*
    522 	 * Zero the page until a process becomes runnable.
    523 	 */
    524 	for (i = 0; i < PAGE_SIZE / sizeof(dp[0]); i++) {
    525 		if (ci->ci_want_resched) {
    526 			rv = false;
    527 			break;
    528 		}
    529 		*dp++ = 0;
    530 	}
    531 
    532 	/*
    533 	 * Restore relocation (MMU on).
    534 	 */
    535 	MTMSR(msr);
    536 #ifdef PMAPCOUNTERS
    537 	if (rv)
    538 		PMAPCOUNT(idlezeroed_pages);
    539 #endif
    540 	return rv;
    541 }
    542