• Evan Green's avatar
    tty: serial: msm_geni_serial: Fix TX infinite loop · 638a6f4e
    Evan Green authored
    The GENI serial driver handled transmit by leaving stuff in the
    common circular buffer until it had completely caught up to the head,
    then clearing it out all at once. This is a suboptimal way to do
    transmit, as it leaves data in the circular buffer that could be
    freed. Moreover, the logic implementing it is wrong, and it is easy to
    get into a situation where the UART infinitely writes out the same buffer.
    
    I could reproduce infinite serial output of the same buffer by running
    dmesg, then hitting Ctrl-C. I believe what happened is xmit_size was
    something large, marching towards a larger value. Then the generic OS
    code flushed out the buffer and replaced it with two characters. Now the
    xmit_size is a large value marching towards a small value, which it wasn't
    expecting. The driver subtracts xmit_size (very large) from
    uart_circ_chars_pending (2), underflows, and repeats ad nauseum. The
    locking isn't wrong here, as the locks are held whenever the buffer is
    manipulated, it's just that the driver wasn't expecting the buffer to be
    flushed out from underneath it in between transmits.
    
    This change reworks transmit to grab what it can from the circular buffer,
    and then update ->tail, both fixing the underflow and freeing up space
    for a smoother circular experience.
    Signed-off-by: default avatarEvan Green <evgreen@chromium.org>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    638a6f4e
qcom_geni_serial.c 33.2 KB