msm: bam_dmux: delay shutdown until DL polling is complete

Bam_dmux assumes that a shutdown event will not occur while downlink (DL)
polling is active. If this assumption does not hold, bam_dmux stops
polling, but does not cleanly switch back to interrupt mode until the next
power-on event. This is a problem because the next power-on event could
occur in the distant future and until that time some resources may be
incorrectly accessed or not released. Instead, if a shutdown event occurs
while DL polling is active, delay processing of that event until polling
completes.

CRs-Fixed: 503046
Change-Id: I67e4216b4820942e6070944557cd13f59600a2aa
Signed-off-by: Brent Hronik <bhronik@codeaurora.org>
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 26282f7..986357e 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -231,6 +231,7 @@
 /* A2 power collaspe */
 #define UL_TIMEOUT_DELAY 1000	/* in ms */
 #define ENABLE_DISCONNECT_ACK	0x1
+#define SHUTDOWN_TIMEOUT_MS	500
 static void toggle_apps_ack(void);
 static void reconnect_to_bam(void);
 static void disconnect_to_bam(void);
@@ -271,6 +272,7 @@
 static int power_management_only_mode;
 static int in_ssr;
 static int ssr_skipped_disconnect;
+static struct completion shutdown_completion;
 
 struct outside_notify_func {
 	void (*notify)(void *, int, unsigned long);
@@ -1065,6 +1067,7 @@
 		goto fail;
 	}
 	polling_mode = 0;
+	complete_all(&shutdown_completion);
 	release_wakelock();
 
 	/* handle any rx packets before interrupt was enabled */
@@ -1265,6 +1268,7 @@
 					" not disabled\n", __func__, ret);
 				break;
 			}
+			INIT_COMPLETION(shutdown_completion);
 			grab_wakelock();
 			polling_mode = 1;
 			/*
@@ -1744,6 +1748,14 @@
 	struct list_head *node;
 	struct rx_pkt_info *info;
 	unsigned long flags;
+	unsigned long time_remaining;
+
+	time_remaining = wait_for_completion_timeout(&shutdown_completion,
+			msecs_to_jiffies(SHUTDOWN_TIMEOUT_MS));
+	if (time_remaining == 0) {
+		pr_err("%s: shutdown completion timed out\n", __func__);
+		ssrestart_check();
+	}
 
 	bam_connection_is_active = 0;
 
@@ -2346,6 +2358,8 @@
 	init_completion(&ul_wakeup_ack_completion);
 	init_completion(&bam_connection_completion);
 	init_completion(&dfab_unvote_completion);
+	init_completion(&shutdown_completion);
+	complete_all(&shutdown_completion);
 	INIT_DELAYED_WORK(&ul_timeout_work, ul_timeout);
 	INIT_DELAYED_WORK(&queue_rx_work, queue_rx_work_func);
 	wake_lock_init(&bam_wakelock, WAKE_LOCK_SUSPEND, "bam_dmux_wakelock");