Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch Fix a problem with intr_unmask() that can cause a f...



details:   https://anonhg.NetBSD.org/src/rev/a6e435a4a38f
branches:  trunk
changeset: 466685:a6e435a4a38f
user:      thorpej <thorpej%NetBSD.org@localhost>
date:      Mon Dec 30 23:32:29 2019 +0000

description:
Fix a problem with intr_unmask() that can cause a forever-loop:
- When handling the source-is-masked case in the interrupt vector, set the
  interrupt bit in a new ci_imasked field and ensure the bit is cleared
  from ci_ipending.
- In intr_unmask(), transfer the bit from ci_imasked to ci_ipending for
  non-level-sensitive interrupts (the PIC does the work for us in the
  level-sensitive case), and only force pending interrupts to be processed
  in this case.  (In all cases, make sure the now-unmasked bit is cleared
  from ci_imasked.)

Before, the bit was left in ci_ipending so as not to use edge-triggered
interrupts while the source is masked, but Xspllower() relies on the
pending bits getting cleared.

Tested by forcing all wm(4) interrupts on my test system though an
intr_mask() / softint / intr_unmask() cycle and exercising the network
heavily.

diffstat:

 sys/arch/amd64/amd64/genassym.cf |   3 ++-
 sys/arch/amd64/amd64/vector.S    |  13 +++++++++----
 sys/arch/i386/i386/genassym.cf   |   3 ++-
 sys/arch/i386/i386/vector.S      |  15 ++++++++++-----
 sys/arch/x86/include/cpu.h       |   4 +++-
 sys/arch/x86/x86/intr.c          |  23 +++++++++++++++++++----
 6 files changed, 45 insertions(+), 16 deletions(-)

diffs (196 lines):

diff -r 6a02865fb425 -r a6e435a4a38f sys/arch/amd64/amd64/genassym.cf
--- a/sys/arch/amd64/amd64/genassym.cf  Mon Dec 30 22:13:46 2019 +0000
+++ b/sys/arch/amd64/amd64/genassym.cf  Mon Dec 30 23:32:29 2019 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: genassym.cf,v 1.79 2019/12/22 15:09:39 thorpej Exp $
+#      $NetBSD: genassym.cf,v 1.80 2019/12/30 23:32:29 thorpej Exp $
 
 #
 # Copyright (c) 1998, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -252,6 +252,7 @@
 define CPU_INFO_IDEPTH         offsetof(struct cpu_info, ci_idepth)
 if !defined(XENPV)
 define CPU_INFO_IPENDING       offsetof(struct cpu_info, ci_ipending)
+define CPU_INFO_IMASKED        offsetof(struct cpu_info, ci_imasked)
 define CPU_INFO_IMASK          offsetof(struct cpu_info, ci_imask)
 define CPU_INFO_IUNMASK        offsetof(struct cpu_info, ci_iunmask)
 define CPU_INFO_ISOURCES       offsetof(struct cpu_info, ci_isources)
diff -r 6a02865fb425 -r a6e435a4a38f sys/arch/amd64/amd64/vector.S
--- a/sys/arch/amd64/amd64/vector.S     Mon Dec 30 22:13:46 2019 +0000
+++ b/sys/arch/amd64/amd64/vector.S     Mon Dec 30 23:32:29 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: vector.S,v 1.72 2019/12/22 15:09:39 thorpej Exp $      */
+/*     $NetBSD: vector.S,v 1.73 2019/12/30 23:32:29 thorpej Exp $      */
 
 /*
  * Copyright (c) 1998, 2007, 2008 The NetBSD Foundation, Inc.
@@ -392,7 +392,7 @@
        incl    CPUVAR(IDEPTH)                                          ;\
        movq    IS_HANDLERS(%r14),%rbx                                  ;\
        cmpl    $0,IS_MASK_COUNT(%r14)  /* source currently masked? */  ;\
-       jne     7f                      /* yes, hold it */              ;\
+       jne     12f                     /* yes, hold it */              ;\
 6:                                                                     \
        movl    IH_LEVEL(%rbx),%r12d                                    ;\
        cmpl    %r13d,%r12d                                             ;\
