On Tue, Nov 20, 2018 at 04:44:56PM +0100, Mark Kettenis wrote:
> > Date: Mon, 19 Nov 2018 20:35:44 +0100
> > From: Patrick Wildt <patr...@blueri.se>
> > 
> > On Mon, Nov 19, 2018 at 08:16:31PM +0100, Patrick Wildt wrote:
> > > On Mon, Nov 19, 2018 at 11:27:54AM -0700, Theo de Raadt wrote:
> > > > > That means bnxt(4) and dwpcie(4) share the same interrupt line, but 
> > > > > one
> > > > > has IPL_AUDIO and the other one IPL_NET.  Since the highest IPL on a
> > > > > pin counts, this line is now IPL_AUDIO (which is >IPL_VM).  A bnxt(4)
> > > > > interrupt is now allowed to interrupt IPL_VM.
> > > > > 
> > > > > I don't think there's a regression, I think it behaves as implemented.
> > > > > The question that remains is: How should it behave if not like that?
> 
> Admittedly the current INTx implementation in dwpcie(4) is a bit of a
> hack.  The hardware has a register that signals which of the four
> legacy PCI interrupts pin was triggered so the driver really should
> expose itself as a secondary interrupt controller.  But proper support
> for secondary interrupt controllers requires a bit of thought.  For
> one thing we'd need a way to unblock interrupts on decondary interrupt
> controllers in response to an splx(9) call.
> 
> > > > When shared, it should operate at the lowest level not the highest.  
> > > > That
> > > > may cause other difficulties.
> > > 
> > > Actually it seems like we do set the lowest level, not the highest,
> > > sorry.  But I think there might be a bug.  I will have a look.
> > > 
> > 
> > I hope I'm not wrong, but I think there's a bug in the calculation
> > code.  The ampinctc_calc_mask() function sets the priority of an IRQ
> > every time a handler is established or disestablished on the given IRQ.
> > In this case, the IPL_AUDIO is probably established before the IPL_NET,
> > thus when the IPL_NET establish happens, iq_irq is already set to "max"
> > as in IPL_AUDIO.  That means the code that sets the priority to "min" is
> > skipped, as the continue statement will take effect.
> > 
> > I guess each intrq object should have the lowest and highest IPL, and
> > the loop should only continue of both are the same.  The lowest IPL is
> > then set for the IPL priority, and the highest IPL is used to splraise()
> > once the IRQ actually hits and the handler is suppoed to run.
> > 
> > Untested, I hope that someone has a look as well and to spot if I have
> > a mistake in my understanding.
> > 
> > We have this issue in at least 4 files: agintc/ampintc for arm64/armv7.
> > 
> > Patrick
> > 
> > diff --git a/sys/arch/arm64/dev/ampintc.c b/sys/arch/arm64/dev/ampintc.c
> > index 2c4ce63a150..a1b28a20ea7 100644
> > --- a/sys/arch/arm64/dev/ampintc.c
> > +++ b/sys/arch/arm64/dev/ampintc.c
> > @@ -160,8 +160,8 @@ struct intrhand {
> >  
> >  struct intrq {
> >     TAILQ_HEAD(, intrhand) iq_list; /* handler list */
> > -   int iq_irq;                     /* IRQ to mask while handling */
> > -   int iq_levels;                  /* IPL_*'s this IRQ has */
> > +   int iq_irq_max;                 /* IRQ to mask while handling */
> > +   int iq_irq_min;                 /* lowest IRQ when shared */
> >     int iq_ist;                     /* share type */
> >  };
> >  
> > @@ -469,14 +469,16 @@ ampintc_calc_mask(void)
> >                             min = ih->ih_ipl;
> >             }
> >  
> > -           if (sc->sc_handler[irq].iq_irq == max) {
> > -                   continue;
> > -           }
> > -           sc->sc_handler[irq].iq_irq = max;
> > -
> >             if (max == IPL_NONE)
> >                     min = IPL_NONE;
> >  
> > +           if (sc->sc_handler[irq].iq_irq_max == max ||
> > +               sc->sc_handler[irq].iq_irq_min == min)
> > +                   continue;
> 
> Shouldn't that be && instead of ||?

Yes, you are right, it should be &&.

> > +
> > +           sc->sc_handler[irq].iq_irq_max = max;
> > +           sc->sc_handler[irq].iq_irq_min = min;
> > +
> >             /* Enable interrupts at lower levels, clear -> enable */
> >             /* Set interrupt priority/enable */
> >             if (min != IPL_NONE) {
> > @@ -604,7 +606,7 @@ ampintc_route_irq(void *v, int enable, struct cpu_info 
> > *ci)
> >     bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICRn(ih->ih_irq), 0);
> >     if (enable) {
> >             ampintc_set_priority(ih->ih_irq,
> > -               sc->sc_handler[ih->ih_irq].iq_irq);
> > +               sc->sc_handler[ih->ih_irq].iq_irq_min);
> >             ampintc_intr_enable(ih->ih_irq);
> >     }
> >  
> > @@ -646,7 +648,7 @@ ampintc_irq_handler(void *frame)
> >     if (irq >= sc->sc_nintr)
> >             return;
> >  
> > -   pri = sc->sc_handler[irq].iq_irq;
> > +   pri = sc->sc_handler[irq].iq_irq_max;
> >     s = ampintc_splraise(pri);
> >     TAILQ_FOREACH(ih, &sc->sc_handler[irq].iq_list, ih_list) {
> >  #ifdef MULTIPROCESSOR
> > 
> > 
> 

Reply via email to