Module Name: src Committed By: uebayasi Date: Sun Nov 14 15:06:34 UTC 2010
Modified Files: src/sys/uvm: uvm_page.c uvm_page.h uvm_pglist.c Log Message: Be a little more friendly to dynamic physical segment registration. Maintain an array of pointer to struct vm_physseg, instead of struct array. So that VM subsystem can take its pointer safely. Pointer to this struct will replace raw paddr_t usage in the future. Dynamic removal is not supported yet. Only MD data structure changes, no kernel bump needed. Tested on i386, amd64, powerpc/ibm40x, arm11. To generate a diff of this commit: cvs rdiff -u -r1.163 -r1.164 src/sys/uvm/uvm_page.c cvs rdiff -u -r1.66 -r1.67 src/sys/uvm/uvm_page.h cvs rdiff -u -r1.46 -r1.47 src/sys/uvm/uvm_pglist.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/uvm/uvm_page.c diff -u src/sys/uvm/uvm_page.c:1.163 src/sys/uvm/uvm_page.c:1.164 --- src/sys/uvm/uvm_page.c:1.163 Fri Nov 12 05:23:41 2010 +++ src/sys/uvm/uvm_page.c Sun Nov 14 15:06:34 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: uvm_page.c,v 1.163 2010/11/12 05:23:41 uebayasi Exp $ */ +/* $NetBSD: uvm_page.c,v 1.164 2010/11/14 15:06:34 uebayasi Exp $ */ /* * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -97,7 +97,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uvm_page.c,v 1.163 2010/11/12 05:23:41 uebayasi Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uvm_page.c,v 1.164 2010/11/14 15:06:34 uebayasi Exp $"); #include "opt_ddb.h" #include "opt_uvmhist.h" @@ -125,9 +125,13 @@ * physical memory config is stored in vm_physmem. */ -struct vm_physseg vm_physmem[VM_PHYSSEG_MAX]; /* XXXCDC: uvm.physmem */ -int vm_nphysseg = 0; /* XXXCDC: uvm.nphysseg */ -#define vm_nphysmem vm_nphysseg +SIMPLEQ_HEAD(vm_physseg_freelist, vm_physseg); + +struct vm_physseg *vm_physmem_ptrs[VM_PHYSSEG_MAX]; +int vm_nphysmem = 0; +static struct vm_physseg vm_physmem_store[VM_PHYSSEG_MAX]; +static struct vm_physseg_freelist vm_physmem_freelist = + SIMPLEQ_HEAD_INITIALIZER(vm_physmem_freelist); /* * Some supported CPUs in a given architecture don't support all @@ -181,6 +185,15 @@ static void uvm_pageinsert(struct uvm_object *, struct vm_page *); static void uvm_pageremove(struct uvm_object *, struct vm_page *); +static struct vm_physseg *uvm_physseg_alloc( + struct vm_physseg_freelist * const, struct vm_physseg **, int, + const paddr_t, const paddr_t); +static void uvm_physseg_free(struct vm_physseg_freelist *, + struct vm_physseg **, struct vm_physseg *); +static void uvm_physseg_init(void); +static void uvm_physseg_insert(struct vm_physseg *, + struct vm_physseg **, int); +static void uvm_physseg_remove(struct vm_physseg **, struct vm_physseg *); /* * per-object tree of pages @@ -684,7 +697,6 @@ panic("uvm_page_physget: out of memory!"); vm_nphysmem--; for (x = lcv ; x < vm_nphysmem ; x++) - /* structure copy */ VM_PHYSMEM_PTR_SWAP(x, x + 1); } return (true); @@ -702,7 +714,6 @@ panic("uvm_page_physget: out of memory!"); vm_nphysmem--; for (x = lcv ; x < vm_nphysmem ; x++) - /* structure copy */ VM_PHYSMEM_PTR_SWAP(x, x + 1); } return (true); @@ -733,7 +744,6 @@ panic("uvm_page_physget: out of memory!"); vm_nphysmem--; for (x = lcv ; x < vm_nphysmem ; x++) - /* structure copy */ VM_PHYSMEM_PTR_SWAP(x, x + 1); } return (true); @@ -768,31 +778,18 @@ uvm_page_physload(paddr_t start, paddr_t end, paddr_t avail_start, paddr_t avail_end, int free_list) { - int preload, lcv; - psize_t npages; - struct vm_page *pgs; - struct vm_physseg *ps; + struct vm_physseg *seg; + int lcv; - if (uvmexp.pagesize == 0) - panic("uvm_page_physload: page size not set!"); if (free_list >= VM_NFREELIST || free_list < VM_FREELIST_DEFAULT) panic("uvm_page_physload: bad free list %d", free_list); - if (start >= end) - panic("uvm_page_physload: start >= end"); - - /* - * do we have room? - */ - if (vm_nphysmem == VM_PHYSSEG_MAX) { - printf("uvm_page_physload: unable to load physical memory " - "segment\n"); - printf("\t%d segments allocated, ignoring 0x%llx -> 0x%llx\n", - VM_PHYSSEG_MAX, (long long)start, (long long)end); - printf("\tincrease VM_PHYSSEG_MAX\n"); - return; - } + seg = uvm_physseg_alloc(&vm_physmem_freelist, vm_physmem_ptrs, + vm_nphysmem, start, end); + KASSERT(seg != NULL); + seg->avail_start = avail_start; + seg->avail_end = avail_end; /* * check to see if this is a "preload" (i.e. uvm_page_init hasn't been * called yet, so malloc is not available). @@ -802,112 +799,184 @@ if (VM_PHYSMEM_PTR(lcv)->pgs) break; } - preload = (lcv == vm_nphysmem); + if (lcv == vm_nphysmem) { + seg->pgs = NULL; + seg->lastpg = NULL; + seg->free_list = free_list; + } else { + panic("uvm_page_physload: " + "tried to add RAM after uvm_page_init"); + } + vm_nphysmem++; +} - /* - * if VM is already running, attempt to malloc() vm_page structures - */ +#if 0 +void +uvm_page_physunload(void *cookie) +{ + struct vm_physseg *seg = cookie; - if (!preload) { - panic("uvm_page_physload: tried to add RAM after vm_mem_init"); - } else { - pgs = NULL; - npages = 0; + panic("memory unload is not supported yet"); + + uvm_physseg_free(&vm_physmem_freelist, vm_physmem_ptrs, seg); + vm_nphysmem--; +} +#endif + +int uvm_physseg_inited; + +static struct vm_physseg * +uvm_physseg_alloc(struct vm_physseg_freelist *freelist, + struct vm_physseg **segs, int nsegs, + const paddr_t start, const paddr_t end) +{ + struct vm_physseg *ps; + + if (uvmexp.pagesize == 0) + panic("uvm_page_physload: page size not set!"); + if (start >= end) + panic("uvm_page_physload: start >= end"); + if (nsegs == VM_PHYSSEG_MAX) + panic("uvm_page_physload: unable to load physical memory " + "segment\n" + "\t%d segments allocated, ignoring 0x%llx -> 0x%llx\n" + "\tincrease VM_PHYSSEG_MAX\n", + VM_PHYSSEG_MAX, (long long)start, (long long)end); + + if (uvm_physseg_inited == 0) { + uvm_physseg_inited = 1; + uvm_physseg_init(); } - /* - * now insert us in the proper place in vm_physmem[] - */ + ps = SIMPLEQ_FIRST(freelist); + KASSERT(ps != NULL); + SIMPLEQ_REMOVE_HEAD(freelist, list); + + ps->start = start; + ps->end = end; + uvm_physseg_insert(ps, segs, nsegs); + return ps; +} + +void +uvm_physseg_free(struct vm_physseg_freelist *freelist, + struct vm_physseg **segs, struct vm_physseg *seg) +{ + + uvm_physseg_remove(segs, seg); + SIMPLEQ_INSERT_TAIL(freelist, seg, list); +} + +static void +uvm_physseg_init(void) +{ + int lcv; + + for (lcv = 0; lcv < VM_PHYSSEG_MAX; lcv++) { + SIMPLEQ_INSERT_TAIL(&vm_physmem_freelist, + &vm_physmem_store[lcv], list); + } +} + +static void +uvm_physseg_insert(struct vm_physseg *ps, + struct vm_physseg **segs, int nsegs) +{ #if (VM_PHYSSEG_STRAT == VM_PSTRAT_RANDOM) /* random: put it at the end (easy!) */ - ps = VM_PHYSMEM_PTR(vm_nphysmem); + segs[nsegs] = ps; #elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH) { + int lcv; int x; /* sort by address for binary search */ - for (lcv = 0 ; lcv < vm_nphysmem ; lcv++) - if (start < VM_PHYSMEM_PTR(lcv)->start) + for (lcv = 0 ; lcv < nsegs ; lcv++) + if (ps->start < segs[lcv]->start) break; - ps = VM_PHYSMEM_PTR(lcv); /* move back other entries, if necessary ... */ - for (x = vm_nphysmem ; x > lcv ; x--) - /* structure copy */ - VM_PHYSMEM_PTR_SWAP(x, x - 1); + for (x = nsegs ; x > lcv ; x--) + segs[x] = segs[x - 1]; + segs[lcv] = ps; } #elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BIGFIRST) { + int lcv; int x; /* sort by largest segment first */ - for (lcv = 0 ; lcv < vm_nphysmem ; lcv++) - if ((end - start) > - (VM_PHYSMEM_PTR(lcv)->end - VM_PHYSMEM_PTR(lcv)->start)) + for (lcv = 0 ; lcv < nsegs ; lcv++) + if ((ps->end - ps->start) > + (segs[lcv]->end - segs[lcv]->start)) break; - ps = VM_PHYSMEM_PTR(lcv); /* move back other entries, if necessary ... */ - for (x = vm_nphysmem ; x > lcv ; x--) - /* structure copy */ - VM_PHYSMEM_PTR_SWAP(x, x - 1); + for (x = nsegs ; x > lcv ; x--) + segs[x] = segs[x - 1]; + segs[lcv] = ps; } #else panic("uvm_page_physload: unknown physseg strategy selected!"); #endif +} - ps->start = start; - ps->end = end; - ps->avail_start = avail_start; - ps->avail_end = avail_end; - if (preload) { - ps->pgs = NULL; - } else { - ps->pgs = pgs; - ps->lastpg = pgs + npages; - } - ps->free_list = free_list; - vm_nphysmem++; +static void +uvm_physseg_remove(struct vm_physseg **segs, struct vm_physseg *seg) +{ + struct vm_physseg **segp; - if (!preload) { - uvmpdpol_reinit(); + for (segp = segs; segp < segs + VM_PHYSSEG_MAX; segp++) + if (*segp == seg) + break; + if (segp == segs + VM_PHYSSEG_MAX) + panic("unknown segment: %p", seg); + while (segp + 1 < segs + VM_PHYSSEG_MAX) { + *segp = *(segp + 1); + segp++; } + *segp = NULL; } /* - * when VM_PHYSSEG_MAX is 1, we can simplify these functions + * vm_physseg_find: find vm_physseg structure that belongs to a PA */ +#define VM_PHYSSEG_OP_PF 1 +#define VM_PHYSSEG_OP_PG 2 + #if VM_PHYSSEG_MAX == 1 -static inline int vm_physseg_find_contig(struct vm_physseg *, int, paddr_t, int *); +#define VM_PHYSSEG_FIND vm_physseg_find_contig #elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH) -static inline int vm_physseg_find_bsearch(struct vm_physseg *, int, paddr_t, int *); +#define VM_PHYSSEG_FIND vm_physseg_find_bsearch #else -static inline int vm_physseg_find_linear(struct vm_physseg *, int, paddr_t, int *); +#define VM_PHYSSEG_FIND vm_physseg_find_linear #endif -/* - * vm_physseg_find: find vm_physseg structure that belongs to a PA - */ +static inline int VM_PHYSSEG_FIND(struct vm_physseg **, int, int, + paddr_t, const struct vm_page *, int *); +static inline bool vm_physseg_within_p(struct vm_physseg *, int, paddr_t, + const struct vm_page *, int *); +static inline bool vm_physseg_ge_p(struct vm_physseg *, int, paddr_t, + const struct vm_page *, int *); +static inline bool vm_physseg_lt_p(struct vm_physseg *, int, paddr_t, + const struct vm_page *, int *); + int vm_physseg_find(paddr_t pframe, int *offp) { -#if VM_PHYSSEG_MAX == 1 - return vm_physseg_find_contig(vm_physmem, vm_nphysseg, pframe, offp); -#elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH) - return vm_physseg_find_bsearch(vm_physmem, vm_nphysseg, pframe, offp); -#else - return vm_physseg_find_linear(vm_physmem, vm_nphysseg, pframe, offp); -#endif + return VM_PHYSSEG_FIND(vm_physmem_ptrs, vm_nphysmem, VM_PHYSSEG_OP_PF, + pframe, NULL, offp); } #if VM_PHYSSEG_MAX == 1 static inline int -vm_physseg_find_contig(struct vm_physseg *segs, int nsegs, paddr_t pframe, int *offp) +vm_physseg_find_contig(struct vm_physseg **segs, int nsegs, int op, + paddr_t pframe, const struct vm_page *pg, int *offp) { /* 'contig' case */ - if (pframe >= segs[0].start && pframe < segs[0].end) { - if (offp) - *offp = pframe - segs[0].start; + if (nsegs == 0) + return(-1); + if (vm_physseg_within_p(segs[0], op, pframe, pg, offp)) { return(0); } return(-1); @@ -916,7 +985,8 @@ #elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH) static inline int -vm_physseg_find_bsearch(struct vm_physseg *segs, int nsegs, paddr_t pframe, int *offp) +vm_physseg_find_bsearch(struct vm_physseg **segs, int nsegs, int op, + paddr_t pframe, const struct vm_page *pg, int *offp) { /* binary search for it */ u_int start, len, try; @@ -938,11 +1008,9 @@ try = start + (len / 2); /* try in the middle */ /* start past our try? */ - if (pframe >= segs[try].start) { + if (vm_physseg_ge_p(segs[try], op, pframe, pg, offp)) { /* was try correct? */ - if (pframe < segs[try].end) { - if (offp) - *offp = pframe - segs[try].start; + if (vm_physseg_lt_p(segs[try], op, pframe, pg, offp)) { return(try); /* got it */ } start = try + 1; /* next time, start here */ @@ -960,16 +1028,14 @@ #else static inline int -vm_physseg_find_linear(struct vm_physseg *segs, int nsegs, paddr_t pframe, int *offp) +vm_physseg_find_linear(struct vm_physseg **segs, int nsegs, int op, + paddr_t pframe, const struct vm_page *pg, int *offp) { /* linear search for it */ int lcv; for (lcv = 0; lcv < nsegs; lcv++) { - if (pframe >= segs[lcv].start && - pframe < segs[lcv].end) { - if (offp) - *offp = pframe - segs[lcv].start; + if (vm_physseg_within_p(segs[lcv], op, pframe, pg, offp)) { return(lcv); /* got it */ } } @@ -977,6 +1043,49 @@ } #endif +static inline bool +vm_physseg_within_p(struct vm_physseg *seg, int op, paddr_t pframe, + const struct vm_page *pg, int *offp) +{ + + return vm_physseg_ge_p(seg, op, pframe, pg, offp) && + vm_physseg_lt_p(seg, op, pframe, pg, offp); +} + +static inline bool +vm_physseg_ge_p(struct vm_physseg *seg, int op, paddr_t pframe, + const struct vm_page *pg, int *offp) +{ + + switch (op) { + case VM_PHYSSEG_OP_PF: + if (offp) + *offp = pframe - seg->start; + return pframe >= seg->start; + case VM_PHYSSEG_OP_PG: + if (offp) + *offp = pg - seg->pgs; + return pg >= seg->pgs; + default: + return false; + } +} + +static inline bool +vm_physseg_lt_p(struct vm_physseg *seg, int op, paddr_t pframe, + const struct vm_page *pg, int *offp) +{ + + switch (op) { + case VM_PHYSSEG_OP_PF: + return pframe < seg->end; + case VM_PHYSSEG_OP_PG: + return pg < seg->lastpg; + default: + return false; + } +} + /* * PHYS_TO_VM_PAGE: find vm_page for a PA. used by MI code to get vm_pages * back from an I/O mapping (ugh!). used in some MD code as well. Index: src/sys/uvm/uvm_page.h diff -u src/sys/uvm/uvm_page.h:1.66 src/sys/uvm/uvm_page.h:1.67 --- src/sys/uvm/uvm_page.h:1.66 Fri Nov 12 07:59:24 2010 +++ src/sys/uvm/uvm_page.h Sun Nov 14 15:06:34 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: uvm_page.h,v 1.66 2010/11/12 07:59:24 uebayasi Exp $ */ +/* $NetBSD: uvm_page.h,v 1.67 2010/11/14 15:06:34 uebayasi Exp $ */ /* * Copyright (c) 1997 Charles D. Cranor and Washington University. @@ -238,6 +238,8 @@ int free_list; /* which free list they belong on */ struct vm_page *pgs; /* vm_page structures (from start) */ struct vm_page *lastpg; /* vm_page structure for end */ + SIMPLEQ_ENTRY(vm_physseg) list; + #ifdef __HAVE_PMAP_PHYSSEG struct pmap_physseg pmseg; /* pmap specific (MD) data */ #endif @@ -255,12 +257,14 @@ * physical memory config is stored in vm_physmem. */ -#define VM_PHYSMEM_PTR(i) (&vm_physmem[i]) -#define VM_PHYSMEM_PTR_SWAP(i, j) \ - do { vm_physmem[(i)] = vm_physmem[(j)]; } while (0) +#define VM_PHYSMEM_PTR(i) (vm_physmem_ptrs[i]) +#define VM_PHYSMEM_PTR_SWAP(i, j) \ + do { VM_PHYSMEM_PTR(i) = VM_PHYSMEM_PTR(j); } while (0) + +extern struct vm_physseg *vm_physmem_ptrs[VM_PHYSSEG_MAX]; +extern int vm_nphysmem; -extern struct vm_physseg vm_physmem[VM_PHYSSEG_MAX]; -extern int vm_nphysseg; +#define vm_nphysseg vm_nphysmem /* XXX backward compat */ /* * prototypes: the following prototypes define the interface to pages Index: src/sys/uvm/uvm_pglist.c diff -u src/sys/uvm/uvm_pglist.c:1.46 src/sys/uvm/uvm_pglist.c:1.47 --- src/sys/uvm/uvm_pglist.c:1.46 Thu Jun 17 03:13:58 2010 +++ src/sys/uvm/uvm_pglist.c Sun Nov 14 15:06:34 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: uvm_pglist.c,v 1.46 2010/06/17 03:13:58 mrg Exp $ */ +/* $NetBSD: uvm_pglist.c,v 1.47 2010/11/14 15:06:34 uebayasi Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uvm_pglist.c,v 1.46 2010/06/17 03:13:58 mrg Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uvm_pglist.c,v 1.47 2010/11/14 15:06:34 uebayasi Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -133,7 +133,7 @@ #endif #ifdef PGALLOC_VERBOSE printf("pgalloc: contig %d pgs from psi %ld\n", num, - (long)(ps - vm_physmem)); + (long)(ps - VM_PHYSMEM_PTR(0))); #endif KASSERT(mutex_owned(&uvm_fpageqlock)); @@ -164,11 +164,11 @@ * Make sure this is a managed physical page. */ - if (vm_physseg_find(try, &cidx) != ps - vm_physmem) + if (vm_physseg_find(try, &cidx) != ps - VM_PHYSMEM_PTR(0)) panic("pgalloc contig: botch1"); if (cidx != try - ps->start) panic("pgalloc contig: botch2"); - if (vm_physseg_find(try + num - 1, &cidx) != ps - vm_physmem) + if (vm_physseg_find(try + num - 1, &cidx) != ps - VM_PHYSMEM_PTR(0)) panic("pgalloc contig: botch3"); if (cidx != try - ps->start + num - 1) panic("pgalloc contig: botch4"); @@ -246,12 +246,12 @@ for (fl = 0; fl < VM_NFREELIST; fl++) { #if (VM_PHYSSEG_STRAT == VM_PSTRAT_BIGFIRST) - for (psi = vm_nphysseg - 1 ; psi >= 0 ; psi--) + for (psi = vm_nphysmem - 1 ; psi >= 0 ; psi--) #else - for (psi = 0 ; psi < vm_nphysseg ; psi++) + for (psi = 0 ; psi < vm_nphysmem ; psi++) #endif { - ps = &vm_physmem[psi]; + ps = VM_PHYSMEM_PTR(psi); if (ps->free_list != fl) continue; @@ -292,7 +292,7 @@ #endif #ifdef PGALLOC_VERBOSE printf("pgalloc: simple %d pgs from psi %ld\n", num, - (long)(ps - vm_physmem)); + (long)(ps - VM_PHYSMEM_PTR(0))); #endif KASSERT(mutex_owned(&uvm_fpageqlock)); @@ -303,7 +303,7 @@ for (try = max(atop(low), ps->avail_start); try < limit; try ++) { #ifdef DEBUG - if (vm_physseg_find(try, &cidx) != ps - vm_physmem) + if (vm_physseg_find(try, &cidx) != ps - VM_PHYSMEM_PTR(0)) panic("pgalloc simple: botch1"); if (cidx != (try - ps->start)) panic("pgalloc simple: botch2"); @@ -345,12 +345,12 @@ for (fl = 0; fl < VM_NFREELIST; fl++) { #if (VM_PHYSSEG_STRAT == VM_PSTRAT_BIGFIRST) - for (psi = vm_nphysseg - 1 ; psi >= 0 ; psi--) + for (psi = vm_nphysmem - 1 ; psi >= 0 ; psi--) #else - for (psi = 0 ; psi < vm_nphysseg ; psi++) + for (psi = 0 ; psi < vm_nphysmem ; psi++) #endif { - ps = &vm_physmem[psi]; + ps = VM_PHYSMEM_PTR(psi); if (ps->free_list != fl) continue;