@@ -406,7 +406,7 @@
        jnz     6b                                                      ;\
 5:                                                                     \
        cmpl    $0,IS_MASK_COUNT(%r14)  /* source now masked? */        ;\
-       jne     7f                      /* yes, deal */                 ;\
+       jne     12f                     /* yes, deal */                 ;\
        cli                                                             ;\
        unmask(num)                     /* unmask it in hardware */     ;\
        late_ack(num)                                                   ;\
@@ -415,10 +415,15 @@
 7:                                                                     \
        cli                                                             ;\
        orl     $(1 << num),CPUVAR(IPENDING)                            ;\
-       level_mask(num)                                                 ;\
+8:     level_mask(num)                                                 ;\
        late_ack(num)                                                   ;\
        sti                                                             ;\
        jmp     _C_LABEL(Xdoreti)       /* lower spl and do ASTs */     ;\
+12:                                                                    \
+       cli                                                             ;\
+       orl     $(1 << num),CPUVAR(IMASKED)                             ;\
+       btrl    $(num),CPUVAR(IPENDING)                                 ;\
+       jmp     8b                                                      ;\
 10:                                                                    \
        cli                                                             ;\
        orl     $(1 << num),CPUVAR(IPENDING)                            ;\
diff -r 6a02865fb425 -r a6e435a4a38f sys/arch/i386/i386/genassym.cf
--- a/sys/arch/i386/i386/genassym.cf    Mon Dec 30 22:13:46 2019 +0000
+++ b/sys/arch/i386/i386/genassym.cf    Mon Dec 30 23:32:29 2019 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: genassym.cf,v 1.116 2019/12/22 15:09:39 thorpej Exp $
+#      $NetBSD: genassym.cf,v 1.117 2019/12/30 23:32:29 thorpej Exp $
 
 #
 # Copyright (c) 1998, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -274,6 +274,7 @@
 define CPU_INFO_GDT            offsetof(struct cpu_info, ci_gdt)
 if !defined(XENPV)
 define CPU_INFO_IPENDING       offsetof(struct cpu_info, ci_ipending)
+define CPU_INFO_IMASKED        offsetof(struct cpu_info, ci_imasked)
 define CPU_INFO_IMASK          offsetof(struct cpu_info, ci_imask)
 define CPU_INFO_ISOURCES       offsetof(struct cpu_info, ci_isources)
 define CPU_INFO_IUNMASK        offsetof(struct cpu_info, ci_iunmask)
diff -r 6a02865fb425 -r a6e435a4a38f sys/arch/i386/i386/vector.S
--- a/sys/arch/i386/i386/vector.S       Mon Dec 30 22:13:46 2019 +0000
+++ b/sys/arch/i386/i386/vector.S       Mon Dec 30 23:32:29 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: vector.S,v 1.84 2019/12/22 15:09:39 thorpej Exp $      */
+/*     $NetBSD: vector.S,v 1.85 2019/12/30 23:32:29 thorpej Exp $      */
 
 /*
  * Copyright 2002 (c) Wasabi Systems, Inc.
@@ -65,7 +65,7 @@
  */
 
 #include <machine/asm.h>
-__KERNEL_RCSID(0, "$NetBSD: vector.S,v 1.84 2019/12/22 15:09:39 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vector.S,v 1.85 2019/12/30 23:32:29 thorpej Exp $");
 
 #include "opt_ddb.h"
 #include "opt_multiprocessor.h"
@@ -409,7 +409,7 @@
        sti                                                             ;\
        movl    IS_HANDLERS(%ebp),%ebx                                  ;\
        cmpl    $0,IS_MASK_COUNT(%ebp)  /* source currently masked? */  ;\
-       jne     7f                      /* yes, hold it */              ;\
+       jne     12f                     /* yes, hold it */              ;\
 6:                                                                     \
        movl    IH_LEVEL(%ebx),%edi                                     ;\
        cmpl    %esi,%edi                                               ;\
