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).
This commit is contained in:
jdc 2013-12-08 10:12:39 +00:00
parent 2098c8504e
commit 9949853838

View File

@ -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 <sys/cdefs.h>
__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(&region_freelist)) {
me = MMUQ_FIRST(&region_freelist);
MMUQ_REMOVE(me, me_list);
if (!mmuq_empty(&region_freelist)) {
me = mmuq_first(&region_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(&region_lru))
if (mmuq_empty(&region_lru))
panic("region_alloc: all smegs gone");
me = MMUQ_FIRST(&region_lru);
me = mmuq_first(&region_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(&region_freelist, me, me_list);
mmuq_insert_tail(&region_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(&region_freelist);
MMUQ_INIT(&region_lru);
MMUQ_INIT(&region_locked);
mmuq_init(&region_freelist);
mmuq_init(&region_lru);
mmuq_init(&region_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(&region_locked,
mmureg, me_list);
mmuq_insert_tail(&region_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(&region_freelist, mmureg, me_list);
mmuq_insert_tail(&region_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;