Subject: Re: COM driver and the ST16C1550
To: None <tech-kern@netbsd.org>
From: Allen Briggs <briggs@wasabisystems.com>
List: tech-kern
Date: 08/29/2001 22:28:12
I sent this a month and a half back or so...
> Hi. I've been working with the ST16C1550 UART from EXAR. It is
> supposedly 16550-compatible, but it doesn't quite seem to be. When
> operating in interrupt mode, it gets stuck in the receive interrupt
> loop because the only interrupt condition is TXRDY. The following
> patch seems to work for me, but I don't know if it will break existing
> drivers. Unfortunately, I don't know any definite way to distinguish
> this from a genuine ns16550a...
I've gotten a bit further on the diff, and I exchanged some email with
Onno van der Linden back then. Here's one of his private responses
(with his permission):
========================================================================
[ I wrote ]
> > I was trying to preserve the current behavior as much as
> > possible--handling everything else, then reloading the xmit.
> > This seems to make the most sense for the heldchange processing.
[ Onno replied ]
> You need the tx intrhandling inside the loop, but it should be
> called once and it should be readable code. What I would do is
> - add an extra txintronce variable initialized with 0
> - create an inline txintr function (or a huge define) that contains
> everything handled by and including the if (ISSET(lsr, LSR_TXRDY))
> statement
> - at the end of the loop add (right before the while)
> if (!txintronce) {
> txtintronce = 1;
> txintr();
> }
>
> If we don't need the txintronce variable we could
> - create an inline txintr function (or a huge define) that contains
> everything inside of the if (ISSET(lsr, LSR_TXRDY)) statement
> - at the the end of the loop add (right before the while)
> if (ISSET(lsr, LSR_TXRDY))
> txintr();
>
> I don't think we really need the txintronce construction.
>
> And while we're there, why not create a couple more inline functions
> (rxintr, msrintr) that are called from within comintr ?
========================================================================
I didn't see anything different in the chip setup to explain the
behavior that I was seeing. The following diff does work for me...
Does anyone have any thoughts?
-allen
Index: com.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/ic/com.c,v
retrieving revision 1.188
diff -u -r1.188 com.c
--- com.c 2001/08/27 14:27:01 1.188
+++ com.c 2001/08/30 02:28:34
@@ -2036,7 +2036,7 @@
put = sc->sc_rbput;
cc = sc->sc_rbavail;
- do {
+again: do {
u_char msr, delta;
lsr = bus_space_read_1(iot, ioh, com_lsr);
@@ -2114,7 +2114,6 @@
bus_space_write_1(iot, ioh, com_ier, 0);
delay(10);
bus_space_write_1(iot, ioh, com_ier,sc->sc_ier);
- iir = IIR_NOPEND;
continue;
}
}
@@ -2187,7 +2186,8 @@
sc->sc_st_check = 1;
}
- } while (!ISSET((iir = bus_space_read_1(iot, ioh, com_iir)), IIR_NOPEND));
+ } while (ISSET((iir = bus_space_read_1(iot, ioh, com_iir)), IIR_RXRDY)
+ || ((iir & IIR_IMASK) == 0));
/*
* Done handling any receive interrupts. See if data can be
@@ -2228,6 +2228,10 @@
}
}
}
+
+ if (!ISSET((iir = bus_space_read_1(iot, ioh, com_iir)), IIR_NOPEND))
+ goto again;
+
COM_UNLOCK(sc);
/* Wake up the poller. */