Skip to content

Commit

Permalink
serial: 8250: 8250_omap: Fix possible interrupt storm on K3 SoCs
Browse files Browse the repository at this point in the history
On K3 family of SoCs (which includes AM654 SoC), it is observed that RX
TIMEOUT is signalled after RX FIFO has been drained, in which case a
dummy read of RX FIFO is required to clear RX TIMEOUT condition.
Otherwise, this would lead to an interrupt storm.

Fix this by introducing UART_RX_TIMEOUT_QUIRK flag and doing a dummy
read in IRQ handler when RX TIMEOUT is reported with no data in RX FIFO.

Fixes: be70874 ("serial: 8250_omap: Add support for AM654 UART controller")
Reported-by: Jan Kiszka <jan.kiszka@siemens.com>
Tested-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
Link: https://lore.kernel.org/r/20210622145704.11168-1-vigneshr@ti.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
r-vignesh authored and gregkh committed Jun 24, 2021
1 parent 08b0adb commit b67e830
Showing 1 changed file with 19 additions and 1 deletion.
20 changes: 19 additions & 1 deletion drivers/tty/serial/8250/8250_omap.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#define UART_ERRATA_CLOCK_DISABLE (1 << 3)
#define UART_HAS_EFR2 BIT(4)
#define UART_HAS_RHR_IT_DIS BIT(5)
#define UART_RX_TIMEOUT_QUIRK BIT(6)

#define OMAP_UART_FCR_RX_TRIG 6
#define OMAP_UART_FCR_TX_TRIG 4
Expand Down Expand Up @@ -104,6 +105,9 @@
#define UART_OMAP_EFR2 0x23
#define UART_OMAP_EFR2_TIMEOUT_BEHAVE BIT(6)

/* RX FIFO occupancy indicator */
#define UART_OMAP_RX_LVL 0x64

struct omap8250_priv {
int line;
u8 habit;
Expand Down Expand Up @@ -611,6 +615,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port);
static irqreturn_t omap8250_irq(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
struct omap8250_priv *priv = port->private_data;
struct uart_8250_port *up = up_to_u8250p(port);
unsigned int iir;
int ret;
Expand All @@ -625,6 +630,18 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
serial8250_rpm_get(up);
iir = serial_port_in(port, UART_IIR);
ret = serial8250_handle_irq(port, iir);

/*
* On K3 SoCs, it is observed that RX TIMEOUT is signalled after
* FIFO has been drained, in which case a dummy read of RX FIFO
* is required to clear RX TIMEOUT condition.
*/
if (priv->habit & UART_RX_TIMEOUT_QUIRK &&
(iir & UART_IIR_RX_TIMEOUT) == UART_IIR_RX_TIMEOUT &&
serial_port_in(port, UART_OMAP_RX_LVL) == 0) {
serial_port_in(port, UART_RX);
}

serial8250_rpm_put(up);

return IRQ_RETVAL(ret);
Expand Down Expand Up @@ -1218,7 +1235,8 @@ static struct omap8250_dma_params am33xx_dma = {

static struct omap8250_platdata am654_platdata = {
.dma_params = &am654_dma,
.habit = UART_HAS_EFR2 | UART_HAS_RHR_IT_DIS,
.habit = UART_HAS_EFR2 | UART_HAS_RHR_IT_DIS |
UART_RX_TIMEOUT_QUIRK,
};

static struct omap8250_platdata am33xx_platdata = {
Expand Down

0 comments on commit b67e830

Please sign in to comment.