Module Name:    src
Committed By:   thorpej
Date:           Sun Dec 22 15:09:39 UTC 2019

Modified Files:
        src/sys/arch/amd64/amd64: genassym.cf vector.S
        src/sys/arch/i386/i386: genassym.cf vector.S
        src/sys/arch/x86/include: intr.h
        src/sys/arch/x86/x86: intr.c

Log Message:
Add intr_mask() and corresponding intr_unmask() calls that allow specific
interrupt lines / sources to be masked as needed (rather than making a
set of sources by IPL as with spl*()).


To generate a diff of this commit:
cvs rdiff -u -r1.78 -r1.79 src/sys/arch/amd64/amd64/genassym.cf
cvs rdiff -u -r1.71 -r1.72 src/sys/arch/amd64/amd64/vector.S
cvs rdiff -u -r1.115 -r1.116 src/sys/arch/i386/i386/genassym.cf
cvs rdiff -u -r1.83 -r1.84 src/sys/arch/i386/i386/vector.S
cvs rdiff -u -r1.60 -r1.61 src/sys/arch/x86/include/intr.h
cvs rdiff -u -r1.147 -r1.148 src/sys/arch/x86/x86/intr.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/amd64/amd64/genassym.cf
diff -u src/sys/arch/amd64/amd64/genassym.cf:1.78 src/sys/arch/amd64/amd64/genassym.cf:1.79
--- src/sys/arch/amd64/amd64/genassym.cf:1.78	Thu Nov 21 19:27:54 2019
+++ src/sys/arch/amd64/amd64/genassym.cf	Sun Dec 22 15:09:39 2019
@@ -1,4 +1,4 @@
-#	$NetBSD: genassym.cf,v 1.78 2019/11/21 19:27:54 ad Exp $
+#	$NetBSD: genassym.cf,v 1.79 2019/12/22 15:09:39 thorpej Exp $
 
 #
 # Copyright (c) 1998, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -321,7 +321,8 @@ define	IS_FLAGS	offsetof(struct intrsour
 define	IS_PIN		offsetof(struct intrsource, is_pin)
 define	IS_TYPE		offsetof(struct intrsource, is_type)
 define	IS_MAXLEVEL	offsetof(struct intrsource, is_maxlevel)
-define	IS_LWP			offsetof(struct intrsource, is_lwp)
+define	IS_LWP		offsetof(struct intrsource, is_lwp)
+define	IS_MASK_COUNT	offsetof(struct intrsource, is_mask_count)
 
 define	IPL_NONE		IPL_NONE
 define	IPL_PREEMPT		IPL_PREEMPT

Index: src/sys/arch/amd64/amd64/vector.S
diff -u src/sys/arch/amd64/amd64/vector.S:1.71 src/sys/arch/amd64/amd64/vector.S:1.72
--- src/sys/arch/amd64/amd64/vector.S:1.71	Sun Nov 17 14:07:00 2019
+++ src/sys/arch/amd64/amd64/vector.S	Sun Dec 22 15:09:39 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: vector.S,v 1.71 2019/11/17 14:07:00 maxv Exp $	*/
+/*	$NetBSD: vector.S,v 1.72 2019/12/22 15:09:39 thorpej Exp $	*/
 
 /*
  * Copyright (c) 1998, 2007, 2008 The NetBSD Foundation, Inc.
@@ -391,6 +391,8 @@ IDTVEC(handle_ ## name ## num)						;\
 	sti								;\
 	incl	CPUVAR(IDEPTH)						;\
 	movq	IS_HANDLERS(%r14),%rbx					;\
+	cmpl	$0,IS_MASK_COUNT(%r14)	/* source currently masked? */	;\
+	jne	7f			/* yes, hold it */		;\
 6:									\
 	movl	IH_LEVEL(%rbx),%r12d					;\
 	cmpl	%r13d,%r12d						;\
