1
linux/drivers/serial
Ondrej Puzman e4f05af136 8250: fix uninitialized FIFOs
I have found a bug in 8250.c driver which causes that 16550A uart FIFOs
are not turned on during initialization if they are manually configured
by setserial. UART is then working only as plain 16450 without FIFOs. On
systems with higher interrupt latency this causes buffer overruns and
loss of received data when using higher communication speeds.

I'm working for a company which produces industrial computers. These
devices typically contain high number (8 or more) of traditional 16550A
uarts - we use TL16C554A chips, but that is not much relevant. UARTs are
connected to the CPU by ISA bus (Celeron based devices) or LPC bus (Atom
based devices).

In the Linux the UARTs are using standard 8250.c driver and are
initialized using setserial command:
setserial /dev/ttyS4 uart 16550A port 0x3E0 irq 10 baud_base 115200

This executes the UART initialization through serial8250_startup()
function. At the beginning of the function up->capabilities is
initialized from uart_config:
 up->capabilities = uart_config[up->port.type].flags;
Please note that neither up->port.fifosize nor up->tx_loadsz is
initialized here!!

Later in the same function serial8250_clear_fifos() is called and
disables FIFOs. The above comment says that they will be reenabled in
set_termios (they won't ...)

After serial8250_startup() the serial8250_set_termios() is called. In
this function the following check fails because up->port.fifosize is
zero because it is not initialized correctly.

        if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) {
                if (baud < 2400)
                        fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
                else
                        fcr = uart_config[up->port.type].fcr;
        }

fcr variable remains zero and in the end the FCR register is set to zero
which results in disabled FIFOs even if the UART type is 16550A. This is
also true for other types of UARTs with FIFOs.

If the UART is autoconfigured via 'setserial /dev/ttySx autoconfig' then
port.fifosize and tx_loadsz are initialized correctly in the
autoconfig() function and the UART is working correctly then.

I checked the source codes and I can say that this bug is present in
2.6.x series of kernels for a couple of years. Namely I can confirm its
presence in 2.6.16.57, 2.6.32.24 and 2.6.36.1 (tested all of them on our
hardware).

I think it was not noticed before because not many people use manually
configured non PNP UARTs on ISA/LPC bus these days. Also the data loss
caused by buffer overruns occures only if  IRQ latency is higher then
time needed to receive one character on given communication speed.
For example our hardware looses received characters only if the UARTs
are connected throught LPC bus with SERIRQ (serial IRQ transport) and
not if they are connected to ISA bus because LPC SERIRQ has higher
interrupt latency then parallel ISA interupt lines.

Here is the patch to correct the bug created against 2.6.36.1:

