Subject: kern/3844: Support for automatic hardware flow control on 16650 UARTs
To: None <gnats-bugs@gnats.netbsd.org>
From: Dave Huang <khym@bga.com>
List: netbsd-bugs
Date: 07/08/1997 18:07:14
>Number: 3844
>Category: kern
>Synopsis: Support for automatic hardware flow control on 16650 UARTs
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: kern-bug-people (Kernel Bug People)
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Tue Jul 8 16:20:01 1997
>Last-Modified:
>Originator: Dave Huang
>Organization:
Name: Dave Huang | Mammal, mammal / their names are called /
INet: khym@bga.com | they raise a paw / the bat, the cat /
FurryMUCK: Dahan | dolphin and dog / koala bear and hog -- TMBG
Dahan: Hani G Y+C 21 Y++ L+++ W- C++ T++ A+ E+ S++ V++ F- Q+++ P+ B+ PA+ PL++
>Release: NetBSD-current as of July 4, 1997
>Environment:
System: NetBSD dahan.metonymy.com 1.2G NetBSD 1.2G (SPIFF) #58: Sat Jul 5 05:00:30 CDT 1997 khym@dahan.metonymy.com:/usr/src.local/sys/arch/i386/compile/SPIFF i386
>Description:
I recently bought one of these Turbo 4COM boards from
www.byterunner.com, a 4-port card with 16650 UARTs on it. It's got a
32-byte FIFO, vs. the 16-byte one on the 16550, so I was able to run
at 115200 baud with about the same amount of overruns as I had been
getting at 57600 baud with my 16550 card.
Not bad, but a nifty feature of the 16650 is that it has automatic
flow control; if the FIFO gets too full, it can automatically lower
RTS until the FIFO empties out some. And if the other end lowers CTS,
it can automatically stop sending.
So, here's a quick patch to detect a 16650 and enable automatic
hardware flow control if CRTSCTS is set (the 16650 can also do
automatic XON/XOFF flow control, but I didn't bother with that).
The copyright/license stuff on st16650reg.h probably needs to be fixed
up some. The file's just a copy of ns16550reg.h with a couple of lines
added, so I copied ns16550reg.h's license.
With this patch, I can run two simultaneous 115200 baud null modem
PPP connections, with data flowing both ways, and not get any overruns
at all. And this is on my wimpy 4MB 25MHZ 80386. I can even flood ping
it with big packets and not get overruns :) (the throughput does drop
a lot, but it's much better than if it were randomly losing
characters). I'm sure it could handle even more ports without losing
characters, but I don't have enough computers around to test it out...
>How-To-Repeat:
>Fix:
diff -uP /usr/src/sys/dev/ic/st16650reg.h ./ic/st16650reg.h
--- /usr/src/sys/dev/ic/st16650reg.h Wed Dec 31 18:00:00 1969
+++ ./ic/st16650reg.h Tue Jul 8 04:43:00 1997
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ns16550.h 7.1 (Berkeley) 5/9/91
+ */
+
+/*
+ * ST16650A UART registers
+ */
+
+#define com_data 0 /* data register (R/W) */
+#define com_dlbl 0 /* divisor latch low (W) */
+#define com_dlbh 1 /* divisor latch high (W) */
+#define com_ier 1 /* interrupt enable (W) */
+#define com_iir 2 /* interrupt identification (R) */
+#define com_fifo 2 /* FIFO control (W) */
+#define com_efr 2 /* Enhanced feature register (R/W) */
+#define com_lctl 3 /* line control register (R/W) */
+#define com_cfcr 3 /* line control register (R/W) */
+#define com_mcr 4 /* modem control register (R/W) */
+#define com_xon1 4 /* XON 1 character (R/W) */
+#define com_lsr 5 /* line status register (R/W) */
+#define com_xon2 5 /* XON 2 character (R/W) */
+#define com_msr 6 /* modem status register (R/W) */
+#define com_xoff1 6 /* XOFF 1 character (R/W) */
+#define com_scratch 7 /* scratch register (R/W) */
+#define com_xoff2 7 /* XOFF 2 character (R/W) */
diff -uP /usr/src/sys/dev/isa/com.c ./isa/com.c
--- /usr/src/sys/dev/isa/com.c Sun Jul 6 06:20:58 1997
+++ ./isa/com.c Tue Jul 8 04:51:59 1997
@@ -70,6 +70,7 @@
/*
* COM driver, uses National Semiconductor NS16450/NS16550AF UART
+ * Supports automatic hardware flow control on StarTech ST16C650A UART
*/
#include <sys/param.h>
#include <sys/systm.h>
@@ -91,7 +92,7 @@
#include <dev/isa/comreg.h>
#include <dev/isa/comvar.h>
-#include <dev/ic/ns16550reg.h>
+#include <dev/ic/st16650reg.h>
#ifdef COM_HAYESP
#include <dev/ic/hayespreg.h>
#endif
@@ -393,6 +394,7 @@
int hayesp_ports[] = { 0x140, 0x180, 0x280, 0x300, 0 };
int *hayespp;
#endif
+ u_char iir;
if (iobase == comconsaddr) {
comconsattached = 1;
@@ -455,8 +457,25 @@
if (ISSET(bus_space_read_1(iot, ioh, com_fifo), FIFO_TRIGGER_14)
== FIFO_TRIGGER_14) {
SET(sc->sc_hwflags, COM_HW_FIFO);
- printf(": ns16550a, working fifo\n");
- sc->sc_fifolen = 16;
+
+ /*
+ * Okay, we have at least a 16550, check to
+ * see if it's a 16650. Save the IIR, then
+ * write a magic value into LCR and see if the
+ * IIR changes into the EFR.
+ */
+ iir = bus_space_read_1(iot, ioh, com_iir);
+ bus_space_write_1(iot, ioh, com_lcr, LCR_EERS);
+ if (bus_space_read_1(iot, ioh, com_iir) != iir) {
+ SET(sc->sc_hwflags, COM_HW_FLOW);
+ printf(": st16650a, working fifo\n");
+ sc->sc_fifolen = 32;
+ } else {
+ printf(": ns16550a, working fifo\n");
+ sc->sc_fifolen = 16;
+ }
+
+ bus_space_write_1(iot, ioh, com_lcr, LCR_8BITS);
} else
printf(": ns16550, broken fifo\n");
else
@@ -910,6 +929,7 @@
sc->sc_msr_cts = MSR_CTS;
sc->sc_r_hiwat = RXHIWAT;
sc->sc_r_lowat = RXLOWAT;
+ sc->sc_efr = EFR_AUTORTS | EFR_AUTOCTS;
} else if (ISSET(t->c_cflag, MDMBUF)) {
/*
* For DTR/DCD flow control, make sure we don't toggle DTR for
@@ -920,6 +940,7 @@
sc->sc_msr_cts = MSR_DCD;
sc->sc_r_hiwat = RXHIWAT;
sc->sc_r_lowat = RXLOWAT;
+ sc->sc_efr = 0;
} else {
/*
* If no flow control, then always set RTS. This will make
@@ -931,6 +952,7 @@
sc->sc_msr_cts = 0;
sc->sc_r_hiwat = 0;
sc->sc_r_lowat = 0;
+ sc->sc_efr = 0;
if (ISSET(sc->sc_mcr, MCR_DTR))
SET(sc->sc_mcr, MCR_RTS);
else
@@ -1042,6 +1064,10 @@
bus_space_write_1(iot, ioh, com_ier, 0);
+ if (ISSET(sc->sc_hwflags, COM_HW_FLOW)) {
+ bus_space_write_1(iot, ioh, com_lcr, LCR_EERS);
+ bus_space_write_1(iot, ioh, com_efr, sc->sc_efr);
+ }
bus_space_write_1(iot, ioh, com_lcr, sc->sc_lcr | LCR_DLAB);
bus_space_write_1(iot, ioh, com_dlbl, sc->sc_dlbl);
bus_space_write_1(iot, ioh, com_dlbh, sc->sc_dlbh);
@@ -1694,6 +1720,8 @@
int rate;
{
+ bus_space_write_1(iot, ioh, com_lcr, LCR_EERS);
+ bus_space_write_1(iot, ioh, com_efr, 0);
bus_space_write_1(iot, ioh, com_lcr, LCR_DLAB);
rate = comspeed(rate);
bus_space_write_1(iot, ioh, com_dlbl, rate);
diff -uP /usr/src/sys/dev/isa/comreg.h ./isa/comreg.h
--- /usr/src/sys/dev/isa/comreg.h Mon Oct 14 11:35:11 1996
+++ ./isa/comreg.h Tue Jul 8 04:45:26 1997
@@ -45,6 +45,8 @@
#define IER_ETXRDY 0x2 /* Enable transmitter empty interrupt */
#define IER_ERLS 0x4 /* Enable line status interrupt */
#define IER_EMSC 0x8 /* Enable modem status interrupt */
+#define IER_ERTS 0x40 /* Enable RTS interrupt */
+#define IER_ECTS 0x80 /* Enable CTS interrupt */
/* interrupt identification register */
#define IIR_IMASK 0xf
@@ -66,7 +68,22 @@
#define FIFO_TRIGGER_8 0x80 /* ibid 8 */
#define FIFO_TRIGGER_14 0xc0 /* ibid 14 */
+/* enhanced feature register */
+#define EFR_AUTOCTS 0x80 /* Automatic CTS flow control */
+#define EFR_AUTORTS 0x40 /* Automatic RTS flow control */
+#define EFR_SPECIAL 0x20 /* Special char detect */
+#define EFR_EFCR 0x10 /* Enhanced function control bit */
+#define EFR_TXFLOWBOTH 0x0c /* Automatic transmit XON/XOFF 1 and 2 */
+#define EFR_TXFLOW1 0x08 /* Automatic transmit XON/XOFF 1 */
+#define EFR_TXFLOW2 0x04 /* Automatic transmit XON/XOFF 2 */
+#define EFR_TXFLOWNONE 0x00 /* No automatic XON/XOFF transmit */
+#define EFR_RXFLOWBOTH 0x03 /* Automatic receive XON/XOFF 1 and 2 */
+#define EFR_RXFLOW1 0x02 /* Automatic receive XON/XOFF 1 */
+#define EFR_RXFLOW2 0x01 /* Automatic receive XON/XOFF 2 */
+#define EFR_RXFLOWNONE 0x00 /* No automatic XON/XOFF receive */
+
/* line control register */
+#define LCR_EERS 0xBF /* Enable access to Enhanced Register Set */
#define LCR_DLAB 0x80 /* Divisor latch access enable */
#define LCR_SBREAK 0x40 /* Break Control */
#define LCR_PZERO 0x38 /* Space parity */
diff -uP /usr/src/sys/dev/isa/comvar.h ./isa/comvar.h
--- /usr/src/sys/dev/isa/comvar.h Sun Jul 6 06:20:59 1997
+++ ./isa/comvar.h Tue Jul 8 04:47:16 1997
@@ -40,6 +40,7 @@
#define COM_HW_NOIEN 0x01
#define COM_HW_FIFO 0x02
#define COM_HW_HAYESP 0x04
+#define COM_HW_FLOW 0x08
#define COM_HW_CONSOLE 0x40
#define COM_HW_KGDB 0x80
@@ -70,7 +71,7 @@
int sc_fifolen;
u_char sc_msr, sc_msr_delta, sc_msr_mask, sc_mcr, sc_mcr_active, sc_lcr,
- sc_ier, sc_fifo, sc_dlbl, sc_dlbh;
+ sc_ier, sc_fifo, sc_dlbl, sc_dlbh, sc_efr;
u_char sc_mcr_dtr, sc_mcr_rts, sc_msr_cts, sc_msr_dcd;
int sc_r_hiwat;
>Audit-Trail:
>Unformatted: