|
|
@@ -0,0 +1,77 @@
|
|
|
+From patchwork Fri Jul 13 11:32:42 2018
|
|
|
+Content-Type: text/plain; charset="utf-8"
|
|
|
+MIME-Version: 1.0
|
|
|
+Content-Transfer-Encoding: 7bit
|
|
|
+Subject: serial8250 on tegra hsuart: recover from spurious interrupts due to
|
|
|
+ tegra2 silicon bug
|
|
|
+X-Patchwork-Submitter: "David R. Piegdon" <[email protected]>
|
|
|
+X-Patchwork-Id: 943440
|
|
|
+Message-Id: <[email protected]>
|
|
|
+To: [email protected]
|
|
|
+Date: Fri, 13 Jul 2018 11:32:42 +0000
|
|
|
+From: "David R. Piegdon" <[email protected]>
|
|
|
+List-Id: <linux-tegra.vger.kernel.org>
|
|
|
+
|
|
|
+Hi,
|
|
|
+a while back I sent a few mails regarding spurious interrupts in the
|
|
|
+UARTA (hsuart) block of the Tegra2 SoC, when using the 8250 driver for
|
|
|
+it instead of the hsuart driver. After going down a pretty deep
|
|
|
+debugging/testing hole, I think I found a patch that fixes the issue. So
|
|
|
+far testing in a reboot-cycle suggests that the error frequency dropped
|
|
|
+from >3% of all reboots to at least <0.05% of all reboots. Tests
|
|
|
+continue to run over the weekend.
|
|
|
+
|
|
|
+The patch below already is a second iteration; the first did not reset
|
|
|
+the MCR or contain the lines below '// clear interrupts'. This resulted
|
|
|
+in no more spurious interrupts, but in a few % of spurious interrupts
|
|
|
+that were recovered the UART block did not receive any characters any
|
|
|
+more. So further resetting was required to fully reacquire operational
|
|
|
+state of the UART block.
|
|
|
+
|
|
|
+I'd love any comments/suggestions on this!
|
|
|
+
|
|
|
+Cheers,
|
|
|
+
|
|
|
+David
|
|
|
+
|
|
|
+--- a/drivers/tty/serial/8250/8250_core.c
|
|
|
++++ b/drivers/tty/serial/8250/8250_core.c
|
|
|
+@@ -134,6 +134,38 @@ static irqreturn_t serial8250_interrupt(
|
|
|
+
|
|
|
+ if (l == i->head && pass_counter++ > PASS_LIMIT)
|
|
|
+ break;
|
|
|
++
|
|
|
++#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
|
|
++ if (!handled && (port->type == PORT_TEGRA)) {
|
|
|
++ /*
|
|
|
++ * Fix Tegra 2 CPU silicon bug where sometimes
|
|
|
++ * "TX holding register empty" interrupts result in a
|
|
|
++ * bad (metastable?) state in Tegras HSUART IP core.
|
|
|
++ * Only way to recover seems to be to reset all
|
|
|
++ * interrupts as well as the TX queue and the MCR.
|
|
|
++ * But we don't want to loose any outgoing characters,
|
|
|
++ * so only do it if the RX and TX queues are empty.
|
|
|
++ */
|
|
|
++ unsigned char lsr = port->serial_in(port, UART_LSR);
|
|
|
++ const unsigned char fifo_empty_mask =
|
|
|
++ (UART_LSR_TEMT | UART_LSR_THRE);
|
|
|
++ if (((lsr & (UART_LSR_DR | fifo_empty_mask)) ==
|
|
|
++ fifo_empty_mask)) {
|
|
|
++ port->serial_out(port, UART_IER, 0);
|
|
|
++ port->serial_out(port, UART_MCR, 0);
|
|
|
++ serial8250_clear_and_reinit_fifos(up);
|
|
|
++ port->serial_out(port, UART_MCR, up->mcr);
|
|
|
++ port->serial_out(port, UART_IER, up->ier);
|
|
|
++ // clear interrupts
|
|
|
++ serial_port_in(port, UART_LSR);
|
|
|
++ serial_port_in(port, UART_RX);
|
|
|
++ serial_port_in(port, UART_IIR);
|
|
|
++ serial_port_in(port, UART_MSR);
|
|
|
++ up->lsr_saved_flags = 0;
|
|
|
++ up->msr_saved_flags = 0;
|
|
|
++ }
|
|
|
++ }
|
|
|
++#endif
|
|
|
+ } while (l != end);
|
|
|
+
|
|
|
+ spin_unlock(&i->lock);
|