Signed-off-by: Ondrej Puzman <puzman@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-12-10 15:22:25 -08:00
..
cpm_uart serial: cpu_uart: Remove unused uart_cpm_port fields 2010-11-11 11:35:59 -08:00
jsm jsm: Remove the uart port on errors 2010-10-22 10:20:10 -07:00
8250_accent.c
8250_acorn.c
8250_boca.c
8250_early.c serial: print early console device address in hex 2010-08-23 18:17:20 -07:00
8250_exar_st16c554.c
8250_fourport.c
8250_gsc.c include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h 2010-03-30 22:02:32 +09:00
8250_hp300.c include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h 2010-03-30 22:02:32 +09:00
8250_hub6.c
8250_mca.c
8250_pci.c Serial: ce4100: Add PCI UART support for the ce4100 2010-11-30 17:21:50 -08:00
8250_pnp.c serial: 8250_pnp - add Fujitsu Wacom device 2010-04-30 09:20:34 -07:00
8250.c 8250: fix uninitialized FIFOs 2010-12-10 15:22:25 -08:00
8250.h
21285.c tty: serial - fix tty back references in termios 2010-08-10 13:47:41 -07:00
68328serial.c 68328serial: check return value of copy_*_user() instead of access_ok() 2010-08-23 18:17:22 -07:00
68328serial.h arch/m68knommu: Removing dead 68328_SERIAL_UART2 config option 2010-10-21 10:17:29 +10:00
68360serial.c tty: icount changeover for other main devices 2010-10-22 10:20:05 -07:00
altera_jtaguart.c serial: Add driver for the Altera JTAG UART 2010-05-21 09:34:30 -07:00
altera_uart.c altera_uart: Don't use plain integer as NULL pointer 2010-10-22 10:20:09 -07:00
amba-pl010.c serial: amba-pl010: fix set_ldisc 2010-09-20 16:30:00 -07:00
amba-pl011.c ARM: Fix section build warnings for AMBA drivers 2010-07-27 10:48:43 +01:00
apbuart.c of/device: Replace struct of_device with struct platform_device 2010-08-06 09:25:50 -06:00
apbuart.h
atmel_serial.c serial: general fixes in the serial_rs485 structure 2010-08-10 13:47:45 -07:00
bcm63xx_uart.c serial: bcm63xx_uart: allow more than one uart to be registered. 2010-03-02 14:43:19 -08:00
bfin_5xx.c tty: serial - fix tty referencing in set_ldisc 2010-08-10 13:47:41 -07:00
bfin_sport_uart.c Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial 2010-10-24 13:41:39 -07:00
bfin_sport_uart.h Update broken web addresses in the kernel. 2010-10-18 11:03:14 +02:00
clps711x.c
crisv10.c CRIS: Fix RS485 delay handling. 2010-10-28 12:13:27 +02:00
crisv10.h
dz.c
dz.h
icom.c tty: Fix up char drivers request_room usage 2010-03-02 14:43:22 -08:00
icom.h
ifx6x60.c serial: ifx6x60: fix memory leak 2010-11-30 17:25:46 -08:00
ifx6x60.h ifx6x60: SPI protocol driver for Infineon 6x60 modem 2010-11-11 11:35:57 -08:00
imx.c serial/imx: check that the buffer is non-empty before sending it out 2010-10-22 10:20:10 -07:00
ioc3_serial.c Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6 2010-10-21 14:27:18 -07:00
ioc4_serial.c tty: serial - fix tty back references in termios 2010-08-10 13:47:41 -07:00
ip22zilog.c
ip22zilog.h
Kconfig serial: fix pch_uart kconfig & build 2010-12-10 15:17:19 -08:00
kgdboc.c kdb,kgdb: fix sparse fixups 2010-10-22 15:34:12 -05:00
m32r_sio_reg.h
m32r_sio.c
m32r_sio.h
Makefile serial: omap-serial: Add support for kernel debugger 2010-12-10 15:17:19 -08:00
max3100.c tty: serial - fix tty back references in termios 2010-08-10 13:47:41 -07:00
max3107-aava.c serial: max3107: Abstract out the platform specific bits 2010-08-10 13:47:44 -07:00
max3107.c serial: max3107: Fix memory leaks when returning on error 2010-10-22 10:20:03 -07:00
max3107.h serial: max3107: Fix gpiolib support 2010-08-10 13:47:46 -07:00
mcf.c serial: mcf: don't take spinlocks in already protected functions 2010-08-10 13:47:45 -07:00
mfd.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6 2010-10-22 19:59:04 -07:00
mpc52xx_uart.c serial: mpc52xx: make printout for type more generic 2010-11-16 12:50:18 -08:00
mpsc.c powerpc/mpsc: Set the port device in the mpsc serial driver 2010-04-07 14:12:36 +10:00
mrst_max3110.c serial: mrst_max3110: Make the IRQ option runtime 2010-10-22 10:20:03 -07:00
mrst_max3110.h serial: mrst_max3110: some code cleanup 2010-10-22 10:20:03 -07:00
msm_serial.c msm_serial: fix serial on trout 2010-06-04 13:37:16 -07:00
msm_serial.h msm_serial: fix serial on trout 2010-06-04 13:37:16 -07:00
mux.c include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h 2010-03-30 22:02:32 +09:00
netx-serial.c
nwpserial.c of/device: Replace struct of_device with struct platform_device 2010-08-06 09:25:50 -06:00
of_serial.c powerpc, of_serial: Endianness issues setting up the serial ports 2010-10-07 17:21:15 -06:00
omap-serial.c serial: omap-serial: Add support for kernel debugger 2010-12-10 15:17:19 -08:00
pch_uart.c Serial: EG20T: add PCH_UART driver 2010-11-30 17:23:44 -08:00
pmac_zilog.c powerpc/macio: Fix probing of macio devices by using the right of match table 2010-06-02 17:50:38 +10:00
pmac_zilog.h
pnx8xxx_uart.c
pxa.c include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h 2010-03-30 22:02:32 +09:00
s3c24a0.c
s3c2400.c
s3c2410.c
s3c2412.c
s3c2440.c
s3c6400.c
s5pv210.c ARM: S5PV310: Add serial port support 2010-08-05 18:32:42 +09:00
sa1100.c
samsung.c ARM: S5P64X0: Add UART serial support for S5P6450 2010-10-18 18:33:04 +09:00
samsung.h
sb1250-duart.c
sc26xx.c
serial_core.c 8250: add a UPIO_DWAPB32 for 32 bit accesses 2010-12-10 15:19:38 -08:00
serial_cs.c serial_cs: drop spurious flush_scheduled_work() call 2010-10-16 11:07:07 +02:00
serial_ks8695.c ARM: 6030/1: KS8695: enable console 2010-04-23 10:01:56 +01:00
serial_lh7a40x.c
serial_txx9.c
sh-sci.c Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 2010-05-31 13:14:26 +09:00
sh-sci.h Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 2010-08-16 13:32:24 +09:00
sn_console.c Input: sysrq - drop tty argument form handle_sysrq() 2010-08-21 00:34:45 -07:00
suncore.c sparc: Really fix "console=" for serial consoles. 2010-08-16 12:26:09 -07:00
suncore.h
sunhv.c of/device: Replace struct of_device with struct platform_device 2010-08-06 09:25:50 -06:00
sunsab.c of/device: Replace struct of_device with struct platform_device 2010-08-06 09:25:50 -06:00
sunsab.h
sunsu.c of/device: Replace struct of_device with struct platform_device 2010-08-06 09:25:50 -06:00
sunzilog.c of/device: Replace struct of_device with struct platform_device 2010-08-06 09:25:50 -06:00
sunzilog.h
timbuart.c timbuart: use __devinit and __devexit macros for probe and remove 2010-08-10 13:47:45 -07:00
timbuart.h
uartlite.c Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial 2010-10-24 13:41:39 -07:00
ucc_uart.c of/device: Replace struct of_device with struct platform_device 2010-08-06 09:25:50 -06:00
vr41xx_siu.c
vt8500_serial.c serial: Add support for UART on VIA VT8500 and compatibles 2010-11-11 11:35:57 -08:00
zs.c
zs.h