msm: bam_dmux: Fix SSRestart UL State Handling

Properly handle cleaning up state of an active uplink
when a subsystem restart occurs.

CRs-Fixed: 327972
Change-Id: Ide191d26b66c9857d36893abb680fa440487a855
Signed-off-by: Eric Holmberg <eholmber@codeaurora.org>
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 4ccfbb7..2720774 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -336,11 +336,16 @@
 	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
 	list_for_each_entry(info, &bam_tx_pool, list_node) {
 		if (!reported) {
-			DMUX_LOG_KERR("%s: tx pool not empty\n", func);
+			bam_dmux_log("%s: tx pool not empty\n", func);
+			if (!in_global_reset)
+				pr_err("%s: tx pool not empty\n", func);
 			reported = 1;
 		}
-		DMUX_LOG_KERR("%s: node=%p ts=%u.%09lu\n", __func__,
-		&info->list_node, info->ts_sec, info->ts_nsec);
+		bam_dmux_log("%s: node=%p ts=%u.%09lu\n", __func__,
+			&info->list_node, info->ts_sec, info->ts_nsec);
+		if (!in_global_reset)
+			pr_err("%s: node=%p ts=%u.%09lu\n", __func__,
+			&info->list_node, info->ts_sec, info->ts_nsec);
 	}
 	spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
 }
@@ -1245,8 +1250,11 @@
 	int i;
 
 	for (i = 0; i < BAM_DMUX_NUM_CHANNELS; ++i) {
-		if (bam_ch_is_open(i))
+		if (bam_ch_is_open(i)) {
 			bam_ch[i].notify(bam_ch[i].priv, event, data);
+			bam_dmux_log("%s: cid=%d, event=%d, data=%lu\n",
+					__func__, i, event, data);
+		}
 	}
 }
 
@@ -1283,6 +1291,36 @@
 		smsm_change_state(SMSM_APPS_STATE, SMSM_A2_POWER_CONTROL, 0);
 }
 
+/*
+ * @note:  Must be called with ul_wakeup_lock locked.
+ */
+static inline void ul_powerdown(void)
+{
+	bam_dmux_log("%s: powerdown\n", __func__);
+	verify_tx_queue_is_empty(__func__);
+
+	if (a2_pc_disabled) {
+		wait_for_dfab = 1;
+		INIT_COMPLETION(dfab_unvote_completion);
+		release_wakelock();
+	} else {
+		wait_for_ack = 1;
+		INIT_COMPLETION(ul_wakeup_ack_completion);
+		power_vote(0);
+	}
+	bam_is_connected = 0;
+	notify_all(BAM_DMUX_UL_DISCONNECTED, (unsigned long)(NULL));
+}
+
+static inline void ul_powerdown_finish(void)
+{
+	if (a2_pc_disabled && wait_for_dfab) {
+		unvote_dfab();
+		complete_all(&dfab_unvote_completion);
+		wait_for_dfab = 0;
+	}
+}
+
 static void ul_timeout(struct work_struct *work)
 {
 	unsigned long flags;
@@ -1296,33 +1334,18 @@
 				msecs_to_jiffies(UL_TIMEOUT_DELAY));
 		return;
 	}
-	if (ul_packet_written) {
-		bam_dmux_log("%s: packet written\n", __func__);
-		ul_packet_written = 0;
-		schedule_delayed_work(&ul_timeout_work,
-				msecs_to_jiffies(UL_TIMEOUT_DELAY));
-	} else {
-		bam_dmux_log("%s: powerdown\n", __func__);
-		verify_tx_queue_is_empty(__func__);
-
-		if (a2_pc_disabled) {
-			wait_for_dfab = 1;
-			INIT_COMPLETION(dfab_unvote_completion);
-			release_wakelock();
+	if (bam_is_connected) {
+		if (ul_packet_written) {
+			bam_dmux_log("%s: packet written\n", __func__);
+			ul_packet_written = 0;
+			schedule_delayed_work(&ul_timeout_work,
+					msecs_to_jiffies(UL_TIMEOUT_DELAY));
 		} else {
-			wait_for_ack = 1;
-			INIT_COMPLETION(ul_wakeup_ack_completion);
-			power_vote(0);
+			ul_powerdown();
 		}
-		bam_is_connected = 0;
-		notify_all(BAM_DMUX_UL_DISCONNECTED, (unsigned long)(NULL));
 	}
 	write_unlock_irqrestore(&ul_wakeup_lock, flags);
-	if (a2_pc_disabled && wait_for_dfab) {
-		unvote_dfab();
-		complete_all(&dfab_unvote_completion);
-		wait_for_dfab = 0;
-	}
+	ul_powerdown_finish();
 }
 static void ul_wakeup(void)
 {
@@ -1426,8 +1449,20 @@
 {
 	struct list_head *node;
 	struct rx_pkt_info *info;
+	unsigned long flags;
 
 	bam_connection_is_active = 0;
+
+	/* handle disconnect during active UL */
+	write_lock_irqsave(&ul_wakeup_lock, flags);
+	if (bam_is_connected) {
+		bam_dmux_log("%s: UL active - forcing powerdown\n", __func__);
+		ul_powerdown();
+	}
+	write_unlock_irqrestore(&ul_wakeup_lock, flags);
+	ul_powerdown_finish();
+
+	/* tear down BAM connection */
 	INIT_COMPLETION(bam_connection_completion);
 	sps_disconnect(bam_tx_pipe);
 	sps_disconnect(bam_rx_pipe);
@@ -1531,7 +1566,18 @@
 
 	bam_dmux_log("%s: begin\n", __func__);
 	in_global_reset = 1;
+
+	/* Handle uplink Powerdown */
+	write_lock_irqsave(&ul_wakeup_lock, flags);
+	if (bam_is_connected) {
+		ul_powerdown();
+		wait_for_ack = 0;
+	}
+	write_unlock_irqrestore(&ul_wakeup_lock, flags);
+	ul_powerdown_finish();
 	a2_pc_disabled = 0;
+
+	/* Cleanup Channel States */
 	for (i = 0; i < BAM_DMUX_NUM_CHANNELS; ++i) {
 		temp_remote_status = bam_ch_is_remote_open(i);
 		bam_ch[i].status &= ~BAM_CH_REMOTE_OPEN;
@@ -1544,7 +1590,8 @@
 						bam_ch[i].name, 2);
 		}
 	}
-	/*cleanup UL*/
+
+	/* Cleanup pending UL data */
 	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
 	while (!list_empty(&bam_tx_pool)) {
 		node = bam_tx_pool.next;
@@ -1565,7 +1612,7 @@
 		kfree(info);
 	}
 	spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
-	power_vote(0);
+
 	bam_dmux_log("%s: complete\n", __func__);
 	return NOTIFY_DONE;
 }