kern/121421: [uart][patch]: Tune 16550A FIFO interrupt level via device.hints

Tetsuya Uemura t_uemura at macome.co.jp
Thu Mar 6 08:30:01 UTC 2008


>Number:         121421
>Category:       kern
>Synopsis:       [uart][patch]: Tune 16550A FIFO interrupt level via device.hints
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Thu Mar 06 08:30:00 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator:     Tetsuya Uemura
>Release:        7.0-PRERELEASE
>Organization:
MACOME, Corp.
>Environment:
FreeBSD s2882g3nr.macome.co.jp 7.0-PRERELEASE FreeBSD 7.0-PRERELEASE #0: Fri Feb  1 08:56:55 JST 2008     root at s2882g3nr.macome.co.jp:/usr/obj/usr/src/sys/S2882G3NR  amd64
>Description:
I have a timing sensitive sensor device connected to the onboard 16550A clone which doesn't work correct because the 16550A FIFO interrupt latency is too large.

The latency can be reduced by lowering the FIFO interrupt level, though there is no way to do so in the stock uart(4) driver, which always set the level fairly high (FCR_RX_MEDH).

With the attached patch, the FIFO interrupt level can be changed to low (FCR_RX_LOW), fairly low (FCR_RX_MEDL) or high (FCR_RX_HIGH) by setting one of 0x100, 0x200 or 0x800 bit to hint.uart.N.flags, while the default is still FCR_RX_MEDH.

Thanks in advance.
>How-To-Repeat:
1. Establish a 9600 bps serial connection. The one is the transmitter and the other is the receiver.
2. Send 1 byte from the transmitter.
3. The receiver receives the data 5 millisecs or more after the transmitter sent it.

Most of the delay is introduced by the FIFO. The delay between the interrupt handler and the application is about or less than a few handreds of microsecs.
>Fix:
Lowering the FIFO interrupt level from the default 8 bytes to 4 or 1.

Patch attached with submission follows:

--- uart.h.orig	2007-04-03 07:00:22.000000000 +0900
+++ uart.h	2008-03-05 15:36:39.000000000 +0900
@@ -73,6 +73,10 @@
  */
 #define	UART_FLAGS_CONSOLE(f)		((f) & 0x10)
 #define	UART_FLAGS_DBGPORT(f)		((f) & 0x80)
+#define	UART_FLAGS_FCR_RX_LOW(f)	((f) & 0x100)
+#define	UART_FLAGS_FCR_RX_MEDL(f)	((f) & 0x200)
+#define	UART_FLAGS_FCR_RX_MEDH(f)	((f) & 0x400)
+#define	UART_FLAGS_FCR_RX_HIGH(f)	((f) & 0x800)
 
 /*
  * Data parity values (magical numbers related to ns8250).
--- uart_dev_ns8250.c.orig	2007-04-03 10:21:10.000000000 +0900
+++ uart_dev_ns8250.c	2008-03-05 15:45:48.000000000 +0900
@@ -382,11 +382,24 @@
 {
 	struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc;
 	struct uart_bas *bas;
+	unsigned int ivar;
 
 	bas = &sc->sc_bas;
 
 	ns8250->mcr = uart_getreg(bas, REG_MCR);
-	ns8250->fcr = FCR_ENABLE | FCR_RX_MEDH;
+	ns8250->fcr = FCR_ENABLE;
+	if (!resource_int_value(
+		"uart", device_get_unit(sc->sc_dev), "flags", &ivar)) {
+		if (UART_FLAGS_FCR_RX_LOW(ivar)) 
+			ns8250->fcr |= FCR_RX_LOW;
+		else if (UART_FLAGS_FCR_RX_MEDL(ivar)) 
+			ns8250->fcr |= FCR_RX_MEDL;
+		else if (UART_FLAGS_FCR_RX_HIGH(ivar)) 
+			ns8250->fcr |= FCR_RX_HIGH;
+		else
+			ns8250->fcr |= FCR_RX_MEDH;
+	} else 
+		ns8250->fcr |= FCR_RX_MEDH;
 	uart_setreg(bas, REG_FCR, ns8250->fcr);
 	uart_barrier(bas);
 	ns8250_bus_flush(sc, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER);


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list