diff mbox series

serial: 8250: Move alpha-specific quirk out of the core

Message ID af967f273724aff4cff3c49470110a48f790794e.1639676574.git.lukas@wunner.de
State New
Headers show
Series serial: 8250: Move alpha-specific quirk out of the core | expand

Commit Message

Lukas Wunner Dec. 16, 2021, 5:52 p.m. UTC
struct uart_8250_port contains mcr_mask and mcr_force members whose
sole purpose is to work around an alpha-specific quirk.  This code
doesn't belong in the core where it is executed by everyone else,
so move it to a proper ->set_mctrl callback which is used on alpha only.

The alpha-specific quirk was introduced in January 1995:
https://git.kernel.org/pub/scm/linux/kernel/git/history/history.git/diff/drivers/char/serial.c?h=1.1.83

The members in struct uart_8250_port were added in 2002:
https://git.kernel.org/history/history/c/4524aad27854

The quirk applies to non-PCI alphas and arch/alpha/Kconfig specifies
"select FORCE_PCI if !ALPHA_JENSEN".  So apparently the only affected
machine is the EISA-based Jensen that Linus was working on back then:
https://lore.kernel.org/all/CAHk-=wj1JWZ3sCrGz16nxEj7=0O+srMg6Ah3iPTDXSPKEws_SA@mail.gmail.com/

Up until now the quirk is not applied unless CONFIG_PCI is disabled.
If users forget to do that, the serial ports aren't usable on Jensen
and the machine may not boot in the first place.  Avoid by confining
the quirk to CONFIG_ALPHA_JENSEN instead.

Signed-off-by: Lukas Wunner <lukas@wunner.de>
Cc: Russell King <rmk+kernel@armlinux.org.uk>
Cc: Ulrich Teichert <krypton@ulrich-teichert.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
Compile-tested only.

 drivers/tty/serial/8250/8250.h       | 11 +----------
 drivers/tty/serial/8250/8250_alpha.c | 15 +++++++++++++++
 drivers/tty/serial/8250/8250_core.c  |  8 +++-----
 drivers/tty/serial/8250/8250_port.c  |  2 +-
 drivers/tty/serial/8250/Makefile     |  1 +
 include/linux/serial_8250.h          |  2 --
 6 files changed, 21 insertions(+), 18 deletions(-)
 create mode 100644 drivers/tty/serial/8250/8250_alpha.c

Comments

Lukas Wunner Dec. 18, 2021, 9:06 a.m. UTC | #1
On Thu, Dec 16, 2021 at 09:36:20PM +0100, Ulrich Teichert wrote:
> > struct uart_8250_port contains mcr_mask and mcr_force members whose
> > sole purpose is to work around an alpha-specific quirk.  This code
> > doesn't belong in the core where it is executed by everyone else,
> > so move it to a proper ->set_mctrl callback which is used on alpha only.
[...]
> > The quirk applies to non-PCI alphas and arch/alpha/Kconfig specifies
> > "select FORCE_PCI if !ALPHA_JENSEN".  So apparently the only affected
> > machine is the EISA-based Jensen that Linus was working on back then:
[...]
> > Up until now the quirk is not applied unless CONFIG_PCI is disabled.
> > If users forget to do that, the serial ports aren't usable on Jensen
> > and the machine may not boot in the first place.  Avoid by confining
> > the quirk to CONFIG_ALPHA_JENSEN instead.
> 
> Wouldn't that mean that you can't use a generic Alpha kernel on the Jensen
> anymore? CONFIG_ALPHA_JENSEN is only set if you specifically select the
> Jensen as target, not when you build a generic kernel. That would be a step
> back in my opinion, as the Debian generic kernel from debian-ports did
> as least boot up on real hardware and the serial console worked just fine

The generic Alpha kernel has CONFIG_PCI=y, so the quirk is not applied,
both with and without the present patch.

You should be able to trigger the lockup that the quirk seeks to avoid
by closing the tty of either of the serial ports.  E.g., if you're using
the serial console, "cat" something to the other serial port's tty.
That will clear TIOCM_OUT2 in serial8250_do_shutdown() and should thus
provoke the lockup.  Alternatively, compile and run the little program
below on the Jensen.  (Pass a serial port tty as argument.)

Should you not be able to reproduce the lockup, then the quirk wouldn't
be necessary anymore and could be removed.

Thanks!

Lukas

-- >8 --

#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#define TIOCM_OUT1	0x2000
#define TIOCM_OUT2	0x4000

int main(int argc, char* argv[]) {
	int fd, ret, flags;

	if (argc < 2)
		return 1;

	fd = open(argv[1], O_RDWR);
	if (fd < 0)
		return 2;

	ret = ioctl(fd, TIOCMGET, &flags);
	if (ret < 0)
		goto close;

	flags &= ~(TIOCM_OUT1 | TIOCM_OUT2);
	ret = ioctl(fd, TIOCMSET, &flags);

close:
	close(fd);

	return ret;
}
Lukas Wunner Dec. 28, 2021, 5:33 p.m. UTC | #2
On Sun, Dec 19, 2021 at 06:37:56PM +0100, Ulrich Teichert wrote:
> Thanks for the explanation and the reproducer program. I tried yesterday
> to install a recent Linux-Alpha distribution on any of my Alphas to
> be able to build natively and check my self-build kernels before burning
> a CD-ROM, but I failed. Neither gentoo nor Debian nor T2 was installable on
> my Miatas (the Personal Workstations) or my Avanti (AlphaStation 400),
> either failing to boot or recognizing the disks or the CD-ROM, or switching
> to a framebuffer which did not work or just dying on the hardware detection.
> That was a bit frustrating, but I have to follow plan B now and do cross-builds
> from amd_x64 to Alpha - that's easy for the kernel (infact, that's what
> I've been doing from the start), but generating something bootable that
> way is a challenge and needs more time than I usually have during the week,
> but I will tackle it over my xmas vacation,

No worries, whenever you get to spend more time with the Jensen and come
across issues with the serial ports, we can look into it.

I've just sent out an updated version of the patch which also applies
the Jensen quirk if a generic kernel is used.  It auto-detects at
runtime whether the kernel is running on a Jensen.  If on the other hand
the kernel is compiled specifically for the Jensen, the quirk is applied
unconditionally.

I've also realized that a code comment in sunsu.c refers to the Alpha
quirk, so I'm updating it to point to the new location.  It looks like
a JavaStation thin client of the same era had a similar hardware erratum
as the Jensen.

Thanks,

Lukas
diff mbox series

Patch

diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 6473361525d1..ec5f9f4da6d3 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -241,16 +241,7 @@  static inline int serial8250_in_MCR(struct uart_8250_port *up)
 	return mctrl;
 }
 
-#if defined(__alpha__) && !defined(CONFIG_PCI)
-/*
- * Digital did something really horribly wrong with the OUT1 and OUT2
- * lines on at least some ALPHA's.  The failure mode is that if either
- * is cleared, the machine locks up with endless interrupts.
- */
-#define ALPHA_KLUDGE_MCR  (UART_MCR_OUT2 | UART_MCR_OUT1)
-#else
-#define ALPHA_KLUDGE_MCR 0
-#endif
+void alpha_8250_set_mctrl(struct uart_port *port, unsigned int mctrl);
 
 #ifdef CONFIG_SERIAL_8250_PNP
 int serial8250_pnp_init(void);
diff --git a/drivers/tty/serial/8250/8250_alpha.c b/drivers/tty/serial/8250/8250_alpha.c
new file mode 100644
index 000000000000..c87a5a6e0ee1
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_alpha.c
@@ -0,0 +1,15 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/serial_8250.h>
+
+void alpha_8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	/*
+	 * Digital did something really horribly wrong with the OUT1 and OUT2
+	 * lines on Alpha Jensen.  The failure mode is that if either is
+	 * cleared, the machine locks up with endless interrupts.
+	 */
+	mctrl |= TIOCM_OUT1 | TIOCM_OUT2;
+
+	serial8250_do_set_mctrl(port, mctrl);
+}
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 1ce193daea7f..92f92ac7c2be 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -509,11 +509,9 @@  static void __init serial8250_isa_init_ports(void)
 
 		up->ops = &univ8250_driver_ops;
 
-		/*
-		 * ALPHA_KLUDGE_MCR needs to be killed.
-		 */
-		up->mcr_mask = ~ALPHA_KLUDGE_MCR;
-		up->mcr_force = ALPHA_KLUDGE_MCR;
+		if (IS_ENABLED(CONFIG_ALPHA_JENSEN))
+			port->set_mctrl = alpha_8250_set_mctrl;
+
 		serial8250_set_defaults(up);
 	}
 
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 5d9a0e9f75d4..3b12bfc1ed67 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -2026,7 +2026,7 @@  void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
 
 	mcr = serial8250_TIOCM_to_MCR(mctrl);
 
-	mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
+	mcr |= up->mcr;
 
 	serial8250_out_MCR(up, mcr);
 }
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index b9bcd73c8997..043beae6f71b 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -5,6 +5,7 @@ 
 
 obj-$(CONFIG_SERIAL_8250)		+= 8250.o 8250_base.o
 8250-y					:= 8250_core.o
+8250-$(CONFIG_ALPHA_JENSEN)		+= 8250_alpha.o
 8250-$(CONFIG_SERIAL_8250_PNP)		+= 8250_pnp.o
 8250_base-y				:= 8250_port.o
 8250_base-$(CONFIG_SERIAL_8250_DMA)	+= 8250_dma.o
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index 5db211f43b29..ff84a3ed10ea 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -104,8 +104,6 @@  struct uart_8250_port {
 	unsigned char		ier;
 	unsigned char		lcr;
 	unsigned char		mcr;
-	unsigned char		mcr_mask;	/* mask of user bits */
-	unsigned char		mcr_force;	/* mask of forced bits */
 	unsigned char		cur_iotype;	/* Running I/O type */
 	unsigned int		rpm_tx_active;
 	unsigned char		canary;		/* non-zero during system sleep