1 /* 2 * kmsg dumper that ensures the OPAL console fully flushes panic messages 3 * 4 * Author: Russell Currey <ruscur@russell.cc> 5 * 6 * Copyright 2015 IBM Corporation. 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the 10 * Free Software Foundation; either version 2 of the License, or (at your 11 * option) any later version. 12 */ 13 14 #include <linux/kmsg_dump.h> 15 #include <linux/delay.h> 16 17 #include <asm/opal.h> 18 #include <asm/opal-api.h> 19 20 /* 21 * Console output is controlled by OPAL firmware. The kernel regularly calls 22 * OPAL_POLL_EVENTS, which flushes some console output. In a panic state, 23 * however, the kernel no longer calls OPAL_POLL_EVENTS and the panic message 24 * may not be completely printed. This function does not actually dump the 25 * message, it just ensures that OPAL completely flushes the console buffer. 26 */ 27 static void force_opal_console_flush(struct kmsg_dumper *dumper, 28 enum kmsg_dump_reason reason) 29 { 30 s64 rc; 31 32 /* 33 * Outside of a panic context the pollers will continue to run, 34 * so we don't need to do any special flushing. 35 */ 36 if (reason != KMSG_DUMP_PANIC) 37 return; 38 39 if (opal_check_token(OPAL_CONSOLE_FLUSH)) { 40 do { 41 rc = OPAL_BUSY; 42 while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { 43 rc = opal_console_flush(0); 44 if (rc == OPAL_BUSY_EVENT) { 45 mdelay(OPAL_BUSY_DELAY_MS); 46 opal_poll_events(NULL); 47 } else if (rc == OPAL_BUSY) { 48 mdelay(OPAL_BUSY_DELAY_MS); 49 } 50 } 51 } while (rc == OPAL_PARTIAL); /* More to flush */ 52 53 } else { 54 int i; 55 56 /* 57 * If OPAL_CONSOLE_FLUSH is not implemented in the firmware, 58 * the console can still be flushed by calling the polling 59 * function enough times to flush the buffer. We don't know 60 * how much output still needs to be flushed, but we can be 61 * generous since the kernel is in panic and doesn't need 62 * to do much else. 63 */ 64 printk(KERN_NOTICE "opal: OPAL_CONSOLE_FLUSH missing.\n"); 65 for (i = 0; i < 1024; i++) { 66 opal_poll_events(NULL); 67 } 68 } 69 } 70 71 static struct kmsg_dumper opal_kmsg_dumper = { 72 .dump = force_opal_console_flush 73 }; 74 75 void __init opal_kmsg_init(void) 76 { 77 int rc; 78 79 /* Add our dumper to the list */ 80 rc = kmsg_dump_register(&opal_kmsg_dumper); 81 if (rc != 0) 82 pr_err("opal: kmsg_dump_register failed; returned %d\n", rc); 83 } 84