Add a loader tunable "hw.broken_txfifo" which enables a workaround for a

bug in old versions of QEMU (and Xen, and other places using QEMU code).
On those buggy emulated UARTs, the "TX idle" interrupt gets lost; with
this workaround, we spinwait for the TX to happen and then send ourselves
the interrupt.  It's ugly but it works, while minimizing the impact on
the code for the !broken_txfifo case.

MFC after:	2 weeks
This commit is contained in:
Colin Percival 2013-01-27 23:33:42 +00:00
parent 4bdf739335
commit 1c60b24baa
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=246016

View File

@ -31,6 +31,8 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <machine/bus.h>
#include <dev/uart/uart.h>
@ -845,6 +847,11 @@ ns8250_bus_setsig(struct uart_softc *sc, int sig)
return (0);
}
static int broken_txfifo = 0;
SYSCTL_INT(_hw, OID_AUTO, broken_txfifo, CTLFLAG_RW | CTLFLAG_TUN,
&broken_txfifo, 0, "UART FIFO has QEMU emulation bug");
TUNABLE_INT("hw.broken_txfifo", &broken_txfifo);
static int
ns8250_bus_transmit(struct uart_softc *sc)
{
@ -862,7 +869,12 @@ ns8250_bus_transmit(struct uart_softc *sc)
uart_setreg(bas, REG_DATA, sc->sc_txbuf[i]);
uart_barrier(bas);
}
sc->sc_txbusy = 1;
if (broken_txfifo)
ns8250_drain(bas, UART_DRAIN_TRANSMITTER);
else
sc->sc_txbusy = 1;
uart_unlock(sc->sc_hwmtx);
if (broken_txfifo)
uart_sched_softih(sc, SER_INT_TXIDLE);
return (0);
}