On Thu, 30 May 2024, Douglas Anderson wrote: > The qcom_geni_serial_poll_bit() is supposed to be able to be used to > poll a bit that's will become set when a TX transfer finishes. Because > of this it tries to set its timeout based on how long the UART will > take to shift out all of the queued bytes. There are two problems > here: > 1. There appears to be a hidden extra word on the firmware side which > is the word that the firmware has already taken out of the FIFO and > is currently shifting out. We need to account for this. > 2. The timeout calculation was assuming that it would only need 8 bits > on the wire to shift out 1 byte. This isn't true. Typically 10 bits > are used (8 data bits, 1 start and 1 stop bit), but as much as 13 > bits could be used (14 if we allowed 9 bits per byte, which we > don't). > > The too-short timeout was seen causing problems in a future patch > which more properly waited for bytes to transfer out of the UART > before cancelling. > > Fixes: c4f528795d1a ("tty: serial: msm_geni_serial: Add serial driver support for GENI based QUP") > Signed-off-by: Douglas Anderson <dianders@xxxxxxxxxxxx> > --- > > Changes in v2: > - New > > drivers/tty/serial/qcom_geni_serial.c | 32 ++++++++++++++++++++++++--- > 1 file changed, 29 insertions(+), 3 deletions(-) > > diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c > index 2bd25afe0d92..32e025705f99 100644 > --- a/drivers/tty/serial/qcom_geni_serial.c > +++ b/drivers/tty/serial/qcom_geni_serial.c > @@ -271,7 +271,8 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport, > u32 reg; > struct qcom_geni_serial_port *port; > unsigned int baud; > - unsigned int fifo_bits; > + unsigned int max_queued_bytes; > + unsigned int max_queued_bits; > unsigned long timeout_us = 20000; > struct qcom_geni_private_data *private_data = uport->private_data; > > @@ -280,12 +281,37 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport, > baud = port->baud; > if (!baud) > baud = 115200; > - fifo_bits = port->tx_fifo_depth * port->tx_fifo_width; > + > + /* > + * Add 1 to tx_fifo_depth to account for the hidden register > + * on the firmware side that can hold a word. > + */ > + max_queued_bytes = > + DIV_ROUND_UP((port->tx_fifo_depth + 1) * port->tx_fifo_width, > + BITS_PER_BYTE); > + > + /* > + * The maximum number of bits per byte on the wire is 13 from: > + * - 1 start bit > + * - 8 data bits > + * - 1 parity bit > + * - 3 stop bits > + * > + * While we could try count the actual bits per byte based on > + * the port configuration, this is a rough timeout anyway so > + * using the max is fine. > + */ > + max_queued_bits = max_queued_bytes * 13; > + > /* > * Total polling iterations based on FIFO worth of bytes to be > * sent at current baud. Add a little fluff to the wait. > + * > + * NOTE: this assumes that flow control isn't used, but with > + * flow control we could wait indefinitely and that wouldn't > + * be OK. > */ > - timeout_us = ((fifo_bits * USEC_PER_SEC) / baud) + 500; > + timeout_us = ((max_queued_bits * USEC_PER_SEC) / baud) + 500; You should try to generalize the existing uart_fifo_timeout() to suit what you're trying to do here instead of writing more variants of code with this same intent. -- i.