1fedab560Sae112802 /* 2fedab560Sae112802 * CDDL HEADER START 3fedab560Sae112802 * 4fedab560Sae112802 * The contents of this file are subject to the terms of the 5fedab560Sae112802 * Common Development and Distribution License (the "License"). 6fedab560Sae112802 * You may not use this file except in compliance with the License. 7fedab560Sae112802 * 8fedab560Sae112802 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fedab560Sae112802 * or http://www.opensolaris.org/os/licensing. 10fedab560Sae112802 * See the License for the specific language governing permissions 11fedab560Sae112802 * and limitations under the License. 12fedab560Sae112802 * 13fedab560Sae112802 * When distributing Covered Code, include this CDDL HEADER in each 14fedab560Sae112802 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fedab560Sae112802 * If applicable, add the following below this CDDL HEADER, with the 16fedab560Sae112802 * fields enclosed by brackets "[]" replaced with your own identifying 17fedab560Sae112802 * information: Portions Copyright [yyyy] [name of copyright owner] 18fedab560Sae112802 * 19fedab560Sae112802 * CDDL HEADER END 20fedab560Sae112802 */ 21fedab560Sae112802 /* 2256f33205SJonathan Adams * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23fedab560Sae112802 * Use is subject to license terms. 24fedab560Sae112802 */ 25fedab560Sae112802 26fedab560Sae112802 /* 27fedab560Sae112802 * Kernel Physical Mapping (segkpm) hat interface routines for sun4v. 28fedab560Sae112802 */ 29fedab560Sae112802 30fedab560Sae112802 #include <sys/types.h> 31fedab560Sae112802 #include <vm/hat.h> 32fedab560Sae112802 #include <vm/hat_sfmmu.h> 33fedab560Sae112802 #include <vm/page.h> 34fedab560Sae112802 #include <sys/cmn_err.h> 35fedab560Sae112802 #include <sys/machsystm.h> 36fedab560Sae112802 #include <vm/seg_kpm.h> 37fedab560Sae112802 #include <vm/mach_kpm.h> 38af4c679fSSean McEnroe #include <vm/faultcode.h> 39af4c679fSSean McEnroe 40af4c679fSSean McEnroe extern pfn_t memseg_get_start(struct memseg *); 41fedab560Sae112802 42fedab560Sae112802 /* 43fedab560Sae112802 * Kernel Physical Mapping (kpm) facility 44fedab560Sae112802 */ 45fedab560Sae112802 46af4c679fSSean McEnroe 47fedab560Sae112802 void 48fedab560Sae112802 mach_kpm_init() 49fedab560Sae112802 { 50fedab560Sae112802 uintptr_t start, end; 51fedab560Sae112802 struct memlist *pmem; 52fedab560Sae112802 53fedab560Sae112802 /* 54fedab560Sae112802 * Map each of the memsegs into the kpm segment, coalesing 55fedab560Sae112802 * adjacent memsegs to allow mapping with the largest 56fedab560Sae112802 * possible pages. 57fedab560Sae112802 */ 58fedab560Sae112802 pmem = phys_install; 5956f33205SJonathan Adams start = pmem->ml_address; 6056f33205SJonathan Adams end = start + pmem->ml_size; 61fedab560Sae112802 for (;;) { 6256f33205SJonathan Adams if (pmem == NULL || pmem->ml_address > end) { 63fedab560Sae112802 hat_devload(kas.a_hat, kpm_vbase + start, 64fedab560Sae112802 end - start, mmu_btop(start), 65fedab560Sae112802 PROT_READ | PROT_WRITE, 66fedab560Sae112802 HAT_LOAD | HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST); 67fedab560Sae112802 if (pmem == NULL) 68fedab560Sae112802 break; 6956f33205SJonathan Adams start = pmem->ml_address; 70fedab560Sae112802 } 7156f33205SJonathan Adams end = pmem->ml_address + pmem->ml_size; 7256f33205SJonathan Adams pmem = pmem->ml_next; 73fedab560Sae112802 } 74fedab560Sae112802 } 75fedab560Sae112802 76fedab560Sae112802 /* -- hat_kpm interface section -- */ 77fedab560Sae112802 78fedab560Sae112802 /* 79fedab560Sae112802 * Mapin a locked page and return the vaddr. 80fedab560Sae112802 */ 81fedab560Sae112802 /*ARGSUSED*/ 82fedab560Sae112802 caddr_t 83fedab560Sae112802 hat_kpm_mapin(struct page *pp, struct kpme *kpme) 84fedab560Sae112802 { 85fedab560Sae112802 caddr_t vaddr; 86fedab560Sae112802 87fedab560Sae112802 if (kpm_enable == 0) { 88fedab560Sae112802 cmn_err(CE_WARN, "hat_kpm_mapin: kpm_enable not set"); 89fedab560Sae112802 return ((caddr_t)NULL); 90fedab560Sae112802 } 91fedab560Sae112802 92fedab560Sae112802 if (pp == NULL || PAGE_LOCKED(pp) == 0) { 93fedab560Sae112802 cmn_err(CE_WARN, "hat_kpm_mapin: pp zero or not locked"); 94fedab560Sae112802 return ((caddr_t)NULL); 95fedab560Sae112802 } 96fedab560Sae112802 97fedab560Sae112802 vaddr = hat_kpm_page2va(pp, 1); 98fedab560Sae112802 99fedab560Sae112802 return (vaddr); 100fedab560Sae112802 } 101fedab560Sae112802 102fedab560Sae112802 /* 103fedab560Sae112802 * Mapout a locked page. 104fedab560Sae112802 */ 105fedab560Sae112802 /*ARGSUSED*/ 106fedab560Sae112802 void 107fedab560Sae112802 hat_kpm_mapout(struct page *pp, struct kpme *kpme, caddr_t vaddr) 108fedab560Sae112802 { 109fedab560Sae112802 #ifdef DEBUG 110fedab560Sae112802 if (kpm_enable == 0) { 111fedab560Sae112802 cmn_err(CE_WARN, "hat_kpm_mapout: kpm_enable not set"); 112fedab560Sae112802 return; 113fedab560Sae112802 } 114fedab560Sae112802 115fedab560Sae112802 if (IS_KPM_ADDR(vaddr) == 0) { 116fedab560Sae112802 cmn_err(CE_WARN, "hat_kpm_mapout: no kpm address"); 117fedab560Sae112802 return; 118fedab560Sae112802 } 119fedab560Sae112802 120fedab560Sae112802 if (pp == NULL || PAGE_LOCKED(pp) == 0) { 121fedab560Sae112802 cmn_err(CE_WARN, "hat_kpm_mapout: page zero or not locked"); 122fedab560Sae112802 return; 123fedab560Sae112802 } 124fedab560Sae112802 #endif 125fedab560Sae112802 } 126fedab560Sae112802 127fedab560Sae112802 /* 128d20abfaaSPavel Tatashin * hat_kpm_mapin_pfn is used to obtain a kpm mapping for physical 129d20abfaaSPavel Tatashin * memory addresses that are not described by a page_t. It can 130d20abfaaSPavel Tatashin * also be used for normal pages that are not locked, but beware 131d20abfaaSPavel Tatashin * this is dangerous - no locking is performed, so the identity of 132d20abfaaSPavel Tatashin * the page could change. hat_kpm_mapin_pfn is not supported when 133d20abfaaSPavel Tatashin * vac_colors > 1, because the chosen va depends on the page identity, 134d20abfaaSPavel Tatashin * which could change. 135d20abfaaSPavel Tatashin * The caller must only pass pfn's for valid physical addresses; violation 136d20abfaaSPavel Tatashin * of this rule will cause panic. 137d20abfaaSPavel Tatashin */ 138d20abfaaSPavel Tatashin caddr_t 139d20abfaaSPavel Tatashin hat_kpm_mapin_pfn(pfn_t pfn) 140d20abfaaSPavel Tatashin { 141d20abfaaSPavel Tatashin caddr_t paddr, vaddr; 142d20abfaaSPavel Tatashin 143d20abfaaSPavel Tatashin if (kpm_enable == 0) 144d20abfaaSPavel Tatashin return ((caddr_t)NULL); 145d20abfaaSPavel Tatashin 146d20abfaaSPavel Tatashin paddr = (caddr_t)ptob(pfn); 147d20abfaaSPavel Tatashin vaddr = (uintptr_t)kpm_vbase + paddr; 148d20abfaaSPavel Tatashin 149d20abfaaSPavel Tatashin return ((caddr_t)vaddr); 150d20abfaaSPavel Tatashin } 151d20abfaaSPavel Tatashin 152d20abfaaSPavel Tatashin /*ARGSUSED*/ 153d20abfaaSPavel Tatashin void 154d20abfaaSPavel Tatashin hat_kpm_mapout_pfn(pfn_t pfn) 155d20abfaaSPavel Tatashin { 156d20abfaaSPavel Tatashin /* empty */ 157d20abfaaSPavel Tatashin } 158d20abfaaSPavel Tatashin 159d20abfaaSPavel Tatashin /* 160fedab560Sae112802 * Return the kpm virtual address for the page at pp. 161fedab560Sae112802 */ 162fedab560Sae112802 /*ARGSUSED*/ 163fedab560Sae112802 caddr_t 164fedab560Sae112802 hat_kpm_page2va(struct page *pp, int checkswap) 165fedab560Sae112802 { 166fedab560Sae112802 uintptr_t paddr, vaddr; 167fedab560Sae112802 168fedab560Sae112802 ASSERT(kpm_enable); 169fedab560Sae112802 170fedab560Sae112802 paddr = ptob(pp->p_pagenum); 171fedab560Sae112802 172fedab560Sae112802 vaddr = (uintptr_t)kpm_vbase + paddr; 173fedab560Sae112802 174fedab560Sae112802 return ((caddr_t)vaddr); 175fedab560Sae112802 } 176fedab560Sae112802 177fedab560Sae112802 /* 178fedab560Sae112802 * Return the page for the kpm virtual address vaddr. 179fedab560Sae112802 * Caller is responsible for the kpm mapping and lock 180fedab560Sae112802 * state of the page. 181fedab560Sae112802 */ 182fedab560Sae112802 page_t * 183fedab560Sae112802 hat_kpm_vaddr2page(caddr_t vaddr) 184fedab560Sae112802 { 185fedab560Sae112802 uintptr_t paddr; 186fedab560Sae112802 pfn_t pfn; 187fedab560Sae112802 188fedab560Sae112802 ASSERT(IS_KPM_ADDR(vaddr)); 189fedab560Sae112802 190fedab560Sae112802 SFMMU_KPM_VTOP(vaddr, paddr); 191fedab560Sae112802 pfn = (pfn_t)btop(paddr); 192fedab560Sae112802 193fedab560Sae112802 return (page_numtopp_nolock(pfn)); 194fedab560Sae112802 } 195*79afa7fbSSean McEnroe /*ARGSUSED*/ 196fedab560Sae112802 /* 197fedab560Sae112802 * hat_kpm_fault is called from segkpm_fault when a kpm tsbmiss occurred. 198fedab560Sae112802 * This should never happen on sun4v. 199fedab560Sae112802 */ 200fedab560Sae112802 int 201fedab560Sae112802 hat_kpm_fault(struct hat *hat, caddr_t vaddr) 202fedab560Sae112802 { 203*79afa7fbSSean McEnroe /* 204*79afa7fbSSean McEnroe * Return FC_NOMAP for sun4v to allow the t_lofault_handler 205*79afa7fbSSean McEnroe * to handle this fault if one is installed 206*79afa7fbSSean McEnroe */ 207fedab560Sae112802 208*79afa7fbSSean McEnroe return (FC_NOMAP); 209fedab560Sae112802 } 210fedab560Sae112802 211fedab560Sae112802 /*ARGSUSED*/ 212fedab560Sae112802 void 213fedab560Sae112802 hat_kpm_mseghash_clear(int nentries) 214fedab560Sae112802 {} 215fedab560Sae112802 216fedab560Sae112802 /*ARGSUSED*/ 217fedab560Sae112802 void 218fedab560Sae112802 hat_kpm_mseghash_update(pgcnt_t inx, struct memseg *msp) 219fedab560Sae112802 {} 220fedab560Sae112802 221fedab560Sae112802 /*ARGSUSED*/ 222fedab560Sae112802 void 223fedab560Sae112802 hat_kpm_addmem_mseg_update(struct memseg *msp, pgcnt_t nkpmpgs, 224fedab560Sae112802 offset_t kpm_pages_off) 2259853d9e8SJason Beloro { 2269853d9e8SJason Beloro pfn_t base, end; 2279853d9e8SJason Beloro 2289853d9e8SJason Beloro /* 2299853d9e8SJason Beloro * kphysm_add_memory_dynamic() does not set nkpmpgs 2309853d9e8SJason Beloro * when page_t memory is externally allocated. That 2319853d9e8SJason Beloro * code must properly calculate nkpmpgs in all cases 2329853d9e8SJason Beloro * if nkpmpgs needs to be used at some point. 2339853d9e8SJason Beloro */ 2349853d9e8SJason Beloro 235af4c679fSSean McEnroe /* 236af4c679fSSean McEnroe * The meta (page_t) pages for dynamically added memory are allocated 237af4c679fSSean McEnroe * either from the incoming memory itself or from existing memory. 238af4c679fSSean McEnroe * In the former case the base of the incoming pages will be different 239af4c679fSSean McEnroe * than the base of the dynamic segment so call memseg_get_start() to 240af4c679fSSean McEnroe * get the actual base of the incoming memory for each case. 241af4c679fSSean McEnroe */ 242af4c679fSSean McEnroe 243af4c679fSSean McEnroe base = memseg_get_start(msp); 2449853d9e8SJason Beloro end = msp->pages_end; 2459853d9e8SJason Beloro 2469853d9e8SJason Beloro hat_devload(kas.a_hat, kpm_vbase + mmu_ptob(base), 2479853d9e8SJason Beloro mmu_ptob(end - base), base, PROT_READ | PROT_WRITE, 2489853d9e8SJason Beloro HAT_LOAD | HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST); 2499853d9e8SJason Beloro } 2509853d9e8SJason Beloro 2519853d9e8SJason Beloro /* 2529853d9e8SJason Beloro * Return end of metadata for an already setup memseg. 2539853d9e8SJason Beloro */ 2549853d9e8SJason Beloro caddr_t 2559853d9e8SJason Beloro hat_kpm_mseg_reuse(struct memseg *msp) 2569853d9e8SJason Beloro { 2579853d9e8SJason Beloro return ((caddr_t)msp->epages); 2589853d9e8SJason Beloro } 259fedab560Sae112802 260fedab560Sae112802 /*ARGSUSED*/ 261fedab560Sae112802 void 262fedab560Sae112802 hat_kpm_addmem_mseg_insert(struct memseg *msp) 263fedab560Sae112802 {} 264fedab560Sae112802 265fedab560Sae112802 /*ARGSUSED*/ 266fedab560Sae112802 void 267fedab560Sae112802 hat_kpm_addmem_memsegs_update(struct memseg *msp) 268fedab560Sae112802 {} 269fedab560Sae112802 270fedab560Sae112802 /*ARGSUSED*/ 271fedab560Sae112802 void 272fedab560Sae112802 hat_kpm_delmem_mseg_update(struct memseg *msp, struct memseg **mspp) 2739853d9e8SJason Beloro { 2749853d9e8SJason Beloro pfn_t base, end; 2759853d9e8SJason Beloro 276af4c679fSSean McEnroe /* 277af4c679fSSean McEnroe * The meta (page_t) pages for dynamically added memory are allocated 278af4c679fSSean McEnroe * either from the incoming memory itself or from existing memory. 279af4c679fSSean McEnroe * In the former case the base of the incoming pages will be different 280af4c679fSSean McEnroe * than the base of the dynamic segment so call memseg_get_start() to 281af4c679fSSean McEnroe * get the actual base of the incoming memory for each case. 282af4c679fSSean McEnroe */ 283af4c679fSSean McEnroe 284af4c679fSSean McEnroe base = memseg_get_start(msp); 2859853d9e8SJason Beloro end = msp->pages_end; 2869853d9e8SJason Beloro 2879853d9e8SJason Beloro hat_unload(kas.a_hat, kpm_vbase + mmu_ptob(base), mmu_ptob(end - base), 2889853d9e8SJason Beloro HAT_UNLOAD | HAT_UNLOAD_UNLOCK | HAT_UNLOAD_UNMAP); 2899853d9e8SJason Beloro } 290fedab560Sae112802 291fedab560Sae112802 /*ARGSUSED*/ 292fedab560Sae112802 void 293fedab560Sae112802 hat_kpm_split_mseg_update(struct memseg *msp, struct memseg **mspp, 294fedab560Sae112802 struct memseg *lo, struct memseg *mid, struct memseg *hi) 295fedab560Sae112802 {} 296fedab560Sae112802 297fedab560Sae112802 /* 298fedab560Sae112802 * Walk the memsegs chain, applying func to each memseg span and vcolor. 299fedab560Sae112802 */ 300fedab560Sae112802 void 301fedab560Sae112802 hat_kpm_walk(void (*func)(void *, void *, size_t), void *arg) 302fedab560Sae112802 { 303fedab560Sae112802 pfn_t pbase, pend; 304fedab560Sae112802 void *base; 305fedab560Sae112802 size_t size; 306fedab560Sae112802 struct memseg *msp; 307fedab560Sae112802 308fedab560Sae112802 for (msp = memsegs; msp; msp = msp->next) { 309fedab560Sae112802 pbase = msp->pages_base; 310fedab560Sae112802 pend = msp->pages_end; 311fedab560Sae112802 base = ptob(pbase) + kpm_vbase; 312fedab560Sae112802 size = ptob(pend - pbase); 313fedab560Sae112802 func(arg, base, size); 314fedab560Sae112802 } 315fedab560Sae112802 } 316fedab560Sae112802 317fedab560Sae112802 318fedab560Sae112802 /* -- sfmmu_kpm internal section -- */ 319fedab560Sae112802 320fedab560Sae112802 /* 321fedab560Sae112802 * Return the page frame number if a valid segkpm mapping exists 322fedab560Sae112802 * for vaddr, otherwise return PFN_INVALID. No locks are grabbed. 323fedab560Sae112802 * Should only be used by other sfmmu routines. 324fedab560Sae112802 */ 325fedab560Sae112802 pfn_t 326fedab560Sae112802 sfmmu_kpm_vatopfn(caddr_t vaddr) 327fedab560Sae112802 { 328fedab560Sae112802 uintptr_t paddr; 329fedab560Sae112802 pfn_t pfn; 330fedab560Sae112802 page_t *pp; 331fedab560Sae112802 332fedab560Sae112802 ASSERT(kpm_enable && IS_KPM_ADDR(vaddr)); 333fedab560Sae112802 334fedab560Sae112802 SFMMU_KPM_VTOP(vaddr, paddr); 335fedab560Sae112802 pfn = (pfn_t)btop(paddr); 336fedab560Sae112802 pp = page_numtopp_nolock(pfn); 337a75003d5Sae112802 if (pp) 338fedab560Sae112802 return (pfn); 339fedab560Sae112802 else 340fedab560Sae112802 return ((pfn_t)PFN_INVALID); 341fedab560Sae112802 } 342