Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

serial: 8250: 8250_omap.c: Add support for handling UART error conditions

The DMA IRQ handler does not accounts for the overrun(OE) or any other
errors being reported by the IP before triggering a DMA transaction which
leads to the interrupts not being handled resulting into an IRQ storm.

The way to handle OE is to:
1. Reset the RX FIFO.
2. Read the UART_RESUME register, which clears the internal flag

Earlier, the driver issued DMA transations even in case of OE which shouldn't
be done according to the OE handling mechanism mentioned above, as we are
resetting the FIFO's, refer section: "12.1.6.4.8.1.3.6 Overrun During
Receive" [0].

[0] https://www.ti.com/lit/pdf/spruiu1

Signed-off-by: Moteen Shah <m-shah@ti.com>
Link: https://patch.msgid.link/20260112081829.63049-2-m-shah@ti.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Moteen Shah and committed by
Greg Kroah-Hartman
623b07b3 93bb95a1

+21 -2
+21 -2
drivers/tty/serial/8250/8250_omap.c
··· 100 100 #define OMAP_UART_REV_52 0x0502 101 101 #define OMAP_UART_REV_63 0x0603 102 102 103 + /* Resume register */ 104 + #define UART_OMAP_RESUME 0x0B 105 + 103 106 /* Interrupt Enable Register 2 */ 104 107 #define UART_OMAP_IER2 0x1B 105 108 #define UART_OMAP_IER2_RHR_IT_DIS BIT(2) ··· 122 119 /* Timeout low and High */ 123 120 #define UART_OMAP_TO_L 0x26 124 121 #define UART_OMAP_TO_H 0x27 125 - 126 122 struct omap8250_priv { 127 123 void __iomem *membase; 128 124 int line; ··· 1258 1256 return status; 1259 1257 } 1260 1258 1259 + static void am654_8250_handle_uart_errors(struct uart_8250_port *up, u8 iir, u16 status) 1260 + { 1261 + if (status & UART_LSR_OE) { 1262 + serial8250_clear_and_reinit_fifos(up); 1263 + serial_in(up, UART_LSR); 1264 + serial_in(up, UART_OMAP_RESUME); 1265 + } else { 1266 + if (status & (UART_LSR_FE | UART_LSR_PE | UART_LSR_BI)) 1267 + serial_in(up, UART_RX); 1268 + if (iir & UART_IIR_XOFF) 1269 + serial_in(up, UART_IIR); 1270 + } 1271 + } 1272 + 1261 1273 static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir, 1262 1274 u16 status) 1263 1275 { ··· 1282 1266 * Queue a new transfer if FIFO has data. 1283 1267 */ 1284 1268 if ((status & (UART_LSR_DR | UART_LSR_BI)) && 1285 - (up->ier & UART_IER_RDI)) { 1269 + (up->ier & UART_IER_RDI) && !(status & UART_LSR_OE)) { 1270 + am654_8250_handle_uart_errors(up, iir, status); 1286 1271 omap_8250_rx_dma(up); 1287 1272 serial_out(up, UART_OMAP_EFR2, UART_OMAP_EFR2_TIMEOUT_BEHAVE); 1288 1273 } else if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) { ··· 1299 1282 serial_out(up, UART_OMAP_EFR2, 0x0); 1300 1283 up->ier |= UART_IER_RLSI | UART_IER_RDI; 1301 1284 serial_out(up, UART_IER, up->ier); 1285 + } else { 1286 + am654_8250_handle_uart_errors(up, iir, status); 1302 1287 } 1303 1288 } 1304 1289