Print this page
no need for bad-op segment op functions
The segment drivers have a number of bad-op functions that simply panic.
Keeping the function pointer NULL will accomplish the same thing in most
cases. In other cases, keeping the function pointer NULL will result in
proper error code being returned.
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/vm/seg_kpm.c
+++ new/usr/src/uts/common/vm/seg_kpm.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License, Version 1.0 only
6 6 * (the "License"). You may not use this file except in compliance
7 7 * with the License.
8 8 *
9 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 * or http://www.opensolaris.org/os/licensing.
11 11 * See the License for the specific language governing permissions
12 12 * and limitations under the License.
13 13 *
14 14 * When distributing Covered Code, include this CDDL HEADER in each
15 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 * If applicable, add the following below this CDDL HEADER, with the
17 17 * fields enclosed by brackets "[]" replaced with your own identifying
18 18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 19 *
20 20 * CDDL HEADER END
21 21 */
22 22 /*
23 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 28 * Kernel Physical Mapping (kpm) segment driver (segkpm).
29 29 *
30 30 * This driver delivers along with the hat_kpm* interfaces an alternative
31 31 * mechanism for kernel mappings within the 64-bit Solaris operating system,
32 32 * which allows the mapping of all physical memory into the kernel address
33 33 * space at once. This is feasible in 64 bit kernels, e.g. for Ultrasparc II
34 34 * and beyond processors, since the available VA range is much larger than
35 35 * possible physical memory. Momentarily all physical memory is supported,
36 36 * that is represented by the list of memory segments (memsegs).
37 37 *
38 38 * Segkpm mappings have also very low overhead and large pages are used
39 39 * (when possible) to minimize the TLB and TSB footprint. It is also
40 40 * extentable for other than Sparc architectures (e.g. AMD64). Main
41 41 * advantage is the avoidance of the TLB-shootdown X-calls, which are
42 42 * normally needed when a kernel (global) mapping has to be removed.
43 43 *
44 44 * First example of a kernel facility that uses the segkpm mapping scheme
45 45 * is seg_map, where it is used as an alternative to hat_memload().
46 46 * See also hat layer for more information about the hat_kpm* routines.
47 47 * The kpm facilty can be turned off at boot time (e.g. /etc/system).
48 48 */
49 49
50 50 #include <sys/types.h>
51 51 #include <sys/param.h>
52 52 #include <sys/sysmacros.h>
53 53 #include <sys/systm.h>
54 54 #include <sys/vnode.h>
55 55 #include <sys/cmn_err.h>
56 56 #include <sys/debug.h>
57 57 #include <sys/thread.h>
58 58 #include <sys/cpuvar.h>
59 59 #include <sys/bitmap.h>
60 60 #include <sys/atomic.h>
61 61 #include <sys/lgrp.h>
62 62
63 63 #include <vm/seg_kmem.h>
64 64 #include <vm/seg_kpm.h>
65 65 #include <vm/hat.h>
66 66 #include <vm/as.h>
67 67 #include <vm/seg.h>
68 68 #include <vm/page.h>
69 69
70 70 /*
71 71 * Global kpm controls.
72 72 * See also platform and mmu specific controls.
73 73 *
74 74 * kpm_enable -- global on/off switch for segkpm.
75 75 * . Set by default on 64bit platforms that have kpm support.
76 76 * . Will be disabled from platform layer if not supported.
77 77 * . Can be disabled via /etc/system.
78 78 *
79 79 * kpm_smallpages -- use only regular/system pagesize for kpm mappings.
80 80 * . Can be useful for critical debugging of kpm clients.
81 81 * . Set to zero by default for platforms that support kpm large pages.
82 82 * The use of kpm large pages reduces the footprint of kpm meta data
83 83 * and has all the other advantages of using large pages (e.g TLB
84 84 * miss reduction).
85 85 * . Set by default for platforms that don't support kpm large pages or
86 86 * where large pages cannot be used for other reasons (e.g. there are
87 87 * only few full associative TLB entries available for large pages).
88 88 *
89 89 * segmap_kpm -- separate on/off switch for segmap using segkpm:
90 90 * . Set by default.
91 91 * . Will be disabled when kpm_enable is zero.
92 92 * . Will be disabled when MAXBSIZE != PAGESIZE.
93 93 * . Can be disabled via /etc/system.
94 94 *
95 95 */
↓ open down ↓ |
95 lines elided |
↑ open up ↑ |
96 96 int kpm_enable = 1;
97 97 int kpm_smallpages = 0;
98 98 int segmap_kpm = 1;
99 99
100 100 /*
101 101 * Private seg op routines.
102 102 */
103 103 faultcode_t segkpm_fault(struct hat *hat, struct seg *seg, caddr_t addr,
104 104 size_t len, enum fault_type type, enum seg_rw rw);
105 105 static void segkpm_dump(struct seg *);
106 -static void segkpm_badop(void);
107 -static int segkpm_notsup(void);
106 +static int segkpm_pagelock(struct seg *seg, caddr_t addr, size_t len,
107 + struct page ***page, enum lock_type type,
108 + enum seg_rw rw);
108 109 static int segkpm_capable(struct seg *, segcapability_t);
109 110
110 -#define SEGKPM_BADOP(t) (t(*)())segkpm_badop
111 -#define SEGKPM_NOTSUP (int(*)())segkpm_notsup
112 -
113 111 static struct seg_ops segkpm_ops = {
114 - .dup = SEGKPM_BADOP(int),
115 - .unmap = SEGKPM_BADOP(int),
116 - .free = SEGKPM_BADOP(void),
117 112 .fault = segkpm_fault,
118 - .faulta = SEGKPM_BADOP(int),
119 - .setprot = SEGKPM_BADOP(int),
120 - .checkprot = SEGKPM_BADOP(int),
121 - .kluster = SEGKPM_BADOP(int),
122 - .sync = SEGKPM_BADOP(int),
123 - .incore = SEGKPM_BADOP(size_t),
124 - .lockop = SEGKPM_BADOP(int),
125 - .getprot = SEGKPM_BADOP(int),
126 - .getoffset = SEGKPM_BADOP(u_offset_t),
127 - .gettype = SEGKPM_BADOP(int),
128 - .getvp = SEGKPM_BADOP(int),
129 - .advise = SEGKPM_BADOP(int),
130 113 .dump = segkpm_dump,
131 - .pagelock = SEGKPM_NOTSUP,
132 - .setpagesize = SEGKPM_BADOP(int),
133 - .getmemid = SEGKPM_BADOP(int),
134 - .getpolicy = SEGKPM_BADOP(lgrp_mem_policy_info_t *),
114 + .pagelock = segkpm_pagelock,
135 115 .capable = segkpm_capable,
136 116 .inherit = seg_inherit_notsup,
117 +//#ifndef SEGKPM_SUPPORT
118 +#if 0
119 +#error FIXME: define nop
120 + .dup = nop,
121 + .unmap = nop,
122 + .free = nop,
123 + .faulta = nop,
124 + .setprot = nop,
125 + .checkprot = nop,
126 + .kluster = nop,
127 + .sync = nop,
128 + .incore = nop,
129 + .lockop = nop,
130 + .getprot = nop,
131 + .getoffset = nop,
132 + .gettype = nop,
133 + .getvp = nop,
134 + .advise = nop,
135 + .setpagesize = nop,
136 + .getmemid = nop,
137 + .getpolicy = nop,
138 +#endif
137 139 };
138 140
139 141 /*
140 142 * kpm_pgsz and kpm_pgshft are set by platform layer.
141 143 */
142 144 size_t kpm_pgsz; /* kpm page size */
143 145 uint_t kpm_pgshft; /* kpm page shift */
144 146 u_offset_t kpm_pgoff; /* kpm page offset mask */
145 147 uint_t kpmp2pshft; /* kpm page to page shift */
146 148 pgcnt_t kpmpnpgs; /* how many pages per kpm page */
147 149
148 150
149 151 #ifdef SEGKPM_SUPPORT
150 152
151 153 int
152 154 segkpm_create(struct seg *seg, void *argsp)
153 155 {
154 156 struct segkpm_data *skd;
155 157 struct segkpm_crargs *b = (struct segkpm_crargs *)argsp;
156 158 ushort_t *p;
157 159 int i, j;
158 160
159 161 ASSERT(seg->s_as && RW_WRITE_HELD(&seg->s_as->a_lock));
160 162 ASSERT(btokpmp(seg->s_size) >= 1 &&
161 163 kpmpageoff((uintptr_t)seg->s_base) == 0 &&
162 164 kpmpageoff((uintptr_t)seg->s_base + seg->s_size) == 0);
163 165
164 166 skd = kmem_zalloc(sizeof (struct segkpm_data), KM_SLEEP);
165 167
166 168 seg->s_data = (void *)skd;
167 169 seg->s_ops = &segkpm_ops;
168 170 skd->skd_prot = b->prot;
169 171
170 172 /*
171 173 * (1) Segkpm virtual addresses are based on physical adresses.
172 174 * From this and in opposite to other segment drivers it is
173 175 * often required to allocate a page first to be able to
174 176 * calculate the final segkpm virtual address.
175 177 * (2) Page allocation is done by calling page_create_va(),
176 178 * one important input argument is a virtual address (also
177 179 * expressed by the "va" in the function name). This function
178 180 * is highly optimized to select the right page for an optimal
179 181 * processor and platform support (e.g. virtual addressed
180 182 * caches (VAC), physical addressed caches, NUMA).
181 183 *
182 184 * Because of (1) the approach is to generate a faked virtual
183 185 * address for calling page_create_va(). In order to exploit
184 186 * the abilities of (2), especially to utilize the cache
185 187 * hierarchy (3) and to avoid VAC alias conflicts (4) the
186 188 * selection has to be done carefully. For each virtual color
187 189 * a separate counter is provided (4). The count values are
188 190 * used for the utilization of all cache lines (3) and are
189 191 * corresponding to the cache bins.
190 192 */
191 193 skd->skd_nvcolors = b->nvcolors;
192 194
193 195 p = skd->skd_va_select =
194 196 kmem_zalloc(NCPU * b->nvcolors * sizeof (ushort_t), KM_SLEEP);
195 197
196 198 for (i = 0; i < NCPU; i++)
197 199 for (j = 0; j < b->nvcolors; j++, p++)
198 200 *p = j;
199 201
200 202 return (0);
201 203 }
202 204
203 205 /*
204 206 * This routine is called via a machine specific fault handling
205 207 * routine.
206 208 */
207 209 /* ARGSUSED */
208 210 faultcode_t
209 211 segkpm_fault(struct hat *hat, struct seg *seg, caddr_t addr, size_t len,
210 212 enum fault_type type, enum seg_rw rw)
211 213 {
212 214 ASSERT(seg->s_as && AS_LOCK_HELD(seg->s_as, &seg->s_as->a_lock));
213 215
214 216 switch (type) {
215 217 case F_INVAL:
216 218 return (hat_kpm_fault(hat, addr));
217 219 case F_SOFTLOCK:
218 220 case F_SOFTUNLOCK:
219 221 return (0);
220 222 default:
221 223 return (FC_NOSUPPORT);
222 224 }
223 225 /*NOTREACHED*/
224 226 }
225 227
226 228 #define addr_to_vcolor(addr, vcolors) \
227 229 ((int)(((uintptr_t)(addr) & ((vcolors << PAGESHIFT) - 1)) >> PAGESHIFT))
228 230
229 231 /*
230 232 * Create a virtual address that can be used for invocations of
231 233 * page_create_va. Goal is to utilize the cache hierarchy (round
232 234 * robin bins) and to select the right color for virtual indexed
233 235 * caches. It isn't exact since we also increment the bin counter
234 236 * when the caller uses VOP_GETPAGE and gets a hit in the page
235 237 * cache, but we keep the bins turning for cache distribution
236 238 * (see also segkpm_create block comment).
237 239 */
238 240 caddr_t
239 241 segkpm_create_va(u_offset_t off)
240 242 {
241 243 int vcolor;
242 244 ushort_t *p;
243 245 struct segkpm_data *skd = (struct segkpm_data *)segkpm->s_data;
244 246 int nvcolors = skd->skd_nvcolors;
245 247 caddr_t va;
246 248
247 249 vcolor = (nvcolors > 1) ? addr_to_vcolor(off, nvcolors) : 0;
248 250 p = &skd->skd_va_select[(CPU->cpu_id * nvcolors) + vcolor];
249 251 va = (caddr_t)ptob(*p);
250 252
251 253 atomic_add_16(p, nvcolors);
252 254
253 255 return (va);
254 256 }
255 257
256 258 /*
257 259 * Unload mapping if the instance has an active kpm mapping.
258 260 */
259 261 void
260 262 segkpm_mapout_validkpme(struct kpme *kpme)
261 263 {
262 264 caddr_t vaddr;
263 265 page_t *pp;
264 266
265 267 retry:
266 268 if ((pp = kpme->kpe_page) == NULL) {
267 269 return;
268 270 }
269 271
270 272 if (page_lock(pp, SE_SHARED, (kmutex_t *)NULL, P_RECLAIM) == 0)
271 273 goto retry;
272 274
273 275 /*
274 276 * Check if segkpm mapping is not unloaded in the meantime
275 277 */
↓ open down ↓ |
129 lines elided |
↑ open up ↑ |
276 278 if (kpme->kpe_page == NULL) {
277 279 page_unlock(pp);
278 280 return;
279 281 }
280 282
281 283 vaddr = hat_kpm_page2va(pp, 1);
282 284 hat_kpm_mapout(pp, kpme, vaddr);
283 285 page_unlock(pp);
284 286 }
285 287
286 -static void
287 -segkpm_badop()
288 -{
289 - panic("segkpm_badop");
290 -}
291 -
292 288 #else /* SEGKPM_SUPPORT */
293 289
294 290 /* segkpm stubs */
295 291
296 292 /*ARGSUSED*/
297 -int segkpm_create(struct seg *seg, void *argsp) { return (0); }
293 +int segkpm_create(struct seg *seg, void *argsp)
294 +{
295 + return (0);
296 +}
298 297
299 298 /* ARGSUSED */
300 299 faultcode_t
301 300 segkpm_fault(struct hat *hat, struct seg *seg, caddr_t addr, size_t len,
302 301 enum fault_type type, enum seg_rw rw)
303 302 {
304 - return ((faultcode_t)0);
303 + return (0);
305 304 }
306 305
307 306 /* ARGSUSED */
308 -caddr_t segkpm_create_va(u_offset_t off) { return (NULL); }
307 +caddr_t segkpm_create_va(u_offset_t off)
308 +{
309 + return (NULL);
310 +}
309 311
310 312 /* ARGSUSED */
311 -void segkpm_mapout_validkpme(struct kpme *kpme) {}
312 -
313 -static void
314 -segkpm_badop() {}
313 +void segkpm_mapout_validkpme(struct kpme *kpme)
314 +{
315 +}
315 316
316 317 #endif /* SEGKPM_SUPPORT */
317 318
319 +/* ARGSUSED */
318 320 static int
319 -segkpm_notsup()
321 +segkpm_pagelock(struct seg *seg, caddr_t addr, size_t len,
322 + struct page ***page, enum lock_type type, enum seg_rw rw)
320 323 {
321 324 return (ENOTSUP);
322 325 }
323 326
324 327 /*
325 328 * segkpm pages are not dumped, so we just return
326 329 */
327 330 /*ARGSUSED*/
328 331 static void
329 332 segkpm_dump(struct seg *seg)
330 -{}
333 +{
334 +}
331 335
332 336 /*
333 337 * We claim to have no special capabilities.
334 338 */
335 339 /*ARGSUSED*/
336 340 static int
337 341 segkpm_capable(struct seg *seg, segcapability_t capability)
338 342 {
339 343 return (0);
340 344 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX