Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

serial: Z85C30: avoid a hang at console switch-over

Changes to the generic console support code that happened a while ago
introduced a scenario where the initial console is used in parallel with
the final console during a brief period when switching between the two is
in progress. During that time a message about the switch-over is printed.

With some combinations of chips, firmware and drivers, such as the Zilog
Z85C30 SCC used with the DECstation, a hang may happen because the
firmware used for the initial console may not expect the state of the chip
after it has been initialised by the driver. This is not a bug in the
firmware, as some registers it would have to examine are write-only.

This is a workaround for the Z85C30 which reuses the power-management
callback to keep the transmitter of the line associated with the console
enabled. It reflects the consensus reached in a discussion a while ago.

Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org>
Cc: Jiri Slaby <jirislaby@gmail.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Maciej W. Rozycki and committed by
Linus Torvalds
37713591 b76c5a07

+19 -2
+19 -2
drivers/serial/zs.c
··· 787 787 zport->regs[1] &= ~RxINT_MASK; 788 788 zport->regs[1] |= RxINT_ALL | TxINT_ENAB | EXT_INT_ENAB; 789 789 zport->regs[3] |= RxENABLE; 790 - zport->regs[5] |= TxENAB; 791 790 zport->regs[15] |= BRKIE; 792 791 write_zsreg(zport, R1, zport->regs[1]); 793 792 write_zsreg(zport, R3, zport->regs[3]); ··· 813 814 814 815 spin_lock_irqsave(&scc->zlock, flags); 815 816 816 - zport->regs[5] &= ~TxENAB; 817 817 zport->regs[3] &= ~RxENABLE; 818 818 write_zsreg(zport, R5, zport->regs[5]); 819 819 write_zsreg(zport, R3, zport->regs[3]); ··· 957 959 spin_unlock_irqrestore(&scc->zlock, flags); 958 960 } 959 961 962 + /* 963 + * Hack alert! 964 + * Required solely so that the initial PROM-based console 965 + * works undisturbed in parallel with this one. 966 + */ 967 + static void zs_pm(struct uart_port *uport, unsigned int state, 968 + unsigned int oldstate) 969 + { 970 + struct zs_port *zport = to_zport(uport); 971 + 972 + if (state < 3) 973 + zport->regs[5] |= TxENAB; 974 + else 975 + zport->regs[5] &= ~TxENAB; 976 + write_zsreg(zport, R5, zport->regs[5]); 977 + } 978 + 960 979 961 980 static const char *zs_type(struct uart_port *uport) 962 981 { ··· 1056 1041 .startup = zs_startup, 1057 1042 .shutdown = zs_shutdown, 1058 1043 .set_termios = zs_set_termios, 1044 + .pm = zs_pm, 1059 1045 .type = zs_type, 1060 1046 .release_port = zs_release_port, 1061 1047 .request_port = zs_request_port, ··· 1206 1190 return ret; 1207 1191 1208 1192 zs_reset(zport); 1193 + zs_pm(uport, 0, -1); 1209 1194 1210 1195 if (options) 1211 1196 uart_parse_options(options, &baud, &parity, &bits, &flow);