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