From 9949853838aaee5d1bb16865f8b72ba2cf986512 Mon Sep 17 00:00:00 2001 From: jdc Date: Sun, 8 Dec 2013 10:12:39 +0000 Subject: [PATCH] Use a double linked list with a static head to track MMU entries. Code from martin@. Tested on SUN4 (4/330), SUN4C (SS2), and SUN4M (Krups, 4/630). --- sys/arch/sparc/sparc/pmap.c | 156 +++++++++++++++++++++--------------- 1 file changed, 93 insertions(+), 63 deletions(-) diff --git a/sys/arch/sparc/sparc/pmap.c b/sys/arch/sparc/sparc/pmap.c index a5d003f26c38..1fd134231d59 100644 --- a/sys/arch/sparc/sparc/pmap.c +++ b/sys/arch/sparc/sparc/pmap.c @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.c,v 1.353 2013/11/25 02:59:14 christos Exp $ */ +/* $NetBSD: pmap.c,v 1.354 2013/12/08 10:12:39 jdc Exp $ */ /* * Copyright (c) 1996 @@ -56,7 +56,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.353 2013/11/25 02:59:14 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.354 2013/12/08 10:12:39 jdc Exp $"); #include "opt_ddb.h" #include "opt_kgdb.h" @@ -279,12 +279,12 @@ pvhead4m(u_int pte) * by flushing (and invalidating) a TLB entry when appropriate before * altering an in-memory page table entry. */ -struct mmuq; struct mmuentry { - TAILQ_ENTRY(mmuentry) me_list; /* usage list link */ + struct { + struct mmuentry *prev, *next; + } me_list; /* usage list link */ TAILQ_ENTRY(mmuentry) me_pmchain; /* pmap owner link */ struct pmap *me_pmap; /* pmap, if in use */ - struct mmuq *me_queue; /* where do we live */ u_short me_vreg; /* associated virtual region/segment */ u_short me_vseg; /* associated virtual region/segment */ u_short me_cookie; /* hardware SMEG/PMEG number */ @@ -295,24 +295,54 @@ struct mmuentry { struct mmuentry *mmusegments; /* allocated in pmap_bootstrap */ struct mmuentry *mmuregions; /* allocated in pmap_bootstrap */ -TAILQ_HEAD(mmuq, mmuentry); -struct mmuq segm_freelist, segm_lru, segm_locked; -struct mmuq region_freelist, region_lru, region_locked; +#if defined(SUN4) || defined(SUN4C) +struct mmuentry segm_freelist, segm_lru, segm_locked; +#if defined(SUN4_MMU3L) +struct mmuentry region_freelist, region_lru, region_locked; +#endif +/* + * We use a double linked list looping through its static head (which + * alway remains on the list), so we can remove any other member from + * a list without knowing which list it is on. + */ +static void inline +mmuq_remove(struct mmuentry *e) +{ + e->me_list.next->me_list.prev = e->me_list.prev; + e->me_list.prev->me_list.next = e->me_list.next; +} -#define MMUQ_INIT(head) TAILQ_INIT(head) +static void inline +mmuq_init(struct mmuentry *e) +{ + memset(e, 0, sizeof(*e)); + e->me_list.next = e; + e->me_list.prev = e; +} -#define MMUQ_REMOVE(elm, field) do { \ - TAILQ_REMOVE(elm->me_queue, elm,field); \ - elm->me_queue = NULL; \ -} while (/*CONSTCOND*/0) +static inline struct mmuentry * +mmuq_first(struct mmuentry *head) +{ + KASSERT(head->me_list.next != head); + return head->me_list.next; +} -#define MMUQ_INSERT_TAIL(head, elm, field) do { \ - TAILQ_INSERT_TAIL(head, elm, field); \ - elm->me_queue = head; \ -} while (/*CONSTCOND*/0) +static inline bool +mmuq_empty(struct mmuentry *head) +{ + return head->me_list.next == head; +} + +static inline void +mmuq_insert_tail(struct mmuentry *head, struct mmuentry *e) +{ + e->me_list.prev = head->me_list.prev; + e->me_list.next = head; + head->me_list.prev->me_list.next = e; + head->me_list.prev = e; +} +#endif -#define MMUQ_EMPTY(head) TAILQ_EMPTY(head) -#define MMUQ_FIRST(head) TAILQ_FIRST(head) int seginval; /* [4/4c] the invalid segment number */ int reginval; /* [4/3mmu] the invalid region number */ @@ -912,7 +942,7 @@ pgt_page_free(struct pool *pp, void *v) { vaddr_t va; paddr_t pa; - bool rv __diagused; + bool rv; va = (vaddr_t)v; rv = pmap_extract(pmap_kernel(), va, &pa); @@ -1545,10 +1575,10 @@ mmu_setup4m_L3(int pagtblptd, struct segmap *sp) /* * MMU management. */ -static int me_alloc(struct mmuq *, struct pmap *, int, int); +static int me_alloc(struct mmuentry *, struct pmap *, int, int); static void me_free(struct pmap *, u_int); #if defined(SUN4_MMU3L) -static int region_alloc(struct mmuq *, struct pmap *, int); +static int region_alloc(struct mmuentry *, struct pmap *, int); static void region_free(struct pmap *, u_int); #endif @@ -1568,7 +1598,7 @@ static void region_free(struct pmap *, u_int); */ static inline int -me_alloc(struct mmuq *mh, struct pmap *newpm, int newvreg, int newvseg) +me_alloc(struct mmuentry *mh, struct pmap *newpm, int newvreg, int newvseg) { struct mmuentry *me; struct pmap *pm; @@ -1578,16 +1608,16 @@ me_alloc(struct mmuq *mh, struct pmap *newpm, int newvreg, int newvseg) struct segmap *sp; /* try free list first */ - if (!MMUQ_EMPTY(&segm_freelist)) { - me = MMUQ_FIRST(&segm_freelist); - MMUQ_REMOVE(me, me_list); + if (!mmuq_empty(&segm_freelist)) { + me = mmuq_first(&segm_freelist); + mmuq_remove(me); #ifdef DEBUG if (me->me_pmap != NULL) panic("me_alloc: freelist entry has pmap"); if (pmapdebug & PDB_MMU_ALLOC) printf("me_alloc: got pmeg %d\n", me->me_cookie); #endif - MMUQ_INSERT_TAIL(mh, me, me_list); + mmuq_insert_tail(mh, me); /* onto on pmap chain; pmap is already locked, if needed */ TAILQ_INSERT_TAIL(&newpm->pm_seglist, me, me_pmchain); @@ -1611,10 +1641,10 @@ me_alloc(struct mmuq *mh, struct pmap *newpm, int newvreg, int newvseg) } /* no luck, take head of LRU list */ - if (MMUQ_EMPTY(&segm_lru)) + if (mmuq_empty(&segm_lru)) panic("me_alloc: all pmegs gone"); - me = MMUQ_FIRST(&segm_lru); + me = mmuq_first(&segm_lru); pm = me->me_pmap; #ifdef DEBUG if (pmapdebug & (PDB_MMU_ALLOC | PDB_MMU_STEAL)) @@ -1628,8 +1658,8 @@ me_alloc(struct mmuq *mh, struct pmap *newpm, int newvreg, int newvseg) * Remove from LRU list, and insert at end of new list * (probably the LRU list again, but so what?). */ - MMUQ_REMOVE(me, me_list); - MMUQ_INSERT_TAIL(mh, me, me_list); + mmuq_remove(me); + mmuq_insert_tail(mh, me); #ifdef DIAGNOSTIC if (mh == &segm_locked) { @@ -1799,7 +1829,7 @@ me_free(struct pmap *pm, u_int pmeg) TAILQ_REMOVE(&pm->pm_seglist, me, me_pmchain); /* off LRU or lock chain */ - MMUQ_REMOVE(me, me_list); + mmuq_remove(me); #ifdef DIAGNOSTIC if (me->me_statp == NULL) panic("me_statp"); @@ -1809,7 +1839,7 @@ me_free(struct pmap *pm, u_int pmeg) /* no associated pmap; on free list */ me->me_pmap = NULL; - MMUQ_INSERT_TAIL(&segm_freelist, me, me_list); + mmuq_insert_tail(&segm_freelist, me); #ifdef DIAGNOSTIC pmap_stats.ps_npmeg_free++; #endif @@ -1820,7 +1850,7 @@ me_free(struct pmap *pm, u_int pmeg) /* XXX - Merge with segm_alloc/segm_free ? */ int -region_alloc(struct mmuq *mh, struct pmap *newpm, int newvr) +region_alloc(struct mmuentry *mh, struct pmap *newpm, int newvr) { struct mmuentry *me; struct pmap *pm; @@ -1828,16 +1858,16 @@ region_alloc(struct mmuq *mh, struct pmap *newpm, int newvr) struct regmap *rp; /* try free list first */ - if (!MMUQ_EMPTY(®ion_freelist)) { - me = MMUQ_FIRST(®ion_freelist); - MMUQ_REMOVE(me, me_list); + if (!mmuq_empty(®ion_freelist)) { + me = mmuq_first(®ion_freelist); + mmuq_remove(me); #ifdef DEBUG if (me->me_pmap != NULL) panic("region_alloc: freelist entry has pmap"); if (pmapdebug & PDB_MMUREG_ALLOC) printf("region_alloc: got smeg 0x%x\n", me->me_cookie); #endif - MMUQ_INSERT_TAIL(mh, me, me_list); + mmuq_insert_tail(mh, me); /* onto on pmap chain; pmap is already locked, if needed */ TAILQ_INSERT_TAIL(&newpm->pm_reglist, me, me_pmchain); @@ -1850,10 +1880,10 @@ region_alloc(struct mmuq *mh, struct pmap *newpm, int newvr) } /* no luck, take head of LRU list */ - if (MMUQ_EMPTY(®ion_lru)) + if (mmuq_empty(®ion_lru)) panic("region_alloc: all smegs gone"); - me = MMUQ_FIRST(®ion_lru); + me = mmuq_first(®ion_lru); pm = me->me_pmap; if (pm == NULL) @@ -1869,8 +1899,8 @@ region_alloc(struct mmuq *mh, struct pmap *newpm, int newvr) * Remove from LRU list, and insert at end of new list * (probably the LRU list again, but so what?). */ - MMUQ_REMOVE(me, me_list); - MMUQ_INSERT_TAIL(mh, me, me_list); + mmuq_remove(me); + mmuq_insert_tail(mh, me); rp = &pm->pm_regmap[me->me_vreg]; ctx = getcontext4(); @@ -1925,16 +1955,16 @@ region_free(struct pmap *pm, u_int smeg) TAILQ_REMOVE(&pm->pm_reglist, me, me_pmchain); /* off LRU or lock chain */ - MMUQ_REMOVE(me, me_list); + mmuq_remove(me); /* no associated pmap; on free list */ me->me_pmap = NULL; - MMUQ_INSERT_TAIL(®ion_freelist, me, me_list); + mmuq_insert_tail(®ion_freelist, me); } static void mmu_pagein_reg(struct pmap *pm, struct regmap *rp, vaddr_t va, - int vr, struct mmuq *mh) + int vr, struct mmuentry *mh) { int i, s, smeg; @@ -1968,8 +1998,8 @@ mmu_pmeg_lock(int pmeg) { struct mmuentry *me = &mmusegments[pmeg]; - MMUQ_REMOVE(me, me_list); - MMUQ_INSERT_TAIL(&segm_locked, me, me_list); + mmuq_remove(me); + mmuq_insert_tail(&segm_locked, me); #ifdef DIAGNOSTIC (*me->me_statp)--; pmap_stats.ps_npmeg_locked++; @@ -1982,8 +2012,8 @@ mmu_pmeg_unlock(int pmeg) { struct mmuentry *me = &mmusegments[pmeg]; - MMUQ_REMOVE(me, me_list); - MMUQ_INSERT_TAIL(&segm_lru, me, me_list); + mmuq_remove(me); + mmuq_insert_tail(&segm_lru, me); #ifdef DIAGNOSTIC (*me->me_statp)--; pmap_stats.ps_npmeg_lru++; @@ -1993,7 +2023,7 @@ mmu_pmeg_unlock(int pmeg) static void mmu_pagein_seg(struct pmap *pm, struct segmap *sp, vaddr_t va, - int vr, int vs, struct mmuq *mh) + int vr, int vs, struct mmuentry *mh) { int s, i, pmeg, *pte; @@ -2291,7 +2321,7 @@ ctx_free(struct pmap *pm) #if defined(SUN4M) || defined(SUN4D) if (CPU_HAS_SRMMU) { - CPU_INFO_ITERATOR i; + int i; cache_flush_context(ctx); tlb_flush_context(ctx, PMAP_CPUSET(pm)); @@ -2637,7 +2667,7 @@ pv_changepte4m(struct vm_page *pg, int bis, int bic) return; for (; pv != NULL; pv = pv->pv_next) { - int tpte __diagused; + int tpte; pm = pv->pv_pmap; /* XXXSMP: should lock pm */ va = pv->pv_va; @@ -3150,13 +3180,13 @@ pmap_bootstrap4_4c(void *top, int nctx, int nregion, int nsegment) /* Initialize MMU resource queues */ #if defined(SUN4_MMU3L) - MMUQ_INIT(®ion_freelist); - MMUQ_INIT(®ion_lru); - MMUQ_INIT(®ion_locked); + mmuq_init(®ion_freelist); + mmuq_init(®ion_lru); + mmuq_init(®ion_locked); #endif - MMUQ_INIT(&segm_freelist); - MMUQ_INIT(&segm_lru); - MMUQ_INIT(&segm_locked); + mmuq_init(&segm_freelist); + mmuq_init(&segm_lru); + mmuq_init(&segm_locked); /* @@ -3310,8 +3340,8 @@ pmap_bootstrap4_4c(void *top, int nctx, int nregion, int nsegment) for (i = 1; i < nctx; i++) prom_setcontext(i, (void *)p, rcookie); - MMUQ_INSERT_TAIL(®ion_locked, - mmureg, me_list); + mmuq_insert_tail(®ion_locked, + mmureg); TAILQ_INSERT_TAIL(&pmap_kernel()->pm_reglist, mmureg, me_pmchain); #ifdef DIAGNOSTIC @@ -3334,7 +3364,7 @@ pmap_bootstrap4_4c(void *top, int nctx, int nregion, int nsegment) prom_setcontext(i, (void *)p, scookie); /* set up the mmu entry */ - MMUQ_INSERT_TAIL(&segm_locked, mmuseg, me_list); + mmuq_insert_tail(&segm_locked, mmuseg); #ifdef DIAGNOSTIC mmuseg->me_statp = &pmap_stats.ps_npmeg_locked; #endif @@ -3412,7 +3442,7 @@ pmap_bootstrap4_4c(void *top, int nctx, int nregion, int nsegment) rcookie++; mmureg = &mmuregions[rcookie]; mmureg->me_cookie = rcookie; - MMUQ_INSERT_TAIL(®ion_freelist, mmureg, me_list); + mmuq_insert_tail(®ion_freelist, mmureg); #ifdef DIAGNOSTIC mmuseg->me_statp = NULL; #endif @@ -3425,7 +3455,7 @@ pmap_bootstrap4_4c(void *top, int nctx, int nregion, int nsegment) scookie = zseg; mmuseg = &mmusegments[scookie]; mmuseg->me_cookie = scookie; - MMUQ_INSERT_TAIL(&segm_freelist, mmuseg, me_list); + mmuq_insert_tail(&segm_freelist, mmuseg); pmap_stats.ps_npmeg_free++; #ifdef DIAGNOSTIC mmuseg->me_statp = NULL;