]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
serial: dz: Fix bootconsole handover lockup
authorMaciej W. Rozycki <macro@orcam.me.uk>
Wed, 6 May 2026 22:42:35 +0000 (23:42 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 22 May 2026 09:52:34 +0000 (11:52 +0200)
Calling dz_reset() in the course of setting up the serial device causes
line parameters to be reset and the transmitter disabled.  We've been
lucky in that no message is usually produced to the kernel log between
this call and the later call to uart_set_options() in the course of
console setup done by dz_serial_console_init(), or the system would hang
as the console output handler in the firmware tried to access a port the
transmitter of which has been disabled and line parameters messed up.

This will change with the next change to the driver, so fix dz_reset()
such that line parameters are set for 9600n8 console operation as with
the system firmware and the transmitter re-enabled after reset.  This
also means dz_pm() serves no purpose anymore, so drop it.

Fixes: e6ee512f5a77 ("dz.c: Resource management")
Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Cc: stable@vger.kernel.org # v2.6.25+
Link: https://patch.msgid.link/alpine.DEB.2.21.2605062302010.46195@angie.orcam.me.uk
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/dz.c

index d14a40e8cc0ad03051fc865aa6114ee6c51d77a6..03f4fc9248b8155cb2959d21838c597b5ce96abb 100644 (file)
@@ -571,6 +571,18 @@ static void dz_reset(struct dz_port *dport)
        while (dz_in(dport, DZ_CSR) & DZ_CLR);
        iob();
 
+       /*
+        * Set parameters across all lines such as not to interfere
+        * with the initial PROM-based console.  Otherwise any output
+        * produced before the console handover would cause the system
+        * firmware to produce rubbish.
+        */
+       for (int line = 0; line < DZ_NB_PORT; line++)
+               dz_out(dport, DZ_LPR, DZ_B9600 | DZ_CS8 | line);
+
+       /* Re-enable transmission for the initial PROM-based console.  */
+       dz_out(dport, DZ_TCR, tcr);
+
        /* Enable scanning.  */
        dz_out(dport, DZ_CSR, DZ_MSE);
 
@@ -654,26 +666,6 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
        uart_port_unlock_irqrestore(&dport->port, flags);
 }
 
-/*
- * Hack alert!
- * Required solely so that the initial PROM-based console
- * works undisturbed in parallel with this one.
- */
-static void dz_pm(struct uart_port *uport, unsigned int state,
-                 unsigned int oldstate)
-{
-       struct dz_port *dport = to_dport(uport);
-       unsigned long flags;
-
-       uart_port_lock_irqsave(&dport->port, &flags);
-       if (state < 3)
-               dz_start_tx(&dport->port);
-       else
-               dz_stop_tx(&dport->port);
-       uart_port_unlock_irqrestore(&dport->port, flags);
-}
-
-
 static const char *dz_type(struct uart_port *uport)
 {
        return "DZ";
@@ -769,7 +761,6 @@ static const struct uart_ops dz_ops = {
        .startup        = dz_startup,
        .shutdown       = dz_shutdown,
        .set_termios    = dz_set_termios,
-       .pm             = dz_pm,
        .type           = dz_type,
        .release_port   = dz_release_port,
        .request_port   = dz_request_port,
@@ -894,10 +885,7 @@ static int __init dz_console_setup(struct console *co, char *options)
        if (ret)
                return ret;
 
-       spin_lock_init(&dport->port.lock);      /* For dz_pm().  */
-
        dz_reset(dport);
-       dz_pm(uport, 0, -1);
 
        if (options)
                uart_parse_options(options, &baud, &parity, &bits, &flow);