- Tweak the pmap locking protocol slightly -- require that a pmap must

be locked before it can be marked as `active' on a processor.
- Require that pmaps other than the kernel pmap be locked when they
  are passed to pmap_tlb_shootdown().  This, combined with the locking
  protocol tweak, allow us to get a consistent view of `activeness' of
  a pmap, which means we can optmize away a lot of TLB shootdown traffic
  for user pmaps.
- Borrow an idea from the i386mp branch; use the normal SHOOTDOWN IPI
  to deal with hitting the entire TLB, and garbage-collect the TBIA
  and TBIAP IPIs.
This commit is contained in:
thorpej 2001-07-15 16:42:18 +00:00
parent 047e3dd5d8
commit ff62d4c0c5
4 changed files with 89 additions and 84 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ipifuncs.c,v 1.29 2001/05/01 05:16:44 thorpej Exp $ */
/* $NetBSD: ipifuncs.c,v 1.30 2001/07/15 16:42:18 thorpej Exp $ */
/*-
* Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
@ -39,7 +39,7 @@
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.29 2001/05/01 05:16:44 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.30 2001/07/15 16:42:18 thorpej Exp $");
/*
* Interprocessor interrupt handlers.
@ -64,8 +64,6 @@ __KERNEL_RCSID(0, "$NetBSD: ipifuncs.c,v 1.29 2001/05/01 05:16:44 thorpej Exp $"
typedef void (*ipifunc_t)(struct cpu_info *, struct trapframe *);
void alpha_ipi_halt(struct cpu_info *, struct trapframe *);
void alpha_ipi_tbia(struct cpu_info *, struct trapframe *);
void alpha_ipi_tbiap(struct cpu_info *, struct trapframe *);
void alpha_ipi_imb(struct cpu_info *, struct trapframe *);
void alpha_ipi_ast(struct cpu_info *, struct trapframe *);
void alpha_ipi_synch_fpu(struct cpu_info *, struct trapframe *);
@ -79,8 +77,6 @@ void alpha_ipi_pause(struct cpu_info *, struct trapframe *);
ipifunc_t ipifuncs[ALPHA_NIPIS] = {
alpha_ipi_halt,
microset,
alpha_ipi_tbia,
alpha_ipi_tbiap,
pmap_do_tlb_shootdown,
alpha_ipi_imb,
alpha_ipi_ast,
@ -93,8 +89,6 @@ ipifunc_t ipifuncs[ALPHA_NIPIS] = {
const char *ipinames[ALPHA_NIPIS] = {
"halt ipi",
"microset ipi",
"tbia ipi",
"tbiap ipi",
"shootdown ipi",
"imb ipi",
"ast ipi",
@ -257,30 +251,6 @@ alpha_ipi_halt(struct cpu_info *ci, struct trapframe *framep)
/* NOTREACHED */
}
void
alpha_ipi_tbia(struct cpu_info *ci, struct trapframe *framep)
{
/* If we're doing a TBIA, we don't need to do a TBIAP or a SHOOTDOWN. */
atomic_clearbits_ulong(&ci->ci_ipis,
ALPHA_IPI_TBIAP|ALPHA_IPI_SHOOTDOWN);
pmap_tlb_shootdown_q_drain(ci->ci_cpuid, TRUE);
ALPHA_TBIA();
}
void
alpha_ipi_tbiap(struct cpu_info *ci, struct trapframe *framep)
{
/* Can't clear SHOOTDOWN here; might have PG_ASM mappings. */
pmap_tlb_shootdown_q_drain(ci->ci_cpuid, FALSE);
ALPHA_TBIAP();
}
void
alpha_ipi_imb(struct cpu_info *ci, struct trapframe *framep)
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: pmap.c,v 1.181 2001/07/15 05:24:20 thorpej Exp $ */
/* $NetBSD: pmap.c,v 1.182 2001/07/15 16:42:18 thorpej Exp $ */
/*-
* Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
@ -154,7 +154,7 @@
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.181 2001/07/15 05:24:20 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.182 2001/07/15 16:42:18 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -439,6 +439,7 @@ struct pmap_tlb_shootdown_q {
TAILQ_HEAD(, pmap_tlb_shootdown_job) pq_head;
int pq_pte; /* aggregate PTE bits */
int pq_count; /* number of pending requests */
int pq_tbia; /* pending global flush */
struct simplelock pq_slock; /* spin lock on queue */
} pmap_tlb_shootdown_q[ALPHA_MAXPROCS];
@ -459,6 +460,7 @@ do { \
struct pool pmap_tlb_shootdown_job_pool;
void pmap_tlb_shootdown_q_drain(struct pmap_tlb_shootdown_q *);
struct pmap_tlb_shootdown_job *pmap_tlb_shootdown_job_get
(struct pmap_tlb_shootdown_q *);
void pmap_tlb_shootdown_job_put(struct pmap_tlb_shootdown_q *,
@ -2223,13 +2225,13 @@ pmap_activate(struct proc *p)
printf("pmap_activate(%p)\n", p);
#endif
PMAP_LOCK(pmap);
/*
* Mark the pmap in use by this processor.
*/
atomic_setbits_ulong(&pmap->pm_cpus, (1UL << cpu_id));
PMAP_LOCK(pmap);
/*
* Allocate an ASN.
*/
@ -3741,6 +3743,8 @@ pmap_asn_alloc(pmap_t pmap, long cpu_id)
* pmap_tlb_shootdown:
*
* Cause the TLB entry for pmap/va to be shot down.
*
* NOTE: The pmap must be locked here.
*/
void
pmap_tlb_shootdown(pmap_t pmap, vaddr_t va, pt_entry_t pte)
@ -3748,42 +3752,76 @@ pmap_tlb_shootdown(pmap_t pmap, vaddr_t va, pt_entry_t pte)
struct pmap_tlb_shootdown_q *pq;
struct pmap_tlb_shootdown_job *pj;
struct cpu_info *ci, *self = curcpu();
u_long ipinum;
u_long cpumask;
CPU_INFO_ITERATOR cii;
int s;
LOCK_ASSERT((pmap == pmap_kernel()) ||
simple_lock_held(&pmap->pm_slock));
cpumask = 0;
for (CPU_INFO_FOREACH(cii, ci)) {
if (ci == self)
continue;
/*
* The pmap must be locked (unless its the kernel
* pmap, in which case it is okay for it to be
* unlocked), which prevents it from becoming
* active on any additional processors. This makes
* it safe to check for activeness. If it's not
* active on the processor in question, then just
* mark it as needing a new ASN the next time it
* does, saving the IPI. We always have to send
* the IPI for the kernel pmap.
*
* Note if it's marked active now, and it becomes
* inactive by the time the processor receives
* the IPI, that's okay, because it does the right
* thing with it later.
*/
if (pmap != pmap_kernel() &&
PMAP_ISACTIVE(pmap, ci->ci_cpuid) == 0) {
PMAP_INVALIDATE_ASN(pmap, ci->ci_cpuid);
continue;
}
pq = &pmap_tlb_shootdown_q[ci->ci_cpuid];
PSJQ_LOCK(pq, s);
pj = pmap_tlb_shootdown_job_get(pq);
pq->pq_pte |= pte;
/*
* If a global flush is already pending, we
* don't really have to do anything else.
*/
if (pq->pq_tbia) {
PSJQ_UNLOCK(pq, s);
continue;
}
pj = pmap_tlb_shootdown_job_get(pq);
if (pj == NULL) {
/*
* Couldn't allocate a job entry. Just do a
* TBIA[P].
* Couldn't allocate a job entry. Just
* tell the processor to kill everything.
*/
if (pq->pq_pte & PG_ASM)
ipinum = ALPHA_IPI_TBIA;
else
ipinum = ALPHA_IPI_TBIAP;
alpha_send_ipi(ci->ci_cpuid, ipinum);
pq->pq_tbia = 1;
} else {
pj->pj_pmap = pmap;
pj->pj_va = va;
pj->pj_pte = pte;
TAILQ_INSERT_TAIL(&pq->pq_head, pj, pj_list);
ipinum = ALPHA_IPI_SHOOTDOWN;
}
alpha_send_ipi(ci->ci_cpuid, ipinum);
cpumask |= 1UL << ci->ci_cpuid;
PSJQ_UNLOCK(pq, s);
}
alpha_multicast_ipi(cpumask, ALPHA_IPI_SHOOTDOWN);
}
/*
@ -3802,14 +3840,23 @@ pmap_do_tlb_shootdown(struct cpu_info *ci, struct trapframe *framep)
PSJQ_LOCK(pq, s);
if (pq->pq_tbia) {
if (pq->pq_pte & PG_ASM)
ALPHA_TBIA();
else
ALPHA_TBIAP();
pq->pq_tbia = 0;
pmap_tlb_shootdown_q_drain(pq);
} else {
while ((pj = TAILQ_FIRST(&pq->pq_head)) != NULL) {
TAILQ_REMOVE(&pq->pq_head, pj, pj_list);
PMAP_INVALIDATE_TLB(pj->pj_pmap, pj->pj_va,
pj->pj_pte & PG_ASM, pj->pj_pmap->pm_cpus & cpu_mask,
cpu_id);
pj->pj_pte & PG_ASM,
pj->pj_pmap->pm_cpus & cpu_mask, cpu_id);
pmap_tlb_shootdown_job_put(pq, pj);
}
pq->pq_pte = 0;
}
PSJQ_UNLOCK(pq, s);
}
@ -3820,28 +3867,19 @@ pmap_do_tlb_shootdown(struct cpu_info *ci, struct trapframe *framep)
* Drain a processor's TLB shootdown queue. We do not perform
* the shootdown operations. This is merely a convenience
* function.
*
* Note: We expect the queue to be locked.
*/
void
pmap_tlb_shootdown_q_drain(u_long cpu_id, boolean_t all)
pmap_tlb_shootdown_q_drain(struct pmap_tlb_shootdown_q *pq)
{
struct pmap_tlb_shootdown_q *pq = &pmap_tlb_shootdown_q[cpu_id];
struct pmap_tlb_shootdown_job *pj, *npj;
pt_entry_t npte = 0;
int s;
struct pmap_tlb_shootdown_job *pj;
PSJQ_LOCK(pq, s);
for (pj = TAILQ_FIRST(&pq->pq_head); pj != NULL; pj = npj) {
npj = TAILQ_NEXT(pj, pj_list);
if (all || (pj->pj_pte & PG_ASM) == 0) {
while ((pj = TAILQ_FIRST(&pq->pq_head)) != NULL) {
TAILQ_REMOVE(&pq->pq_head, pj, pj_list);
pmap_tlb_shootdown_job_put(pq, pj);
} else
npte |= pj->pj_pte;
}
pq->pq_pte = npte;
PSJQ_UNLOCK(pq, s);
pq->pq_pte = 0;
}
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: intr.h,v 1.47 2001/04/28 06:10:50 thorpej Exp $ */
/* $NetBSD: intr.h,v 1.48 2001/07/15 16:42:19 thorpej Exp $ */
/*-
* Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
@ -160,17 +160,15 @@ _splraise(int s)
*/
#define ALPHA_IPI_HALT (1UL << 0)
#define ALPHA_IPI_MICROSET (1UL << 1)
#define ALPHA_IPI_TBIA (1UL << 2)
#define ALPHA_IPI_TBIAP (1UL << 3)
#define ALPHA_IPI_SHOOTDOWN (1UL << 4)
#define ALPHA_IPI_IMB (1UL << 5)
#define ALPHA_IPI_AST (1UL << 6)
#define ALPHA_IPI_SYNCH_FPU (1UL << 7)
#define ALPHA_IPI_DISCARD_FPU (1UL << 8)
#define ALPHA_IPI_PAUSE (1UL << 9)
#define ALPHA_IPI_PMAP_REACTIVATE (1UL << 10)
#define ALPHA_IPI_SHOOTDOWN (1UL << 2)
#define ALPHA_IPI_IMB (1UL << 3)
#define ALPHA_IPI_AST (1UL << 4)
#define ALPHA_IPI_SYNCH_FPU (1UL << 5)
#define ALPHA_IPI_DISCARD_FPU (1UL << 6)
#define ALPHA_IPI_PAUSE (1UL << 7)
#define ALPHA_IPI_PMAP_REACTIVATE (1UL << 8)
#define ALPHA_NIPIS 11 /* must not exceed 64 */
#define ALPHA_NIPIS 9 /* must not exceed 64 */
struct cpu_info;
struct trapframe;

View File

@ -1,4 +1,4 @@
/* $NetBSD: pmap.h,v 1.51 2001/05/30 12:28:38 mrg Exp $ */
/* $NetBSD: pmap.h,v 1.52 2001/07/15 16:42:19 thorpej Exp $ */
/*-
* Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
@ -182,7 +182,6 @@ void pmap_do_reactivate(struct cpu_info *, struct trapframe *);
void pmap_tlb_shootdown(pmap_t, vaddr_t, pt_entry_t);
void pmap_do_tlb_shootdown(struct cpu_info *, struct trapframe *);
void pmap_tlb_shootdown_q_drain(u_long, boolean_t);
#define PMAP_TLB_SHOOTDOWN(pm, va, pte) \
pmap_tlb_shootdown((pm), (va), (pte))
#else