Subject: Re: Interrupts
To: Michael <macallan18@earthlink.net>
From: Tim Kelly <hockey@dialectronics.com>
List: port-macppc
Date: 12/06/2004 12:17:31
At 10:14 AM -0500 12/6/04, Michael wrote:
>Well, in this case we should probably check the IRQ registers in
>do_pending_intr() and keep looping until >the line goes down, but this may
>cause other problems.
>Moving gc_enable_irq behind the handlers ( or at least behind the part
>that clears the pending bit ) should >do that - it would loop through the
>handlers until the line goes down which may take forever, so it may be >a
>good idea to defer it until we get the next clock interrupt after a couple
>of loops to avoid a deadlock...

If an interrupt comes in after enabling it (gc_enable_irq) but before
ci->ci_ipending is unset, would you lose the interrupt? Do we need to add
some atomic functioning? I love async stuff. It reminds me of the Open
Transport based networking coding I used to do. The solution there was to
use state machines.

Seems to me that Neil's post indicates that simply blinding turning off the
pending virq without making sure the hardware irq has been deasserted with
gc is leaving room to miss some stuff.


       /* Do now unmasked pendings */
        while ((hwpend = (ci->ci_ipending & ~pcpl & HWIRQ_MASK)) != 0) {

       irq = 31 - cntlzw(hwpend);
       is = &intrsources[irq];

       if (!have_openpic)
           gc_enable_irq(is->is_hwirq);

       ci->ci_ipending &= ~(1 << irq);

        ih = is->is_hand;

         while (ih) {
                done = spllower(imask[ih->ih_level]);
                (*ih->ih_fun)(ih->ih_arg);
                ih = ih->ih_next;
           }
           splx(done);

        if (!have_openpic) {
             int_state = gc_read_irq();

              irq = 31 - cntlzw(int_state);
              r_imen = 1 << irq;

             ci->ci_ipending |= r_imen;
             gc_disable_irq(is->is_hwirq);
        }


The addition of the spllower is an optional attempt to enforce IPLs, but
not necessary and may be flawed. It is more a placeholder for what does
actually prevent shared virqs from raising the the highest IPL.

The code overall attempts to turn off the pending interrupt, call the
handlers, and then see if they all deasserted the interrupt. If the
interrupt is still asserted, kick it back into the loop. I could be wrong,
but in the process of iterating over the handlers, a device whose handler
has already been called for this interrupt cycle could request another
interrupt, but it does not get noted because the interrupt was never
deasserted. To me it seems abiguous as to whether a fresh call to ext_intr
would be generated if the interrupt remained asserted. My belief would be
no, this would not be viewed as a fresh interrupt, if I understand level
triggered interrupts. Enabling and disabling the interrupt register might
not affect the state register.

tim