powerpc/xmon: add command to dump OPAL msglog
[cascardo/linux.git] / arch / powerpc / xmon / xmon.c
index d5c8a15..47e195d 100644 (file)
@@ -47,6 +47,9 @@
 #include <asm/debug.h>
 #include <asm/hw_breakpoint.h>
 
+#include <asm/opal.h>
+#include <asm/firmware.h>
+
 #ifdef CONFIG_PPC64
 #include <asm/hvcall.h>
 #include <asm/paca.h>
@@ -119,6 +122,16 @@ static void dump(void);
 static void prdump(unsigned long, long);
 static int ppc_inst_dump(unsigned long, long, int);
 static void dump_log_buf(void);
+
+#ifdef CONFIG_PPC_POWERNV
+static void dump_opal_msglog(void);
+#else
+static inline void dump_opal_msglog(void)
+{
+       printf("Machine is not running OPAL firmware.\n");
+}
+#endif
+
 static void backtrace(struct pt_regs *);
 static void excprint(struct pt_regs *);
 static void prregs(struct pt_regs *);
@@ -202,6 +215,10 @@ Commands:\n\
   df   dump float values\n\
   dd   dump double values\n\
   dl    dump the kernel log buffer\n"
+#ifdef CONFIG_PPC_POWERNV
+  "\
+  do    dump the OPAL message log\n"
+#endif
 #ifdef CONFIG_PPC64
   "\
   dp[#]        dump paca for current cpu, or cpu #\n\
@@ -2253,6 +2270,8 @@ dump(void)
                last_cmd = "di\n";
        } else if (c == 'l') {
                dump_log_buf();
+       } else if (c == 'o') {
+               dump_opal_msglog();
        } else if (c == 'r') {
                scanhex(&ndump);
                if (ndump == 0)
@@ -2395,6 +2414,45 @@ dump_log_buf(void)
        catch_memory_errors = 0;
 }
 
+#ifdef CONFIG_PPC_POWERNV
+static void dump_opal_msglog(void)
+{
+       unsigned char buf[128];
+       ssize_t res;
+       loff_t pos = 0;
+
+       if (!firmware_has_feature(FW_FEATURE_OPAL)) {
+               printf("Machine is not running OPAL firmware.\n");
+               return;
+       }
+
+       if (setjmp(bus_error_jmp) != 0) {
+               printf("Error dumping OPAL msglog!\n");
+               return;
+       }
+
+       catch_memory_errors = 1;
+       sync();
+
+       xmon_start_pagination();
+       while ((res = opal_msglog_copy(buf, pos, sizeof(buf) - 1))) {
+               if (res < 0) {
+                       printf("Error dumping OPAL msglog! Error: %zd\n", res);
+                       break;
+               }
+               buf[res] = '\0';
+               printf("%s", buf);
+               pos += res;
+       }
+       xmon_end_pagination();
+
+       sync();
+       /* wait a little while to see if we get a machine check */
+       __delay(200);
+       catch_memory_errors = 0;
+}
+#endif
+
 /*
  * Memory operations - move, set, print differences
  */