Subject: no sysrq on Cell QS21/QS22 serial console
From: olh@suse.de
References: 422987 - LTC47675, 96313 - LTC16841
Patch-mainline: not yet


a POWER4 system in 'full-system-partition' mode has the console device
on ttyS0. But the user interface to the Linux system console may still
be on the hardware management console (HMC). If this is the case, there
is no way to send a break to trigger a sysrq.
Other setups do already use 'ctrl o' to trigger sysrq. This includes iSeries
virtual console on tty1 or hvc0, and pSeries LPAR console on hvc0 or hvsi0.

This affects also Cell Blades QS2x.

To limit the 'ctrl o' only to the affected systems, query the model property
in the device-tree. The patch makes the serial console not-eight-bit-clean.
Booting with 'console=ttyS0' will disable 'ctrl o', it is only enabled
with console autodetection.

'ctrl o' is currently mapped to 'flush output', see 'stty -a'

Signed-off-by: Olaf Hering <olh@suse.de>
---
 arch/powerpc/include/asm/serial.h   |    6 ++++
 arch/powerpc/kernel/legacy_serial.c |   52 ++++++++++++++++++++++++++++++++++++
 drivers/tty/serial/8250.c           |    6 ++++
 3 files changed, 64 insertions(+)

--- a/arch/powerpc/include/asm/serial.h
+++ b/arch/powerpc/include/asm/serial.h
@@ -15,6 +15,12 @@
 /* Default baud base if not found in device-tree */
 #define BASE_BAUD ( 1843200 / 16 )
 
+#if defined(SUPPORT_SYSRQ) && defined(CONFIG_PPC_PSERIES)
+#undef arch_8250_sysrq_via_ctrl_o
+extern int do_sysrq_via_ctrl_o;
+#define arch_8250_sysrq_via_ctrl_o(ch, port) ((ch) == '\x0f' && do_sysrq_via_ctrl_o && uart_handle_break((port)))
+#endif
+
 #ifdef CONFIG_PPC_UDBG_16550
 extern void find_legacy_serial_ports(void);
 #else
--- a/arch/powerpc/kernel/legacy_serial.c
+++ b/arch/powerpc/kernel/legacy_serial.c
@@ -495,6 +495,55 @@ device_initcall(serial_dev_init);
 
 
 #ifdef CONFIG_SERIAL_8250_CONSOLE
+#if defined(CONFIG_PPC_PSERIES) && defined(CONFIG_SERIAL_8250_CONSOLE)
+/*
+ * Handle the SysRq ^O Hack also via ttyS0 on POWER4 systems
+ * but only on the system console, see asm/serial.h
+ * If they run in FullSystemPartition mode, the firmware console comes in via ttyS0
+ * But BREAK does not work via the HMC, to trigger sysrq.
+ * The same is required for Cell blades
+ */
+int do_sysrq_via_ctrl_o;
+static const char __initdata *need_ctrl_o[] = {
+	"IBM,079", /* QS2x */
+	"IBM,0792-32G", /* QS21 */
+	"IBM,0793-2RZ", /* QS22 */
+	"IBM,7040-681",	/* p690 */
+	"IBM,7040-671", /* p670 */
+	"IBM,7039-651", /* p655 */
+	"IBM,7038-6M2", /* p650 */
+	"IBM,7028-6E4", /* p630 tower */
+	"IBM,7028-6C4", /* p630 rack */
+	"IBM,7029-6E3", /* p615 tower */
+	"IBM,7029-6C3", /* p615 rack */
+	NULL
+};
+static void __init detect_need_for_ctrl_o(void)
+{
+	struct device_node *root;
+	const char *model, *p;
+	int i;
+
+	root = of_find_node_by_path("/");
+	if (!root)
+		return;
+	model = of_get_property(root, "model", NULL);
+	if (model) {
+		i = 0;
+		while (need_ctrl_o[i]) {
+			p = need_ctrl_o[i];
+			if (strncmp(p, model, strlen(p)) == 0) {
+				do_sysrq_via_ctrl_o = 1;
+				DBG("Enable sysrq via CTRL o on model %s\n", model);
+				break;
+			}
+			i++;
+		}
+	}
+	of_node_put(root);
+}
+#endif
+
 /*
  * This is called very early, as part of console_init() (typically just after
  * time_init()). This function is respondible for trying to find a good
@@ -563,6 +612,9 @@ static int __init check_legacy_serial_co
 	if (i >= legacy_serial_count)
 		goto not_found;
 
+#if defined(CONFIG_PPC_PSERIES) && defined(CONFIG_SERIAL_8250_CONSOLE)
+	detect_need_for_ctrl_o();
+#endif
 	of_node_put(prom_stdout);
 
 	DBG("Found serial console at ttyS%d\n", offset);
--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -102,6 +102,8 @@ static unsigned int skip_txen_test; /* f
 #define CONFIG_SERIAL_MANY_PORTS 1
 #endif
 
+#define arch_8250_sysrq_via_ctrl_o(a,b) 0
+
 /*
  * HUB6 is always on.  This will be removed once the header
  * files have been cleaned.
@@ -1423,7 +1425,11 @@ receive_chars(struct uart_8250_port *up,
 
 	do {
 		if (likely(lsr & UART_LSR_DR))
+		{
 			ch = serial_inp(up, UART_RX);
+			if (arch_8250_sysrq_via_ctrl_o(ch, &up->port))
+				goto ignore_char;
+		}
 		else
 			/*
 			 * Intel 82571 has a Serial Over Lan device that will
