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