Skip to content

Commit

Permalink
ns8250: Check if flush via FCR succeeded
Browse files Browse the repository at this point in the history
The emulated UART in the Firecracker VMM (aka the implementation in the
rust-vmm/vm-superio project) includes FIFOs but does not implement the
FCR register, which is used by ns8250_flush to flush the FIFOs.

Check the LSR to see if there is still data in the FIFOs and call
ns8250_drain if necessary.

Discussed with:	emaste, imp, jrtc27
Sponsored by:	https://patreon.com/cperciva
Differential Revision:	https://reviews.freebsd.org/D36979
  • Loading branch information
cperciva committed Oct 18, 2022
1 parent 782105f commit c4b68e7
Showing 1 changed file with 19 additions and 0 deletions.
19 changes: 19 additions & 0 deletions sys/dev/uart/uart_dev_ns8250.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ static void
ns8250_flush(struct uart_bas *bas, int what)
{
uint8_t fcr;
uint8_t lsr;
int drain = 0;

fcr = FCR_ENABLE;
#ifdef CPU_XBURST
Expand All @@ -221,6 +223,23 @@ ns8250_flush(struct uart_bas *bas, int what)
fcr |= FCR_RCV_RST;
uart_setreg(bas, REG_FCR, fcr);
uart_barrier(bas);

/*
* Detect and work around emulated UARTs which don't implement the
* FCR register; on these systems we need to drain the FIFO since
* the flush we request doesn't happen. One such system is the
* Firecracker VMM, aka. the rust-vmm/vm-superio emulation code:
* https://github.com/rust-vmm/vm-superio/issues/83
*/
lsr = uart_getreg(bas, REG_LSR);
if ((lsr & LSR_TEMT) && (what & UART_FLUSH_TRANSMITTER))
drain |= UART_DRAIN_TRANSMITTER;
if ((lsr & LSR_RXRDY) && (what & UART_FLUSH_RECEIVER))
drain |= UART_DRAIN_RECEIVER;
if (drain != 0) {
printf("ns8250: UART FCR is broken\n");
ns8250_drain(bas, drain);
}
}

static int
Expand Down

0 comments on commit c4b68e7

Please sign in to comment.