xref: /illumos-gate/usr/src/uts/sun4v/vm/mach_kpm.c (revision af4c679f647cf088543c762e33d41a3ac52cfa14)
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 /*
22d20abfaaSPavel Tatashin  * Copyright 2009 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>
38*af4c679fSSean McEnroe #include <vm/faultcode.h>
39*af4c679fSSean McEnroe 
40*af4c679fSSean McEnroe extern pfn_t memseg_get_start(struct memseg *);
41fedab560Sae112802 
42fedab560Sae112802 /*
43fedab560Sae112802  * Kernel Physical Mapping (kpm) facility
44fedab560Sae112802  */
45fedab560Sae112802 
46*af4c679fSSean 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;
59fedab560Sae112802 	start = pmem->address;
60fedab560Sae112802 	end = start + pmem->size;
61fedab560Sae112802 	for (;;) {
62fedab560Sae112802 		if (pmem == NULL || pmem->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;
69fedab560Sae112802 			start = pmem->address;
70fedab560Sae112802 		}
71fedab560Sae112802 		end = pmem->address + pmem->size;
72fedab560Sae112802 		pmem = pmem->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 }
195fedab560Sae112802 
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 {
203903a11ebSrh87107 	panic("pagefault in seg_kpm.  hat: 0x%p  vaddr: 0x%p",
204903a11ebSrh87107 	    (void *)hat, (void *)vaddr);
205fedab560Sae112802 
206fedab560Sae112802 	return (0);
207fedab560Sae112802 }
208fedab560Sae112802 
209fedab560Sae112802 /*ARGSUSED*/
210fedab560Sae112802 void
211fedab560Sae112802 hat_kpm_mseghash_clear(int nentries)
212fedab560Sae112802 {}
213fedab560Sae112802 
214fedab560Sae112802 /*ARGSUSED*/
215fedab560Sae112802 void
216fedab560Sae112802 hat_kpm_mseghash_update(pgcnt_t inx, struct memseg *msp)
217fedab560Sae112802 {}
218fedab560Sae112802 
219fedab560Sae112802 /*ARGSUSED*/
220fedab560Sae112802 void
221fedab560Sae112802 hat_kpm_addmem_mseg_update(struct memseg *msp, pgcnt_t nkpmpgs,
222fedab560Sae112802 	offset_t kpm_pages_off)
2239853d9e8SJason Beloro {
2249853d9e8SJason Beloro 	pfn_t base, end;
2259853d9e8SJason Beloro 
2269853d9e8SJason Beloro 	/*
2279853d9e8SJason Beloro 	 * kphysm_add_memory_dynamic() does not set nkpmpgs
2289853d9e8SJason Beloro 	 * when page_t memory is externally allocated.  That
2299853d9e8SJason Beloro 	 * code must properly calculate nkpmpgs in all cases
2309853d9e8SJason Beloro 	 * if nkpmpgs needs to be used at some point.
2319853d9e8SJason Beloro 	 */
2329853d9e8SJason Beloro 
233*af4c679fSSean McEnroe 	/*
234*af4c679fSSean McEnroe 	 * The meta (page_t) pages for dynamically added memory are allocated
235*af4c679fSSean McEnroe 	 * either from the incoming memory itself or from existing memory.
236*af4c679fSSean McEnroe 	 * In the former case the base of the incoming pages will be different
237*af4c679fSSean McEnroe 	 * than the base of the dynamic segment so call memseg_get_start() to
238*af4c679fSSean McEnroe 	 * get the actual base of the incoming memory for each case.
239*af4c679fSSean McEnroe 	 */
240*af4c679fSSean McEnroe 
241*af4c679fSSean McEnroe 	base = memseg_get_start(msp);
2429853d9e8SJason Beloro 	end = msp->pages_end;
2439853d9e8SJason Beloro 
2449853d9e8SJason Beloro 	hat_devload(kas.a_hat, kpm_vbase + mmu_ptob(base),
2459853d9e8SJason Beloro 	    mmu_ptob(end - base), base, PROT_READ | PROT_WRITE,
2469853d9e8SJason Beloro 	    HAT_LOAD | HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST);
2479853d9e8SJason Beloro }
2489853d9e8SJason Beloro 
2499853d9e8SJason Beloro /*
2509853d9e8SJason Beloro  * Return end of metadata for an already setup memseg.
2519853d9e8SJason Beloro  */
2529853d9e8SJason Beloro caddr_t
2539853d9e8SJason Beloro hat_kpm_mseg_reuse(struct memseg *msp)
2549853d9e8SJason Beloro {
2559853d9e8SJason Beloro 	return ((caddr_t)msp->epages);
2569853d9e8SJason Beloro }
257fedab560Sae112802 
258fedab560Sae112802 /*ARGSUSED*/
259fedab560Sae112802 void
260fedab560Sae112802 hat_kpm_addmem_mseg_insert(struct memseg *msp)
261fedab560Sae112802 {}
262fedab560Sae112802 
263fedab560Sae112802 /*ARGSUSED*/
264fedab560Sae112802 void
265fedab560Sae112802 hat_kpm_addmem_memsegs_update(struct memseg *msp)
266fedab560Sae112802 {}
267fedab560Sae112802 
268fedab560Sae112802 /*ARGSUSED*/
269fedab560Sae112802 void
270fedab560Sae112802 hat_kpm_delmem_mseg_update(struct memseg *msp, struct memseg **mspp)
2719853d9e8SJason Beloro {
2729853d9e8SJason Beloro 	pfn_t base, end;
2739853d9e8SJason Beloro 
274*af4c679fSSean McEnroe 	/*
275*af4c679fSSean McEnroe 	 * The meta (page_t) pages for dynamically added memory are allocated
276*af4c679fSSean McEnroe 	 * either from the incoming memory itself or from existing memory.
277*af4c679fSSean McEnroe 	 * In the former case the base of the incoming pages will be different
278*af4c679fSSean McEnroe 	 * than the base of the dynamic segment so call memseg_get_start() to
279*af4c679fSSean McEnroe 	 * get the actual base of the incoming memory for each case.
280*af4c679fSSean McEnroe 	 */
281*af4c679fSSean McEnroe 
282*af4c679fSSean McEnroe 	base = memseg_get_start(msp);
2839853d9e8SJason Beloro 	end = msp->pages_end;
2849853d9e8SJason Beloro 
2859853d9e8SJason Beloro 	hat_unload(kas.a_hat, kpm_vbase +  mmu_ptob(base), mmu_ptob(end - base),
2869853d9e8SJason Beloro 	    HAT_UNLOAD | HAT_UNLOAD_UNLOCK | HAT_UNLOAD_UNMAP);
2879853d9e8SJason Beloro }
288fedab560Sae112802 
289fedab560Sae112802 /*ARGSUSED*/
290fedab560Sae112802 void
291fedab560Sae112802 hat_kpm_split_mseg_update(struct memseg *msp, struct memseg **mspp,
292fedab560Sae112802 	struct memseg *lo, struct memseg *mid, struct memseg *hi)
293fedab560Sae112802 {}
294fedab560Sae112802 
295fedab560Sae112802 /*
296fedab560Sae112802  * Walk the memsegs chain, applying func to each memseg span and vcolor.
297fedab560Sae112802  */
298fedab560Sae112802 void
299fedab560Sae112802 hat_kpm_walk(void (*func)(void *, void *, size_t), void *arg)
300fedab560Sae112802 {
301fedab560Sae112802 	pfn_t	pbase, pend;
302fedab560Sae112802 	void	*base;
303fedab560Sae112802 	size_t	size;
304fedab560Sae112802 	struct memseg *msp;
305fedab560Sae112802 
306fedab560Sae112802 	for (msp = memsegs; msp; msp = msp->next) {
307fedab560Sae112802 		pbase = msp->pages_base;
308fedab560Sae112802 		pend = msp->pages_end;
309fedab560Sae112802 		base = ptob(pbase) + kpm_vbase;
310fedab560Sae112802 		size = ptob(pend - pbase);
311fedab560Sae112802 		func(arg, base, size);
312fedab560Sae112802 	}
313fedab560Sae112802 }
314fedab560Sae112802 
315fedab560Sae112802 
316fedab560Sae112802 /* -- sfmmu_kpm internal section -- */
317fedab560Sae112802 
318fedab560Sae112802 /*
319fedab560Sae112802  * Return the page frame number if a valid segkpm mapping exists
320fedab560Sae112802  * for vaddr, otherwise return PFN_INVALID. No locks are grabbed.
321fedab560Sae112802  * Should only be used by other sfmmu routines.
322fedab560Sae112802  */
323fedab560Sae112802 pfn_t
324fedab560Sae112802 sfmmu_kpm_vatopfn(caddr_t vaddr)
325fedab560Sae112802 {
326fedab560Sae112802 	uintptr_t	paddr;
327fedab560Sae112802 	pfn_t		pfn;
328fedab560Sae112802 	page_t	*pp;
329fedab560Sae112802 
330fedab560Sae112802 	ASSERT(kpm_enable && IS_KPM_ADDR(vaddr));
331fedab560Sae112802 
332fedab560Sae112802 	SFMMU_KPM_VTOP(vaddr, paddr);
333fedab560Sae112802 	pfn = (pfn_t)btop(paddr);
334fedab560Sae112802 	pp = page_numtopp_nolock(pfn);
335a75003d5Sae112802 	if (pp)
336fedab560Sae112802 		return (pfn);
337fedab560Sae112802 	else
338fedab560Sae112802 		return ((pfn_t)PFN_INVALID);
339fedab560Sae112802 }
340