Module Name: src
Committed By: jdc
Date: Sun Dec 8 10:12:39 UTC 2013
Modified Files:
src/sys/arch/sparc/sparc: pmap.c
Log Message:
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).
To generate a diff of this commit:
cvs rdiff -u -r1.353 -r1.354 src/sys/arch/sparc/sparc/pmap.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/arch/sparc/sparc/pmap.c
diff -u src/sys/arch/sparc/sparc/pmap.c:1.353 src/sys/arch/sparc/sparc/pmap.c:1.354
--- src/sys/arch/sparc/sparc/pmap.c:1.353 Mon Nov 25 02:59:14 2013
+++ src/sys/arch/sparc/sparc/pmap.c Sun Dec 8 10:12:39 2013
@@ -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;
-
-#define MMUQ_INIT(head) TAILQ_INIT(head)
-
-#define MMUQ_REMOVE(elm, field) do { \
- TAILQ_REMOVE(elm->me_queue, elm,field); \
- elm->me_queue = NULL; \
-} while (/*CONSTCOND*/0)
-
-#define MMUQ_INSERT_TAIL(head, elm, field) do { \
- TAILQ_INSERT_TAIL(head, elm, field); \
- elm->me_queue = head; \
-} while (/*CONSTCOND*/0)
+#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;
+}
+
+static void inline
+mmuq_init(struct mmuentry *e)
+{
+ memset(e, 0, sizeof(*e));
+ e->me_list.next = e;
+ e->me_list.prev = e;
+}
+
+static inline struct mmuentry *
+mmuq_first(struct mmuentry *head)
+{
+ KASSERT(head->me_list.next != head);
+ return head->me_list.next;
+}
+
+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 seg
/*
* 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
*/
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 *n
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 *n
}
/* 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 *n
* 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 pma
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 pma
}
/* 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 pma
* 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 b
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,
/* Initialize MMU resource queues */
#if defined(SUN4_MMU3L)
- 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(®ion_freelist);
+ mmuq_init(®ion_lru);
+ mmuq_init(®ion_locked);
+#endif
+ mmuq_init(&segm_freelist);
+ mmuq_init(&segm_lru);
+ mmuq_init(&segm_locked);
/*
@@ -3310,8 +3340,8 @@ pmap_bootstrap4_4c(void *top, int nctx,
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,
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,
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,
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;