Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 23 Aug 2001 20:57:58 -0500
From:      Stephen Montgomery-Smith <stephen@math.missouri.edu>
To:        stable@freebsd.org
Subject:   Re: Serious i386 interrupt mask bug in RELENG_4 (was Re: 4.4-RC NFS  panic)
Message-ID:  <3B85B4A6.AFA7A19E@math.missouri.edu>
References:  <200108232134.aa49928@salmon.maths.tcd.ie>

next in thread | previous in thread | raw e-mail | index | archive | help
This patch certainly fixed all of my problems with the computer
freezing, etc, etc.  Thanks.  

(Posting it to STABLE because a lot of people there are also complaining
about this problem.  Look at the bottom of the email for the patch.)


Ian Dowse wrote:
> 
> In message <200108230228.f7N2SqW80434@harmony.village.org>, Warner Losh writes:
> >
> >I think that might be due to a bug in the shared interrupt code that
> >Ian Dowse sent me about earlier today.
> 
> Just to add a few details - there is a bug in the update_masks()
> function in i386/isa/intr_machdep.c that can cause some interrupts
> to occur at times when they should be masked. The problem only
> occurs with certain configurations of shared interrupts and devices,
> and this code is only present in RELENG_4.
> 
> The update_masks() function is called after an interrupt handler
> has been registered or removed. Its main function is to update the
> interrupt masks (tty_imask, net_imask etc) if necessary (e.g if
> IRQ11 is registered by a tty-type device, IRQ11 will be added to
> tty_imask so that future spltty()'s will mask IRQ11).
> 
> A second function of update_masks() is to update the cached copy
> of the interrupt mask stored with each handler for a multiplexed
> interrupt. This is done via the call to update_mux_masks().
> 
> The bug is that update_masks() returns without calling update_mux_masks()
> in some cases where it should call it. Specifically, if a newly-added
> multiplexed interrupt handler has the same maskptr as another
> handler on the same IRQ line, that new handler doesn't get it's
> cached mask set. For example if a single IRQ has a usb device and
> a modem (tty), the second device to register it's handler will get
> its idesc->mask set to 0 instead of the value of tty_imask because
> update_mux_masks() may never be called to set it. Of course, if
> update_masks() is called later for some other device it may correct
> the situation.
> 
> Interrupt handlers are called with intr_mask[irq] or'd into the
> cpl to block further interrupts; for non-multiplexed interrupts
> intr_mask[irq] will set from one of the *_imask masks. However with
> multiplexed interrupts, only the IRQ itself (and SWI_CLOCK_MASK)
> are blocked, and the multiplex handler intr_mux() needs to raise
> the cpl further when necessary. It uses idesc->mask to control
> this.
> 
> When this bug occurs, idesc->mask == 0, so the device interrupt
> handler gets called with only the IRQ and SWI_CLOCK_MASK masked,
> instead of the full *_mask that it requested. Not good.
> 
> On my laptop, this bug causes hangs within minutes of starting to
> use a pccard modem, but as should be apparent from the above it
> could strike virtually anywhere that multiplexed interrupts are
> used. The patch below seems to solve the problem; it just causes
> update_masks() to unconditionally update the masks.
> 
> Ian
> 
> Index: intr_machdep.c
> ===================================================================
> RCS file: /home/iedowse/CVS/src/sys/i386/isa/intr_machdep.c,v
> retrieving revision 1.29.2.2
> diff -u -r1.29.2.2 intr_machdep.c
> --- intr_machdep.c      2000/08/16 05:35:34     1.29.2.2
> +++ intr_machdep.c      2001/08/23 20:24:17
> @@ -651,15 +651,9 @@
> 
>         if (find_idesc(maskptr, irq) == NULL) {
>                 /* no reference to this maskptr was found in this irq's chain */
> -               if ((*maskptr & mask) == 0)
> -                       return;
> -               /* the irq was included in the classes mask, remove it */
>                 *maskptr &= ~mask;
>         } else {
>                 /* a reference to this maskptr was found in this irq's chain */
> -               if ((*maskptr & mask) != 0)
> -                       return;
> -               /* put the irq into the classes mask */
>                 *maskptr |= mask;
>         }
>         /* we need to update all values in the intr_mask[irq] array */
> 
> To Unsubscribe: send mail to majordomo@FreeBSD.org
> with "unsubscribe freebsd-hackers" in the body of the message

-- 
Stephen Montgomery-Smith
stephen@math.missouri.edu
http://www.math.missouri.edu/~stephen

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-stable" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3B85B4A6.AFA7A19E>