xref: /illumos-gate/usr/src/uts/sun4v/vm/mach_kpm.c (revision de81e71e031139a0a7f13b7bf64152c3faa76698)
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 2008 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",
170 	    (void *)hat, (void *)vaddr);
171 
172 	return (0);
173 }
174 
175 /*ARGSUSED*/
176 void
177 hat_kpm_mseghash_clear(int nentries)
178 {}
179 
180 /*ARGSUSED*/
181 void
182 hat_kpm_mseghash_update(pgcnt_t inx, struct memseg *msp)
183 {}
184 
185 /*ARGSUSED*/
186 void
187 hat_kpm_addmem_mseg_update(struct memseg *msp, pgcnt_t nkpmpgs,
188 	offset_t kpm_pages_off)
189 {}
190 
191 /*ARGSUSED*/
192 void
193 hat_kpm_addmem_mseg_insert(struct memseg *msp)
194 {}
195 
196 /*ARGSUSED*/
197 void
198 hat_kpm_addmem_memsegs_update(struct memseg *msp)
199 {}
200 
201 /*ARGSUSED*/
202 caddr_t
203 hat_kpm_mseg_reuse(struct memseg *msp)
204 {
205 	return (0);
206 }
207 
208 /*ARGSUSED*/
209 void
210 hat_kpm_delmem_mseg_update(struct memseg *msp, struct memseg **mspp)
211 {}
212 
213 /*ARGSUSED*/
214 void
215 hat_kpm_split_mseg_update(struct memseg *msp, struct memseg **mspp,
216 	struct memseg *lo, struct memseg *mid, struct memseg *hi)
217 {}
218 
219 /*
220  * Walk the memsegs chain, applying func to each memseg span and vcolor.
221  */
222 void
223 hat_kpm_walk(void (*func)(void *, void *, size_t), void *arg)
224 {
225 	pfn_t	pbase, pend;
226 	void	*base;
227 	size_t	size;
228 	struct memseg *msp;
229 
230 	for (msp = memsegs; msp; msp = msp->next) {
231 		pbase = msp->pages_base;
232 		pend = msp->pages_end;
233 		base = ptob(pbase) + kpm_vbase;
234 		size = ptob(pend - pbase);
235 		func(arg, base, size);
236 	}
237 }
238 
239 
240 /* -- sfmmu_kpm internal section -- */
241 
242 /*
243  * Return the page frame number if a valid segkpm mapping exists
244  * for vaddr, otherwise return PFN_INVALID. No locks are grabbed.
245  * Should only be used by other sfmmu routines.
246  */
247 pfn_t
248 sfmmu_kpm_vatopfn(caddr_t vaddr)
249 {
250 	uintptr_t	paddr;
251 	pfn_t		pfn;
252 	page_t	*pp;
253 
254 	ASSERT(kpm_enable && IS_KPM_ADDR(vaddr));
255 
256 	SFMMU_KPM_VTOP(vaddr, paddr);
257 	pfn = (pfn_t)btop(paddr);
258 	pp = page_numtopp_nolock(pfn);
259 	if (pp)
260 		return (pfn);
261 	else
262 		return ((pfn_t)PFN_INVALID);
263 }
264