Module Name:    src
Committed By:   thorpej
Date:           Fri Sep 25 03:40:12 UTC 2020

Modified Files:
        src/sys/arch/alpha/alpha: interrupt.c
        src/sys/arch/alpha/common: shared_intr.c
        src/sys/arch/alpha/include: cpu.h intr.h types.h
        src/sys/arch/alpha/jensenio: com_jensenio.c jensenio_intr.c
            jenseniovar.h pckbc_jensenio.c
        src/sys/arch/alpha/pci: dwlpx.c pci_2100_a500.c pci_kn300.c pci_kn8ae.c
            pci_machdep.c sio_pic.c
        src/sys/arch/alpha/tc: tc_3000_300.c tc_3000_500.c tcasic.c

Log Message:
Changes to make interrupt {,dis}establish MP-safe on Alpha:
- Protect all of the system interrupt linkage with the cpu_lock mutex.
- Re-order some of the stores to the SCB vector table to make it safe
  in the face of lockless interrupt dispatch.
- Add a framework for routing interrupts to specific CPUs.  Interrupts
  are still funneled only to the primary CPU, but that will change for
  some systems soon.  Ensure that interrupt handler lists are manipulated
  only on the CPUs that handle that specific interrupt source.  This required
  a re-factor of the alpha_shared_intr_*() family of functions.
- Enable __HAVE_INTR_CONTROL, although interrupt redistribution is still
  a no-op.
- Reduce code duplication in the Jenson direct-SCB interrupt handlers.


To generate a diff of this commit:
cvs rdiff -u -r1.89 -r1.90 src/sys/arch/alpha/alpha/interrupt.c
cvs rdiff -u -r1.24 -r1.25 src/sys/arch/alpha/common/shared_intr.c
cvs rdiff -u -r1.96 -r1.97 src/sys/arch/alpha/include/cpu.h
cvs rdiff -u -r1.80 -r1.81 src/sys/arch/alpha/include/intr.h
cvs rdiff -u -r1.59 -r1.60 src/sys/arch/alpha/include/types.h
cvs rdiff -u -r1.17 -r1.18 src/sys/arch/alpha/jensenio/com_jensenio.c
cvs rdiff -u -r1.12 -r1.13 src/sys/arch/alpha/jensenio/jensenio_intr.c
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/alpha/jensenio/jenseniovar.h
cvs rdiff -u -r1.13 -r1.14 src/sys/arch/alpha/jensenio/pckbc_jensenio.c
cvs rdiff -u -r1.38 -r1.39 src/sys/arch/alpha/pci/dwlpx.c
cvs rdiff -u -r1.13 -r1.14 src/sys/arch/alpha/pci/pci_2100_a500.c
cvs rdiff -u -r1.37 -r1.38 src/sys/arch/alpha/pci/pci_kn300.c
cvs rdiff -u -r1.30 -r1.31 src/sys/arch/alpha/pci/pci_kn8ae.c
cvs rdiff -u -r1.25 -r1.26 src/sys/arch/alpha/pci/pci_machdep.c
cvs rdiff -u -r1.44 -r1.45 src/sys/arch/alpha/pci/sio_pic.c
cvs rdiff -u -r1.36 -r1.37 src/sys/arch/alpha/tc/tc_3000_300.c
cvs rdiff -u -r1.35 -r1.36 src/sys/arch/alpha/tc/tc_3000_500.c
cvs rdiff -u -r1.48 -r1.49 src/sys/arch/alpha/tc/tcasic.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/alpha/alpha/interrupt.c
diff -u src/sys/arch/alpha/alpha/interrupt.c:1.89 src/sys/arch/alpha/alpha/interrupt.c:1.90
--- src/sys/arch/alpha/alpha/interrupt.c:1.89	Tue Sep 22 15:24:01 2020
+++ src/sys/arch/alpha/alpha/interrupt.c	Fri Sep 25 03:40:11 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: interrupt.c,v 1.89 2020/09/22 15:24:01 thorpej Exp $ */
+/* $NetBSD: interrupt.c,v 1.90 2020/09/25 03:40:11 thorpej Exp $ */
 
 /*-
  * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
@@ -65,7 +65,7 @@
 
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: interrupt.c,v 1.89 2020/09/22 15:24:01 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: interrupt.c,v 1.90 2020/09/25 03:40:11 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -88,11 +88,10 @@ __KERNEL_RCSID(0, "$NetBSD: interrupt.c,
 #include <machine/cpuconf.h>
 #include <machine/alpha.h>
 
+/* Protected by cpu_lock */
 struct scbvec scb_iovectab[SCB_VECTOIDX(SCB_SIZE - SCB_IOVECBASE)]
 							__read_mostly;
 
-void	netintr(void);
-
 void	scb_stray(void *, u_long);
 
 void
