On 2024-11-04, Jiri Slaby <jirislaby@xxxxxxxxxx> wrote:
Instead of looping fifosize multiplied by random timeout, can we
re-use port->frame_time?
Rather than 10k loops, we could loop
(port->frame_time * some_scaled_padding) / 1000
times. The padding is important because we should not timeout in the
normal scenario. Perhaps using ~2 as @some_padding. Something like:
port->frame_time >> 9
?
The difference between THRE and TEMT is the state of the shift register
only[2]:
"In the FIFO mode, TEMT is set when the transmitter FIFO and shift
register are both empty."
But what's the purpose of spinning _here_? The kernel can run and
FIFO too. Without the kernel waiting for the FIFO.
If we want to wait for fifo to empty, why not *also* the TSR. Meaning:
Did you want UART_LSR_TEMT?
Let us assume we have a line with 640 characters and a FIFO of 64
bytes. For this line, we must wait for the FIFO to empty 10 times. It is
enough to wait for THRE for each of the 64-byte blocks because we are
only interested in refilling the FIFO at this point. Only at the very
end (in the caller... serial8250_console_write()) do we need to wait
for everything to flush to the wire (TEMT).
By waiting on TEMT for each of the 64-byte blocks, we are waiting longer
than necessary. This creates a small window where the FIFO is empty and
there is nothing being transmitted.
I did a simple test on my beaglebone-black hardware, sending 100 lines
of 924 bytes at 9600 bps. Since my hardware uses a 64-byte FIFO, each
line would have 14 such windows.
And indeed, waiting for TEMT rather than only THRE for the 64-byte
blocks resulted in an extra 30ms total transfer for all 92400
bytes. That is about 20us lost in each window by unnecessarily waiting
for TEMT.