Deleted Added
full compact
vm_phys.c (276546) vm_phys.c (285634)
1/*-
2 * Copyright (c) 2002-2006 Rice University
3 * Copyright (c) 2007 Alan L. Cox <alc@cs.rice.edu>
4 * All rights reserved.
5 *
6 * This software was developed for the FreeBSD Project by Alan L. Cox,
7 * Olivier Crameri, Peter Druschel, Sitaram Iyer, and Juan Navarro.
8 *

--- 23 unchanged lines hidden (view full) ---

32/*
33 * Physical memory system implementation
34 *
35 * Any external functions defined by this module are only to be used by the
36 * virtual memory system.
37 */
38
39#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2002-2006 Rice University
3 * Copyright (c) 2007 Alan L. Cox <alc@cs.rice.edu>
4 * All rights reserved.
5 *
6 * This software was developed for the FreeBSD Project by Alan L. Cox,
7 * Olivier Crameri, Peter Druschel, Sitaram Iyer, and Juan Navarro.
8 *

--- 23 unchanged lines hidden (view full) ---

32/*
33 * Physical memory system implementation
34 *
35 * Any external functions defined by this module are only to be used by the
36 * virtual memory system.
37 */
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: stable/10/sys/vm/vm_phys.c 276546 2015-01-02 17:45:52Z alc $");
40__FBSDID("$FreeBSD: stable/10/sys/vm/vm_phys.c 285634 2015-07-16 14:41:58Z kib $");
41
42#include "opt_ddb.h"
43#include "opt_vm.h"
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/lock.h>
48#include <sys/kernel.h>

--- 33 unchanged lines hidden (view full) ---

82 vm_page_t first_page;
83} vm_phys_fictitious_segs[VM_PHYS_FICTITIOUS_NSEGS];
84static struct mtx vm_phys_fictitious_reg_mtx;
85MALLOC_DEFINE(M_FICT_PAGES, "vm_fictitious", "Fictitious VM pages");
86
87static struct vm_freelist
88 vm_phys_free_queues[MAXMEMDOM][VM_NFREELIST][VM_NFREEPOOL][VM_NFREEORDER];
89
41
42#include "opt_ddb.h"
43#include "opt_vm.h"
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/lock.h>
48#include <sys/kernel.h>

--- 33 unchanged lines hidden (view full) ---