@@ -117,9 +116,8 @@ void
 scb_set(u_long vec, void (*func)(void *, u_long), void *arg)
 {
 	u_long idx;
-	int s;
 
-	s = splhigh();
+	KASSERT(mutex_owned(&cpu_lock));
 
 	if (vec < SCB_IOVECBASE || vec >= SCB_SIZE ||
 	    (vec & (SCB_VECSIZE - 1)) != 0)
@@ -130,19 +128,18 @@ scb_set(u_long vec, void (*func)(void *,
 	if (scb_iovectab[idx].scb_func != scb_stray)
 		panic("scb_set: vector 0x%lx already occupied", vec);
 
-	scb_iovectab[idx].scb_func = func;
 	scb_iovectab[idx].scb_arg = arg;
-
-	splx(s);
+	alpha_mb();
+	scb_iovectab[idx].scb_func = func;
+	alpha_mb();
 }
 
 u_long
 scb_alloc(void (*func)(void *, u_long), void *arg)
 {
 	u_long vec, idx;
-	int s;
 
-	s = splhigh();
+	KASSERT(mutex_owned(&cpu_lock));
 
 	/*
 	 * Allocate "downwards", to avoid bumping into
@@ -153,15 +150,14 @@ scb_alloc(void (*func)(void *, u_long), 
 	     vec >= SCB_IOVECBASE; vec -= SCB_VECSIZE) {
 		idx = SCB_VECTOIDX(vec - SCB_IOVECBASE);
 		if (scb_iovectab[idx].scb_func == scb_stray) {
-			scb_iovectab[idx].scb_func = func;
 			scb_iovectab[idx].scb_arg = arg;
-			splx(s);
+			alpha_mb();
+			scb_iovectab[idx].scb_func = func;
+			alpha_mb();
 			return (vec);
 		}
 	}
 
-	splx(s);
-
 	return (SCB_ALLOC_FAILED);
 }
 
@@ -169,9 +165,8 @@ void
 scb_free(u_long vec)
 {
 	u_long idx;
-	int s;
 
-	s = splhigh();
+	KASSERT(mutex_owned(&cpu_lock));
 
 	if (vec < SCB_IOVECBASE || vec >= SCB_SIZE ||
 	    (vec & (SCB_VECSIZE - 1)) != 0)
@@ -183,9 +178,9 @@ scb_free(u_long vec)
 		panic("scb_free: vector 0x%lx is empty", vec);
 
 	scb_iovectab[idx].scb_func = scb_stray;
+	alpha_mb();
 	scb_iovectab[idx].scb_arg = (void *) vec;
-
-	splx(s);
+	alpha_mb();
 }
 
 void
@@ -581,6 +576,28 @@ cpu_intr_p(void)
 }
 
 /*
+ * cpu_intr_redistribute:
+ *
+ *	Redistribute interrupts amongst CPUs eligible to handle them.
+ */
+void
+cpu_intr_redistribute(void)
+{
+	/* XXX Nothing, yet. */
+}
+
+/*
+ * cpu_intr_count:
+ *
+ *	Return the number of device interrupts this CPU handles.
+ */
+unsigned int
+cpu_intr_count(struct cpu_info * const ci)
+{
+	return ci->ci_nintrhand;
+}
+
+/*
  * Security sensitive rate limiting printf
  */
 void

Index: src/sys/arch/alpha/common/shared_intr.c
diff -u src/sys/arch/alpha/common/shared_intr.c:1.24 src/sys/arch/alpha/common/shared_intr.c:1.25
--- src/sys/arch/alpha/common/shared_intr.c:1.24	Wed Sep 23 18:46:02 2020
+++ src/sys/arch/alpha/common/shared_intr.c	Fri Sep 25 03:40:11 2020
@@ -1,4 +1,33 @@
-/* $NetBSD: shared_intr.c,v 1.24 2020/09/23 18:46:02 thorpej Exp $ */
+/* $NetBSD: shared_intr.c,v 1.25 2020/09/25 03:40:11 thorpej Exp $ */
+
+/*
+ * Copyright (c) 2020 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
 
 /*
  * Copyright (c) 1996 Carnegie-Mellon University.
@@ -33,16 +62,19 @@
 
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: shared_intr.c,v 1.24 2020/09/23 18:46:02 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: shared_intr.c,v 1.25 2020/09/25 03:40:11 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
+#include <sys/cpu.h>
+#include <sys/kmem.h>
+#include <sys/kmem.h>
 #include <sys/systm.h>
-#include <sys/malloc.h>
 #include <sys/syslog.h>
 #include <sys/queue.h>
 #include <sys/atomic.h>
 #include <sys/intr.h>
+#include <sys/xcall.h>
 
 static const char *intr_typename(int);
 
@@ -71,8 +103,7 @@ alpha_shared_intr_alloc(unsigned int n, 
 	struct alpha_shared_intr *intr;
 	unsigned int i;
 
-	intr = malloc(n * sizeof (struct alpha_shared_intr), M_DEVBUF,
-	    M_WAITOK);
+	intr = kmem_alloc(n * sizeof(*intr), KM_SLEEP);
 	for (i = 0; i < n; i++) {
 		TAILQ_INIT(&intr[i].intr_q);
 		intr[i].intr_sharetype = IST_NONE;
@@ -80,11 +111,12 @@ alpha_shared_intr_alloc(unsigned int n, 
 		intr[i].intr_nstrays = 0;
 		intr[i].intr_maxstrays = 5;
 		intr[i].intr_private = NULL;
+		intr[i].intr_cpu = NULL;
 		if (namesize != 0) {
-			intr[i].intr_string = malloc(namesize, M_DEVBUF,
-			    M_WAITOK);
-		} else
+			intr[i].intr_string = kmem_zalloc(namesize, KM_SLEEP);
+		} else {
 			intr[i].intr_string = NULL;
+		}
 	}
 
 	return (intr);
@@ -132,24 +164,82 @@ alpha_shared_intr_wrapper(void * const a
 	return rv;
 }
 
-void *
-alpha_shared_intr_establish(struct alpha_shared_intr *intr, unsigned int num,
-    int type, int level, int flags,
+struct alpha_shared_intrhand *
+alpha_shared_intr_alloc_intrhand(struct alpha_shared_intr *intr,
+    unsigned int num, int type, int level, int flags,
     int (*fn)(void *), void *arg, const char *basename)
 {
 	struct alpha_shared_intrhand *ih;
 
 	if (intr[num].intr_sharetype == IST_UNUSABLE) {
-		printf("alpha_shared_intr_establish: %s %d: unusable\n",
+		printf("%s: %s %d: unusable\n", __func__,
 		    basename, num);
 		return NULL;
 	}
 
-	ih = malloc(sizeof *ih, M_DEVBUF, M_WAITOK);
-#ifdef DIAGNOSTIC
-	if (type == IST_NONE)
-		panic("alpha_shared_intr_establish: bogus type");
-#endif
+	KASSERT(type != IST_NONE);
+
+	ih = kmem_alloc(sizeof(*ih), KM_SLEEP);
+
+	ih->ih_intrhead = intr;
+	ih->ih_fn = ih->ih_real_fn = fn;
+	ih->ih_arg = ih->ih_real_arg = arg;
+	ih->ih_level = level;
+	ih->ih_type = type;
+	ih->ih_num = num;
+
+	/*
+	 * Non-MPSAFE interrupts get a wrapper that takes the
+	 * KERNEL_LOCK.
+	 */
+	if ((flags & ALPHA_INTR_MPSAFE) == 0) {
+		ih->ih_fn = alpha_shared_intr_wrapper;
+		ih->ih_arg = ih;
+	}
+
+	return (ih);
+}
+
+void
+alpha_shared_intr_free_intrhand(struct alpha_shared_intrhand *ih)
+{
+
+	kmem_free(ih, sizeof(*ih));
+}
+
+static void
+alpha_shared_intr_link_unlink_xcall(void *arg1, void *arg2)
+{
+	struct alpha_shared_intrhand *ih = arg1;
+	struct alpha_shared_intr *intr = ih->ih_intrhead;
+	struct cpu_info *ci = intr->intr_cpu;
+	unsigned int num = ih->ih_num;
+
+	KASSERT(ci == curcpu() || !mp_online);
+	KASSERT(!cpu_intr_p());
+
+	const unsigned long psl = alpha_pal_swpipl(ALPHA_PSL_IPL_HIGH);
+
+	if (arg2 != NULL) {
+		TAILQ_INSERT_TAIL(&intr[num].intr_q, ih, ih_q);
+		ci->ci_nintrhand++;
+	} else {
+		TAILQ_REMOVE(&intr[num].intr_q, ih, ih_q);
+		ci->ci_nintrhand--;
+	}
+
+	alpha_pal_swpipl(psl);
+}
+
+bool
+alpha_shared_intr_link(struct alpha_shared_intr *intr,
+    struct alpha_shared_intrhand *ih, const char *basename)
+{
+	int type = ih->ih_type;
+	unsigned int num = ih->ih_num;
+
+	KASSERT(mutex_owned(&cpu_lock));
+	KASSERT(ih->ih_intrhead == intr);
 
 	switch (intr[num].intr_sharetype) {
 	case IST_EDGE:
@@ -164,9 +254,10 @@ alpha_shared_intr_establish(struct alpha
 				    intr_typename(intr[num].intr_sharetype));
 				type = intr[num].intr_sharetype;
 			} else {
-				panic("alpha_shared_intr_establish: %s %d: can't share %s with %s",
+				printf("alpha_shared_intr_establish: %s %d: can't share %s with %s\n",
 				    basename, num, intr_typename(type),
 				    intr_typename(intr[num].intr_sharetype));
+				return (false);
 			}
 		}
 		break;
@@ -176,39 +267,47 @@ alpha_shared_intr_establish(struct alpha
 		break;
 	}
 
-	ih->ih_intrhead = intr;
-	ih->ih_fn = ih->ih_real_fn = fn;
-	ih->ih_arg = ih->ih_real_arg = arg;
-	ih->ih_level = level;
-	ih->ih_num = num;
+	intr[num].intr_sharetype = type;
 
 	/*
-	 * Non-MPSAFE interrupts get a wrapper that takes the
-	 * KERNEL_LOCK.
+	 * If a CPU hasn't been assigned yet, just give it to the
+	 * primary.
 	 */
-	if ((flags & ALPHA_INTR_MPSAFE) == 0) {
-		ih->ih_fn = alpha_shared_intr_wrapper;
-		ih->ih_arg = ih;
+	if (intr->intr_cpu == NULL) {
+		intr->intr_cpu = &cpu_info_primary;
 	}
 
-	intr[num].intr_sharetype = type;
-	TAILQ_INSERT_TAIL(&intr[num].intr_q, ih, ih_q);
+	kpreempt_disable();
+	if (intr->intr_cpu == curcpu() || !mp_online) {
+		alpha_shared_intr_link_unlink_xcall(ih, intr);
+	} else {
+		uint64_t where = xc_unicast(XC_HIGHPRI,
+		    alpha_shared_intr_link_unlink_xcall, ih, intr,
+		        intr->intr_cpu);
+		xc_wait(where);
+	}
+	kpreempt_enable();
 
-	return (ih);
+	return (true);
 }
 
 void
-alpha_shared_intr_disestablish(struct alpha_shared_intr *intr, void *cookie,
-    const char *basename)
+alpha_shared_intr_unlink(struct alpha_shared_intr *intr,
+    struct alpha_shared_intrhand *ih, const char *basename)
 {
-	struct alpha_shared_intrhand *ih = cookie;
-	unsigned int num = ih->ih_num;
 
-	/*
-	 * Just remove it from the list and free the entry.  We let
-	 * the caller deal with resetting the share type, if appropriate.
-	 */
-	TAILQ_REMOVE(&intr[num].intr_q, ih, ih_q);
+	KASSERT(mutex_owned(&cpu_lock));
+
+	kpreempt_disable();
+	if (intr->intr_cpu == curcpu() || !mp_online) {
+		alpha_shared_intr_link_unlink_xcall(ih, NULL);
+	} else {
+		uint64_t where = xc_unicast(XC_HIGHPRI,
+		    alpha_shared_intr_link_unlink_xcall, ih, NULL,
+		        intr->intr_cpu);
+		xc_wait(where);
+	}
+	kpreempt_enable();
 }
 
 int
@@ -302,6 +401,21 @@ alpha_shared_intr_get_private(struct alp
 	return (intr[num].intr_private);
 }
 
+void
+alpha_shared_intr_set_cpu(struct alpha_shared_intr *intr, unsigned int num,
+    struct cpu_info *ci)
+{
+
+	intr[num].intr_cpu = ci;
+}
+
+struct cpu_info *
+alpha_shared_intr_get_cpu(struct alpha_shared_intr *intr, unsigned int num)
+{
+
+	return (intr[num].intr_cpu);
+}
+
 struct evcnt *
 alpha_shared_intr_evcnt(struct alpha_shared_intr *intr,
     unsigned int num)

Index: src/sys/arch/alpha/include/cpu.h
diff -u src/sys/arch/alpha/include/cpu.h:1.96 src/sys/arch/alpha/include/cpu.h:1.97
--- src/sys/arch/alpha/include/cpu.h:1.96	Wed Sep 16 04:07:32 2020
+++ src/sys/arch/alpha/include/cpu.h	Fri Sep 25 03:40:11 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: cpu.h,v 1.96 2020/09/16 04:07:32 thorpej Exp $ */
+/* $NetBSD: cpu.h,v 1.97 2020/09/25 03:40:11 thorpej Exp $ */
 
 /*-
  * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -139,6 +139,7 @@ struct cpu_info {
 	volatile u_long ci_flags;	/* flags; see below */
 	uint64_t ci_pcc_freq;		/* cpu cycles/second */
 	struct trapframe *ci_db_regs;	/* registers for debuggers */
+	u_int	ci_nintrhand;		/* # of interrupt handlers */
 };
 
 /* Ensure some cpu_info fields are within the signed 16-bit displacement. */

Index: src/sys/arch/alpha/include/intr.h
diff -u src/sys/arch/alpha/include/intr.h:1.80 src/sys/arch/alpha/include/intr.h:1.81
--- src/sys/arch/alpha/include/intr.h:1.80	Wed Sep 23 18:47:21 2020
+++ src/sys/arch/alpha/include/intr.h	Fri Sep 25 03:40:11 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: intr.h,v 1.80 2020/09/23 18:47:21 thorpej Exp $ */
+/* $NetBSD: intr.h,v 1.81 2020/09/25 03:40:11 thorpej Exp $ */
 
 /*-
  * Copyright (c) 2000, 2001, 2002 The NetBSD Foundation, Inc.
@@ -206,6 +206,7 @@ struct alpha_shared_intrhand {
 	int	(*ih_real_fn)(void *);
 	void	*ih_real_arg;
 	int	ih_level;
+	int	ih_type;
 	unsigned int ih_num;
 };
 
@@ -215,6 +216,7 @@ struct alpha_shared_intr {
 	struct evcnt intr_evcnt;
 	char	*intr_string;
 	void	*intr_private;
+	struct cpu_info *intr_cpu;
 	int	intr_sharetype;
 	int	intr_dfltsharetype;
 	int	intr_nstrays;
@@ -228,10 +230,15 @@ struct alpha_shared_intr {
 struct alpha_shared_intr *alpha_shared_intr_alloc(unsigned int, unsigned int);
 int	alpha_shared_intr_dispatch(struct alpha_shared_intr *,
 	    unsigned int);
-void	*alpha_shared_intr_establish(struct alpha_shared_intr *,
-	    unsigned int, int, int, int, int (*)(void *), void *, const char *);
-void	alpha_shared_intr_disestablish(struct alpha_shared_intr *,
-	    void *, const char *);
+struct alpha_shared_intrhand *
+	alpha_shared_intr_alloc_intrhand(struct alpha_shared_intr *,
+	    unsigned int, int, int, int, int (*)(void *), void *,
+	    const char *);
+void	alpha_shared_intr_free_intrhand(struct alpha_shared_intrhand *);
+bool	alpha_shared_intr_link(struct alpha_shared_intr *,
+	    struct alpha_shared_intrhand *, const char *);
+void	alpha_shared_intr_unlink(struct alpha_shared_intr *,
+	    struct alpha_shared_intrhand *, const char *);
 int	alpha_shared_intr_get_sharetype(struct alpha_shared_intr *,
 	    unsigned int);
 int	alpha_shared_intr_isactive(struct alpha_shared_intr *,
@@ -250,6 +257,11 @@ void	alpha_shared_intr_set_private(struc
 	    unsigned int, void *);
 void	*alpha_shared_intr_get_private(struct alpha_shared_intr *,
 	    unsigned int);
+void	alpha_shared_intr_set_cpu(struct alpha_shared_intr *,
+	    unsigned int, struct cpu_info *ci);
+struct cpu_info	*
+	alpha_shared_intr_get_cpu(struct alpha_shared_intr *,
+	    unsigned int);
 char	*alpha_shared_intr_string(struct alpha_shared_intr *,
 	    unsigned int);
 struct evcnt *alpha_shared_intr_evcnt(struct alpha_shared_intr *,

Index: src/sys/arch/alpha/include/types.h
diff -u src/sys/arch/alpha/include/types.h:1.59 src/sys/arch/alpha/include/types.h:1.60
--- src/sys/arch/alpha/include/types.h:1.59	Sat Sep 19 03:02:07 2020
+++ src/sys/arch/alpha/include/types.h	Fri Sep 25 03:40:11 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: types.h,v 1.59 2020/09/19 03:02:07 thorpej Exp $ */
+/* $NetBSD: types.h,v 1.60 2020/09/25 03:40:11 thorpej Exp $ */
 
 /*-
  * Copyright (c) 1990, 1993
@@ -79,6 +79,7 @@ typedef __register_t	register_t;
 #define	__HAVE_MM_MD_DIRECT_MAPPED_PHYS
 #define	__HAVE_CPU_DATA_FIRST
 #define	__HAVE_FAST_SOFTINTS
+#define	__HAVE_INTR_CONTROL
 #define	__HAVE_CPU_UAREA_ROUTINES
 #define	__HAVE_CPU_LWP_SETPRIVATE
 #define	__HAVE___LWP_GETPRIVATE_FAST

Index: src/sys/arch/alpha/jensenio/com_jensenio.c
diff -u src/sys/arch/alpha/jensenio/com_jensenio.c:1.17 src/sys/arch/alpha/jensenio/com_jensenio.c:1.18
--- src/sys/arch/alpha/jensenio/com_jensenio.c:1.17	Tue Sep 22 15:24:02 2020
+++ src/sys/arch/alpha/jensenio/com_jensenio.c	Fri Sep 25 03:40:11 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: com_jensenio.c,v 1.17 2020/09/22 15:24:02 thorpej Exp $ */
+/* $NetBSD: com_jensenio.c,v 1.18 2020/09/25 03:40:11 thorpej Exp $ */
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: com_jensenio.c,v 1.17 2020/09/22 15:24:02 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: com_jensenio.c,v 1.18 2020/09/25 03:40:11 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -46,6 +46,7 @@ __KERNEL_RCSID(0, "$NetBSD: com_jensenio
 #include <sys/syslog.h>
 #include <sys/types.h>
 #include <sys/device.h>
+#include <sys/cpu.h>
 
 #include <machine/intr.h>
 #include <sys/bus.h>
@@ -63,8 +64,7 @@ struct com_jensenio_softc {
 	struct	com_softc sc_com;	/* real "com" softc */
 
 	/* Jensen-specific goo. */
-	char	sc_vecstr[8];
-	struct evcnt sc_ev_intr;
+	struct jensenio_scb_intrhand sc_jih;
 };
 
 int	com_jensenio_match(device_t, cfdata_t , void *);
@@ -73,8 +73,6 @@ void	com_jensenio_attach(device_t, devic
 CFATTACH_DECL_NEW(com_jensenio, sizeof(struct com_jensenio_softc),
     com_jensenio_match, com_jensenio_attach, NULL, NULL);
 
-void	com_jensenio_intr(void *, u_long);
-
 int
 com_jensenio_match(device_t parent, cfdata_t match, void *aux)
 {
@@ -118,26 +116,13 @@ com_jensenio_attach(device_t parent, dev
 
 	com_attach_subr(sc);
 
-	scb_set(ja->ja_irq[0], com_jensenio_intr, jsc);
+	jensenio_intr_establish(&jsc->sc_jih, ja->ja_irq[0],
+	    0, comintr, sc);
+
 	aprint_normal_dev(self, "interrupting at vector 0x%x\n",
 	    ja->ja_irq[0]);
 
-	snprintf(jsc->sc_vecstr, sizeof(jsc->sc_vecstr), "0x%x", ja->ja_irq[0]);
-	evcnt_attach_dynamic(&jsc->sc_ev_intr, EVCNT_TYPE_INTR,
-	    NULL, "vector", jsc->sc_vecstr);
-
 	if (!pmf_device_register1(self, com_suspend, com_resume, com_cleanup)) {
 		aprint_error_dev(self, "could not establish shutdown hook");
 	}
 }
-
-void
-com_jensenio_intr(void *arg, u_long vec)
-{
-	struct com_jensenio_softc *jsc = arg;
-
-	KERNEL_LOCK(1, NULL);
-	jsc->sc_ev_intr.ev_count++;
-	(void) comintr(&jsc->sc_com);
-	KERNEL_UNLOCK_ONE(NULL);
-}

Index: src/sys/arch/alpha/jensenio/jensenio_intr.c
diff -u src/sys/arch/alpha/jensenio/jensenio_intr.c:1.12 src/sys/arch/alpha/jensenio/jensenio_intr.c:1.13
--- src/sys/arch/alpha/jensenio/jensenio_intr.c:1.12	Tue Sep 22 15:24:02 2020
+++ src/sys/arch/alpha/jensenio/jensenio_intr.c	Fri Sep 25 03:40:11 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: jensenio_intr.c,v 1.12 2020/09/22 15:24:02 thorpej Exp $ */
+/* $NetBSD: jensenio_intr.c,v 1.13 2020/09/25 03:40:11 thorpej Exp $ */
 
 /*-
  * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: jensenio_intr.c,v 1.12 2020/09/22 15:24:02 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: jensenio_intr.c,v 1.13 2020/09/25 03:40:11 thorpej Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -40,6 +40,7 @@ __KERNEL_RCSID(0, "$NetBSD: jensenio_int
 #include <sys/errno.h>
 #include <sys/malloc.h>
 #include <sys/device.h>
+#include <sys/cpu.h>
 #include <sys/syslog.h>
 
 #include <machine/autoconf.h>
@@ -158,6 +159,58 @@ jensenio_intr_init(struct jensenio_confi
 	ic->ic_intr_evcnt = jensenio_eisa_intr_evcnt;
 }
 
+static void
+jensenio_intr_dispatch(void *arg, unsigned long vec)
+{
+	struct jensenio_scb_intrhand *jih = arg;
+
+	jih->jih_evcnt.ev_count++;
+	(void) jih->jih_func(jih->jih_arg);
+}
+
+static void
+jensenio_intr_dispatch_wrapped(void *arg, unsigned long vec)
+{
+	KERNEL_LOCK(1, NULL);
+	jensenio_intr_dispatch(arg, vec);
+	KERNEL_UNLOCK_ONE(NULL);
+}
+
+void
+jensenio_intr_establish(struct jensenio_scb_intrhand *jih,
+    unsigned long vec, int flags, int (*func)(void *), void *arg)
+{
+	void (*scb_func)(void *, unsigned long);
+
+	/*
+	 * Jensen systems are all uniprocessors, but we still do all
+	 * of the KERNEL_LOCK handling as a formality to keep assertions
+	 * valid in MI code.
+	 */
+	KASSERT(CPU_IS_PRIMARY(curcpu()));
+	KASSERT(ncpu == 1);
+	if (flags & ALPHA_INTR_MPSAFE)
+		scb_func = jensenio_intr_dispatch;
+	else
+		scb_func = jensenio_intr_dispatch_wrapped;
+
+	jih->jih_func = func;
+	jih->jih_arg = arg;
+	jih->jih_vec = vec;
+
+	snprintf(jih->jih_vecstr, sizeof(jih->jih_vecstr), "0x%lx",
+	    jih->jih_vec);
+	evcnt_attach_dynamic(&jih->jih_evcnt, EVCNT_TYPE_INTR,
+	    NULL, "vector", jih->jih_vecstr);
+
+	mutex_enter(&cpu_lock);
+
+	scb_set(vec, scb_func, jih);
+	curcpu()->ci_nintrhand++;
+
+	mutex_exit(&cpu_lock);
+}
+
 int
 jensenio_eisa_intr_map(void *v, u_int eirq, eisa_intr_handle_t *ihp)
 {
@@ -211,14 +264,24 @@ jensenio_eisa_intr_establish(void *v, in
 	if (jensenio_intr_deftype[irq] == IST_UNUSABLE) {
 		printf("jensenio_eisa_intr_establish: IRQ %d not usable\n",
 		    irq);
-		return (NULL);
+		return NULL;
 	}
 
-	cookie = alpha_shared_intr_establish(jensenio_eisa_intr, irq,
+	cookie = alpha_shared_intr_alloc_intrhand(jensenio_eisa_intr, irq,
 	    type, level, 0, fn, arg, "eisa irq");
 
-	if (cookie != NULL &&
-	    alpha_shared_intr_firstactive(jensenio_eisa_intr, irq)) {
+	if (cookie == NULL)
+		return NULL;
+
+	mutex_enter(&cpu_lock);
+
+	if (! alpha_shared_intr_link(jensenio_eisa_intr, cookie, "eisa irq")) {
+		mutex_exit(&cpu_lock);
+		alpha_shared_intr_free_intrhand(cookie);
+		return NULL;
+	}
+
+	if (alpha_shared_intr_firstactive(jensenio_eisa_intr, irq)) {
 		scb_set(0x800 + SCB_IDXTOVEC(irq), jensenio_iointr, NULL);
 		jensenio_setlevel(irq,
 		    alpha_shared_intr_get_sharetype(jensenio_eisa_intr,
@@ -226,29 +289,31 @@ jensenio_eisa_intr_establish(void *v, in
 		jensenio_enable_intr(irq, 1);
 	}
 
-	return (cookie);
+	mutex_exit(&cpu_lock);
+
+	return cookie;
 }
 
 void
 jensenio_eisa_intr_disestablish(void *v, void *cookie)
 {
 	struct alpha_shared_intrhand *ih = cookie;
-	int s, irq = ih->ih_num;
+	int irq = ih->ih_num;
 
-	s = splhigh();
+	mutex_enter(&cpu_lock);
 
-	/* Remove it from the link. */
-	alpha_shared_intr_disestablish(jensenio_eisa_intr, cookie,
-	    "eisa irq");
-
-	if (alpha_shared_intr_isactive(jensenio_eisa_intr, irq) == 0) {
+	if (alpha_shared_intr_firstactive(jensenio_eisa_intr, irq)) {
 		jensenio_enable_intr(irq, 0);
 		alpha_shared_intr_set_dfltsharetype(jensenio_eisa_intr,
 		    irq, jensenio_intr_deftype[irq]);
 		scb_free(0x800 + SCB_IDXTOVEC(irq));
 	}
 
-	splx(s);
+	alpha_shared_intr_unlink(jensenio_eisa_intr, cookie, "eisa irq");
+
+	mutex_exit(&cpu_lock);
+
+	alpha_shared_intr_free_intrhand(cookie);
 }
 
 int

Index: src/sys/arch/alpha/jensenio/jenseniovar.h
diff -u src/sys/arch/alpha/jensenio/jenseniovar.h:1.4 src/sys/arch/alpha/jensenio/jenseniovar.h:1.5
--- src/sys/arch/alpha/jensenio/jenseniovar.h:1.4	Mon Apr 28 20:23:11 2008
+++ src/sys/arch/alpha/jensenio/jenseniovar.h	Fri Sep 25 03:40:11 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: jenseniovar.h,v 1.4 2008/04/28 20:23:11 martin Exp $ */
+/* $NetBSD: jenseniovar.h,v 1.5 2020/09/25 03:40:11 thorpej Exp $ */
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -32,6 +32,8 @@
 #ifndef _ALPHA_JENSENIO_JENSENIOVAR_H_
 #define _ALPHA_JENSENIO_JENSENIOVAR_H_
 
+#include <sys/evcnt.h>
+
 /*
  * Arguments used to attach devices to the Jensen I/O bus.
  */
@@ -74,10 +76,25 @@ struct jensenio_config {
 	int	jc_mallocsafe;
 };
 
+/*
+ * Interrupt handle for Jensen I/O interrupts that hook into
+ * the SCB directly.
+ */
+struct jensenio_scb_intrhand {
+	int		(*jih_func)(void *);
+	void		*jih_arg;
+	unsigned long	jih_vec;
+	char		jih_vecstr[8];
+	struct evcnt	jih_evcnt;
+};
+
 void	jensenio_init(struct jensenio_config *, int);
 void	jensenio_bus_io_init(bus_space_tag_t, void *);
 void	jensenio_bus_intio_init(bus_space_tag_t, void *);
 void	jensenio_bus_mem_init(bus_space_tag_t, void *);
 void	jensenio_intr_init(struct jensenio_config *);
 void	jensenio_dma_init(struct jensenio_config *);
+
+void	jensenio_intr_establish(struct jensenio_scb_intrhand *,
+	    unsigned long, int, int (*)(void *), void *);
 #endif /* _ALPHA_JENSENIO_JENSENIOVAR_H_ */

Index: src/sys/arch/alpha/jensenio/pckbc_jensenio.c
diff -u src/sys/arch/alpha/jensenio/pckbc_jensenio.c:1.13 src/sys/arch/alpha/jensenio/pckbc_jensenio.c:1.14
--- src/sys/arch/alpha/jensenio/pckbc_jensenio.c:1.13	Tue Sep 22 15:24:02 2020
+++ src/sys/arch/alpha/jensenio/pckbc_jensenio.c	Fri Sep 25 03:40:11 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: pckbc_jensenio.c,v 1.13 2020/09/22 15:24:02 thorpej Exp $ */
+/* $NetBSD: pckbc_jensenio.c,v 1.14 2020/09/25 03:40:11 thorpej Exp $ */
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: pckbc_jensenio.c,v 1.13 2020/09/22 15:24:02 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pckbc_jensenio.c,v 1.14 2020/09/25 03:40:11 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -43,6 +43,7 @@ __KERNEL_RCSID(0, "$NetBSD: pckbc_jensen
 #include <sys/queue.h>
 #include <sys/intr.h>
 #include <sys/bus.h>
+#include <sys/cpu.h>
 
 #include <dev/ic/i8042reg.h>
 #include <dev/ic/pckbcvar.h>
@@ -53,18 +54,11 @@ __KERNEL_RCSID(0, "$NetBSD: pckbc_jensen
 
 #include <alpha/jensenio/jenseniovar.h>
 
-struct pckbc_jensenio_intrcookie {
-	struct pckbc_softc *ic_sc;
-	struct evcnt ic_ev;
-	u_long ic_vector;
-	char ic_vecstr[8];
-};
-
 struct pckbc_jensenio_softc {
 	struct	pckbc_softc sc_pckbc;	/* real "pckbc" softc */
 
 	/* Jensen-specific goo. */
-	struct pckbc_jensenio_intrcookie sc_ic[PCKBC_NSLOTS];
+	struct jensenio_scb_intrhand sc_jih[PCKBC_NSLOTS];
 };
 
 int	pckbc_jensenio_match(device_t, cfdata_t, void *);
@@ -74,7 +68,6 @@ CFATTACH_DECL_NEW(pckbc_jensenio, sizeof
     pckbc_jensenio_match, pckbc_jensenio_attach, NULL, NULL);
 
 void	pckbc_jensenio_intr_establish(struct pckbc_softc *, pckbc_slot_t);
-void	pckbc_jensenio_intr(void *, u_long);
 
 int
 pckbc_jensenio_match(device_t parent, cfdata_t match, void *aux)
@@ -102,8 +95,8 @@ pckbc_jensenio_attach(device_t parent, d
 	/*
 	 * Set up IRQs.
 	 */
-	jsc->sc_ic[PCKBC_KBD_SLOT].ic_vector = ja->ja_irq[0];
-	jsc->sc_ic[PCKBC_AUX_SLOT].ic_vector = ja->ja_irq[1];
+	jsc->sc_jih[PCKBC_KBD_SLOT].jih_vec = ja->ja_irq[0];
+	jsc->sc_jih[PCKBC_AUX_SLOT].jih_vec = ja->ja_irq[1];
 
 	sc->intr_establish = pckbc_jensenio_intr_establish;
 
@@ -141,26 +134,9 @@ pckbc_jensenio_intr_establish(struct pck
 {
 	struct pckbc_jensenio_softc *jsc = (void *) sc;
 
-	jsc->sc_ic[slot].ic_sc = sc;
+	jensenio_intr_establish(&jsc->sc_jih[slot],
+	    jsc->sc_jih[slot].jih_vec, 0, pckbcintr, sc);
 
-	scb_set(jsc->sc_ic[slot].ic_vector, pckbc_jensenio_intr,
-	    &jsc->sc_ic[slot]);
 	aprint_normal_dev(sc->sc_dv, "%s slot interrupting at vector 0x%lx\n",
-	    pckbc_slot_names[slot], jsc->sc_ic[slot].ic_vector);
-
-	snprintf(jsc->sc_ic[slot].ic_vecstr, sizeof(jsc->sc_ic[slot].ic_vecstr),
-	    "0x%lx", jsc->sc_ic[slot].ic_vector);
-	evcnt_attach_dynamic(&jsc->sc_ic[slot].ic_ev, EVCNT_TYPE_INTR,
-	    NULL, "vector", jsc->sc_ic[slot].ic_vecstr);
-}
-
-void
-pckbc_jensenio_intr(void *arg, u_long vec)
-{
-	struct pckbc_jensenio_intrcookie *ic = arg;
-
-	KERNEL_LOCK(1, NULL);
-	ic->ic_ev.ev_count++;
-	(void) pckbcintr(ic->ic_sc);
-	KERNEL_UNLOCK_ONE(NULL);
+	    pckbc_slot_names[slot], jsc->sc_jih[slot].jih_vec);
 }

Index: src/sys/arch/alpha/pci/dwlpx.c
diff -u src/sys/arch/alpha/pci/dwlpx.c:1.38 src/sys/arch/alpha/pci/dwlpx.c:1.39
--- src/sys/arch/alpha/pci/dwlpx.c:1.38	Mon Feb  6 02:14:14 2012
+++ src/sys/arch/alpha/pci/dwlpx.c	Fri Sep 25 03:40:11 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: dwlpx.c,v 1.38 2012/02/06 02:14:14 matt Exp $ */
+/* $NetBSD: dwlpx.c,v 1.39 2020/09/25 03:40:11 thorpej Exp $ */
 
 /*
  * Copyright (c) 1997 by Matthew Jacob
@@ -32,12 +32,13 @@
 
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: dwlpx.c,v 1.38 2012/02/06 02:14:14 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwlpx.c,v 1.39 2020/09/25 03:40:11 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/device.h>
+#include <sys/cpu.h>
 
 #include <machine/autoconf.h>
 
@@ -251,7 +252,9 @@ dwlpx_init(struct dwlpx_softc *sc)
 	 * Do this even for all HPCs- even for the nonexistent
 	 * one on hose zero of a KFTIA.
 	 */
+	mutex_enter(&cpu_lock);
 	vec = scb_alloc(dwlpx_errintr, sc);
+	mutex_exit(&cpu_lock);
 	if (vec == SCB_ALLOC_FAILED)
 		panic("%s: unable to allocate error vector",
 		    device_xname(sc->dwlpx_dev));

Index: src/sys/arch/alpha/pci/pci_2100_a500.c
diff -u src/sys/arch/alpha/pci/pci_2100_a500.c:1.13 src/sys/arch/alpha/pci/pci_2100_a500.c:1.14
--- src/sys/arch/alpha/pci/pci_2100_a500.c:1.13	Tue Sep 22 15:24:02 2020
+++ src/sys/arch/alpha/pci/pci_2100_a500.c	Fri Sep 25 03:40:11 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: pci_2100_a500.c,v 1.13 2020/09/22 15:24:02 thorpej Exp $ */
+/* $NetBSD: pci_2100_a500.c,v 1.14 2020/09/25 03:40:11 thorpej Exp $ */
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: pci_2100_a500.c,v 1.13 2020/09/22 15:24:02 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci_2100_a500.c,v 1.14 2020/09/25 03:40:11 thorpej Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -40,6 +40,7 @@ __KERNEL_RCSID(0, "$NetBSD: pci_2100_a50
 #include <sys/errno.h>
 #include <sys/malloc.h>
 #include <sys/device.h>
+#include <sys/cpu.h>
 #include <sys/syslog.h>
 
 #include <machine/autoconf.h>
@@ -432,17 +433,29 @@ dec_2100_a500_intr_establish(pci_chipset
 
 	KASSERT(irq < SABLE_MAX_IRQ);
 
-	cookie = alpha_shared_intr_establish(pc->pc_shared_intrs, irq,
+	cookie = alpha_shared_intr_alloc_intrhand(pc->pc_shared_intrs, irq,
 	    dec_2100_a500_intr_deftype[irq], level, flags, func, arg, "T2 irq");
 
-	if (cookie != NULL &&
-	    alpha_shared_intr_firstactive(pc->pc_shared_intrs, irq)) {
+	if (cookie == NULL)
+		return NULL;
+
+	mutex_enter(&cpu_lock);
+
+	if (! alpha_shared_intr_link(pc->pc_shared_intrs, cookie, "T2 irq")) {
+		mutex_exit(&cpu_lock);
+		alpha_shared_intr_free_intrhand(cookie);
+		return NULL;
+	}
+
+	if (alpha_shared_intr_firstactive(pc->pc_shared_intrs, irq)) {
 		scb_set(pc->pc_vecbase + SCB_IDXTOVEC(irq),
 		    dec_2100_a500_iointr, tcp);
 		(*tcp->tc_enable_intr)(tcp, irq, 1);
 	}
 
-	return (cookie);
+	mutex_exit(&cpu_lock);
+
+	return cookie;
 }
 
 static void
@@ -451,20 +464,21 @@ dec_2100_a500_intr_disestablish(pci_chip
 	struct ttwoga_config *tcp = pc->pc_intr_v;
 	struct alpha_shared_intrhand *ih = cookie;
 	unsigned int irq = ih->ih_num;
-	int s;
 
-	s = splhigh();
+	mutex_enter(&cpu_lock);
 
-	alpha_shared_intr_disestablish(pc->pc_shared_intrs, cookie,
-	    "T2 irq");
-	if (alpha_shared_intr_isactive(pc->pc_shared_intrs, irq) == 0) {
+	if (alpha_shared_intr_firstactive(pc->pc_shared_intrs, irq)) {
 		(*tcp->tc_enable_intr)(tcp, irq, 0);
 		alpha_shared_intr_set_dfltsharetype(pc->pc_shared_intrs,
 		    irq, dec_2100_a500_intr_deftype[irq]);
 		scb_free(pc->pc_vecbase + SCB_IDXTOVEC(irq));
 	}
 
-	splx(s);
+	alpha_shared_intr_unlink(pc->pc_shared_intrs, cookie, "T2 irq");
+
+	mutex_exit(&cpu_lock);
+
+	alpha_shared_intr_free_intrhand(cookie);
 }
 
 /*****************************************************************************
@@ -554,11 +568,21 @@ dec_2100_a500_eisa_intr_establish(void *
 		return (NULL);
 	}
 
-	cookie = alpha_shared_intr_establish(pc->pc_shared_intrs, irq,
+	cookie = alpha_shared_intr_alloc_intrhand(pc->pc_shared_intrs, irq,
 	    type, level, 0, fn, arg, "T2 irq");
 
-	if (cookie != NULL &&
-	    alpha_shared_intr_firstactive(pc->pc_shared_intrs, irq)) {
+	if (cookie == NULL)
+		return NULL;
+
+	mutex_enter(&cpu_lock);
+
+	if (! alpha_shared_intr_link(pc->pc_shared_intrs, cookie, "T2 irq")) {
+		mutex_exit(&cpu_lock);
+		alpha_shared_intr_free_intrhand(cookie);
+		return NULL;
+	}
+
+	if (alpha_shared_intr_firstactive(pc->pc_shared_intrs, irq)) {
 		scb_set(pc->pc_vecbase + SCB_IDXTOVEC(irq),
 		    dec_2100_a500_iointr, tcp);
 		(*tcp->tc_setlevel)(tcp, eirq,
@@ -567,7 +591,9 @@ dec_2100_a500_eisa_intr_establish(void *
 		(*tcp->tc_enable_intr)(tcp, irq, 1);
 	}
 
-	return (cookie);
+	mutex_exit(&cpu_lock);
+
+	return cookie;
 }
 
 static void
@@ -576,22 +602,23 @@ dec_2100_a500_eisa_intr_disestablish(voi
 	struct ttwoga_config *tcp = v;
 	pci_chipset_tag_t const pc = &tcp->tc_pc;
 	struct alpha_shared_intrhand *ih = cookie;
-	int s, irq = ih->ih_num;
-
-	s = splhigh();
+	int irq = ih->ih_num;
 
-	/* Remove it from the link. */
-	alpha_shared_intr_disestablish(pc->pc_shared_intrs, cookie,
-	    "T2 irq");
+	mutex_enter(&cpu_lock);
 
-	if (alpha_shared_intr_isactive(pc->pc_shared_intrs, irq) == 0) {
+	if (alpha_shared_intr_firstactive(pc->pc_shared_intrs, irq)) {
 		(*tcp->tc_enable_intr)(tcp, irq, 0);
 		alpha_shared_intr_set_dfltsharetype(pc->pc_shared_intrs,
 		    irq, dec_2100_a500_intr_deftype[irq]);
 		scb_free(pc->pc_vecbase + SCB_IDXTOVEC(irq));
 	}
 
-	splx(s);
+	/* Remove it from the link. */
+	alpha_shared_intr_unlink(pc->pc_shared_intrs, cookie, "T2 irq");
+
+	mutex_exit(&cpu_lock);
+
+	alpha_shared_intr_free_intrhand(cookie);
 }
 
 static int

Index: src/sys/arch/alpha/pci/pci_kn300.c
diff -u src/sys/arch/alpha/pci/pci_kn300.c:1.37 src/sys/arch/alpha/pci/pci_kn300.c:1.38
--- src/sys/arch/alpha/pci/pci_kn300.c:1.37	Tue Sep 22 15:24:02 2020
+++ src/sys/arch/alpha/pci/pci_kn300.c	Fri Sep 25 03:40:11 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: pci_kn300.c,v 1.37 2020/09/22 15:24:02 thorpej Exp $ */
+/* $NetBSD: pci_kn300.c,v 1.38 2020/09/25 03:40:11 thorpej Exp $ */
 
 /*
  * Copyright (c) 1998 by Matthew Jacob
@@ -32,7 +32,7 @@
 
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: pci_kn300.c,v 1.37 2020/09/22 15:24:02 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci_kn300.c,v 1.38 2020/09/25 03:40:11 thorpej Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -41,6 +41,7 @@ __KERNEL_RCSID(0, "$NetBSD: pci_kn300.c,
 #include <sys/errno.h>
 #include <sys/malloc.h>
 #include <sys/device.h>
+#include <sys/cpu.h>
 #include <sys/syslog.h>
 
 #include <machine/autoconf.h>
@@ -213,18 +214,31 @@ dec_kn300_intr_establish(
 	const u_int irq = ihv & 0x3ff;
 	const u_int flags = alpha_pci_intr_handle_get_flags(&ih);
 
-	cookie = alpha_shared_intr_establish(kn300_pci_intr, irq, IST_LEVEL,
-	    level, flags, func, arg, "kn300 irq");
+	cookie = alpha_shared_intr_alloc_intrhand(kn300_pci_intr, irq,
+	    IST_LEVEL, level, flags, func, arg, "kn300 irq");
 
-	if (cookie != NULL &&
-	    alpha_shared_intr_firstactive(kn300_pci_intr, irq)) {
+	if (cookie == NULL)
+		return NULL;
+
+	mutex_enter(&cpu_lock);
+
+	if (! alpha_shared_intr_link(kn300_pci_intr, cookie, "kn300 irq")) {
+		mutex_exit(&cpu_lock);
+		alpha_shared_intr_free_intrhand(cookie);
+		return NULL;
+	}
+
+	if (alpha_shared_intr_firstactive(kn300_pci_intr, irq)) {
 		scb_set(MCPCIA_VEC_PCI + SCB_IDXTOVEC(irq), kn300_iointr, NULL);
 		alpha_shared_intr_set_private(kn300_pci_intr, irq, ccp);
 		savirqs[irq] = (ihv >> 11) & 0x1f;
-		kn300_enable_intr(ccp, savirqs[irq]);
 		alpha_mb();
+		kn300_enable_intr(ccp, savirqs[irq]);
 	}
-	return (cookie);
+
+	mutex_exit(&cpu_lock);
+
+	return cookie;
 }
 
 static void

Index: src/sys/arch/alpha/pci/pci_kn8ae.c
diff -u src/sys/arch/alpha/pci/pci_kn8ae.c:1.30 src/sys/arch/alpha/pci/pci_kn8ae.c:1.31
--- src/sys/arch/alpha/pci/pci_kn8ae.c:1.30	Tue Sep 22 15:24:02 2020
+++ src/sys/arch/alpha/pci/pci_kn8ae.c	Fri Sep 25 03:40:11 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: pci_kn8ae.c,v 1.30 2020/09/22 15:24:02 thorpej Exp $ */
+/* $NetBSD: pci_kn8ae.c,v 1.31 2020/09/25 03:40:11 thorpej Exp $ */
 
 /*
  * Copyright (c) 1997 by Matthew Jacob
@@ -32,7 +32,7 @@
 
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: pci_kn8ae.c,v 1.30 2020/09/22 15:24:02 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci_kn8ae.c,v 1.31 2020/09/25 03:40:11 thorpej Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -41,6 +41,7 @@ __KERNEL_RCSID(0, "$NetBSD: pci_kn8ae.c,
 #include <sys/errno.h>
 #include <sys/malloc.h>
 #include <sys/device.h>
+#include <sys/cpu.h>
 #include <sys/syslog.h>
 
 #include <machine/autoconf.h>
@@ -141,7 +142,9 @@ dec_kn8ae_intr_map(const struct pci_atta
 	}
 	pci_decompose_tag(pc, bustag, NULL, &device, NULL);
 
+	mutex_enter(&cpu_lock);
 	vec = scb_alloc(kn8ae_spurious, NULL);
+	mutex_exit(&cpu_lock);
 	if (vec == SCB_ALLOC_FAILED) {
 		printf("dec_kn8ae_intr_map: no vector available for "
 		    "device %d pin %d\n", device, buspin);
@@ -185,6 +188,7 @@ dec_kn8ae_intr_establish(
 	struct scbvec *scb;
 	u_long vec;
 	int pin, device, hpc;
+	void (*scb_func)(void *, u_long);
 	const u_int ihv = alpha_pci_intr_handle_get_irq(&ih);
 	const u_int flags = alpha_pci_intr_handle_get_flags(&ih);
 
@@ -192,9 +196,12 @@ dec_kn8ae_intr_establish(
 	pin = IH_PIN(ihv);
 	vec = IH_VEC(ihv);
 
+	mutex_enter(&cpu_lock);
+
 	scb = &scb_iovectab[SCB_VECTOIDX(vec - SCB_IOVECBASE)];
 
 	if (scb->scb_func != kn8ae_spurious) {
+		mutex_exit(&cpu_lock);
 		printf("dec_kn8ae_intr_establish: vector 0x%lx not mapped\n",
 		    vec);
 		return (NULL);
@@ -205,17 +212,15 @@ dec_kn8ae_intr_establish(
 	 * so we don't have to worry about it (in theory, at least).
 	 */
 
-	scb->scb_arg = arg;
-	alpha_mb();
 	if (flags & ALPHA_INTR_MPSAFE) {
-		scb->scb_func = (void (*)(void *, u_long))func;
+		scb_func = (void (*)(void *, u_long))func;
 	} else {
 		kn8ae_wrapped_pci_intrs[
 		    SCB_VECTOIDX(vec - SCB_IOVECBASE)].ih_fn = func;
-		alpha_mb();
-		scb->scb_func = kn8ae_intr_wrapper;
+		    scb_func = kn8ae_intr_wrapper;
 	}
-	alpha_mb();
+
+	scb_set(vec, scb_func, arg);
 
 	if (device < 4) {
 		hpc = 0;
@@ -226,10 +231,12 @@ dec_kn8ae_intr_establish(
 		device -= 8;
 		hpc = 2;
 	}
-	REGVAL(PCIA_DEVVEC(hpc, device, pin) + ccp->cc_sysbase) = vec;
 
+	REGVAL(PCIA_DEVVEC(hpc, device, pin) + ccp->cc_sysbase) = vec;
 	kn8ae_enadis_intr(ccp, ih, 1);
 
+	mutex_exit(&cpu_lock);
+
 	cookie = (void *) ih.value;
 
 	return (cookie);
@@ -241,17 +248,17 @@ dec_kn8ae_intr_disestablish(pci_chipset_
 	struct dwlpx_config * const ccp = pc->pc_intr_v;
 	const u_long ihv = (u_long) cookie;
 	pci_intr_handle_t ih = { .value = ihv };
-	struct scbvec *scb;
 	u_long vec;
 
 	vec = IH_VEC(ihv);
 
-	scb = &scb_iovectab[SCB_VECTOIDX(vec - SCB_IOVECBASE)];
-	__USE(scb);
+	mutex_enter(&cpu_lock);
 
 	kn8ae_enadis_intr(ccp, ih, 0);
 
 	scb_free(vec);
+
+	mutex_exit(&cpu_lock);
 }
 
 static void
@@ -267,7 +274,7 @@ kn8ae_enadis_intr(struct dwlpx_config *c
 	const u_int ihv = alpha_pci_intr_handle_get_irq(&ih);
 	unsigned long paddr;
 	uint32_t val;
-	int ionode, hose, device, hpc, busp, s;
+	int ionode, hose, device, hpc, busp;
 
 	ionode = sc->dwlpx_node - 4;
 	hose = sc->dwlpx_hosenum;
@@ -299,8 +306,8 @@ kn8ae_enadis_intr(struct dwlpx_config *c
 	printf("kn8ae_%s_intr: ihv %x imsk 0x%x hpc %d TLSB node %d hose %d\n",
 	    onoff? "enable" : "disable", ihv, val, hpc, ionode + 4, hose);
 #endif
-	s = splhigh();
+	const u_long psl = alpha_pal_swpipl(ALPHA_PSL_IPL_HIGH);
 	REGVAL(PCIA_IMASK(hpc) + paddr) = val;
 	alpha_mb();
-	(void) splx(s);
+	alpha_pal_swpipl(psl);
 }

Index: src/sys/arch/alpha/pci/pci_machdep.c
diff -u src/sys/arch/alpha/pci/pci_machdep.c:1.25 src/sys/arch/alpha/pci/pci_machdep.c:1.26
--- src/sys/arch/alpha/pci/pci_machdep.c:1.25	Tue Sep 22 15:24:02 2020
+++ src/sys/arch/alpha/pci/pci_machdep.c	Fri Sep 25 03:40:11 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: pci_machdep.c,v 1.25 2020/09/22 15:24:02 thorpej Exp $ */
+/* $NetBSD: pci_machdep.c,v 1.26 2020/09/25 03:40:11 thorpej Exp $ */
 
 /*-
  * Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -62,7 +62,7 @@
 
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.25 2020/09/22 15:24:02 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.26 2020/09/25 03:40:11 thorpej Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -70,6 +70,7 @@ __KERNEL_RCSID(0, "$NetBSD: pci_machdep.
 #include <sys/systm.h>
 #include <sys/errno.h>
 #include <sys/device.h>
+#include <sys/cpu.h>
 
 #include <dev/isa/isavar.h>
 #include <dev/pci/pcireg.h>
@@ -234,15 +235,29 @@ alpha_pci_generic_intr_establish(pci_chi
 
 	KASSERT(irq < pc->pc_nirq);
 
-	cookie = alpha_shared_intr_establish(pc->pc_shared_intrs,
+	cookie = alpha_shared_intr_alloc_intrhand(pc->pc_shared_intrs,
 	    irq, IST_LEVEL, level, flags, func, arg, pc->pc_intr_desc);
 
-	if (cookie != NULL &&
-	    alpha_shared_intr_firstactive(pc->pc_shared_intrs, irq)) {
+	if (cookie == NULL)
+		return NULL;
+
+	mutex_enter(&cpu_lock);
+
+	if (! alpha_shared_intr_link(pc->pc_shared_intrs, cookie,
+				     pc->pc_intr_desc)) {
+		mutex_exit(&cpu_lock);
+		alpha_shared_intr_free_intrhand(cookie);
+		return NULL;
+	}
+
+	if (alpha_shared_intr_firstactive(pc->pc_shared_intrs, irq)) {
 		scb_set(pc->pc_vecbase + SCB_IDXTOVEC(irq),
 		    alpha_pci_generic_iointr, pc);
 		pc->pc_intr_enable(pc, irq);
 	}
+
+	mutex_exit(&cpu_lock);
+
 	return cookie;
 }
 
@@ -252,20 +267,21 @@ alpha_pci_generic_intr_disestablish(pci_
 {
 	struct alpha_shared_intrhand * const ih = cookie;
 	const u_int irq = ih->ih_num;
-	int s;
 
-	s = splhigh();
+	mutex_enter(&cpu_lock);
 
-	alpha_shared_intr_disestablish(pc->pc_shared_intrs, cookie,
-	    pc->pc_intr_desc);
-	if (alpha_shared_intr_isactive(pc->pc_shared_intrs, irq) == 0) {
+	if (alpha_shared_intr_firstactive(pc->pc_shared_intrs, irq)) {
 		pc->pc_intr_disable(pc, irq);
 		alpha_shared_intr_set_dfltsharetype(pc->pc_shared_intrs,
 		    irq, IST_NONE);
 		scb_free(pc->pc_vecbase + SCB_IDXTOVEC(irq));
 	}
 
-	splx(s);
+	alpha_shared_intr_unlink(pc->pc_shared_intrs, cookie, pc->pc_intr_desc);
+
+	mutex_exit(&cpu_lock);
+
+	alpha_shared_intr_free_intrhand(cookie);
 }
 
 void

Index: src/sys/arch/alpha/pci/sio_pic.c
diff -u src/sys/arch/alpha/pci/sio_pic.c:1.44 src/sys/arch/alpha/pci/sio_pic.c:1.45
--- src/sys/arch/alpha/pci/sio_pic.c:1.44	Tue Sep 22 15:24:02 2020
+++ src/sys/arch/alpha/pci/sio_pic.c	Fri Sep 25 03:40:11 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: sio_pic.c,v 1.44 2020/09/22 15:24:02 thorpej Exp $ */
+/* $NetBSD: sio_pic.c,v 1.45 2020/09/25 03:40:11 thorpej Exp $ */
 
 /*-
  * Copyright (c) 1998, 2000, 2020 The NetBSD Foundation, Inc.
@@ -59,12 +59,13 @@
 
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: sio_pic.c,v 1.44 2020/09/22 15:24:02 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sio_pic.c,v 1.45 2020/09/25 03:40:11 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/device.h>
 #include <sys/malloc.h>
+#include <sys/cpu.h>
 #include <sys/syslog.h>
 
 #include <machine/intr.h>
@@ -444,29 +445,38 @@ sio_intr_establish(void *v, int irq, int
 	if (irq > ICU_LEN || type == IST_NONE)
 		panic("sio_intr_establish: bogus irq or type");
 
-	cookie = alpha_shared_intr_establish(sio_intr, irq, type, level,
+	cookie = alpha_shared_intr_alloc_intrhand(sio_intr, irq, type, level,
 	    flags, fn, arg, "isa irq");
 
-	if (cookie != NULL &&
-	    alpha_shared_intr_firstactive(sio_intr, irq)) {
+	if (cookie == NULL)
+		return NULL;
+
+	mutex_enter(&cpu_lock);
+
+	if (! alpha_shared_intr_link(sio_intr, cookie, "isa irq")) {
+		mutex_exit(&cpu_lock);
+		alpha_shared_intr_free_intrhand(cookie);
+		return NULL;
+	}
+
+	if (alpha_shared_intr_firstactive(sio_intr, irq)) {
 		scb_set(0x800 + SCB_IDXTOVEC(irq), sio_iointr, NULL);
 		sio_setirqstat(irq, 1,
 		    alpha_shared_intr_get_sharetype(sio_intr, irq));
 	}
 
-	return (cookie);
+	mutex_exit(&cpu_lock);
+
+	return cookie;
 }
 
 void
 sio_intr_disestablish(void *v, void *cookie)
 {
 	struct alpha_shared_intrhand *ih = cookie;
-	int s, ist, irq = ih->ih_num;
+	int ist, irq = ih->ih_num;
 
-	s = splhigh();
-
-	/* Remove it from the link. */
-	alpha_shared_intr_disestablish(sio_intr, cookie, "isa irq");
+	mutex_enter(&cpu_lock);
 
 	/*
 	 * Decide if we should disable the interrupt.  We must ensure
@@ -475,7 +485,7 @@ sio_intr_disestablish(void *v, void *coo
 	 *	- An initially-enabled interrupt is never disabled.
 	 *	- An initially-LT interrupt is never untyped.
 	 */
-	if (alpha_shared_intr_isactive(sio_intr, irq) == 0) {
+	if (alpha_shared_intr_firstactive(sio_intr, irq)) {
 		/*
 		 * IRQs 0, 1, 8, and 13 must always be edge-triggered
 		 * (see setup).
@@ -503,7 +513,12 @@ sio_intr_disestablish(void *v, void *coo
 		scb_free(0x800 + SCB_IDXTOVEC(irq));
 	}
 
-	splx(s);
+	/* Remove it from the link. */
+	alpha_shared_intr_unlink(sio_intr, cookie, "isa irq");
+
+	mutex_exit(&cpu_lock);
+
+	alpha_shared_intr_free_intrhand(cookie);
 }
 
 const char *

Index: src/sys/arch/alpha/tc/tc_3000_300.c
diff -u src/sys/arch/alpha/tc/tc_3000_300.c:1.36 src/sys/arch/alpha/tc/tc_3000_300.c:1.37
--- src/sys/arch/alpha/tc/tc_3000_300.c:1.36	Tue Sep 22 15:24:02 2020
+++ src/sys/arch/alpha/tc/tc_3000_300.c	Fri Sep 25 03:40:11 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: tc_3000_300.c,v 1.36 2020/09/22 15:24:02 thorpej Exp $ */
+/* $NetBSD: tc_3000_300.c,v 1.37 2020/09/25 03:40:11 thorpej Exp $ */
 
 /*
  * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
@@ -29,12 +29,13 @@
 
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: tc_3000_300.c,v 1.36 2020/09/22 15:24:02 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tc_3000_300.c,v 1.37 2020/09/25 03:40:11 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/device.h>
 #include <sys/malloc.h>
+#include <sys/cpu.h>
 
 #include <machine/autoconf.h>
 #include <machine/pte.h>
@@ -143,9 +144,18 @@ tc_3000_300_intr_establish(device_t tcad
 	if (tc_3000_300_intr[dev].tci_func != tc_3000_300_intrnull)
 		panic("tc_3000_300_intr_establish: cookie %lu twice", dev);
 
+	const int s = splhigh();
+
+	/* All TC systems are uniprocessors. */
+	KASSERT(CPU_IS_PRIMARY(curcpu()));
+	KASSERT(ncpu == 1);
+	curcpu()->ci_nintrhand++;
+
 	tc_3000_300_intr[dev].tci_func = func;
 	tc_3000_300_intr[dev].tci_arg = arg;
 
+	splx(s);
+
 	imskp = (volatile uint32_t *)(DEC_3000_300_IOASIC_ADDR + IOASIC_IMSK);
 	switch (dev) {
 	case TC_3000_300_DEV_OPT0:
@@ -187,8 +197,14 @@ tc_3000_300_intr_disestablish(device_t t
 		break;
 	}
 
+	const int s = splhigh();
+
+	curcpu()->ci_nintrhand--;
+
 	tc_3000_300_intr[dev].tci_func = tc_3000_300_intrnull;
 	tc_3000_300_intr[dev].tci_arg = (void *)dev;
+
+	splx(s);
 }
 
 int

Index: src/sys/arch/alpha/tc/tc_3000_500.c
diff -u src/sys/arch/alpha/tc/tc_3000_500.c:1.35 src/sys/arch/alpha/tc/tc_3000_500.c:1.36
--- src/sys/arch/alpha/tc/tc_3000_500.c:1.35	Tue Sep 22 15:24:02 2020
+++ src/sys/arch/alpha/tc/tc_3000_500.c	Fri Sep 25 03:40:11 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: tc_3000_500.c,v 1.35 2020/09/22 15:24:02 thorpej Exp $ */
+/* $NetBSD: tc_3000_500.c,v 1.36 2020/09/25 03:40:11 thorpej Exp $ */
 
 /*
  * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
@@ -29,12 +29,13 @@
 
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: tc_3000_500.c,v 1.35 2020/09/22 15:24:02 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tc_3000_500.c,v 1.36 2020/09/25 03:40:11 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/device.h>
 #include <sys/malloc.h>
+#include <sys/cpu.h>
 
 #include <machine/autoconf.h>
 #include <machine/pte.h>
@@ -166,9 +167,18 @@ tc_3000_500_intr_establish(device_t tcad
 	if (tc_3000_500_intr[dev].tci_func != tc_3000_500_intrnull)
 		panic("tc_3000_500_intr_establish: cookie %lu twice", dev);
 
+	const int s = splhigh();
+
+	/* All TC systems are uniprocessors. */
+	KASSERT(CPU_IS_PRIMARY(curcpu()));
+	KASSERT(ncpu == 1);
+	curcpu()->ci_nintrhand++;
+
 	tc_3000_500_intr[dev].tci_func = func;
 	tc_3000_500_intr[dev].tci_arg = arg;
 
+	splx(s);
+
 	tc_3000_500_imask &= ~tc_3000_500_intrbits[dev];
 	*(volatile uint32_t *)TC_3000_500_IMR_WRITE = tc_3000_500_imask;
 	tc_mb();
@@ -191,8 +201,14 @@ tc_3000_500_intr_disestablish(device_t t
 	*(volatile uint32_t *)TC_3000_500_IMR_WRITE = tc_3000_500_imask;
 	tc_mb();
 
+	const int s = splhigh();
+
+	curcpu()->ci_nintrhand--;
+
 	tc_3000_500_intr[dev].tci_func = tc_3000_500_intrnull;
 	tc_3000_500_intr[dev].tci_arg = (void *)dev;
+
+	splx(s);
 }
 
 int

Index: src/sys/arch/alpha/tc/tcasic.c
diff -u src/sys/arch/alpha/tc/tcasic.c:1.48 src/sys/arch/alpha/tc/tcasic.c:1.49
--- src/sys/arch/alpha/tc/tcasic.c:1.48	Tue Sep 22 15:24:02 2020
+++ src/sys/arch/alpha/tc/tcasic.c	Fri Sep 25 03:40:11 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: tcasic.c,v 1.48 2020/09/22 15:24:02 thorpej Exp $ */
+/* $NetBSD: tcasic.c,v 1.49 2020/09/25 03:40:11 thorpej Exp $ */
 
 /*
  * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
@@ -32,10 +32,11 @@
 
 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
 
-__KERNEL_RCSID(0, "$NetBSD: tcasic.c,v 1.48 2020/09/22 15:24:02 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tcasic.c,v 1.49 2020/09/25 03:40:11 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/cpu.h>
 #include <sys/device.h>
 
 #include <machine/autoconf.h>
@@ -145,7 +146,9 @@ tcasicattach(device_t parent, device_t s
 	(*intr_setup)();
 
 	/* They all come in at 0x800. */
+	mutex_enter(&cpu_lock);
 	scb_set(0x800, iointr, NULL);
+	mutex_exit(&cpu_lock);
 
 	config_found(self, &tba, tcasicprint);
 }

Reply via email to