FreeBSD & 16550/16650 UART Support


Whilst building a home router (an old 486) with FreeBSD 2.2 (FreeBSD version 3 couldn't be used because there is no support for the UltraStor 14F SCSI adaptor any more ... :-0 ) it was noticed that there were significant numbers of serial port SILO errors occurring, despite the use of a 16550 UART. This is not a good thing - it means that the interrupt latency is so high (well at least with the default driver greater than 2*10/115200 seconds = 174 microseconds) that bytes of data were occasionally being lost - which is really bad because this will in turn corrupt PPP frames and thence IP at a higher layer...

Now of course with FreeBSD we can look at the serial driver code and try to figure out what's happening.

The first thing that was noticed is that the 16550 UART FIFO trigger level is set on the highest level of 14 bytes. In a way this is good because it means that the UART will only interrupt the CPU when there are 14 bytes of data waiting (or a UART internal timeout occurs). But this leaves only 2 bytes of space left in the FIFO which is how we can conclude that occassionally the interrupt latency exceeds 2 bytes of 10 bits (start bit, data bits, stop bit) at 115200 baud - 174 microseconds.

With a bit of research we discover that the 16550 UART can be programmed with four different FIFO trigger levels - 1, 4, 8 or 14 bytes.

Changing the trigger level to 1, 4 or 8 bytes does not completely reduce the problem and worse, particularly with a trigger level of 1 byte, the CPU spends too much time servicing serial interrupts. We can then determine that the interrupt latency occassionally exceeds 16*10/115200 = 1.39 millseconds. This is definitely a problem and it is apparent that other people have voiced their concerns about this - but the official answer is that this can happen in i386 land.

It was therefore decided that a better approach was to use 16650 UARTs which have the really useful feature of automatic flow control. This means that the 16650 has the intelligence to perform hardware or software flow control to halt the data flow before the FIFO overflows - and without assistance from the host CPU!

On implementing this it was noticed that the current serial driver did not correctly work with the Startech 16650 UART supplied - so I have modified the driver to correct this.


This driver has been tested with the FreeBSD 2.2.8 kernel - but is will probably work with previous releases. (I'll release a 3.x version soon...)

[You'll need to copy this file to /usr/src/sys/i386/isa/sio.c and then rebuild the kernel.]

© David Burns 1999. Last updated November 1999.