From: Hugo Villeneuve hvilleneuve@dimonoff.com
[ Upstream commit 7d3b793faaab1305994ce568b59d61927235f57b ]
When enabling access to the special register set, Receiver time-out and RHR interrupts can happen. In this case, the IRQ handler will try to read from the FIFO thru the RHR register at address 0x00, but address 0x00 is mapped to DLL register, resulting in erroneous FIFO reading.
Call graph example: sc16is7xx_startup(): entry sc16is7xx_ms_proc(): entry sc16is7xx_set_termios(): entry sc16is7xx_set_baud(): DLH/DLL = $009C --> access special register set sc16is7xx_port_irq() entry --> IIR is 0x0C sc16is7xx_handle_rx() entry sc16is7xx_fifo_read(): --> unable to access FIFO (RHR) because it is mapped to DLL (LCR=LCR_CONF_MODE_A) sc16is7xx_set_baud(): exit --> Restore access to general register set
Fix the problem by claiming the efr_lock mutex when accessing the Special register set.
Fixes: dfeae619d781 ("serial: sc16is7xx") Cc: stable@vger.kernel.org Signed-off-by: Hugo Villeneuve hvilleneuve@dimonoff.com Link: https://lore.kernel.org/r/20240723125302.1305372-3-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org [ Resolve minor conflicts ] Signed-off-by: Bin Lan bin.lan.cn@windriver.com --- drivers/tty/serial/sc16is7xx.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index a723df9b37dd..c07baf5d5a9c 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -545,6 +545,9 @@ 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); + /* Open the LCR divisors for configuration */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_CONF_MODE_A); @@ -558,6 +561,8 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) /* Put LCR back to the normal mode */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
+ mutex_unlock(&one->efr_lock); + return DIV_ROUND_CLOSEST((clk / prescaler) / 16, div); }
[ Sasha's backport helper bot ]
Hi,
The upstream commit SHA1 provided is correct: 7d3b793faaab1305994ce568b59d61927235f57b
WARNING: Author mismatch between patch and upstream commit: Backport author: Bin Lan bin.lan.cn@windriver.com Commit author: Hugo Villeneuve hvilleneuve@dimonoff.com
Status in newer kernel trees: 6.12.y | Present (exact SHA1) 6.11.y | Present (exact SHA1) 6.6.y | Not found 6.1.y | Not found
Note: The patch differs from the upstream commit: --- --- - 2024-11-22 08:33:28.655200931 -0500 +++ /tmp/tmp.UrRvkZ4s0A 2024-11-22 08:33:28.646962417 -0500 @@ -1,3 +1,5 @@ +[ Upstream commit 7d3b793faaab1305994ce568b59d61927235f57b ] + When enabling access to the special register set, Receiver time-out and RHR interrupts can happen. In this case, the IRQ handler will try to read from the FIFO thru the RHR register at address 0x00, but address 0x00 is @@ -22,25 +24,28 @@ Signed-off-by: Hugo Villeneuve hvilleneuve@dimonoff.com Link: https://lore.kernel.org/r/20240723125302.1305372-3-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org +[ Resolve minor conflicts ] +Signed-off-by: Bin Lan bin.lan.cn@windriver.com --- - drivers/tty/serial/sc16is7xx.c | 4 ++++ - 1 file changed, 4 insertions(+) + drivers/tty/serial/sc16is7xx.c | 5 +++++ + 1 file changed, 5 insertions(+)
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c -index 58696e05492ca..b4c1798a1df2a 100644 +index a723df9b37dd..c07baf5d5a9c 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c -@@ -592,6 +592,8 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) +@@ -545,6 +545,9 @@ 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); + - /* Backup LCR and access special register set (DLL/DLH) */ - lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG); + /* Open the LCR divisors for configuration */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, -@@ -606,6 +608,8 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) - /* Restore LCR and access to general register set */ + SC16IS7XX_LCR_CONF_MODE_A); +@@ -558,6 +561,8 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) + /* Put LCR back to the normal mode */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
+ mutex_unlock(&one->efr_lock); @@ -48,3 +53,6 @@ return DIV_ROUND_CLOSEST((clk / prescaler) / 16, div); }
+-- +2.43.0 + ---
Results of testing on various branches:
| Branch | Patch Apply | Build Test | |---------------------------|-------------|------------| | stable/linux-6.1.y | Success | Success |
linux-stable-mirror@lists.linaro.org