Subject: Re: Nell PCMCIA/PRISM-II on Voyager
To: None <eeh@netbsd.org, martin@duskware.de>
From: None <eeh@netbsd.org>
List: port-sparc
Date: 04/23/2002 15:37:02
| > Is the problem just the register accesses or do they share the same interrupt?
|
| Register access. Nell has two interrupt handlers. The hardware can be 
| confiugred which interrupt to generate for what type of event.

I don't think you understand the question.

All interrupts need to block  interrupts of the same level or lower.  If
you get a level 5 interrupt, and the hardware triggers again, you should
not get another interrupt from that device or you could hang or lose interrupts.
The handler needs to complete properly first.

Say you have a serial port and a network device plugged into the two slots,
the serial driver wants splserial() and the network device wants splnet().
Either the hardware needs to be configured to generate two interrupts, one
at splserial() for the serial port and another at splnet() for the NIC, or
you have problems.

If the nell only generates one interrupt for both slots, you have three
implementation choices:

1) Use a high level interrupt for the nell and just jump to the interrupt
handlers at that level.  This will block one device from interrupting the
other, and both drivers need to use the same spl() to block interrupts that
the nell is using.  This is the easiest implementation.

2) Use a high level interrupt for the nell that just reads a couple of registers
and schedules a lower-level soft interrupt for each device in a slot.  This
gives you better interrupt latency issues for slow devices.  But it won't work
at all unless you can force the hardware to generate interrupts of the correct
levels.  And if you cannot determine which slot is generating the interrupt you
need to generate a softint for each slot, which will probably cause lots of
spurious interrupts.

3) Implement software interrupt prioritization just for the nell.  This is
basically what machines without hardware interrupt priorities do, but you
need to be very careful to make it play nicely with the sparc hardware interrupt
priorities to avoid lossage.

To do this, you need to ack the nell interrupt, and set a flag in the nell driver
saying you have a particular interrupt pending.  Then you lower the ipl to that
of the device that's generating the interrupt and dispatch it's interrupt handler.

If you get another interrupt while the handler is active, it will come into the
nell handler, which will acknowledge the nell interrupt.  The nell handler then
needs to determine whether that interrupt is active or not.  If the interrupt is 
active, just ignore it and return [1].  If this is an interrupt for the other
device, and it is a higher IPL than the one that's running, lower the IPL and
dispatch it now.  If it's a lower IPL than the one that's running, set a flag
and exit the nell handler.

When the interrupt handler for a device finishes, it should return to the nell
interrupt handler.  Here you need to increase the IPL once again to the level
of the nell interrupt handler and determine if a flag has been set telling
you got an interrupt from a device but have not dispatched it.  If the flag
is set, you lower the IPL and dispatch that interrupt handler before exiting
the nell interrupt handler.

| > If it's just the register accesses then you need to wrap all accesses to that
| > register with splhigh() or the highest level interrupt the nell card can
| > generate.
|
| Which would effectively mean that the low-priority handler would manually
| force splhigh, thus blocking the other too. So we could just move both to the
| higher interrupt level and be done, right?

That's the whole point.  Anything that could be accessed by two interrupt
handlers or non-interrupt code and an interrupt handler has a potential
race condition and needs protection.  Think about it.  Say you get one 
interrupt, the handler reads the register and is just about to update the
value when another interrupt comes in and modifies the register.  When
the second interrupt finishes, the first one resume and writes back old
data.

| Note that the status change interrupts are very low frequency (i.e. card
| insertion and removal).

You always need to protect interrupts from each other.  

Eduardo