msm: smd: Add SMSM state queue

To reduce the chance of missing SMSM state transitions,
push the SMSM state into a queue in the interrupt handler
and then pull the state for processing the in callback
workqueue.

Change-Id: Ib66bc15f7445369ea7ad2ca271a79ac10b8105a0
CRs-Fixed: 323725
Signed-off-by: Eric Holmberg <eholmber@codeaurora.org>
diff --git a/arch/arm/mach-msm/smd_debug.c b/arch/arm/mach-msm/smd_debug.c
index d7602f2..6171c92 100644
--- a/arch/arm/mach-msm/smd_debug.c
+++ b/arch/arm/mach-msm/smd_debug.c
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/smd_debug.c
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -18,6 +18,7 @@
 #include <linux/debugfs.h>
 #include <linux/list.h>
 #include <linux/ctype.h>
+#include <linux/jiffies.h>
 
 #include <mach/msm_iomap.h>
 
@@ -246,6 +247,7 @@
 	uint32_t new_state;
 };
 static struct SMSM_CB_DATA smsm_cb_data;
+static struct completion smsm_cb_completion;
 
 static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
 {
@@ -253,6 +255,7 @@
 	smsm_cb_data.old_state = old_state;
 	smsm_cb_data.new_state = new_state;
 	smsm_cb_data.data = data;
+	complete_all(&smsm_cb_completion);
 }
 
 #define UT_EQ_INT(a, b) \
@@ -265,6 +268,16 @@
 	} \
 	do {} while (0)
 
+#define UT_GT_INT(a, b) \
+	if ((a) <= (b)) { \
+		i += scnprintf(buf + i, max - i, \
+			"%s:%d " #a "(%d) > " #b "(%d)\n", \
+				__func__, __LINE__, \
+				a, b); \
+		break; \
+	} \
+	do {} while (0)
+
 #define SMSM_CB_TEST_INIT() \
 	do { \
 		smsm_cb_data.cb_count = 0; \
@@ -290,16 +303,21 @@
 
 		/* de-assert SMSM_SMD_INIT to trigger state update */
 		UT_EQ_INT(smsm_cb_data.cb_count, 0);
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 
 		UT_EQ_INT(smsm_cb_data.cb_count, 1);
-		UT_EQ_INT(smsm_cb_data.cb_count, 1);
 		UT_EQ_INT(smsm_cb_data.old_state & SMSM_SMDINIT, SMSM_SMDINIT);
 		UT_EQ_INT(smsm_cb_data.new_state & SMSM_SMDINIT, 0x0);
 		UT_EQ_INT((int)smsm_cb_data.data, 0x1234);
 
 		/* re-assert SMSM_SMD_INIT to trigger state update */
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 2);
 		UT_EQ_INT(smsm_cb_data.old_state & SMSM_SMDINIT, 0x0);
 		UT_EQ_INT(smsm_cb_data.new_state & SMSM_SMDINIT, SMSM_SMDINIT);
@@ -310,8 +328,11 @@
 		UT_EQ_INT(ret, 2);
 
 		/* make sure state change doesn't cause any more callbacks */
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
 		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
+		UT_EQ_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 2);
 
 		i += scnprintf(buf + i, max - i, "Test %d - PASS\n", test_num);
@@ -329,28 +350,49 @@
 		UT_EQ_INT(ret, 1);
 
 		/* verify both callback bits work */
+		INIT_COMPLETION(smsm_cb_completion);
 		UT_EQ_INT(smsm_cb_data.cb_count, 0);
 		smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 1);
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 2);
 
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 3);
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_INIT);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 4);
 
 		/* deregister 1st callback */
 		ret = smsm_state_cb_deregister(SMSM_APPS_STATE, SMSM_SMDINIT,
 				smsm_state_cb, (void *)0x1234);
 		UT_EQ_INT(ret, 1);
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
 		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
+		UT_EQ_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 4);
 
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 5);
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_INIT);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 6);
 
 		/* deregister 2nd callback */
@@ -359,8 +401,11 @@
 		UT_EQ_INT(ret, 2);
 
 		/* make sure state change doesn't cause any more callbacks */
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
 		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_INIT);
+		UT_EQ_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 6);
 
 		i += scnprintf(buf + i, max - i, "Test %d - PASS\n", test_num);
@@ -378,12 +423,18 @@
 		UT_EQ_INT(ret, 0);
 
 		/* verify both callbacks work */
+		INIT_COMPLETION(smsm_cb_completion);
 		UT_EQ_INT(smsm_cb_data.cb_count, 0);
 		smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 1);
 		UT_EQ_INT((int)smsm_cb_data.data, 0x1234);
 
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 2);
 		UT_EQ_INT((int)smsm_cb_data.data, 0x3456);
 
@@ -659,6 +710,8 @@
 	debug_create("version", 0444, dent, debug_read_smem_version);
 	debug_create("smsm_test", 0444, dent, debug_test_smsm);
 
+	init_completion(&smsm_cb_completion);
+
 	return 0;
 }