msm: modem-8960: Print modem error fatal string in the kernel log

When the modem encounters a fatal error, it logs an
error string in shared memory. Use the smem_get_entry API
and print this string out to the kernel log when
the modem signals that it has crashed.

Change-Id: Ibbdd29930f73fb4fa11159aff7e988b436171b6f
Signed-off-by: Vikram Mulukutla <markivx@codeaurora.org>
diff --git a/arch/arm/mach-msm/modem-8960.c b/arch/arm/mach-msm/modem-8960.c
index 7df1c3a..9a1e565 100644
--- a/arch/arm/mach-msm/modem-8960.c
+++ b/arch/arm/mach-msm/modem-8960.c
@@ -27,6 +27,7 @@
 #include <mach/subsystem_restart.h>
 #include <mach/subsystem_notif.h>
 #include <mach/socinfo.h>
+#include <mach/msm_smsm.h>
 
 #include "smd_private.h"
 #include "modem_notifier.h"
@@ -34,6 +35,32 @@
 
 static int crash_shutdown;
 
+#define MAX_SSR_REASON_LEN 81U
+
+static void log_modem_sfr(void)
+{
+	u32 size;
+	char *smem_reason, reason[MAX_SSR_REASON_LEN];
+
+	smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
+	if (!smem_reason || !size) {
+		pr_err("modem subsystem failure reason: (unknown, smem_get_entry failed).\n");
+		return;
+	}
+	if (!smem_reason[0]) {
+		pr_err("modem subsystem failure reason: (unknown, init string found).\n");
+		return;
+	}
+
+	size = min(size, MAX_SSR_REASON_LEN-1);
+	memcpy(reason, smem_reason, size);
+	reason[size] = '\0';
+	pr_err("modem subsystem failure reason: %s.\n", reason);
+
+	smem_reason[0] = '\0';
+	wmb();
+}
+
 static void modem_sw_fatal_fn(struct work_struct *work)
 {
 	uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
@@ -50,6 +77,7 @@
 		pr_err("Modem SMSM state changed to SMSM_RESET.\n"
 			"Probable err_fatal on the modem. "
 			"Calling subsystem restart...\n");
+		log_modem_sfr();
 		subsystem_restart("modem");
 
 	} else if (modem_state & reset_smsm_states) {
@@ -59,7 +87,7 @@
 			__func__);
 		kernel_restart(NULL);
 	} else {
-		/* TODO: Bus unlock code/sequence goes _here_ */
+		log_modem_sfr();
 		subsystem_restart("modem");
 	}
 }
@@ -67,6 +95,7 @@
 static void modem_fw_fatal_fn(struct work_struct *work)
 {
 	pr_err("Watchdog bite received from modem FW!\n");
+	log_modem_sfr();
 	subsystem_restart("modem");
 }
 
@@ -80,9 +109,8 @@
 		return;
 
 	if (new_state & SMSM_RESET) {
-		pr_err("Modem SMSM state changed to SMSM_RESET.\n"
-			"Probable err_fatal on the modem. "
-			"Calling subsystem restart...\n");
+		pr_err("Probable fatal error on the modem.\n");
+		log_modem_sfr();
 		subsystem_restart("modem");
 	}
 }