Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/alpha When removing mappings, hang PV entries to be...



details:   https://anonhg.NetBSD.org/src/rev/f4b9d3e26801
branches:  trunk
changeset: 379410:f4b9d3e26801
user:      thorpej <thorpej%NetBSD.org@localhost>
date:      Sun May 30 14:06:37 2021 +0000

description:
When removing mappings, hang PV entries to be freed off of the
pmap_tlb_context structure, and free them back in bulk after we
release all of our locks (as we do with PT pages that are freed).

diffstat:

 sys/arch/alpha/alpha/pmap.c   |  183 ++++++++++++++++++++++++-----------------
 sys/arch/alpha/include/pmap.h |    5 +-
 2 files changed, 109 insertions(+), 79 deletions(-)

diffs (truncated from 333 to 300 lines):

diff -r 9052cdadfd95 -r f4b9d3e26801 sys/arch/alpha/alpha/pmap.c
--- a/sys/arch/alpha/alpha/pmap.c       Sun May 30 13:34:21 2021 +0000
+++ b/sys/arch/alpha/alpha/pmap.c       Sun May 30 14:06:37 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.c,v 1.288 2021/05/30 13:34:21 thorpej Exp $ */
+/* $NetBSD: pmap.c,v 1.289 2021/05/30 14:06:37 thorpej Exp $ */
 
 /*-
  * Copyright (c) 1998, 1999, 2000, 2001, 2007, 2008, 2020
@@ -135,7 +135,7 @@
 
 #include <sys/cdefs.h>                 /* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.288 2021/05/30 13:34:21 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.289 2021/05/30 14:06:37 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -432,6 +432,71 @@ pmap_activation_lock(pmap_t const pmap)
 #endif /* MULTIPROCESSOR */
 
 /*
+ * TLB context structure; see description in "TLB management" section
+ * below.
+ */
+#define        TLB_CTX_MAXVA           8
+#define        TLB_CTX_ALLVA           PAGE_MASK
+struct pmap_tlb_context {
+       uintptr_t               t_addrdata[TLB_CTX_MAXVA];
+       pmap_t                  t_pmap;
+       struct pmap_pagelist    t_freeptq;
+       struct pmap_pvlist      t_freepvq;
+};
+
+/*
+ * Internal routines
+ */
+static void    alpha_protection_init(void);
+static pt_entry_t pmap_remove_mapping(pmap_t, vaddr_t, pt_entry_t *, bool,
+                                     pv_entry_t *,
+                                     struct pmap_tlb_context *);
+static void    pmap_changebit(struct vm_page *, pt_entry_t, pt_entry_t,
+                              struct pmap_tlb_context *);
+
+/*
+ * PT page management functions.
+ */
+static int     pmap_ptpage_alloc(pmap_t, pt_entry_t *, int);
+static void    pmap_ptpage_free(pmap_t, pt_entry_t *,
+                                struct pmap_tlb_context *);
+static void    pmap_l3pt_delref(pmap_t, vaddr_t, pt_entry_t *,
+                    struct pmap_tlb_context *);
+static void    pmap_l2pt_delref(pmap_t, pt_entry_t *, pt_entry_t *,
+                    struct pmap_tlb_context *);
+static void    pmap_l1pt_delref(pmap_t, pt_entry_t *);
+
+static void    *pmap_l1pt_alloc(struct pool *, int);
+static void    pmap_l1pt_free(struct pool *, void *);
+
+static struct pool_allocator pmap_l1pt_allocator = {
+       pmap_l1pt_alloc, pmap_l1pt_free, 0,
+};
+
+static int     pmap_l1pt_ctor(void *, void *, int);
+
+/*
+ * PV table management functions.
+ */
+static int     pmap_pv_enter(pmap_t, struct vm_page *, vaddr_t, pt_entry_t *,
+                             bool, pv_entry_t);
+static void    pmap_pv_remove(pmap_t, struct vm_page *, vaddr_t, bool,
+                              pv_entry_t *, struct pmap_tlb_context *);
+static void    *pmap_pv_page_alloc(struct pool *, int);
+static void    pmap_pv_page_free(struct pool *, void *);
+
+static struct pool_allocator pmap_pv_page_allocator = {
+       pmap_pv_page_alloc, pmap_pv_page_free, 0,
+};
+
+#ifdef DEBUG
+void   pmap_pv_dump(paddr_t);
+#endif
+
+#define        pmap_pv_alloc()         pool_cache_get(&pmap_pv_cache, PR_NOWAIT)
+#define        pmap_pv_free(pv)        pool_cache_put(&pmap_pv_cache, (pv))
+
+/*
  * Generic routine for freeing pages on a pmap_pagelist back to
  * the system.
  */
