powerpc/powernv: Add a kmsg_dumper that flushes console output on panic
authorRussell Currey <ruscur@russell.cc>
Fri, 27 Nov 2015 06:23:07 +0000 (17:23 +1100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 16 Mar 2016 15:43:01 +0000 (08:43 -0700)
commit affddff69c55eb68969448f35f59054a370bc7c1 upstream.

On BMC machines, console output is controlled by the OPAL firmware and is
only flushed when its pollers are called.  When the kernel is in a panic
state, it no longer calls these pollers and thus console output does not
completely flush, causing some output from the panic to be lost.

Output is only actually lost when the kernel is configured to not power off
or reboot after panic (i.e. CONFIG_PANIC_TIMEOUT is set to 0) since OPAL
flushes the console buffer as part of its power down routines.  Before this
patch, however, only partial output would be printed during the timeout wait.

This patch adds a new kmsg_dumper which gets called at panic time to ensure
panic output is not lost.  It accomplishes this by calling OPAL_CONSOLE_FLUSH
in the OPAL API, and if that is not available, the pollers are called enough
times to (hopefully) completely flush the buffer.

The flushing mechanism will only affect output printed at and before the
kmsg_dump call in kernel/panic.c:panic().  As such, the "end Kernel panic"
message may still be truncated as follows:

>Call Trace:
>[c000000f1f603b00] [c0000000008e9458] dump_stack+0x90/0xbc (unreliable)
>[c000000f1f603b30] [c0000000008e7e78] panic+0xf8/0x2c4
>[c000000f1f603bc0] [c000000000be4860] mount_block_root+0x288/0x33c
>[c000000f1f603c80] [c000000000be4d14] prepare_namespace+0x1f4/0x254
>[c000000f1f603d00] [c000000000be43e8] kernel_init_freeable+0x318/0x350
>[c000000f1f603dc0] [c00000000000bd74] kernel_init+0x24/0x130
>[c000000f1f603e30] [c0000000000095b0] ret_from_kernel_thread+0x5c/0xac
>---[ end Kernel panic - not

This functionality is implemented as a kmsg_dumper as it seems to be the
most sensible way to introduce platform-specific functionality to the
panic function.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Reviewed-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/powerpc/include/asm/opal-api.h
arch/powerpc/include/asm/opal.h
arch/powerpc/platforms/powernv/Makefile
arch/powerpc/platforms/powernv/opal-kmsg.c [new file with mode: 0644]
arch/powerpc/platforms/powernv/opal-wrappers.S
arch/powerpc/platforms/powernv/opal.c

index 8374afed9d0a95cb373e94af41d2e2ceeaae9d90..f8faaaeeca1e16d57dd0a4d9dfff3cb73c7e055d 100644 (file)
 #define OPAL_LEDS_GET_INDICATOR                        114
 #define OPAL_LEDS_SET_INDICATOR                        115
 #define OPAL_CEC_REBOOT2                       116
-#define OPAL_LAST                              116
+#define OPAL_CONSOLE_FLUSH                     117
+#define OPAL_LAST                              117
 
 /* Device tree flags */
 
index 800115910e43a39828e80196aff5499e060c7638..a5fd407213b6e590b35b874dc7b03c486e2fbe0a 100644 (file)
@@ -35,6 +35,7 @@ int64_t opal_console_read(int64_t term_number, __be64 *length,
                          uint8_t *buffer);
 int64_t opal_console_write_buffer_space(int64_t term_number,
                                        __be64 *length);
+void opal_console_flush(void);
 int64_t opal_rtc_read(__be32 *year_month_day,
                      __be64 *hour_minute_second_millisecond);
 int64_t opal_rtc_write(uint32_t year_month_day,
@@ -262,6 +263,8 @@ extern int opal_resync_timebase(void);
 
 extern void opal_lpc_init(void);
 
+extern void opal_kmsg_init(void);
+
 extern int opal_event_request(unsigned int opal_event_nr);
 
 struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr,
index 1c8cdb6250e7c15fb0b26620e0ba43756008cfbc..b9de7ef48849c862fb5550534a97b787ec66fa98 100644 (file)
@@ -2,6 +2,7 @@ obj-y                   += setup.o opal-wrappers.o opal.o opal-async.o idle.o
 obj-y                  += opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
 obj-y                  += rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o
 obj-y                  += opal-msglog.o opal-hmi.o opal-power.o opal-irqchip.o
+obj-y                  += opal-kmsg.o
 
 obj-$(CONFIG_SMP)      += smp.o subcore.o subcore-asm.o
 obj-$(CONFIG_PCI)      += pci.o pci-p5ioc2.o pci-ioda.o
diff --git a/arch/powerpc/platforms/powernv/opal-kmsg.c b/arch/powerpc/platforms/powernv/opal-kmsg.c
new file mode 100644 (file)
index 0000000..bd3b2ee
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * kmsg dumper that ensures the OPAL console fully flushes panic messages
+ *
+ * Author: Russell Currey <ruscur@russell.cc>
+ *
+ * Copyright 2015 IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kmsg_dump.h>
+
+#include <asm/opal.h>
+#include <asm/opal-api.h>
+
+/*
+ * Console output is controlled by OPAL firmware.  The kernel regularly calls
+ * OPAL_POLL_EVENTS, which flushes some console output.  In a panic state,
+ * however, the kernel no longer calls OPAL_POLL_EVENTS and the panic message
+ * may not be completely printed.  This function does not actually dump the
+ * message, it just ensures that OPAL completely flushes the console buffer.
+ */
+static void force_opal_console_flush(struct kmsg_dumper *dumper,
+                                    enum kmsg_dump_reason reason)
+{
+       int i;
+
+       /*
+        * Outside of a panic context the pollers will continue to run,
+        * so we don't need to do any special flushing.
+        */
+       if (reason != KMSG_DUMP_PANIC)
+               return;
+
+       if (opal_check_token(OPAL_CONSOLE_FLUSH)) {
+               opal_console_flush();
+       } else {
+               /*
+                * If OPAL_CONSOLE_FLUSH is not implemented in the firmware,
+                * the console can still be flushed by calling the polling
+                * function enough times to flush the buffer.  We don't know
+                * how much output still needs to be flushed, but we can be
+                * generous since the kernel is in panic and doesn't need
+                * to do much else.
+                */
+               printk(KERN_NOTICE "opal: OPAL_CONSOLE_FLUSH missing.\n");
+               for (i = 0; i < 1024; i++) {
+                       opal_poll_events(NULL);
+               }
+       }
+}
+
+static struct kmsg_dumper opal_kmsg_dumper = {
+       .dump = force_opal_console_flush
+};
+
+void __init opal_kmsg_init(void)
+{
+       int rc;
+
+       /* Add our dumper to the list */
+       rc = kmsg_dump_register(&opal_kmsg_dumper);
+       if (rc != 0)
+               pr_err("opal: kmsg_dump_register failed; returned %d\n", rc);
+}
index b7a464fef7a77be52671a5ef0679f62453cdbede..e45b88a5d7e0f7ed20f68516050a7e8a8c37fa1d 100644 (file)
@@ -301,3 +301,4 @@ OPAL_CALL(opal_flash_erase,                 OPAL_FLASH_ERASE);
 OPAL_CALL(opal_prd_msg,                                OPAL_PRD_MSG);
 OPAL_CALL(opal_leds_get_ind,                   OPAL_LEDS_GET_INDICATOR);
 OPAL_CALL(opal_leds_set_ind,                   OPAL_LEDS_SET_INDICATOR);
+OPAL_CALL(opal_console_flush,                  OPAL_CONSOLE_FLUSH);
index 57cffb80bc36a85d975dc993235c02efda1d7be8..ae29eaf85e9e275bb6575c0115b0e9f6ea7b8d53 100644 (file)
@@ -758,6 +758,9 @@ static int __init opal_init(void)
        opal_pdev_init(opal_node, "ibm,opal-flash");
        opal_pdev_init(opal_node, "ibm,opal-prd");
 
+       /* Initialise OPAL kmsg dumper for flushing console on panic */
+       opal_kmsg_init();
+
        return 0;
 }
 machine_subsys_initcall(powernv, opal_init);