FAILED: patch "[PATCH] serial: sc16is7xx: enable THRI before filling TX FIFO" failed to apply to 6.12-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x 246ac114f485c2affb454240f3ea4fabfce22456
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026081754-ogle-alkalize-4f27@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 246ac114f485c2affb454240f3ea4fabfce22456 Mon Sep 17 00:00:00 2001
From: Luca Fresi <[email protected]>
Date: Wed, 22 Jul 2026 00:24:04 +0200
Subject: [PATCH] serial: sc16is7xx: enable THRI before filling TX FIFO
sc16is7xx_handle_tx() currently requests the THRI enable only after it has filled the TX FIFO. The request is asynchronous because the IER update is performed later by reg_work.
The SC16IS7xx generates a THRI interrupt when the TX FIFO crosses its trigger level. If the FIFO drains past that level before reg_work enables THRI, the chip does not generate a new interrupt. Characters remain queued indefinitely even though the hardware FIFO is empty.
This was observed on an SC16IS752 while both UART channels were active. During the stall the software TX buffer remained non-empty while TXLVL reported 64 bytes free, LSR reported THR and transmitter empty, IER had THRI enabled, and IIR reported no interrupt pending.
Enable THRI synchronously before filling the FIFO so the threshold crossing cannot be missed.
drivers/tty/serial/sc16is7xx.c +3 -0
@@ -827,6 +827,9 @@ static void sc16is7xx_tx_proc(struct kthread_work *ws)msleep (port->rs485.delay_rts_before_send);guard (mutex)(&one->lock); +sc16is7xx_port_update (port,SC16IS7XX_IER_REG , +SC16IS7XX_IER_THRI_BIT , +SC16IS7XX_IER_THRI_BIT );sc16is7xx_handle_tx (port); }
Sasha Levin
maintainerPATCH 1/3 serial: sc16is7xx: rename EFR mutex with generic name
From: Hugo Villeneuve <[email protected]>
[ Upstream commit d9b2d7ddbb973b981c20b21e9228581bb156f66f ]
This mutex is used as a lock when accessing registers that share the same address space, not necessarily EFR registers.
For example, address 0x06 is shared by MSR, TCR and XOFF1 registers, independently of EFR.
Rename the mutex with a more generic name to avoid misinterpreting its usage.
Stable-dep-of: 246ac114f485 ("serial: sc16is7xx: enable THRI before filling TX FIFO")
--- drivers/tty/serial/sc16is7xx.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-)
drivers/tty/serial/sc16is7xx.c +13 -13
@@ -327,7 +327,7 @@ struct sc16is7xx_one_config {struct sc16is7xx_one {struct uart_port port;struct regmap *regmap; -struct mutex efr_lock;/* EFR registers access */ +struct mutex lock;/* For registers sharing same address space. */ struct kthread_work tx_work;struct kthread_work reg_work;struct kthread_delayed_work ms_work;
@@ -433,7 +433,7 @@ static void sc16is7xx_efr_lock(struct uart_port *port) {struct sc16is7xx_one *one =to_sc16is7xx_one (port, port); -mutex_lock (&one->efr_lock); +mutex_lock (&one->lock);/* Backup content of LCR. */ one->old_lcr =sc16is7xx_port_read (port,SC16IS7XX_LCR_REG );
@@ -455,7 +455,7 @@ static void sc16is7xx_efr_unlock(struct uart_port *port)/* Restore original content of LCR */ sc16is7xx_port_write (port,SC16IS7XX_LCR_REG , one->old_lcr); -mutex_unlock (&one->efr_lock); +mutex_unlock (&one->lock); }static void sc16is7xx_ier_clear (struct uart_port *port,u8 bit)
@@ -590,7 +590,7 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)SC16IS7XX_MCR_CLKSEL_BIT , prescaler == 1 ? 0 : SC16IS7XX_MCR_CLKSEL_BIT); -mutex_lock (&one->efr_lock); +mutex_lock (&one->lock);/* Backup LCR and access special register set (DLL/DLH) */ lcr =sc16is7xx_port_read (port,SC16IS7XX_LCR_REG );
@@ -606,7 +606,7 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)/* Restore LCR and access to general register set */ sc16is7xx_port_write (port,SC16IS7XX_LCR_REG , lcr); -mutex_unlock (&one->efr_lock); +mutex_unlock (&one->lock);return DIV_ROUND_CLOSEST ((clk / prescaler) /16 , div); }
@@ -753,7 +753,7 @@ static void sc16is7xx_update_mlines(struct sc16is7xx_one *one)unsigned long flags;unsigned int status, changed; -lockdep_assert_held_once (&one->efr_lock); +lockdep_assert_held_once (&one->lock); status =sc16is7xx_get_hwmctrl (port); changed = status ^ one->old_mctrl;
@@ -784,7 +784,7 @@ static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)struct uart_port *port = &s->p[portno].port;struct sc16is7xx_one *one =to_sc16is7xx_one (port, port); -mutex_lock (&one->efr_lock); +mutex_lock (&one->lock); iir =sc16is7xx_port_read (port,SC16IS7XX_IIR_REG );if (iir &SC16IS7XX_IIR_NO_INT_BIT ) {
@@ -831,7 +831,7 @@ static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) } out_port_irq: -mutex_unlock (&one->efr_lock); +mutex_unlock (&one->lock);return rc; }
@@ -863,9 +863,9 @@ static void sc16is7xx_tx_proc(struct kthread_work *ws) (port->rs485.delay_rts_before_send > 0))msleep (port->rs485.delay_rts_before_send); -mutex_lock (&one->efr_lock); +mutex_lock (&one->lock);sc16is7xx_handle_tx (port); -mutex_unlock (&one->efr_lock); +mutex_unlock (&one->lock); }static void sc16is7xx_reconf_rs485 (struct uart_port *port)
@@ -932,9 +932,9 @@ static void sc16is7xx_ms_proc(struct kthread_work *ws)struct sc16is7xx_port *s =dev_get_drvdata (one->port.dev);if (one->port.state) { -mutex_lock (&one->efr_lock); +mutex_lock (&one->lock);sc16is7xx_update_mlines (one); -mutex_unlock (&one->efr_lock); +mutex_unlock (&one->lock);kthread_queue_delayed_work (&s->kworker, &one->ms_work,HZ ); }
@@ -1604,7 +1604,7 @@ int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype, s->p[i].old_mctrl =0 ; s->p[i].regmap = regmaps[i]; -mutex_init (&s->p[i].efr_lock); +mutex_init (&s->p[i].lock); ret =uart_get_rs485_mode (&s->p[i].port);if (ret)
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/3 serial: sc16is7xx: use guards for simple mutex locks
From: Hugo Villeneuve <[email protected]>
[ Upstream commit 0f4f88bfd7e7bf3f3293045fffdc63586b0a889f ]
Guards can help to make the code more readable, so use them wherever they do so.
In sc16is7xx_port_irq(), labels and 'rc' locals are eliminated completely.
Stable-dep-of: 246ac114f485 ("serial: sc16is7xx: enable THRI before filling TX FIFO")
--- drivers/tty/serial/sc16is7xx.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-)
drivers/tty/serial/sc16is7xx.c +8 -15
@@ -11,6 +11,7 @@#define DEFAULT_SYMBOL_NAMESPACE "SERIAL_NXP_SC16IS7XX"#include <linux/bits.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/device.h>
@@ -779,18 +780,15 @@ static void sc16is7xx_update_mlines(struct sc16is7xx_one *one)static bool sc16is7xx_port_irq (struct sc16is7xx_port *s,int portno) { -bool rc = true;unsigned int iir, rxlen;struct uart_port *port = &s->p[portno].port;struct sc16is7xx_one *one =to_sc16is7xx_one (port, port); -mutex_lock (&one->lock); +guard (mutex)(&one->lock); iir =sc16is7xx_port_read (port,SC16IS7XX_IIR_REG ); -if (iir &SC16IS7XX_IIR_NO_INT_BIT ) { - rc = false; - goto out_port_irq; - } +if (iir &SC16IS7XX_IIR_NO_INT_BIT ) +return false; iir &=SC16IS7XX_IIR_ID_MASK ;
@@ -830,10 +828,7 @@ static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)break ; } -out_port_irq: -mutex_unlock (&one->lock); - -return rc; +return true; }static irqreturn_t sc16is7xx_irq (int irq,void *dev_id)
@@ -863,9 +858,8 @@ static void sc16is7xx_tx_proc(struct kthread_work *ws) (port->rs485.delay_rts_before_send > 0))msleep (port->rs485.delay_rts_before_send); -mutex_lock (&one->lock); +guard (mutex)(&one->lock);sc16is7xx_handle_tx (port); -mutex_unlock (&one->lock); }static void sc16is7xx_reconf_rs485 (struct uart_port *port)
@@ -932,9 +926,8 @@ static void sc16is7xx_ms_proc(struct kthread_work *ws)struct sc16is7xx_port *s =dev_get_drvdata (one->port.dev);if (one->port.state) { -mutex_lock (&one->lock); -sc16is7xx_update_mlines (one); -mutex_unlock (&one->lock); + scoped_guard(mutex, &one->lock) +sc16is7xx_update_mlines (one);kthread_queue_delayed_work (&s->kworker, &one->ms_work,HZ ); }
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/3 serial: sc16is7xx: enable THRI before filling TX FIFO
In reply to Sasha LevinFrom: Luca Fresi <[email protected]>
[ Upstream commit 246ac114f485c2affb454240f3ea4fabfce22456 ]
sc16is7xx_handle_tx() currently requests the THRI enable only after it has filled the TX FIFO. The request is asynchronous because the IER update is performed later by reg_work.
The SC16IS7xx generates a THRI interrupt when the TX FIFO crosses its trigger level. If the FIFO drains past that level before reg_work enables THRI, the chip does not generate a new interrupt. Characters remain queued indefinitely even though the hardware FIFO is empty.
This was observed on an SC16IS752 while both UART channels were active. During the stall the software TX buffer remained non-empty while TXLVL reported 64 bytes free, LSR reported THR and transmitter empty, IER had THRI enabled, and IIR reported no interrupt pending.
Enable THRI synchronously before filling the FIFO so the threshold crossing cannot be missed.
--- drivers/tty/serial/sc16is7xx.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/tty/serial/sc16is7xx.c +3 -0
@@ -859,6 +859,9 @@ static void sc16is7xx_tx_proc(struct kthread_work *ws)msleep (port->rs485.delay_rts_before_send);guard (mutex)(&one->lock); +sc16is7xx_port_update (port,SC16IS7XX_IER_REG , +SC16IS7XX_IER_THRI_BIT , +SC16IS7XX_IER_THRI_BIT );sc16is7xx_handle_tx (port); }
Signature · 1 line
2.53.0