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;
}