@@ -423,7 +423,7 @@
        testl   %ebx,%ebx                                               ;\
        jnz     6b                                                      ;\
        cmpl    $0,IS_MASK_COUNT(%ebp)  /* source now masked? */        ;\
-       jne     7f                      /* yes, deal */                 ;\
+       jne     12f                     /* yes, deal */                 ;\
        cli                                                             ;\
        unmask(num)                     /* unmask it in hardware */     ;\
        late_ack(num)                                                   ;\
@@ -431,9 +431,14 @@
 7:                                                                     \
        cli                                                             ;\
        orl     $(1 << num),CPUVAR(IPENDING)                            ;\
-       level_mask(num)                                                 ;\
+8:     level_mask(num)                                                 ;\
        late_ack(num)                                                   ;\
        jmp     _C_LABEL(Xdoreti)       /* lower spl and do ASTs */     ;\
+12:                                                                    \
+       cli                                                             ;\
+       orl     $(1 << num),CPUVAR(IMASKED)                             ;\
+       btrl    $(num),CPUVAR(IPENDING)                                 ;\
+       jmp     8b                                                      ;\
 10:                                                                    \
        orl     $(1 << num),CPUVAR(IPENDING)                            ;\
        level_mask(num)                                                 ;\
diff -r 6a02865fb425 -r a6e435a4a38f sys/arch/x86/include/cpu.h
--- a/sys/arch/x86/include/cpu.h        Mon Dec 30 22:13:46 2019 +0000
+++ b/sys/arch/x86/include/cpu.h        Mon Dec 30 23:32:29 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: cpu.h,v 1.115 2019/12/01 15:34:46 ad Exp $     */
+/*     $NetBSD: cpu.h,v 1.116 2019/12/30 23:32:29 thorpej Exp $        */
 
 /*
  * Copyright (c) 1990 The Regents of the University of California.
@@ -149,9 +149,11 @@
        struct {
                uint32_t        ipending;
                int             ilevel;
+               uint32_t        imasked;
        } ci_istate __aligned(8);
 #define ci_ipending    ci_istate.ipending
 #define        ci_ilevel       ci_istate.ilevel
+#define        ci_imasked      ci_istate.imasked
        int             ci_idepth;
        void *          ci_intrstack;
        uint32_t        ci_imask[NIPL];
diff -r 6a02865fb425 -r a6e435a4a38f sys/arch/x86/x86/intr.c
--- a/sys/arch/x86/x86/intr.c   Mon Dec 30 22:13:46 2019 +0000
+++ b/sys/arch/x86/x86/intr.c   Mon Dec 30 23:32:29 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: intr.c,v 1.149 2019/12/22 16:50:03 ad Exp $    */
+/*     $NetBSD: intr.c,v 1.150 2019/12/30 23:32:30 thorpej Exp $       */
 
 /*
  * Copyright (c) 2007, 2008, 2009, 2019 The NetBSD Foundation, Inc.
@@ -133,7 +133,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.149 2019/12/22 16:50:03 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.150 2019/12/30 23:32:30 thorpej Exp $");
 
 #include "opt_intrdebug.h"
 #include "opt_multiprocessor.h"
@@ -1052,9 +1052,24 @@
                         * If this interrupt source is being moved, don't
                         * unmask it at the hw.
                         */
-                       if (! source->is_distribute_pending)
+                       if (! source->is_distribute_pending) {
                                (*pic->pic_hwunmask)(pic, ih->ih_pin);
-                       force_pending = true;
+                       }
+
+                       /*
+                        * For level-sensitive interrupts, the hardware
+                        * will let us know.  For everything else, we
+                        * need to explicitly handle interrupts that
+                        * happened when when the source was masked.
+                        */
+                       const uint32_t bit = (1U << ih->ih_slot);
+                       if (ci->ci_imasked & bit) {
+                               ci->ci_imasked &= ~bit;
+                               if (source->is_type != IST_LEVEL) {
+                                       ci->ci_ipending |= bit;
+                                       force_pending = true;
+                               }
+                       }
                }
        }
 



Home | Main Index | Thread Index | Old Index