]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
serial: zs: Switch to using channel reset
authorMaciej W. Rozycki <macro@orcam.me.uk>
Wed, 6 May 2026 22:42:43 +0000 (23:42 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 22 May 2026 09:52:34 +0000 (11:52 +0200)
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 <macro@orcam.me.uk>
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 <gregkh@linuxfoundation.org>
drivers/tty/serial/zs.c
drivers/tty/serial/zs.h

index bb10cd8aa7dcf5e3dfa584ff379d63b771f46404..71cab10a33c3785c65b2eb39498786e77e114a78 100644 (file)
@@ -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);
index 26ef8eafa1c1204ca2b891701aabf2b3dedd28a8..8e51f847bc03f90b9b8ed76d0b7a8a5b8ac12790 100644 (file)
@@ -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__ */