From: Maciej W. Rozycki Date: Wed, 6 May 2026 22:42:43 +0000 (+0100) Subject: serial: zs: Switch to using channel reset X-Git-Tag: v7.1-rc6~10^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8572955630f30948837088aa98bcbe0532d1ceac;p=thirdparty%2Flinux.git serial: zs: Switch to using channel reset Switch the driver to using the channel reset rather than hardware reset, simplifying handling by removing an interference between channels that causes the other channel to become uninitialised afterwards. There is little difference between the two kinds of reset in terms of register settings that result, and we initialise the whole register set right away anyway. However this prevents a hang from happening should the console output handler in the firmware try to access the other port whose transmitter has been disabled and line parameters messed up. For example this will happen if the keyboard port (port A) is chosen for the system console, unusually but not insanely for a headless system, as the port is wired to a standard DA-15 connector and an adapter can be easily made. Or with the next change in place this would happen for the regular console port (port B), since the keyboard port (port A) will be initialised first. Just remove the unnecessary complication then, a channel reset is good enough. We still need the initialisation marker, now per channel rather than per SCC, as for the console port zs_reset() will be called twice: once early on via zs_serial_console_init() for the console setup only, and then again via zs_config_port() as the port is associated with a TTY device. Fixes: 8b4a40809e53 ("zs: move to the serial subsystem") Signed-off-by: Maciej W. Rozycki Cc: stable@vger.kernel.org # v2.6.23+ Link: https://patch.msgid.link/alpine.DEB.2.21.2605062323430.46195@angie.orcam.me.uk Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c index bb10cd8aa7dcf..71cab10a33c37 100644 --- a/drivers/tty/serial/zs.c +++ b/drivers/tty/serial/zs.c @@ -832,21 +832,22 @@ static void zs_shutdown(struct uart_port *uport) static void zs_reset(struct zs_port *zport) { + struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A]; struct zs_scc *scc = zport->scc; int irq; unsigned long flags; spin_lock_irqsave(&scc->zlock, flags); irq = !irqs_disabled_flags(flags); - if (!scc->initialised) { + if (!zport->initialised) { /* Reset the pointer first, just in case... */ read_zsreg(zport, R0); /* And let the current transmission finish. */ zs_line_drain(zport, irq); - write_zsreg(zport, R9, FHWRES); + write_zsreg(zport, R9, zport == zport_a ? CHRA : CHRB); udelay(10); write_zsreg(zport, R9, 0); - scc->initialised = 1; + zport->initialised = 1; } load_zsregs(zport, zport->regs, irq); spin_unlock_irqrestore(&scc->zlock, flags); diff --git a/drivers/tty/serial/zs.h b/drivers/tty/serial/zs.h index 26ef8eafa1c12..8e51f847bc03f 100644 --- a/drivers/tty/serial/zs.h +++ b/drivers/tty/serial/zs.h @@ -22,6 +22,7 @@ struct zs_port { struct zs_scc *scc; /* Containing SCC. */ struct uart_port port; /* Underlying UART. */ + int initialised; /* For the console port. */ int clk_mode; /* May be 1, 16, 32, or 64. */ @@ -41,7 +42,6 @@ struct zs_scc { struct zs_port zport[2]; spinlock_t zlock; atomic_t irq_guard; - int initialised; }; #endif /* __KERNEL__ */