From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 68CD433BBD9; Fri, 9 Oct 2026 14:31:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791556272; cv=none; b=np2n1NseTWlOqkgtB4mbvTsxgsm53CtZG4NrApDvqyzrfQUyoB+NMgnqjgt6TvFHJZ3AWxxBcVSNUECJ2bg7lL2iRGzFEiM8WeJGjOPHDlwqyaSIs/9itM4+rJG0ieXpLX9z/2sy99S7l/y+nDZIgj/x7EybR02kQctYUqR6zGI= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791556272; c=relaxed/simple; bh=gXnHetRZ7ORoM/TNZEEO9VVYGdAbs5opVKOkhhtAcLo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nh+RdCbBrB4MxuiVpZPh9NEZovnROYsMXL0pX/Ejy1VrV3np33J8ZpPhphjMhdXv90FX+1mYBoLX8HtxzR5x638AfTG3FevJ+Nk5EhM9nlu4qEdjOEz9SubL1iRYffehqsniwOk8HSN2/n1gwD7CI3Ct9b1dlXUCC4A1WXQxOL8= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b=W+Drd58o; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b="W+Drd58o" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C75D11F000FF; Fri, 9 Oct 2026 14:31:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1791556271; bh=yHZ90/tUPVDy7H5dDyPN0wesfymytUcZ6pCBz+/1ol8=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=W+Drd58ozCuJ/nBpt66yzxMoxuoicNyq2dhxt+1ORl8Y+H87oXwgdEmJ93mOYDBV5 4cDiFBSX/84jDGdaPEJLM0ioT7gOXfqGmzrjGkd3p/6W/S8vxXHKM5uL+5XBJPeN5P H8qM9GlM0hmdEbyG9GlFWxRJ+fGJv1P+J+RH1nmA= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, stable@kernel.org, Tobias Gannert , Paul Mbewe , David Laight Subject: [PATCH 6.18 207/403] serial: sc16is7xx: refill TX FIFO below trigger using fresh TXLVL Date: Fri, 9 Oct 2026 16:09:28 +0200 Message-ID: <20261009140956.979873520@linuxfoundation.org> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261009140952.119038291@linuxfoundation.org> References: <20261009140952.119038291@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore Precedence: bulk X-Mailing-List: patches@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 6.18-stable review patch. If anyone has any objections, please let me know. ------------------ From: Paul Mbewe commit 527484911a40f6e84cf47e8bc490f7da61ab4151 upstream. sc16is7xx_handle_tx() reads TXLVL once and sizes the hardware TX FIFO write from that value. TXLVL reports free space in the hardware TX FIFO. On this SPI-backed path, hardirq/softirq activity, RT scheduling, and waiting for synchronous SPI transfers can delay the refill while the UART continues draining. The TXLVL value can therefore become stale before the hardware TX FIFO write completes. One failing ftrace with the default 8-free-space trigger showed: tx_start txlvl=9 txlvl_read_us=580 tx_pre_write sent=9 pre_write_us=16 tx_segment sent=9 seg_us=364 tx_post_write txlvl_before=9 sent=9 txlvl_after=12 pending_after=29 post_gap_us=12 post_txlvl_us=130 The driver read 9 free spaces and wrote 9 bytes to the hardware TX FIFO, but the post-write TXLVL read still reported 12 free spaces while 29 bytes remained queued in the xmit kfifo. Even allowing for the post-write read window, the hardware TX FIFO had not been filled below the 8-free-space trigger, so no new threshold crossing was expected. The captured failing samples had the same pattern: data remained queued in the xmit kfifo while post-write TXLVL remained above the hardware trigger. The hardware TX FIFO then drained empty before another refill was requested, producing an unintended gap on the wire. Fix this by re-reading TXLVL after each hardware TX FIFO write while data remains queued in the xmit kfifo. If TXLVL is still at or above the trigger, top up the hardware TX FIFO again. Stop when the xmit kfifo is empty or a TXLVL read confirms that hardware TX FIFO free space is strictly below the trigger. Stopping when TXLVL was equal to the trigger still allowed TX gaps in the tested workload. Continuing until TXLVL was strictly below the trigger eliminated the observed gaps caused by stale-TXLVL under-fill. Program the hardware TX trigger explicitly through TLR using the same constant as the refill-loop threshold. This prevents the software refill condition from diverging from the programmed hardware trigger. Tested on SC16IS752 over 1 MHz SPI on an i.MX6ULL single-core PREEMPT_RT system, transmitting RS-485 at 115200 baud 8N1 under continuous Modbus RTU load. Fixes: dfeae619d781 ("serial: sc16is7xx") Cc: stable@kernel.org Reported-by: Tobias Gannert Link: https://lore.kernel.org/linux-serial/20260623112225.82386-3-paultyson.mbewe@ziehl-abegg.de/ Signed-off-by: Paul Mbewe Reviewed-by: David Laight Link: https://patch.msgid.link/20260930145628.566535-2-paultyson.mbewe@ziehl-abegg.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -246,6 +246,8 @@ #define SC16IS7XX_TLR_TX_TRIGGER(words) ((((words) / 4) & 0x0f) << 0) #define SC16IS7XX_TLR_RX_TRIGGER(words) ((((words) / 4) & 0x0f) << 4) +#define SC16IS7XX_TX_TRIGGER_LEVEL 8 + /* IOControl register bits (Only 75x/76x) */ #define SC16IS7XX_IOCONTROL_LATCH_BIT BIT(0) /* Enable input latching */ #define SC16IS7XX_IOCONTROL_MODEM_A_BIT BIT(1) /* Enable GPIO[7:4] as modem A pins */ @@ -694,6 +696,21 @@ static void sc16is7xx_handle_rx(struct u tty_flip_buffer_push(&port->state->port); } +static unsigned int sc16is7xx_txlvl(struct uart_port *port) +{ + unsigned int txlvl; + + txlvl = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG); + if (txlvl > SC16IS7XX_FIFO_SIZE) { + dev_err_ratelimited(port->dev, + "chip reports %u free bytes in TX FIFO, but it only has %u\n", + txlvl, SC16IS7XX_FIFO_SIZE); + return 0; + } + + return txlvl; +} + static void sc16is7xx_handle_tx(struct uart_port *port) { struct tty_port *tport = &port->state->port; @@ -715,13 +732,7 @@ static void sc16is7xx_handle_tx(struct u } /* Limit to space available in TX FIFO */ - txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG); - if (txlen > SC16IS7XX_FIFO_SIZE) { - dev_err_ratelimited(port->dev, - "chip reports %d free bytes in TX fifo, but it only has %d", - txlen, SC16IS7XX_FIFO_SIZE); - txlen = 0; - } + txlen = sc16is7xx_txlvl(port); /* Handle circular buffer wrap-around by sending multiple segments */ while (txlen > 0 && !kfifo_is_empty(&tport->xmit_fifo)) { @@ -734,7 +745,14 @@ static void sc16is7xx_handle_tx(struct u sc16is7xx_fifo_write(port, tail, to_send); uart_xmit_advance(port, to_send); - txlen -= to_send; + + if (kfifo_is_empty(&tport->xmit_fifo)) + break; + + /* Refill below the trigger to enable the next THRI crossing. */ + txlen = sc16is7xx_txlvl(port); + if (txlen < SC16IS7XX_TX_TRIGGER_LEVEL) + break; } uart_port_lock_irqsave(port, &flags); @@ -1186,6 +1204,10 @@ static int sc16is7xx_startup(struct uart SC16IS7XX_TCR_RX_RESUME(24) | SC16IS7XX_TCR_RX_HALT(48)); + /* Sync hardware and software TX trigger levels */ + sc16is7xx_port_write(port, SC16IS7XX_TLR_REG, + SC16IS7XX_TLR_TX_TRIGGER(SC16IS7XX_TX_TRIGGER_LEVEL)); + /* Disable TCR/TLR access */ sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, SC16IS7XX_MCR_TCRTLR_BIT, 0);