PERFORCE change 36548 for review
Marcel Moolenaar
marcel at FreeBSD.org
Wed Aug 20 21:32:22 PDT 2003
http://perforce.freebsd.org/chv.cgi?CH=36548
Change 36548 by marcel at marcel_nfs on 2003/08/20 21:31:41
o Fix a hang on sparc64 caused by the ns8250 driver
enabling Tx interrupts. Something special must be
going on on sparc64 that goes beyond using the
device for keyboard or mouse.
We now don't enable Tx interrupts until we actually
need to transmit data.
o Move the logic that clears pending interrupts to
a seperate function so that we can reuse it in
*bus_attach() prior to enabling interrupts.
o In *bus_attach(), don't call ns8250_flush() for it
can only be called when the UART has FIFOs. Instead
call ns8250_bus_flush(), which drains non-FIFO UARTS.
As a side-effect ns8250_bus_flush() preserves the
FIFO setting, so we can program the FIFO prior to
flushing it.
o In *bus_detach(), disable interrupts and clear any
pending interrupts.
o In *bus_transmit(), only wait for the transmitter
holding register to be empty once, not prior to
writing each character to it. We're now close to 99%
efficient on a 115200 bps line (and faster than sio(4)).
NOTE: pluto1 (and pluto2 for that matter) suffers from the
loss of Tx interrupts. This change may on the offchance fix
it, because we reenable Tx interrupts everytime we fill
the Tx FIFO, but I doubt it. I expect we need to tweak some
more when we extend testing to a wide variety of hardware.
Affected files ...
.. //depot/projects/uart/dev/uart/uart_dev_ns8250.c#18 edit
Differences ...
==== //depot/projects/uart/dev/uart/uart_dev_ns8250.c#18 (text+ko) ====
@@ -42,6 +42,29 @@
#define DEFAULT_RCLK 1843200
+/*
+ * Clear pending interrupts. THRE is cleared by reading IIR. Data
+ * that may have been received gets lost here.
+ */
+static void
+ns8250_clrint(struct uart_bas *bas)
+{
+ uint8_t iir;
+
+ iir = uart_getreg(bas, REG_IIR);
+ while ((iir & IIR_NOPEND) == 0) {
+ iir &= IIR_IMASK;
+ if (iir == IIR_RLS)
+ (void)uart_getreg(bas, REG_LSR);
+ else if (iir == IIR_RXRDY || iir == IIR_RXTOUT)
+ (void)uart_getreg(bas, REG_DATA);
+ else if (iir == IIR_MLSC)
+ (void)uart_getreg(bas, REG_MSR);
+ uart_barrier(bas);
+ iir = uart_getreg(bas, REG_IIR);
+ }
+}
+
static int
ns8250_delay(struct uart_bas *bas)
{
@@ -240,7 +263,6 @@
ns8250_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
int parity)
{
- uint8_t iir;
if (bas->rclk == 0)
bas->rclk = DEFAULT_RCLK;
@@ -258,23 +280,7 @@
uart_setreg(bas, REG_MCR, MCR_IENABLE | MCR_RTS | MCR_DTR);
uart_barrier(bas);
- /*
- * Clear pending interrupts. THRE is cleared by reading IIR. Data
- * that may have been received gets lost here.
- */
- iir = uart_getreg(bas, REG_IIR);
- while ((iir & IIR_NOPEND) == 0) {
- iir &= IIR_IMASK;
- if (iir == IIR_RLS)
- (void)uart_getreg(bas, REG_LSR);
- else if (iir == IIR_RXRDY || iir == IIR_RXTOUT)
- (void)uart_getreg(bas, REG_DATA);
- else if (iir == IIR_MLSC)
- (void)uart_getreg(bas, REG_MSR);
- uart_barrier(bas);
- iir = uart_getreg(bas, REG_IIR);
- }
- uart_barrier(bas);
+ ns8250_clrint(bas);
}
static void
@@ -331,6 +337,7 @@
struct ns8250_softc {
struct uart_softc base;
uint8_t fcr;
+ uint8_t ier;
uint8_t mcr;
int signals;
};
@@ -385,26 +392,32 @@
ns8250->mcr = uart_getreg(bas, REG_MCR);
ns8250->fcr = FCR_ENABLE | FCR_RX_MEDH;
- ns8250_flush(bas, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER);
uart_setreg(bas, REG_FCR, ns8250->fcr);
uart_barrier(bas);
+ ns8250_bus_flush(sc, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER);
+
if (ns8250->mcr & MCR_DTR)
ns8250->signals |= UART_SIG_DTR;
if (ns8250->mcr & MCR_RTS)
ns8250->signals |= UART_SIG_RTS;
ns8250_bus_getsig(sc);
- uart_setreg(bas, REG_IER,
- IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC);
+ ns8250_clrint(bas);
+ ns8250->ier = IER_EMSC | IER_ERLS | IER_ERXRDY;
+ uart_setreg(bas, REG_IER, ns8250->ier);
uart_barrier(bas);
-
return (0);
}
static int
ns8250_bus_detach(struct uart_softc *sc)
{
+ struct uart_bas *bas;
+ bas = &sc->sc_bas;
+ uart_setreg(bas, REG_IER, 0);
+ uart_barrier(bas);
+ ns8250_clrint(bas);
return (0);
}
@@ -667,14 +680,16 @@
static int
ns8250_bus_transmit(struct uart_softc *sc)
{
+ struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc;
struct uart_bas *bas;
int i;
bas = &sc->sc_bas;
-
+ while ((uart_getreg(bas, REG_LSR) & LSR_THRE) == 0)
+ ;
+ uart_setreg(bas, REG_IER, ns8250->ier | IER_ETXRDY);
+ uart_barrier(bas);
for (i = 0; i < sc->sc_txdatasz; i++) {
- while ((uart_getreg(bas, REG_LSR) & LSR_THRE) == 0)
- ;
uart_setreg(bas, REG_DATA, sc->sc_txbuf[i]);
uart_barrier(bas);
}
More information about the p4-projects
mailing list