xref: /onnv-gate/usr/src/uts/common/os/bp_map.c (revision 2236:31cd1215427e)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*2236Scth  * Common Development and Distribution License (the "License").
6*2236Scth  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
221299Scth  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <sys/sysmacros.h>
300Sstevel@tonic-gate #include <sys/systm.h>
310Sstevel@tonic-gate #include <sys/mman.h>
320Sstevel@tonic-gate #include <sys/buf.h>
330Sstevel@tonic-gate #include <sys/vmem.h>
340Sstevel@tonic-gate #include <sys/cmn_err.h>
350Sstevel@tonic-gate #include <sys/debug.h>
360Sstevel@tonic-gate #include <sys/machparam.h>
370Sstevel@tonic-gate #include <vm/page.h>
380Sstevel@tonic-gate #include <vm/seg_kmem.h>
391299Scth #include <vm/seg_kpm.h>
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #ifdef __sparc
420Sstevel@tonic-gate #include <sys/cpu_module.h>
430Sstevel@tonic-gate #define	BP_FLUSH(addr, size)	flush_instr_mem((void *)addr, size);
440Sstevel@tonic-gate #else
450Sstevel@tonic-gate #define	BP_FLUSH(addr, size)
460Sstevel@tonic-gate #endif
470Sstevel@tonic-gate 
480Sstevel@tonic-gate static vmem_t *bp_map_arena;
490Sstevel@tonic-gate static size_t bp_align;
500Sstevel@tonic-gate static uint_t bp_devload_flags = PROT_READ | PROT_WRITE | HAT_NOSYNC;
511299Scth int	bp_max_cache = 1 << 17;		/* 128K default; tunable */
521299Scth int	bp_mapin_kpm_enable = 1;	/* enable default; tunable */
530Sstevel@tonic-gate 
540Sstevel@tonic-gate static void *
550Sstevel@tonic-gate bp_vmem_alloc(vmem_t *vmp, size_t size, int vmflag)
560Sstevel@tonic-gate {
570Sstevel@tonic-gate 	return (vmem_xalloc(vmp, size, bp_align, 0, 0, NULL, NULL, vmflag));
580Sstevel@tonic-gate }
590Sstevel@tonic-gate 
600Sstevel@tonic-gate void
610Sstevel@tonic-gate bp_init(size_t align, uint_t devload_flags)
620Sstevel@tonic-gate {
630Sstevel@tonic-gate 	bp_align = MAX(align, PAGESIZE);
640Sstevel@tonic-gate 	bp_devload_flags |= devload_flags;
650Sstevel@tonic-gate 
660Sstevel@tonic-gate 	if (bp_align <= bp_max_cache)
670Sstevel@tonic-gate 		bp_map_arena = vmem_create("bp_map", NULL, 0, bp_align,
680Sstevel@tonic-gate 		    bp_vmem_alloc, vmem_free, heap_arena,
690Sstevel@tonic-gate 		    MIN(8 * bp_align, bp_max_cache), VM_SLEEP);
700Sstevel@tonic-gate }
710Sstevel@tonic-gate 
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate  * common routine so can be called with/without VM_SLEEP
740Sstevel@tonic-gate  */
750Sstevel@tonic-gate void *
760Sstevel@tonic-gate bp_mapin_common(struct buf *bp, int flag)
770Sstevel@tonic-gate {
781299Scth 	struct as	*as;
791299Scth 	pfn_t		pfnum;
801299Scth 	page_t		*pp;
811299Scth 	page_t		**pplist;
821299Scth 	caddr_t		kaddr;
831299Scth 	caddr_t		addr;
841299Scth 	uintptr_t	off;
851299Scth 	size_t		size;
861299Scth 	pgcnt_t		npages;
871299Scth 	int		color;
880Sstevel@tonic-gate 
890Sstevel@tonic-gate 	/* return if already mapped in, no pageio/physio, or physio to kas */
900Sstevel@tonic-gate 	if ((bp->b_flags & B_REMAPPED) ||
910Sstevel@tonic-gate 	    !(bp->b_flags & (B_PAGEIO | B_PHYS)) ||
920Sstevel@tonic-gate 	    (((bp->b_flags & (B_PAGEIO | B_PHYS)) == B_PHYS) &&
930Sstevel@tonic-gate 	    ((bp->b_proc == NULL) || (bp->b_proc->p_as == &kas))))
940Sstevel@tonic-gate 		return (bp->b_un.b_addr);
950Sstevel@tonic-gate 
960Sstevel@tonic-gate 	ASSERT((bp->b_flags & (B_PAGEIO | B_PHYS)) != (B_PAGEIO | B_PHYS));
970Sstevel@tonic-gate 
981299Scth 	addr = (caddr_t)bp->b_un.b_addr;
991299Scth 	off = (uintptr_t)addr & PAGEOFFSET;
1001299Scth 	size = P2ROUNDUP(bp->b_bcount + off, PAGESIZE);
1011299Scth 	npages = btop(size);
1021299Scth 
1031299Scth 	/* Fastpath single page IO to locked memory by using kpm. */
1041299Scth 	if ((bp->b_flags & (B_SHADOW | B_PAGEIO)) && (npages == 1) &&
1051299Scth 	    kpm_enable && bp_mapin_kpm_enable) {
1061299Scth 		if (bp->b_flags & B_SHADOW)
1071299Scth 			pp = *bp->b_shadow;
1081299Scth 		else
1091299Scth 			pp = bp->b_pages;
1101299Scth 		kaddr = hat_kpm_mapin(pp, NULL);
1111299Scth 		bp->b_un.b_addr = kaddr + off;
1121299Scth 		bp->b_flags |= B_REMAPPED;
1131299Scth 		return (bp->b_un.b_addr);
1141299Scth 	}
1151299Scth 
1160Sstevel@tonic-gate 	/*
1170Sstevel@tonic-gate 	 * Allocate kernel virtual space for remapping.
1180Sstevel@tonic-gate 	 */
1190Sstevel@tonic-gate 	color = bp_color(bp);
1200Sstevel@tonic-gate 	ASSERT(color < bp_align);
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	if (bp_map_arena != NULL) {
1230Sstevel@tonic-gate 		kaddr = (caddr_t)vmem_alloc(bp_map_arena,
1240Sstevel@tonic-gate 		    P2ROUNDUP(color + size, bp_align), flag);
1250Sstevel@tonic-gate 		if (kaddr == NULL)
1260Sstevel@tonic-gate 			return (NULL);
1270Sstevel@tonic-gate 		kaddr += color;
1280Sstevel@tonic-gate 	} else {
1290Sstevel@tonic-gate 		kaddr = vmem_xalloc(heap_arena, size, bp_align, color,
1300Sstevel@tonic-gate 		    0, NULL, NULL, flag);
1310Sstevel@tonic-gate 		if (kaddr == NULL)
1320Sstevel@tonic-gate 			return (NULL);
1330Sstevel@tonic-gate 	}
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	ASSERT(P2PHASE((uintptr_t)kaddr, bp_align) == color);
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 	/*
1380Sstevel@tonic-gate 	 * Map bp into the virtual space we just allocated.
1390Sstevel@tonic-gate 	 */
1400Sstevel@tonic-gate 	if (bp->b_flags & B_PAGEIO) {
1410Sstevel@tonic-gate 		pp = bp->b_pages;
1421299Scth 		pplist = NULL;
1430Sstevel@tonic-gate 	} else if (bp->b_flags & B_SHADOW) {
1441299Scth 		pp = NULL;
1450Sstevel@tonic-gate 		pplist = bp->b_shadow;
1460Sstevel@tonic-gate 	} else {
1471299Scth 		pp = NULL;
1481299Scth 		pplist = NULL;
1490Sstevel@tonic-gate 		if (bp->b_proc == NULL || (as = bp->b_proc->p_as) == NULL)
1500Sstevel@tonic-gate 			as = &kas;
1510Sstevel@tonic-gate 	}
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	bp->b_flags |= B_REMAPPED;
1540Sstevel@tonic-gate 	bp->b_un.b_addr = kaddr + off;
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	while (npages-- != 0) {
1570Sstevel@tonic-gate 		if (pp) {
1580Sstevel@tonic-gate 			pfnum = pp->p_pagenum;
1590Sstevel@tonic-gate 			pp = pp->p_next;
1600Sstevel@tonic-gate 		} else if (pplist == NULL) {
1611299Scth 			pfnum = hat_getpfnum(as->a_hat,
1621299Scth 			    (caddr_t)((uintptr_t)addr & MMU_PAGEMASK));
1631299Scth 			if (pfnum == PFN_INVALID)
1640Sstevel@tonic-gate 				panic("bp_mapin_common: hat_getpfnum for"
1650Sstevel@tonic-gate 				    " addr %p failed\n", (void *)addr);
1660Sstevel@tonic-gate 			addr += PAGESIZE;
1670Sstevel@tonic-gate 		} else {
1680Sstevel@tonic-gate 			pfnum = (*pplist)->p_pagenum;
1690Sstevel@tonic-gate 			pplist++;
1700Sstevel@tonic-gate 		}
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 		hat_devload(kas.a_hat, kaddr, PAGESIZE, pfnum,
1730Sstevel@tonic-gate 		    bp_devload_flags, HAT_LOAD_LOCK);
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 		kaddr += PAGESIZE;
1760Sstevel@tonic-gate 	}
1770Sstevel@tonic-gate 	return (bp->b_un.b_addr);
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate /*
1810Sstevel@tonic-gate  * Convert bp for pageio/physio to a kernel addressable location.
1820Sstevel@tonic-gate  */
1830Sstevel@tonic-gate void
1840Sstevel@tonic-gate bp_mapin(struct buf *bp)
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate 	(void) bp_mapin_common(bp, VM_SLEEP);
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate /*
1900Sstevel@tonic-gate  * Release all the resources associated with a previous bp_mapin() call.
1910Sstevel@tonic-gate  */
1920Sstevel@tonic-gate void
1930Sstevel@tonic-gate bp_mapout(struct buf *bp)
1940Sstevel@tonic-gate {
1951299Scth 	caddr_t		addr;
1961299Scth 	uintptr_t	off;
1971299Scth 	uintptr_t	base;
1981299Scth 	uintptr_t	color;
1991299Scth 	size_t		size;
2001299Scth 	pgcnt_t		npages;
2011299Scth 	page_t		*pp;
2021299Scth 
2031299Scth 	if ((bp->b_flags & B_REMAPPED) == 0)
2041299Scth 		return;
2051299Scth 
2061299Scth 	addr = bp->b_un.b_addr;
2071299Scth 	off = (uintptr_t)addr & PAGEOFFSET;
2081299Scth 	size = P2ROUNDUP(bp->b_bcount + off, PAGESIZE);
2091299Scth 	npages = btop(size);
2101299Scth 
2111299Scth 	bp->b_un.b_addr = (caddr_t)off;		/* debugging aid */
2121299Scth 
2131299Scth 	if ((bp->b_flags & (B_SHADOW | B_PAGEIO)) && (npages == 1) &&
2141299Scth 	    kpm_enable && bp_mapin_kpm_enable) {
2151299Scth 		if (bp->b_flags & B_SHADOW)
2161299Scth 			pp = *bp->b_shadow;
2170Sstevel@tonic-gate 		else
2181299Scth 			pp = bp->b_pages;
219*2236Scth 		addr = (caddr_t)((uintptr_t)addr & MMU_PAGEMASK);
2201299Scth 		hat_kpm_mapout(pp, NULL, addr);
2210Sstevel@tonic-gate 		bp->b_flags &= ~B_REMAPPED;
2221299Scth 		return;
2230Sstevel@tonic-gate 	}
2241299Scth 
2251299Scth 	base = (uintptr_t)addr & MMU_PAGEMASK;
2261299Scth 	BP_FLUSH(base, size);
2271299Scth 	hat_unload(kas.a_hat, (void *)base, size,
2281299Scth 	    HAT_UNLOAD_NOSYNC | HAT_UNLOAD_UNLOCK);
2291299Scth 	if (bp_map_arena != NULL) {
2301299Scth 		color = P2PHASE(base, bp_align);
2311299Scth 		vmem_free(bp_map_arena, (void *)(base - color),
2321299Scth 		    P2ROUNDUP(color + size, bp_align));
2331299Scth 	} else
2341299Scth 		vmem_free(heap_arena, (void *)base, size);
2351299Scth 	bp->b_flags &= ~B_REMAPPED;
2360Sstevel@tonic-gate }
237