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 /* 29 * Kernel Physical Mapping (segkpm) hat interface routines for sun4v. 30 */ 31 32 #include <sys/types.h> 33 #include <vm/hat.h> 34 #include <vm/hat_sfmmu.h> 35 #include <vm/page.h> 36 #include <sys/cmn_err.h> 37 #include <sys/machsystm.h> 38 #include <vm/seg_kpm.h> 39 #include <vm/mach_kpm.h> 40 41 /* 42 * Kernel Physical Mapping (kpm) facility 43 */ 44 45 void 46 mach_kpm_init() 47 { 48 uintptr_t start, end; 49 struct memlist *pmem; 50 51 /* 52 * Map each of the memsegs into the kpm segment, coalesing 53 * adjacent memsegs to allow mapping with the largest 54 * possible pages. 55 */ 56 pmem = phys_install; 57 start = pmem->address; 58 end = start + pmem->size; 59 for (;;) { 60 if (pmem == NULL || pmem->address > end) { 61 hat_devload(kas.a_hat, kpm_vbase + start, 62 end - start, mmu_btop(start), 63 PROT_READ | PROT_WRITE, 64 HAT_LOAD | HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST); 65 if (pmem == NULL) 66 break; 67 start = pmem->address; 68 } 69 end = pmem->address + pmem->size; 70 pmem = pmem->next; 71 } 72 } 73 74 /* -- hat_kpm interface section -- */ 75 76 /* 77 * Mapin a locked page and return the vaddr. 78 */ 79 /*ARGSUSED*/ 80 caddr_t 81 hat_kpm_mapin(struct page *pp, struct kpme *kpme) 82 { 83 caddr_t vaddr; 84 85 if (kpm_enable == 0) { 86 cmn_err(CE_WARN, "hat_kpm_mapin: kpm_enable not set"); 87 return ((caddr_t)NULL); 88 } 89 90 if (pp == NULL || PAGE_LOCKED(pp) == 0) { 91 cmn_err(CE_WARN, "hat_kpm_mapin: pp zero or not locked"); 92 return ((caddr_t)NULL); 93 } 94 95 vaddr = hat_kpm_page2va(pp, 1); 96 97 return (vaddr); 98 } 99 100 /* 101 * Mapout a locked page. 102 */ 103 /*ARGSUSED*/ 104 void 105 hat_kpm_mapout(struct page *pp, struct kpme *kpme, caddr_t vaddr) 106 { 107 #ifdef DEBUG 108 if (kpm_enable == 0) { 109 cmn_err(CE_WARN, "hat_kpm_mapout: kpm_enable not set"); 110 return; 111 } 112 113 if (IS_KPM_ADDR(vaddr) == 0) { 114 cmn_err(CE_WARN, "hat_kpm_mapout: no kpm address"); 115 return; 116 } 117 118 if (pp == NULL || PAGE_LOCKED(pp) == 0) { 119 cmn_err(CE_WARN, "hat_kpm_mapout: page zero or not locked"); 120 return; 121 } 122 #endif 123 } 124 125 /* 126 * Return the kpm virtual address for the page at pp. 127 */ 128 /*ARGSUSED*/ 129 caddr_t 130 hat_kpm_page2va(struct page *pp, int checkswap) 131 { 132 uintptr_t paddr, vaddr; 133 134 ASSERT(kpm_enable); 135 136 paddr = ptob(pp->p_pagenum); 137 138 vaddr = (uintptr_t)kpm_vbase + paddr; 139 140 return ((caddr_t)vaddr); 141 } 142 143 /* 144 * Return the page for the kpm virtual address vaddr. 145 * Caller is responsible for the kpm mapping and lock 146 * state of the page. 147 */ 148 page_t * 149 hat_kpm_vaddr2page(caddr_t vaddr) 150 { 151 uintptr_t paddr; 152 pfn_t pfn; 153 154 ASSERT(IS_KPM_ADDR(vaddr)); 155 156 SFMMU_KPM_VTOP(vaddr, paddr); 157 pfn = (pfn_t)btop(paddr); 158 159 return (page_numtopp_nolock(pfn)); 160 } 161 162 /* 163 * hat_kpm_fault is called from segkpm_fault when a kpm tsbmiss occurred. 164 * This should never happen on sun4v. 165 */ 166 int 167 hat_kpm_fault(struct hat *hat, caddr_t vaddr) 168 { 169 panic("pagefault in seg_kpm. hat: 0x%p vaddr: 0x%p", hat, vaddr); 170 171 return (0); 172 } 173 174 /*ARGSUSED*/ 175 void 176 hat_kpm_mseghash_clear(int nentries) 177 {} 178 179 /*ARGSUSED*/ 180 void 181 hat_kpm_mseghash_update(pgcnt_t inx, struct memseg *msp) 182 {} 183 184 /*ARGSUSED*/ 185 void 186 hat_kpm_addmem_mseg_update(struct memseg *msp, pgcnt_t nkpmpgs, 187 offset_t kpm_pages_off) 188 {} 189 190 /*ARGSUSED*/ 191 void 192 hat_kpm_addmem_mseg_insert(struct memseg *msp) 193 {} 194 195 /*ARGSUSED*/ 196 void 197 hat_kpm_addmem_memsegs_update(struct memseg *msp) 198 {} 199 200 /*ARGSUSED*/ 201 caddr_t 202 hat_kpm_mseg_reuse(struct memseg *msp) 203 { 204 return (0); 205 } 206 207 /*ARGSUSED*/ 208 void 209 hat_kpm_delmem_mseg_update(struct memseg *msp, struct memseg **mspp) 210 {} 211 212 /*ARGSUSED*/ 213 void 214 hat_kpm_split_mseg_update(struct memseg *msp, struct memseg **mspp, 215 struct memseg *lo, struct memseg *mid, struct memseg *hi) 216 {} 217 218 /* 219 * Walk the memsegs chain, applying func to each memseg span and vcolor. 220 */ 221 void 222 hat_kpm_walk(void (*func)(void *, void *, size_t), void *arg) 223 { 224 pfn_t pbase, pend; 225 void *base; 226 size_t size; 227 struct memseg *msp; 228 229 for (msp = memsegs; msp; msp = msp->next) { 230 pbase = msp->pages_base; 231 pend = msp->pages_end; 232 base = ptob(pbase) + kpm_vbase; 233 size = ptob(pend - pbase); 234 func(arg, base, size); 235 } 236 } 237 238 239 /* -- sfmmu_kpm internal section -- */ 240 241 /* 242 * Return the page frame number if a valid segkpm mapping exists 243 * for vaddr, otherwise return PFN_INVALID. No locks are grabbed. 244 * Should only be used by other sfmmu routines. 245 */ 246 pfn_t 247 sfmmu_kpm_vatopfn(caddr_t vaddr) 248 { 249 uintptr_t paddr; 250 pfn_t pfn; 251 page_t *pp; 252 253 ASSERT(kpm_enable && IS_KPM_ADDR(vaddr)); 254 255 SFMMU_KPM_VTOP(vaddr, paddr); 256 pfn = (pfn_t)btop(paddr); 257 pp = page_numtopp_nolock(pfn); 258 if (pp) 259 return (pfn); 260 else 261 return ((pfn_t)PFN_INVALID); 262 } 263