82 vm_page_t first_page;
83} vm_phys_fictitious_segs[VM_PHYS_FICTITIOUS_NSEGS];
84static struct mtx vm_phys_fictitious_reg_mtx;
85MALLOC_DEFINE(M_FICT_PAGES, "vm_fictitious", "Fictitious VM pages");
86
87static struct vm_freelist
88 vm_phys_free_queues[MAXMEMDOM][VM_NFREELIST][VM_NFREEPOOL][VM_NFREEORDER];
89
90static int vm_nfreelists = VM_FREELIST_DEFAULT + 1;
90static int vm_nfreelists;
91
91
92/*
93 * Provides the mapping from VM_FREELIST_* to free list indices (flind).
94 */
95static int vm_freelist_to_flind[VM_NFREELIST];
96
97CTASSERT(VM_FREELIST_DEFAULT == 0);
98
99#ifdef VM_FREELIST_ISADMA
100#define VM_ISADMA_BOUNDARY 16777216
101#endif
102#ifdef VM_FREELIST_DMA32
103#define VM_DMA32_BOUNDARY ((vm_paddr_t)1 << 32)
104#endif
105
106/*
107 * Enforce the assumptions made by vm_phys_add_seg() and vm_phys_init() about
108 * the ordering of the free list boundaries.
109 */
110#if defined(VM_ISADMA_BOUNDARY) && defined(VM_LOWMEM_BOUNDARY)
111CTASSERT(VM_ISADMA_BOUNDARY < VM_LOWMEM_BOUNDARY);
112#endif
113#if defined(VM_LOWMEM_BOUNDARY) && defined(VM_DMA32_BOUNDARY)
114CTASSERT(VM_LOWMEM_BOUNDARY < VM_DMA32_BOUNDARY);
115#endif
116
92static int cnt_prezero;
93SYSCTL_INT(_vm_stats_misc, OID_AUTO, cnt_prezero, CTLFLAG_RD,
94 &cnt_prezero, 0, "The number of physical pages prezeroed at idle time");
95
96static int sysctl_vm_phys_free(SYSCTL_HANDLER_ARGS);
97SYSCTL_OID(_vm, OID_AUTO, phys_free, CTLTYPE_STRING | CTLFLAG_RD,
98 NULL, 0, sysctl_vm_phys_free, "A", "Phys Free Info");
99
100static int sysctl_vm_phys_segs(SYSCTL_HANDLER_ARGS);
101SYSCTL_OID(_vm, OID_AUTO, phys_segs, CTLTYPE_STRING | CTLFLAG_RD,
102 NULL, 0, sysctl_vm_phys_segs, "A", "Phys Seg Info");
103
104SYSCTL_INT(_vm, OID_AUTO, ndomains, CTLFLAG_RD,
105 &vm_ndomains, 0, "Number of physical memory domains available.");
106
107static vm_page_t vm_phys_alloc_domain_pages(int domain, int flind, int pool,
108 int order);
117static int cnt_prezero;
118SYSCTL_INT(_vm_stats_misc, OID_AUTO, cnt_prezero, CTLFLAG_RD,
119 &cnt_prezero, 0, "The number of physical pages prezeroed at idle time");
120
121static int sysctl_vm_phys_free(SYSCTL_HANDLER_ARGS);
122SYSCTL_OID(_vm, OID_AUTO, phys_free, CTLTYPE_STRING | CTLFLAG_RD,
123 NULL, 0, sysctl_vm_phys_free, "A", "Phys Free Info");
124
125static int sysctl_vm_phys_segs(SYSCTL_HANDLER_ARGS);
126SYSCTL_OID(_vm, OID_AUTO, phys_segs, CTLTYPE_STRING | CTLFLAG_RD,
127 NULL, 0, sysctl_vm_phys_segs, "A", "Phys Seg Info");
128
129SYSCTL_INT(_vm, OID_AUTO, ndomains, CTLFLAG_RD,
130 &vm_ndomains, 0, "Number of physical memory domains available.");
131
132static vm_page_t vm_phys_alloc_domain_pages(int domain, int flind, int pool,
133 int order);
109static void _vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end, int flind,
110 int domain);
111static void vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end, int flind);
134static void _vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end, int domain);
135static void vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end);
112static int vm_phys_paddr_to_segind(vm_paddr_t pa);
113static void vm_phys_split_pages(vm_page_t m, int oind, struct vm_freelist *fl,
114 int order);
115
116static __inline int
117vm_rr_selectdomain(void)
118{
119#if MAXMEMDOM > 1

--- 118 unchanged lines hidden (view full) ---

238 fl[order].lcnt--;
239 m->order = VM_NFREEORDER;
240}
241
242/*
243 * Create a physical memory segment.
244 */
245static void
136static int vm_phys_paddr_to_segind(vm_paddr_t pa);
137static void vm_phys_split_pages(vm_page_t m, int oind, struct vm_freelist *fl,
138 int order);
139
140static __inline int
141vm_rr_selectdomain(void)
142{
143#if MAXMEMDOM > 1

--- 118 unchanged lines hidden (view full) ---

262 fl[order].lcnt--;
263 m->order = VM_NFREEORDER;
264}
265
266/*
267 * Create a physical memory segment.
268 */
269static void
246_vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end, int flind, int domain)
270_vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end, int domain)
247{
248 struct vm_phys_seg *seg;
249
250 KASSERT(vm_phys_nsegs < VM_PHYSSEG_MAX,
251 ("vm_phys_create_seg: increase VM_PHYSSEG_MAX"));
252 KASSERT(domain < vm_ndomains,
253 ("vm_phys_create_seg: invalid domain provided"));
254 seg = &vm_phys_segs[vm_phys_nsegs++];
255 while (seg > vm_phys_segs && (seg - 1)->start >= end) {
256 *seg = *(seg - 1);
257 seg--;
258 }
259 seg->start = start;
260 seg->end = end;
261 seg->domain = domain;
271{
272 struct vm_phys_seg *seg;
273
274 KASSERT(vm_phys_nsegs < VM_PHYSSEG_MAX,
275 ("vm_phys_create_seg: increase VM_PHYSSEG_MAX"));
276 KASSERT(domain < vm_ndomains,
277 ("vm_phys_create_seg: invalid domain provided"));
278 seg = &vm_phys_segs[vm_phys_nsegs++];
279 while (seg > vm_phys_segs && (seg - 1)->start >= end) {
280 *seg = *(seg - 1);
281 seg--;
282 }
283 seg->start = start;
284 seg->end = end;
285 seg->domain = domain;
262 seg->free_queues = &vm_phys_free_queues[domain][flind];
263}
264
265static void
286}
287
288static void
266vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end, int flind)
289vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end)
267{
268 int i;
269
270 if (mem_affinity == NULL) {
290{
291 int i;
292
293 if (mem_affinity == NULL) {
271 _vm_phys_create_seg(start, end, flind, 0);
294 _vm_phys_create_seg(start, end, 0);
272 return;
273 }
274
275 for (i = 0;; i++) {
276 if (mem_affinity[i].end == 0)
277 panic("Reached end of affinity info");
278 if (mem_affinity[i].end <= start)
279 continue;
280 if (mem_affinity[i].start > start)
281 panic("No affinity info for start %jx",
282 (uintmax_t)start);
283 if (mem_affinity[i].end >= end) {
295 return;
296 }
297
298 for (i = 0;; i++) {
299 if (mem_affinity[i].end == 0)
300 panic("Reached end of affinity info");
301 if (mem_affinity[i].end <= start)
302 continue;
303 if (mem_affinity[i].start > start)
304 panic("No affinity info for start %jx",
305 (uintmax_t)start);
306 if (mem_affinity[i].end >= end) {
284 _vm_phys_create_seg(start, end, flind,
307 _vm_phys_create_seg(start, end,
285 mem_affinity[i].domain);
286 break;
287 }
308 mem_affinity[i].domain);
309 break;
310 }
288 _vm_phys_create_seg(start, mem_affinity[i].end, flind,
311 _vm_phys_create_seg(start, mem_affinity[i].end,
289 mem_affinity[i].domain);
290 start = mem_affinity[i].end;
291 }
292}
293
294/*
295 * Add a physical memory segment.
296 */
297void
298vm_phys_add_seg(vm_paddr_t start, vm_paddr_t end)
299{
312 mem_affinity[i].domain);
313 start = mem_affinity[i].end;
314 }
315}
316
317/*
318 * Add a physical memory segment.
319 */
320void
321vm_phys_add_seg(vm_paddr_t start, vm_paddr_t end)
322{
323 vm_paddr_t paddr;
300
301 KASSERT((start & PAGE_MASK) == 0,
302 ("vm_phys_define_seg: start is not page aligned"));
303 KASSERT((end & PAGE_MASK) == 0,
304 ("vm_phys_define_seg: end is not page aligned"));
324
325 KASSERT((start & PAGE_MASK) == 0,
326 ("vm_phys_define_seg: start is not page aligned"));
327 KASSERT((end & PAGE_MASK) == 0,
328 ("vm_phys_define_seg: end is not page aligned"));
329
330 /*
331 * Split the physical memory segment if it spans two or more free
332 * list boundaries.
333 */
334 paddr = start;
305#ifdef VM_FREELIST_ISADMA
335#ifdef VM_FREELIST_ISADMA
306 if (start < 16777216) {
307 if (end > 16777216) {
308 vm_phys_create_seg(start, 16777216,
309 VM_FREELIST_ISADMA);
310 vm_phys_create_seg(16777216, end, VM_FREELIST_DEFAULT);
311 } else
312 vm_phys_create_seg(start, end, VM_FREELIST_ISADMA);
313 if (VM_FREELIST_ISADMA >= vm_nfreelists)
314 vm_nfreelists = VM_FREELIST_ISADMA + 1;
315 } else
336 if (paddr < VM_ISADMA_BOUNDARY && end > VM_ISADMA_BOUNDARY) {
337 vm_phys_create_seg(paddr, VM_ISADMA_BOUNDARY);
338 paddr = VM_ISADMA_BOUNDARY;
339 }
316#endif
340#endif
317#ifdef VM_FREELIST_HIGHMEM
318 if (end > VM_HIGHMEM_ADDRESS) {
319 if (start < VM_HIGHMEM_ADDRESS) {
320 vm_phys_create_seg(start, VM_HIGHMEM_ADDRESS,
321 VM_FREELIST_DEFAULT);
322 vm_phys_create_seg(VM_HIGHMEM_ADDRESS, end,
323 VM_FREELIST_HIGHMEM);
324 } else
325 vm_phys_create_seg(start, end, VM_FREELIST_HIGHMEM);
326 if (VM_FREELIST_HIGHMEM >= vm_nfreelists)
327 vm_nfreelists = VM_FREELIST_HIGHMEM + 1;
328 } else
341#ifdef VM_FREELIST_LOWMEM
342 if (paddr < VM_LOWMEM_BOUNDARY && end > VM_LOWMEM_BOUNDARY) {
343 vm_phys_create_seg(paddr, VM_LOWMEM_BOUNDARY);
344 paddr = VM_LOWMEM_BOUNDARY;
345 }
329#endif
346#endif
330 vm_phys_create_seg(start, end, VM_FREELIST_DEFAULT);
347#ifdef VM_FREELIST_DMA32
348 if (paddr < VM_DMA32_BOUNDARY && end > VM_DMA32_BOUNDARY) {
349 vm_phys_create_seg(paddr, VM_DMA32_BOUNDARY);
350 paddr = VM_DMA32_BOUNDARY;
351 }
352#endif
353 vm_phys_create_seg(paddr, end);
331}
332
333/*
334 * Initialize the physical memory allocator.
354}
355
356/*
357 * Initialize the physical memory allocator.
358 *
359 * Requires that vm_page_array is initialized!
335 */
336void
337vm_phys_init(void)
338{
339 struct vm_freelist *fl;
340 struct vm_phys_seg *seg;
360 */
361void
362vm_phys_init(void)
363{
364 struct vm_freelist *fl;
365 struct vm_phys_seg *seg;
341#ifdef VM_PHYSSEG_SPARSE
342 long pages;
366 u_long npages;
367 int dom, flind, freelist, oind, pind, segind;
368
369 /*
370 * Compute the number of free lists, and generate the mapping from the
371 * manifest constants VM_FREELIST_* to the free list indices.
372 *
373 * Initially, the entries of vm_freelist_to_flind[] are set to either
374 * 0 or 1 to indicate which free lists should be created.
375 */
376 npages = 0;
377 for (segind = vm_phys_nsegs - 1; segind >= 0; segind--) {
378 seg = &vm_phys_segs[segind];
379#ifdef VM_FREELIST_ISADMA
380 if (seg->end <= VM_ISADMA_BOUNDARY)
381 vm_freelist_to_flind[VM_FREELIST_ISADMA] = 1;
382 else
343#endif
383#endif
344 int dom, flind, oind, pind, segind;
384#ifdef VM_FREELIST_LOWMEM
385 if (seg->end <= VM_LOWMEM_BOUNDARY)
386 vm_freelist_to_flind[VM_FREELIST_LOWMEM] = 1;
387 else
388#endif
389#ifdef VM_FREELIST_DMA32
390 if (
391#ifdef VM_DMA32_NPAGES_THRESHOLD
392 /*
393 * Create the DMA32 free list only if the amount of
394 * physical memory above physical address 4G exceeds the
395 * given threshold.
396 */
397 npages > VM_DMA32_NPAGES_THRESHOLD &&
398#endif
399 seg->end <= VM_DMA32_BOUNDARY)
400 vm_freelist_to_flind[VM_FREELIST_DMA32] = 1;
401 else
402#endif
403 {
404 npages += atop(seg->end - seg->start);
405 vm_freelist_to_flind[VM_FREELIST_DEFAULT] = 1;
406 }
407 }
408 /* Change each entry into a running total of the free lists. */
409 for (freelist = 1; freelist < VM_NFREELIST; freelist++) {
410 vm_freelist_to_flind[freelist] +=
411 vm_freelist_to_flind[freelist - 1];
412 }
413 vm_nfreelists = vm_freelist_to_flind[VM_NFREELIST - 1];
414 KASSERT(vm_nfreelists > 0, ("vm_phys_init: no free lists"));
415 /* Change each entry into a free list index. */
416 for (freelist = 0; freelist < VM_NFREELIST; freelist++)
417 vm_freelist_to_flind[freelist]--;
345
418
419 /*
420 * Initialize the first_page and free_queues fields of each physical
421 * memory segment.
422 */
346#ifdef VM_PHYSSEG_SPARSE
423#ifdef VM_PHYSSEG_SPARSE
347 pages = 0;
424 npages = 0;
348#endif
349 for (segind = 0; segind < vm_phys_nsegs; segind++) {
350 seg = &vm_phys_segs[segind];
351#ifdef VM_PHYSSEG_SPARSE
425#endif
426 for (segind = 0; segind < vm_phys_nsegs; segind++) {
427 seg = &vm_phys_segs[segind];
428#ifdef VM_PHYSSEG_SPARSE
352 seg->first_page = &vm_page_array[pages];
353 pages += atop(seg->end - seg->start);
429 seg->first_page = &vm_page_array[npages];
430 npages += atop(seg->end - seg->start);
354#else
355 seg->first_page = PHYS_TO_VM_PAGE(seg->start);
356#endif
431#else
432 seg->first_page = PHYS_TO_VM_PAGE(seg->start);
433#endif
434#ifdef VM_FREELIST_ISADMA
435 if (seg->end <= VM_ISADMA_BOUNDARY) {
436 flind = vm_freelist_to_flind[VM_FREELIST_ISADMA];
437 KASSERT(flind >= 0,
438 ("vm_phys_init: ISADMA flind < 0"));
439 } else
440#endif
441#ifdef VM_FREELIST_LOWMEM
442 if (seg->end <= VM_LOWMEM_BOUNDARY) {
443 flind = vm_freelist_to_flind[VM_FREELIST_LOWMEM];
444 KASSERT(flind >= 0,
445 ("vm_phys_init: LOWMEM flind < 0"));
446 } else
447#endif
448#ifdef VM_FREELIST_DMA32
449 if (seg->end <= VM_DMA32_BOUNDARY) {
450 flind = vm_freelist_to_flind[VM_FREELIST_DMA32];
451 KASSERT(flind >= 0,
452 ("vm_phys_init: DMA32 flind < 0"));
453 } else
454#endif
455 {
456 flind = vm_freelist_to_flind[VM_FREELIST_DEFAULT];
457 KASSERT(flind >= 0,
458 ("vm_phys_init: DEFAULT flind < 0"));
459 }
460 seg->free_queues = &vm_phys_free_queues[seg->domain][flind];
357 }
461 }
462
463 /*
464 * Initialize the free queues.
465 */
358 for (dom = 0; dom < vm_ndomains; dom++) {
359 for (flind = 0; flind < vm_nfreelists; flind++) {
360 for (pind = 0; pind < VM_NFREEPOOL; pind++) {
361 fl = vm_phys_free_queues[dom][flind][pind];
362 for (oind = 0; oind < VM_NFREEORDER; oind++)
363 TAILQ_INIT(&fl[oind].pl);
364 }
365 }

--- 73 unchanged lines hidden (view full) ---

439 if (m != NULL)
440 return (m);
441 }
442 }
443 return (NULL);
444}
445
446/*
466 for (dom = 0; dom < vm_ndomains; dom++) {
467 for (flind = 0; flind < vm_nfreelists; flind++) {
468 for (pind = 0; pind < VM_NFREEPOOL; pind++) {
469 fl = vm_phys_free_queues[dom][flind][pind];
470 for (oind = 0; oind < VM_NFREEORDER; oind++)
471 TAILQ_INIT(&fl[oind].pl);
472 }
473 }

--- 73 unchanged lines hidden (view full) ---

547 if (m != NULL)
548 return (m);
549 }
550 }
551 return (NULL);
552}
553
554/*
447 * Find and dequeue a free page on the given free list, with the
448 * specified pool and order
555 * Allocate a contiguous, power of two-sized set of physical pages from the
556 * specified free list. The free list must be specified using one of the
557 * manifest constants VM_FREELIST_*.
558 *
559 * The free page queues must be locked.
449 */
450vm_page_t
560 */
561vm_page_t
451vm_phys_alloc_freelist_pages(int flind, int pool, int order)
562vm_phys_alloc_freelist_pages(int freelist, int pool, int order)
452{
453 vm_page_t m;
454 int dom, domain;
455
563{
564 vm_page_t m;
565 int dom, domain;
566
456 KASSERT(flind < VM_NFREELIST,
457 ("vm_phys_alloc_freelist_pages: freelist %d is out of range", flind));
567 KASSERT(freelist < VM_NFREELIST,
568 ("vm_phys_alloc_freelist_pages: freelist %d is out of range",
569 freelist));
458 KASSERT(pool < VM_NFREEPOOL,
459 ("vm_phys_alloc_freelist_pages: pool %d is out of range", pool));
460 KASSERT(order < VM_NFREEORDER,
461 ("vm_phys_alloc_freelist_pages: order %d is out of range", order));
570 KASSERT(pool < VM_NFREEPOOL,
571 ("vm_phys_alloc_freelist_pages: pool %d is out of range", pool));
572 KASSERT(order < VM_NFREEORDER,
573 ("vm_phys_alloc_freelist_pages: order %d is out of range", order));
462
463 for (dom = 0; dom < vm_ndomains; dom++) {
464 domain = vm_rr_selectdomain();
574 for (dom = 0; dom < vm_ndomains; dom++) {
575 domain = vm_rr_selectdomain();
465 m = vm_phys_alloc_domain_pages(domain, flind, pool, order);
576 m = vm_phys_alloc_domain_pages(domain,
577 vm_freelist_to_flind[freelist], pool, order);
466 if (m != NULL)
467 return (m);
468 }
469 return (NULL);
470}
471
472static vm_page_t
473vm_phys_alloc_domain_pages(int domain, int flind, int pool, int order)

--- 537 unchanged lines hidden ---
578 if (m != NULL)
579 return (m);
580 }
581 return (NULL);
582}
583
584static vm_page_t
585vm_phys_alloc_domain_pages(int domain, int flind, int pool, int order)

--- 537 unchanged lines hidden ---