Subject: Re: Interrupts
To: Michael <macallan18@earthlink.net>
From: Neil Ludban <nludban@columbus.rr.com>
List: port-macppc
Date: 12/06/2004 08:18:14
Michael wrote:
> Hello,
>
>
>>I also think this snippet is mighty interesting... note comment.
>>
>>void GrandCentralInterruptController::enableVector(long vectorNumber,
>> IOInterruptVector *vector)
>>{
>> unsigned long maskTmp;
>>
>> maskTmp = lwbrx(maskReg);
>> maskTmp |= (1 << vectorNumber);
>> stwbrx(maskTmp, maskReg);
>> eieio();
>> if (lwbrx(levelsReg) & (1 << vectorNumber)) {
>> // lost the interrupt
>> causeVector(vectorNumber, vector);
>> }
>>}
>
>
> Yes, this agrees with the comment from Linux I posted earlier - if you enable
> an interrupt and its line is already active it won't fire. I've added something
> similar without apparent change but my code might be wrong ( I just marked the
> interrupt as pending in this case so it would be called soon enough ). We can't
> call it directly because that would disrupt the priority handling, but when we
> enable an interrupt it's because it was marked pending and got disabled temporarily
> so we're going to call its handler anyway and won't (really) lose interrupts
> because of this.
But NetBSD calls gc_enable_irq() _before_ calling the pending interrupt handlers.
For unintelligent interrupt controllers, this is correct for edge-sensitive and
unshared level-sensitive interrupts. A race condition exists for shared level-
sensitive interrupts: when two devices have pending interrupts, the interrupt line
is never deasserted if the first device gets another interrupt before the second
device is handled.
do_pending_int()
{
/* Do now unmasked pendings */
while (...) {
if (!have_openpic)
gc_enable_irq()
[call interrupt handlers]
if (!have_openpic)
ci->ci_ipending |= gc_read_lost_irqs();
}
}
-Neil