Module Name:    src
Committed By:   thorpej
Date:           Sun May 30 14:06:37 UTC 2021

Modified Files:
        src/sys/arch/alpha/alpha: pmap.c
        src/sys/arch/alpha/include: pmap.h

Log Message:
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).


To generate a diff of this commit:
cvs rdiff -u -r1.288 -r1.289 src/sys/arch/alpha/alpha/pmap.c
cvs rdiff -u -r1.94 -r1.95 src/sys/arch/alpha/include/pmap.h

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/alpha/alpha/pmap.c
diff -u src/sys/arch/alpha/alpha/pmap.c:1.288 src/sys/arch/alpha/alpha/pmap.c:1.289
--- src/sys/arch/alpha/alpha/pmap.c:1.288	Sun May 30 13:34:21 2021
+++ src/sys/arch/alpha/alpha/pmap.c	Sun May 30 14:06:37 2021
@@ -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);
+	} else {
+		KASSERT(tlbctx != NULL);
+		LIST_INSERT_HEAD(&tlbctx->t_freepvq, pv, pv_link);
+	}
 }
 
 /*

Index: src/sys/arch/alpha/include/pmap.h
diff -u src/sys/arch/alpha/include/pmap.h:1.94 src/sys/arch/alpha/include/pmap.h:1.95
--- src/sys/arch/alpha/include/pmap.h:1.94	Sun May 30 13:34:21 2021
+++ src/sys/arch/alpha/include/pmap.h	Sun May 30 14:06:37 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.h,v 1.94 2021/05/30 13:34:21 thorpej Exp $ */
+/* $NetBSD: pmap.h,v 1.95 2021/05/30 14:06:37 thorpej Exp $ */
 
 /*-
  * Copyright (c) 1998, 1999, 2000, 2001, 2007 The NetBSD Foundation, Inc.
@@ -133,6 +133,7 @@
  */
 
 LIST_HEAD(pmap_pagelist, vm_page);
+LIST_HEAD(pmap_pvlist, pv_entry);
 
 struct pmap_percpu {
 	unsigned int		pmc_asn;	/* address space number */
@@ -151,7 +152,7 @@ struct pmap {	/* pmaps are aligned to CO
 	unsigned int		pm_count;	/* [24] reference count */
 	unsigned int		__pm_spare0;	/* [28] spare field */
 	struct pmap_pagelist	pm_ptpages;	/* [32] list of PT pages */
-	LIST_HEAD(, pv_entry)	pm_pvents;	/* [40] list of PV entries */
+	struct pmap_pvlist	pm_pvents;	/* [40] list of PV entries */
 	TAILQ_ENTRY(pmap)	pm_list;	/* [48] list of all pmaps */
 	/* -- COHERENCY_UNIT boundary -- */
 	struct pmap_percpu	pm_percpu[];	/* [64] per-CPU data */

Reply via email to