@@ -447,6 +512,21 @@ pmap_pagelist_free(struct pmap_pagelist 
 }
 
 /*
+ * Generic routine for freeing a list of PV entries back to the
+ * system.
+ */
+static void
+pmap_pvlist_free(struct pmap_pvlist * const list)
+{
+       pv_entry_t pv;
+
+       while ((pv = LIST_FIRST(list)) != NULL) {
+               LIST_REMOVE(pv, pv_link);
+               pmap_pv_free(pv);
+       }
+}
+
+/*
  * TLB management.
  *
  * TLB invalidations need to be performed on local and remote CPUs
@@ -518,9 +598,6 @@ pmap_pagelist_free(struct pmap_pagelist 
  * window size (defined as 64KB on alpha in <machine/vmparam.h>).
  */
 
-#define        TLB_CTX_MAXVA           8
-#define        TLB_CTX_ALLVA           PAGE_MASK
-
 #define        TLB_CTX_F_ASM           __BIT(0)
 #define        TLB_CTX_F_IMB           __BIT(1)
 #define        TLB_CTX_F_KIMB          __BIT(2)
@@ -538,12 +615,6 @@ pmap_pagelist_free(struct pmap_pagelist 
 #define        TLB_CTX_SETVA(ctx, i, va)                                       \
        (ctx)->t_addrdata[(i)] = (va) | ((ctx)->t_addrdata[(i)] & PAGE_MASK)
 
-struct pmap_tlb_context {
-       uintptr_t       t_addrdata[TLB_CTX_MAXVA];
-       pmap_t          t_pmap;
-       struct pmap_pagelist t_freeptq;
-};
-
 static struct {
        kmutex_t        lock;
        struct evcnt    events;
@@ -689,6 +760,7 @@ pmap_tlb_context_init(struct pmap_tlb_co
        tlbctx->t_addrdata[1] = flags;
        tlbctx->t_pmap = NULL;
        LIST_INIT(&tlbctx->t_freeptq);
+       LIST_INIT(&tlbctx->t_freepvq);
 }
 
 static void
@@ -1081,65 +1153,18 @@ pmap_tlb_shootdown_ipi(struct cpu_info *
 }
 #endif /* MULTIPROCESSOR */
 
-static __inline void
-pmap_tlb_ptpage_drain(struct pmap_tlb_context * const tlbctx)
+static inline void
+pmap_tlb_context_drain(struct pmap_tlb_context * const tlbctx)
 {
-       pmap_pagelist_free(&tlbctx->t_freeptq);
+       if (! LIST_EMPTY(&tlbctx->t_freeptq)) {
+               pmap_pagelist_free(&tlbctx->t_freeptq);
+       }
+       if (! LIST_EMPTY(&tlbctx->t_freepvq)) {
+               pmap_pvlist_free(&tlbctx->t_freepvq);
+       }
 }
 
 /*
- * Internal routines
- */
-static void    alpha_protection_init(void);
-static pt_entry_t pmap_remove_mapping(pmap_t, vaddr_t, pt_entry_t *, bool,
-                                     pv_entry_t *,
-                                     struct pmap_tlb_context *);
-static void    pmap_changebit(struct vm_page *, pt_entry_t, pt_entry_t,
-                              struct pmap_tlb_context *);
-
-/*
- * PT page management functions.
- */
-static int     pmap_ptpage_alloc(pmap_t, pt_entry_t *, int);
-static void    pmap_ptpage_free(pmap_t, pt_entry_t *,
-                                struct pmap_tlb_context *);
-static void    pmap_l3pt_delref(pmap_t, vaddr_t, pt_entry_t *,
-                    struct pmap_tlb_context *);
-static void    pmap_l2pt_delref(pmap_t, pt_entry_t *, pt_entry_t *,
-                    struct pmap_tlb_context *);
-static void    pmap_l1pt_delref(pmap_t, pt_entry_t *);
-
-static void    *pmap_l1pt_alloc(struct pool *, int);
-static void    pmap_l1pt_free(struct pool *, void *);
-
-static struct pool_allocator pmap_l1pt_allocator = {
-       pmap_l1pt_alloc, pmap_l1pt_free, 0,
-};
-
-static int     pmap_l1pt_ctor(void *, void *, int);
-
-/*
- * PV table management functions.
- */
-static int     pmap_pv_enter(pmap_t, struct vm_page *, vaddr_t, pt_entry_t *,
-                             bool, pv_entry_t);
-static void    pmap_pv_remove(pmap_t, struct vm_page *, vaddr_t, bool,
-                              pv_entry_t *);
-static void    *pmap_pv_page_alloc(struct pool *, int);
-static void    pmap_pv_page_free(struct pool *, void *);
-
-static struct pool_allocator pmap_pv_page_allocator = {
-       pmap_pv_page_alloc, pmap_pv_page_free, 0,
-};
-
-#ifdef DEBUG
-void   pmap_pv_dump(paddr_t);
-#endif
-
-#define        pmap_pv_alloc()         pool_cache_get(&pmap_pv_cache, PR_NOWAIT)
-#define        pmap_pv_free(pv)        pool_cache_put(&pmap_pv_cache, (pv))
-
-/*
  * ASN management functions.
  */
 static u_int   pmap_asn_alloc(pmap_t, struct cpu_info *);
@@ -1721,6 +1746,8 @@ pmap_remove_internal(pmap_t pmap, vaddr_
                pmap_tlb_shootnow(tlbctx);
                /* kernel PT pages are never freed. */
                KASSERT(LIST_EMPTY(&tlbctx->t_freeptq));
+               /* ...but we might have freed PV entries. */
+               pmap_tlb_context_drain(tlbctx);
                TLB_COUNT(reason_remove_kernel);
 
                return;
@@ -1803,7 +1830,7 @@ pmap_remove_internal(pmap_t pmap, vaddr_
        PMAP_MAP_TO_HEAD_UNLOCK();
        PMAP_UNLOCK(pmap);
        pmap_tlb_shootnow(tlbctx);
-       pmap_tlb_ptpage_drain(tlbctx);
+       pmap_tlb_context_drain(tlbctx);
        TLB_COUNT(reason_remove_user);
 }
 
@@ -1895,7 +1922,7 @@ pmap_page_protect(struct vm_page *pg, vm
        mutex_exit(lock);
        PMAP_HEAD_TO_MAP_UNLOCK();
        pmap_tlb_shootnow(&tlbctx);
-       pmap_tlb_ptpage_drain(&tlbctx);
+       pmap_tlb_context_drain(&tlbctx);
        TLB_COUNT(reason_page_protect_none);
 }
 
@@ -2007,7 +2034,7 @@ pmap_enter_l2pt_delref(pmap_t const pmap
        pmap_l2pt_delref(pmap, l1pte, l2pte, &tlbctx);
        PMAP_UNLOCK(pmap);
        pmap_tlb_shootnow(&tlbctx);
-       pmap_tlb_ptpage_drain(&tlbctx);
+       pmap_tlb_context_drain(&tlbctx);
        TLB_COUNT(reason_enter_l2pt_delref);
 }
 
@@ -2035,7 +2062,7 @@ pmap_enter_l3pt_delref(pmap_t const pmap
        pmap_l3pt_delref(pmap, va, pte, &tlbctx);
        PMAP_UNLOCK(pmap);
        pmap_tlb_shootnow(&tlbctx);
-       pmap_tlb_ptpage_drain(&tlbctx);
+       pmap_tlb_context_drain(&tlbctx);
        TLB_COUNT(reason_enter_l3pt_delref);
 }
 
@@ -2936,8 +2963,8 @@ pmap_remove_mapping(pmap_t pmap, vaddr_t
 
 #ifdef DEBUG
        if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT))
-               printf("pmap_remove_mapping(%p, %lx, %p, %d, %p)\n",
-                      pmap, va, pte, dolock, opvp);
+               printf("pmap_remove_mapping(%p, %lx, %p, %d, %p, %p)\n",
+                      pmap, va, pte, dolock, opvp, tlbctx);
 #endif
 
        /*
@@ -2988,7 +3015,7 @@ pmap_remove_mapping(pmap_t pmap, vaddr_t
                 */
                pg = PHYS_TO_VM_PAGE(pa);
                KASSERT(pg != NULL);
-               pmap_pv_remove(pmap, pg, va, dolock, opvp);
+               pmap_pv_remove(pmap, pg, va, dolock, opvp, tlbctx);
                KASSERT(opvp == NULL || *opvp != NULL);
        }
 
@@ -3296,7 +3323,7 @@ pmap_pv_enter(pmap_t pmap, struct vm_pag
  */
 static void
 pmap_pv_remove(pmap_t pmap, struct vm_page *pg, vaddr_t va, bool dolock,
-       pv_entry_t *opvp)
+    pv_entry_t *opvp, struct pmap_tlb_context * const tlbctx)
 {
        struct vm_page_md * const md = VM_PAGE_TO_MD(pg);
        pv_entry_t pv, *pvp;
@@ -3333,10 +3360,12 @@ pmap_pv_remove(pmap_t pmap, struct vm_pa
                mutex_exit(lock);
        }
 
-       if (opvp != NULL)
+       if (opvp != NULL) {
                *opvp = pv;
-       else
-               pmap_pv_free(pv);



Home | Main Index | Thread Index | Old Index