bcm27xx: 6.1: add kernel patches
[openwrt/openwrt.git] / target / linux / bcm27xx / patches-6.1 / 950-0698-serial-8250-Add-NOMSI-bug-for-bcm2835aux.patch
1 From 501e87c5f421654e1bb6fd4a25de46420549cae8 Mon Sep 17 00:00:00 2001
2 From: Phil Elwell <phil@raspberrypi.com>
3 Date: Mon, 24 Apr 2023 11:48:31 +0100
4 Subject: [PATCH] serial: 8250: Add NOMSI bug for bcm2835aux
5
6 The BCM2835 mini-UART has no modem status interrupt, causing all
7 transmission to stop, never to use, if a speed change ever happens
8 while the CTS signal is high.
9
10 Add a simple polling mechanism in order to allow recovery in that
11 situation.
12
13 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
14 ---
15 drivers/tty/serial/8250/8250.h | 1 +
16 drivers/tty/serial/8250/8250_bcm2835aux.c | 1 +
17 drivers/tty/serial/8250/8250_core.c | 15 +++++++++++++++
18 drivers/tty/serial/8250/8250_port.c | 9 +++++++++
19 4 files changed, 26 insertions(+)
20
21 --- a/drivers/tty/serial/8250/8250.h
22 +++ b/drivers/tty/serial/8250/8250.h
23 @@ -93,6 +93,7 @@ struct serial8250_config {
24 #define UART_BUG_THRE BIT(3) /* UART has buggy THRE reassertion */
25 #define UART_BUG_PARITY BIT(4) /* UART mishandles parity if FIFO enabled */
26 #define UART_BUG_TXRACE BIT(5) /* UART Tx fails to set remote DR */
27 +#define UART_BUG_NOMSI BIT(6) /* UART has no modem status interrupt */
28
29
30 #ifdef CONFIG_SERIAL_8250_SHARE_IRQ
31 --- a/drivers/tty/serial/8250/8250_bcm2835aux.c
32 +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c
33 @@ -109,6 +109,7 @@ static int bcm2835aux_serial_probe(struc
34 UPF_SKIP_TEST | UPF_IOREMAP;
35 up.port.rs485_config = serial8250_em485_config;
36 up.port.rs485_supported = serial8250_em485_supported;
37 + up.bugs |= UART_BUG_NOMSI;
38 up.rs485_start_tx = bcm2835aux_rs485_start_tx;
39 up.rs485_stop_tx = bcm2835aux_rs485_stop_tx;
40
41 --- a/drivers/tty/serial/8250/8250_core.c
42 +++ b/drivers/tty/serial/8250/8250_core.c
43 @@ -252,6 +252,18 @@ static void serial8250_timeout(struct ti
44 mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port));
45 }
46
47 +static void serial8250_cts_poll_timeout(struct timer_list *t)
48 +{
49 + struct uart_8250_port *up = from_timer(up, t, timer);
50 + unsigned long flags;
51 +
52 + spin_lock_irqsave(&up->port.lock, flags);
53 + serial8250_modem_status(up);
54 + spin_unlock_irqrestore(&up->port.lock, flags);
55 + if (up->port.hw_stopped)
56 + mod_timer(&up->timer, jiffies + 1);
57 +}
58 +
59 static void serial8250_backup_timeout(struct timer_list *t)
60 {
61 struct uart_8250_port *up = from_timer(up, t, timer);
62 @@ -314,6 +326,9 @@ static void univ8250_setup_timer(struct
63 uart_poll_timeout(port) + HZ / 5);
64 }
65
66 + if (up->bugs & UART_BUG_NOMSI)
67 + up->timer.function = serial8250_cts_poll_timeout;
68 +
69 /*
70 * If the "interrupt" for this port doesn't correspond with any
71 * hardware interrupt, we use a timer-based system. The original
72 --- a/drivers/tty/serial/8250/8250_port.c
73 +++ b/drivers/tty/serial/8250/8250_port.c
74 @@ -1559,6 +1559,9 @@ static void serial8250_stop_tx(struct ua
75 serial_icr_write(up, UART_ACR, up->acr);
76 }
77 serial8250_rpm_put(up);
78 +
79 + if (port->hw_stopped && (up->bugs & UART_BUG_NOMSI))
80 + mod_timer(&up->timer, jiffies + 1);
81 }
82
83 static inline void __start_tx(struct uart_port *port)
84 @@ -1669,6 +1672,9 @@ static void serial8250_start_tx(struct u
85 struct uart_8250_port *up = up_to_u8250p(port);
86 struct uart_8250_em485 *em485 = up->em485;
87
88 + if (up->bugs & UART_BUG_NOMSI)
89 + del_timer(&up->timer);
90 +
91 if (!port->x_char && uart_circ_empty(&port->state->xmit))
92 return;
93
94 @@ -1889,6 +1895,9 @@ unsigned int serial8250_modem_status(str
95 uart_handle_cts_change(port, status & UART_MSR_CTS);
96
97 wake_up_interruptible(&port->state->port.delta_msr_wait);
98 + } else if (up->bugs & UART_BUG_NOMSI && port->hw_stopped &&
99 + status & UART_MSR_CTS) {
100 + uart_handle_cts_change(port, status & UART_MSR_CTS);
101 }
102
103 return status;