xref: /illumos-gate/usr/src/uts/sun4v/vm/mach_kpm.c (revision 79afa7fba66c808623862442107f913bce5ea783)
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
mach_kpm_init()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
hat_kpm_mapin(struct page * pp,struct kpme * kpme)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
hat_kpm_mapout(struct page * pp,struct kpme * kpme,caddr_t vaddr)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
hat_kpm_mapin_pfn(pfn_t pfn)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
hat_kpm_mapout_pfn(pfn_t pfn)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
hat_kpm_page2va(struct page * pp,int checkswap)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 *
hat_kpm_vaddr2page(caddr_t vaddr)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
hat_kpm_fault(struct hat * hat,caddr_t vaddr)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
hat_kpm_mseghash_clear(int nentries)213fedab560Sae112802 hat_kpm_mseghash_clear(int nentries)
214fedab560Sae112802 {}
215fedab560Sae112802 
216fedab560Sae112802 /*ARGSUSED*/
217fedab560Sae112802 void
hat_kpm_mseghash_update(pgcnt_t inx,struct memseg * msp)218fedab560Sae112802 hat_kpm_mseghash_update(pgcnt_t inx, struct memseg *msp)
219fedab560Sae112802 {}
220fedab560Sae112802 
221fedab560Sae112802 /*ARGSUSED*/
222fedab560Sae112802 void
hat_kpm_addmem_mseg_update(struct memseg * msp,pgcnt_t nkpmpgs,offset_t kpm_pages_off)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
hat_kpm_mseg_reuse(struct memseg * msp)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
hat_kpm_addmem_mseg_insert(struct memseg * msp)262fedab560Sae112802 hat_kpm_addmem_mseg_insert(struct memseg *msp)
263fedab560Sae112802 {}
264fedab560Sae112802 
265fedab560Sae112802 /*ARGSUSED*/
266fedab560Sae112802 void
hat_kpm_addmem_memsegs_update(struct memseg * msp)267fedab560Sae112802 hat_kpm_addmem_memsegs_update(struct memseg *msp)
268fedab560Sae112802 {}
269fedab560Sae112802 
270fedab560Sae112802 /*ARGSUSED*/
271fedab560Sae112802 void
hat_kpm_delmem_mseg_update(struct memseg * msp,struct memseg ** mspp)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
hat_kpm_split_mseg_update(struct memseg * msp,struct memseg ** mspp,struct memseg * lo,struct memseg * mid,struct memseg * hi)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
hat_kpm_walk(void (* func)(void *,void *,size_t),void * arg)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
sfmmu_kpm_vatopfn(caddr_t vaddr)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