@@ -403,6 +405,8 @@ IDTVEC(handle_ ## name ## num)						;\
 	testq	%rbx,%rbx						;\
 	jnz	6b							;\
 5:									\
+	cmpl	$0,IS_MASK_COUNT(%r14)	/* source now masked? */	;\
+	jne	7f			/* yes, deal */			;\
 	cli								;\
 	unmask(num)			/* unmask it in hardware */	;\
 	late_ack(num)							;\

Index: src/sys/arch/i386/i386/genassym.cf
diff -u src/sys/arch/i386/i386/genassym.cf:1.115 src/sys/arch/i386/i386/genassym.cf:1.116
--- src/sys/arch/i386/i386/genassym.cf:1.115	Thu Nov 21 19:27:54 2019
+++ src/sys/arch/i386/i386/genassym.cf	Sun Dec 22 15:09:39 2019
@@ -1,4 +1,4 @@
-#	$NetBSD: genassym.cf,v 1.115 2019/11/21 19:27:54 ad Exp $
+#	$NetBSD: genassym.cf,v 1.116 2019/12/22 15:09:39 thorpej Exp $
 
 #
 # Copyright (c) 1998, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -322,6 +322,7 @@ define	IS_PIN			offsetof(struct intrsour
 define	IS_TYPE			offsetof(struct intrsource, is_type)
 define	IS_MAXLEVEL		offsetof(struct intrsource, is_maxlevel)
 define	IS_LWP			offsetof(struct intrsource, is_lwp)
+define	IS_MASK_COUNT		offsetof(struct intrsource, is_mask_count)
 
 define	IPL_NONE		IPL_NONE
 define	IPL_PREEMPT		IPL_PREEMPT

Index: src/sys/arch/i386/i386/vector.S
diff -u src/sys/arch/i386/i386/vector.S:1.83 src/sys/arch/i386/i386/vector.S:1.84
--- src/sys/arch/i386/i386/vector.S:1.83	Fri Feb 15 08:54:01 2019
+++ src/sys/arch/i386/i386/vector.S	Sun Dec 22 15:09:39 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: vector.S,v 1.83 2019/02/15 08:54:01 nonaka Exp $	*/
+/*	$NetBSD: vector.S,v 1.84 2019/12/22 15:09:39 thorpej Exp $	*/
 
 /*
  * Copyright 2002 (c) Wasabi Systems, Inc.
@@ -65,7 +65,7 @@
  */
 
 #include <machine/asm.h>
-__KERNEL_RCSID(0, "$NetBSD: vector.S,v 1.83 2019/02/15 08:54:01 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vector.S,v 1.84 2019/12/22 15:09:39 thorpej Exp $");
 
 #include "opt_ddb.h"
 #include "opt_multiprocessor.h"
@@ -408,6 +408,8 @@ IDTVEC(intr_ ## name ## num)						;\
 	IDEPTH_INCR							;\
 	sti								;\
 	movl	IS_HANDLERS(%ebp),%ebx					;\
+	cmpl	$0,IS_MASK_COUNT(%ebp)	/* source currently masked? */	;\
+	jne	7f			/* yes, hold it */		;\
 6:									\
 	movl	IH_LEVEL(%ebx),%edi					;\
 	cmpl	%esi,%edi						;\
@@ -420,6 +422,8 @@ IDTVEC(intr_ ## name ## num)						;\
 	addl	$4,%esp			/* toss the arg */		;\
 	testl	%ebx,%ebx						;\
 	jnz	6b							;\
+	cmpl	$0,IS_MASK_COUNT(%ebp)	/* source now masked? */	;\
+	jne	7f			/* yes, deal */			;\
 	cli								;\
 	unmask(num)			/* unmask it in hardware */	;\
 	late_ack(num)							;\

Index: src/sys/arch/x86/include/intr.h
diff -u src/sys/arch/x86/include/intr.h:1.60 src/sys/arch/x86/include/intr.h:1.61
--- src/sys/arch/x86/include/intr.h:1.60	Thu Feb 14 08:18:25 2019
+++ src/sys/arch/x86/include/intr.h	Sun Dec 22 15:09:39 2019
@@ -1,7 +1,7 @@
-/*	$NetBSD: intr.h,v 1.60 2019/02/14 08:18:25 cherry Exp $	*/
+/*	$NetBSD: intr.h,v 1.61 2019/12/22 15:09:39 thorpej Exp $	*/
 
 /*-
- * Copyright (c) 1998, 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2001, 2006, 2007, 2008, 2019 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -95,6 +95,16 @@ struct intrsource {
 	u_long ipl_evt_mask2[NR_EVENT_CHANNELS];
 #endif
 	struct evcnt is_evcnt;		/* interrupt counter per cpu */
+	/*
+	 * is_mask_count requires special handling; it can only be modifed
+	 * or examined on the CPU that owns the interrupt source, and such
+	 * references need to be protected by disabling interrupts.  This
+	 * is because intr_mask() can be called from an interrupt handler.
+	 * is_distribute_pending does not require such special handling
+	 * because intr_unmask() cannot be called from an interrupt handler.
+	 */
+	u_int is_mask_count;		/* masked? (nested) [see above] */
+	int is_distribute_pending;	/* ci<->ci move pending [cpu_lock] */
 	int is_flags;			/* see below */
 	int is_type;			/* level, edge */
 	int is_idtvec;
@@ -215,6 +225,8 @@ void x86_nmi(void);
 void *intr_establish_xname(int, struct pic *, int, int, int, int (*)(void *),
 			   void *, bool, const char *);
 void *intr_establish(int, struct pic *, int, int, int, int (*)(void *), void *, bool);
+void intr_mask(struct intrhand *);
+void intr_unmask(struct intrhand *);
 void intr_disestablish(struct intrhand *);
 void intr_add_pcibus(struct pcibus_attach_args *);
 const char *intr_string(intr_handle_t, char *, size_t);

Index: src/sys/arch/x86/x86/intr.c
diff -u src/sys/arch/x86/x86/intr.c:1.147 src/sys/arch/x86/x86/intr.c:1.148
--- src/sys/arch/x86/x86/intr.c:1.147	Fri Nov  8 04:15:02 2019
+++ src/sys/arch/x86/x86/intr.c	Sun Dec 22 15:09:39 2019
@@ -1,11 +1,11 @@
-/*	$NetBSD: intr.c,v 1.147 2019/11/08 04:15:02 msaitoh Exp $	*/
+/*	$NetBSD: intr.c,v 1.148 2019/12/22 15:09:39 thorpej Exp $	*/
 
 /*
- * Copyright (c) 2007, 2008, 2009 The NetBSD Foundation, Inc.
+ * Copyright (c) 2007, 2008, 2009, 2019 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
- * by Andrew Doran.
+ * by Andrew Doran, and by Jason R. Thorpe.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -133,7 +133,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.147 2019/11/08 04:15:02 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.148 2019/12/22 15:09:39 thorpej Exp $");
 
 #include "opt_intrdebug.h"
 #include "opt_multiprocessor.h"
@@ -743,6 +743,34 @@ intr_append_intrsource_xname(struct intr
 }
 
 /*
+ * Called on bound CPU to handle calling pic_hwunmask from contexts
+ * that are not already running on the bound CPU.
+ *
+ * => caller (on initiating CPU) holds cpu_lock on our behalf
+ * => arg1: struct intrhand *ih
+ */
+static void
+intr_hwunmask_xcall(void *arg1, void *arg2)
+{
+	struct intrhand * const ih = arg1;
+	struct cpu_info * const ci = ih->ih_cpu;
+
+	KASSERT(ci == curcpu() || !mp_online);
+
+	const u_long psl = x86_read_psl();
+	x86_disable_intr();
+
+	struct intrsource * const source = ci->ci_isources[ih->ih_slot];
+	struct pic * const pic = source->is_pic;
+
+	if (source->is_mask_count == 0) {
+		(*pic->pic_hwunmask)(pic, ih->ih_pin);
+	}
+
+	x86_write_psl(psl);
+}
+
+/*
  * Handle per-CPU component of interrupt establish.
  *
  * => caller (on initiating CPU) holds cpu_lock on our behalf
@@ -958,7 +986,12 @@ intr_establish_xname(int legacy_irq, str
 
 	/* All set up, so add a route for the interrupt and unmask it. */
 	(*pic->pic_addroute)(pic, ci, pin, idt_vec, type);
-	(*pic->pic_hwunmask)(pic, pin);
+	if (ci == curcpu() || !mp_online) {
+		intr_hwunmask_xcall(ih, NULL);
+	} else {
+		where = xc_unicast(0, intr_hwunmask_xcall, ih, NULL, ci);
+		xc_wait(where);
+	}
 	mutex_exit(&cpu_lock);
 
 	if (bootverbose || cpu_index(ci) != 0)
@@ -980,6 +1013,118 @@ intr_establish(int legacy_irq, struct pi
 }
 
 /*
+ * Called on bound CPU to handle intr_mask() / intr_unmask().
+ *
+ * => caller (on initiating CPU) holds cpu_lock on our behalf
+ * => arg1: struct intrhand *ih
+ * => arg2: true -> mask, false -> unmask.
+ */
+static void
+intr_mask_xcall(void *arg1, void *arg2)
+{
+	struct intrhand * const ih = arg1;
+	const uintptr_t mask = (uintptr_t)arg2;
+	struct cpu_info * const ci = ih->ih_cpu;
+	bool force_pending = false;
+
+	KASSERT(ci == curcpu() || !mp_online);
+
+	/*
+	 * We need to disable interrupts to hold off the interrupt
+	 * vectors.
+	 */
+	const u_long psl = x86_read_psl();
+	x86_disable_intr();
+
+	struct intrsource * const source = ci->ci_isources[ih->ih_slot];
+	struct pic * const pic = source->is_pic;
+
+	if (mask) {
+		source->is_mask_count++;
+		KASSERT(source->is_mask_count != 0);
+		if (source->is_mask_count == 1) {
+			(*pic->pic_hwmask)(pic, ih->ih_pin);
+		}
+	} else {
+		KASSERT(source->is_mask_count != 0);
+		if (--source->is_mask_count == 0) {
+			/*
+			 * If this interrupt source is being moved, don't
+			 * unmask it at the hw.
+			 */
+			if (! source->is_distribute_pending)
+				(*pic->pic_hwunmask)(pic, ih->ih_pin);
+			force_pending = true;
+		}
+	}
+
+	/* Re-enable interrupts. */
+	x86_write_psl(psl);
+
+	if (force_pending) {
+		/* Force processing of any pending interrupts. */
+		splx(splhigh());
+	}
+}
+
+static void
+intr_mask_internal(struct intrhand * const ih, const bool mask)
+{
+
+	/*
+	 * Call out to the remote CPU to update its interrupt state.
+	 * Only make RPCs if the APs are up and running.
+	 */
+	mutex_enter(&cpu_lock);
+	struct cpu_info * const ci = ih->ih_cpu;
+	void * const mask_arg = (void *)(uintptr_t)mask;
+	if (ci == curcpu() || !mp_online) {
+		intr_mask_xcall(ih, mask_arg);
+	} else {
+		const uint64_t where =
+		    xc_unicast(0, intr_mask_xcall, ih, mask_arg, ci);
+		xc_wait(where);
+	}
+	mutex_exit(&cpu_lock);
+}
+
+void
+intr_mask(struct intrhand *ih)
+{
+
+	if (cpu_intr_p()) {
+		/*
+		 * Special case of calling intr_mask() from an interrupt
+		 * handler: we MUST be called from the bound CPU for this
+		 * interrupt (presumably from a handler we're about to
+		 * mask).
+		 *
+		 * We can't take the cpu_lock in this case, and we must
+		 * therefore be extra careful.
+		 */
+		struct cpu_info * const ci = ih->ih_cpu;
+		KASSERT(ci == curcpu() || !mp_online);
+		intr_mask_xcall(ih, (void *)(uintptr_t)true);
+		return;
+	}
+
+	intr_mask_internal(ih, true);
+}
+
+void
+intr_unmask(struct intrhand *ih)
+{
+
+	/*
+	 * This is not safe to call from an interrupt context because
+	 * we don't want to accidentally unmask an interrupt source
+	 * that's masked because it's being serviced.
+	 */
+	KASSERT(!cpu_intr_p());
+	intr_mask_internal(ih, false);
+}
+
+/*
  * Called on bound CPU to handle intr_disestablish().
  *
  * => caller (on initiating CPU) holds cpu_lock on our behalf
@@ -1039,7 +1184,7 @@ intr_disestablish_xcall(void *arg1, void
 	if (source->is_handlers == NULL)
 		(*pic->pic_delroute)(pic, ci, ih->ih_pin, idtvec,
 		    source->is_type);
-	else
+	else if (source->is_mask_count == 0)
 		(*pic->pic_hwunmask)(pic, ih->ih_pin);
 
 	/* Re-enable interrupts. */
@@ -1854,10 +1999,14 @@ intr_set_affinity(struct intrsource *isp
 		return err;
 	}
 
+	/* Prevent intr_unmask() from reenabling the source at the hw. */
+	isp->is_distribute_pending = true;
+
 	pin = isp->is_pin;
 	(*pic->pic_hwmask)(pic, pin); /* for ci_ipending check */
-	while (oldci->ci_ipending & (1 << oldslot))
+	while (oldci->ci_ipending & (1 << oldslot)) {
 		(void)kpause("intrdist", false, 1, &cpu_lock);
+	}
 
 	kpreempt_disable();
 
@@ -1892,9 +2041,16 @@ intr_set_affinity(struct intrsource *isp
 	isp->is_active_cpu = newci->ci_cpuid;
 	(*pic->pic_addroute)(pic, newci, pin, idt_vec, isp->is_type);
 
-	kpreempt_enable();
+	isp->is_distribute_pending = false;
+	if (newci == curcpu() || !mp_online) {
+		intr_hwunmask_xcall(ih, NULL);
+	} else {
+		uint64_t where;
+		where = xc_unicast(0, intr_hwunmask_xcall, ih, NULL, newci);
+		xc_wait(where);
+	}
 
-	(*pic->pic_hwunmask)(pic, pin);
+	kpreempt_enable();
 
 	return err;
 }

Reply via email to