Subject: MacPPC interrupts - Cyclades
To: None <port-macppc@netbsd.org>
From: Donald Lee <donlee_ppc@icompute.com>
List: port-macppc
Date: 12/31/2000 20:38:53
Hello all,

I have the Cyclades 8Y PCI card working pretty well in my 7600/132.
I have 8 working serial ports. ( YEAH! )

I had to resort to a kludge to make it go, though.  Can anyone tell me
why?

From experimentation, it looks like the card posts additional interrupts
either while I'm in the interrupt handler, or possibly somewhere else,
and the interrupt handler never gets called.  I worked around this by
putting a check in the poll routine to check the registers on the card.
I found that I was indeed missing interrupts, and if I call the interrupt
handler "manually" from the poll routine, then it works OK.

Tonight, I added another twist.  I added the got_one variable in the
interrupt and I force it to make a "clean" trip through the interrupt
handler before I let it return.  This reduced the frequency of these
"lost" interrupts, but has not eliminated them.

I don't have much experience with hardware at this level, but it seems to
me that there should be some way that I can eliminate this
window rather than simply making it small.  For instance, on most
systems, you can disable the interrupts in a way that will hold them
"pending" so that you can go and handle your hardware, and if something
new should come up in the meantime, you get re-invoked when you return
from the handler and the interrupts get re-enabled.

Any help would be much appreciated.  I'll be cleaning up the code for
submission in a send-pr, even if I don't get this fixed up "right".
The existing 1.5 code hangs, and is not very useful.

-dgl-


The pseudo code looks like this: (real code in NetBSD 1.5 src/sys/dev/ic/cy.c
		my version is at ftp://ftp.icompute.com/pub/donlee/cy.c


cy_poll()	/* called from callout periodically */
	{
	move chars from userland to ring buffers...

	if (CY_REGISTERS() == interrupt_pending)
		{
		cy_intr();	/* missed an interrupt - call it manually */
		}
	}

cy_intr()
	{

again:
	got_one = 0;
	for (each chip/channel)
		{
		if (CY_REGISTERS() == interrupt_pending)
			{
			got_one = 1;
			do_interrupt_stuff();
			}
		}
	if (got_one) goto again; /* did work - check for more */

	clear_board_interrupt();
	}