Commit 0475afdd authored by Udit Kumar's avatar Udit Kumar Committed by felix
Browse files

serial: 8250_omap: Implementation of Errata i2310

stable inclusion
from stable-v5.10.221
commit cb879300669881970eabebe64bd509dbbe42b9de
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IAGEP6
CVE: CVE-2024-42095

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=cb879300669881970eabebe64bd509dbbe42b9de

--------------------------------

commit 9d141c1e615795eeb93cd35501ad144ee997a826 upstream.

As per Errata i2310[0], Erroneous timeout can be triggered,
if this Erroneous interrupt is not cleared then it may leads
to storm of interrupts, therefore apply Errata i2310 solution.

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

 page 23

Fixes: b67e830d ("serial: 8250: 8250_omap: Fix possible interrupt storm on K3 SoCs")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarUdit Kumar <u-kumar1@ti.com>
Link: https://lore.kernel.org/r/20240619105903.165434-1-u-kumar1@ti.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarFelix Fu <fuzhen5@huawei.com>
parent ba646506
Loading
Loading
Loading
Loading
+20 −5
Original line number Diff line number Diff line
@@ -164,6 +164,10 @@ static void uart_write(struct omap8250_priv *priv, u32 reg, u32 val)
	writel(val, priv->membase + (reg << OMAP_UART_REGSHIFT));
}

/* Timeout low and High */
#define UART_OMAP_TO_L                 0x26
#define UART_OMAP_TO_H                 0x27

/*
 * Called on runtime PM resume path from omap8250_restore_regs(), and
 * omap8250_set_mctrl().
@@ -647,13 +651,24 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)

	/*
	 * 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.
	 * FIFO has been drained or erroneously.
	 * So apply solution of Errata i2310 as mentioned in
	 * https://www.ti.com/lit/pdf/sprz536
	 */
	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);
		(iir & UART_IIR_RX_TIMEOUT) == UART_IIR_RX_TIMEOUT) {
		unsigned char efr2, timeout_h, timeout_l;

		efr2 = serial_in(up, UART_OMAP_EFR2);
		timeout_h = serial_in(up, UART_OMAP_TO_H);
		timeout_l = serial_in(up, UART_OMAP_TO_L);
		serial_out(up, UART_OMAP_TO_H, 0xFF);
		serial_out(up, UART_OMAP_TO_L, 0xFF);
		serial_out(up, UART_OMAP_EFR2, UART_OMAP_EFR2_TIMEOUT_BEHAVE);
		serial_in(up, UART_IIR);
		serial_out(up, UART_OMAP_EFR2, efr2);
		serial_out(up, UART_OMAP_TO_H, timeout_h);
		serial_out(up, UART_OMAP_TO_L, timeout_l);
	}

	/* Stop processing interrupts on input overrun */