Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 20 Aug 2003 21:32:20 -0700 (PDT)
From:      Marcel Moolenaar <marcel@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 36548 for review
Message-ID:  <200308210432.h7L4WKip031216@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=36548

Change 36548 by marcel@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);
 	}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200308210432.h7L4WKip031216>