Subject: Re: Interrupts
To: None <port-macppc@NetBSD.ORG>
From: Donald Lee <MacPPC1@caution.icompute.com>
List: port-macppc
Date: 12/06/2004 00:16:38
If anyone comes up with code, I'd be tickled to death to test it,
esp. if it applies to 1.6.x.   This could explain several of my most
annoying problems, and if so, I'd be very happy.

I can test and verify if this is relevant to:

	Cyclades serial lost interrupts

	ATA/IDE card lost interrupts

	CPU upgrades behaving badly.

-dgl-


>Hello,
>
>> This 'solution' is far from optimal - an active line without the corresponding interrupt bit set doesn't always mean a lost interrupt,
>> and just ORing the level register on the interrupt register also locks things up - no idea why though.
>> But I think we need something like this - better call IRQ handlers a little more often than lose interupts and get all kinds of
>> nastiness.
>
>Just had a look at the Darwin source ( thanks Allan for kicking me there ) - see http://darwinsource.opendarwin.org/10.0.1/xnu-124.1/iokit/Drivers/platform/drvAppleGrandCentral/ - the interesting part is this:
>    // Do all the sources for events, plus any pending interrupts.
>    // Also add in the "level" sensitive sources
>    maskTmp = lwbrx(maskReg);
>    events = lwbrx(eventsReg) & ~kTypeLevelMask;
>    events |= lwbrx(levelsReg) & maskTmp & kTypeLevelMask;
>    events |= pendingEvents & maskTmp;
>    pendingEvents = 0;
>    eieio();
>
>So they OR in a few bits from the level register. kTypeLevelMask is defined as 
>#define kTypeLevelMask (0x3FF00000)
>which means IRQ 20 - 29.
>After that:
>    // Since we have to clear the level'd one clear the current edge's too.
>    stwbrx(kTypeLevelMask | events, clearReg);
>    eieio();
>So it /always/ clears the PCI interrupts.
>
>Also interesting:
>#define kEventsOffset    (0x00020)
>#define kMaskOffset      (0x00024)
>#define kClearOffset     (0x00028)
>#define kLevelsOffset    (0x0002C)
>apparently Darwin thinks gc uses only 32 IRQs, while NetBSD thinks 64.
>
>#define interrupt_reg	(obio_base + 0x10)
>#define INT_STATE_REG_H  (interrupt_reg + 0x00)
>#define INT_ENABLE_REG_H (interrupt_reg + 0x04)
>#define INT_CLEAR_REG_H  (interrupt_reg + 0x08)
>#define INT_LEVEL_REG_H  (interrupt_reg + 0x0c)
>#define INT_STATE_REG_L  (interrupt_reg + 0x10)
>#define INT_ENABLE_REG_L (interrupt_reg + 0x14)
>#define INT_CLEAR_REG_L  (interrupt_reg + 0x18)
>#define INT_LEVEL_REG_L  (interrupt_reg + 0x1c)
>
>have fun
>Michael