Merge "msm: ipc: Send Resume_Tx from the client/server context"
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 64986d0..dd90c9e 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -98,6 +98,7 @@
 #define IPC_ROUTER_LOG_EVENT_ERROR      0x00
 #define IPC_ROUTER_LOG_EVENT_TX         0x01
 #define IPC_ROUTER_LOG_EVENT_RX         0x02
+#define IPC_ROUTER_DUMMY_DEST_NODE	0xFFFFFFFF
 
 static LIST_HEAD(control_ports);
 static DECLARE_RWSEM(control_ports_lock_lha5);
@@ -926,7 +927,8 @@
 
 static int msm_ipc_router_send_control_msg(
 		struct msm_ipc_router_xprt_info *xprt_info,
-		union rr_control_msg *msg)
+		union rr_control_msg *msg,
+		uint32_t dst_node_id)
 {
 	struct rr_packet *pkt;
 	struct sk_buff *ipc_rtr_pkt;
@@ -986,7 +988,10 @@
 	hdr->src_port_id = IPC_ROUTER_ADDRESS;
 	hdr->confirm_rx = 0;
 	hdr->size = sizeof(*msg);
-	hdr->dst_node_id = xprt_info->remote_node_id;
+	if (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)
+		hdr->dst_node_id = dst_node_id;
+	else
+		hdr->dst_node_id = xprt_info->remote_node_id;
 	hdr->dst_port_id = IPC_ROUTER_ADDRESS;
 	skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
 	pkt->pkt_fragment_q = pkt_fragment_q;
@@ -1031,7 +1036,7 @@
 				ctl.srv.port_id =
 					server_port->server_addr.port_id;
 				msm_ipc_router_send_control_msg(xprt_info,
-								&ctl);
+					&ctl, IPC_ROUTER_DUMMY_DEST_NODE);
 			}
 		}
 	}
@@ -1132,7 +1137,8 @@
 
 	down_read(&xprt_info_list_lock_lha5);
 	list_for_each_entry(xprt_info, &xprt_info_list, list) {
-		msm_ipc_router_send_control_msg(xprt_info, ctl);
+		msm_ipc_router_send_control_msg(xprt_info, ctl,
+					IPC_ROUTER_DUMMY_DEST_NODE);
 	}
 	up_read(&xprt_info_list_lock_lha5);
 
@@ -1150,7 +1156,8 @@
 	down_read(&xprt_info_list_lock_lha5);
 	list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
 		if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
-			msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
+			msm_ipc_router_send_control_msg(fwd_xprt_info, ctl,
+						IPC_ROUTER_DUMMY_DEST_NODE);
 	}
 	up_read(&xprt_info_list_lock_lha5);
 
@@ -1252,7 +1259,8 @@
 		list_for_each_entry(tmp_xprt_info, &xprt_info_list, list) {
 			if (tmp_xprt_info != xprt_info)
 				continue;
-			msm_ipc_router_send_control_msg(tmp_xprt_info, &msg);
+			msm_ipc_router_send_control_msg(tmp_xprt_info, &msg,
+						IPC_ROUTER_DUMMY_DEST_NODE);
 			break;
 		}
 		up_read(&xprt_info_list_lock_lha5);
@@ -1498,7 +1506,8 @@
 	/* Send a reply HELLO message */
 	memset(&ctl, 0, sizeof(ctl));
 	ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
-	rc = msm_ipc_router_send_control_msg(xprt_info, &ctl);
+	rc = msm_ipc_router_send_control_msg(xprt_info, &ctl,
+						IPC_ROUTER_DUMMY_DEST_NODE);
 	if (rc < 0) {
 		pr_err("%s: Error sending reply HELLO message\n", __func__);
 		return rc;
@@ -1751,7 +1760,6 @@
 	struct msm_ipc_port *port_ptr;
 	struct sk_buff *head_skb;
 	struct msm_ipc_router_remote_port *rport_ptr;
-	uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
 
 	struct msm_ipc_router_xprt_info *xprt_info =
 		container_of(work,
@@ -1814,10 +1822,6 @@
 #endif
 #endif
 
-		resume_tx = hdr->confirm_rx;
-		resume_tx_node_id = hdr->dst_node_id;
-		resume_tx_port_id = hdr->dst_port_id;
-
 		down_read(&local_ports_lock_lha2);
 		port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
 		if (!port_ptr) {
@@ -1825,7 +1829,7 @@
 				hdr->dst_port_id);
 			up_read(&local_ports_lock_lha2);
 			release_pkt(pkt);
-			goto process_done;
+			return;
 		}
 
 		down_read(&routing_table_lock_lha3);
@@ -1841,26 +1845,12 @@
 					hdr->src_port_id);
 				up_read(&routing_table_lock_lha3);
 				up_read(&local_ports_lock_lha2);
-				goto process_done;
+				return;
 			}
 		}
 		up_read(&routing_table_lock_lha3);
 		post_pkt_to_port(port_ptr, pkt, 0);
 		up_read(&local_ports_lock_lha2);
-
-process_done:
-		if (resume_tx) {
-			union rr_control_msg msg;
-			memset(&msg, 0, sizeof(msg));
-			msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
-			msg.cli.node_id = resume_tx_node_id;
-			msg.cli.port_id = resume_tx_port_id;
-
-			RR("x RESUME_TX id=%d:%08x\n",
-			   msg.cli.node_id, msg.cli.port_id);
-			msm_ipc_router_send_control_msg(xprt_info, &msg);
-		}
-
 	}
 	return;
 
@@ -2239,11 +2229,56 @@
 	return 0;
 }
 
+/**
+ * msm_ipc_router_send_resume_tx() - Send Resume_Tx message
+ * @data: Pointer to received data packet that has confirm_rx bit set
+ *
+ * @return: On success, number of bytes transferred is returned, else
+ *	    standard linux error code is returned.
+ *
+ * This function sends the Resume_Tx event to the remote node that
+ * sent the data with confirm_rx field set. In case of a multi-hop
+ * scenario also, this function makes sure that the destination node_id
+ * to which the resume_tx event should reach is right.
+ */
+static int msm_ipc_router_send_resume_tx(void *data)
+{
+	union rr_control_msg msg;
+	struct rr_header *hdr = (struct rr_header *)data;
+	struct msm_ipc_routing_table_entry *rt_entry;
+	int ret;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
+	msg.cli.node_id = hdr->dst_node_id;
+	msg.cli.port_id = hdr->dst_port_id;
+	down_read(&routing_table_lock_lha3);
+	rt_entry = lookup_routing_table(hdr->src_node_id);
+	if (!rt_entry) {
+		pr_err("%s: %d Node is not present",
+				__func__, hdr->src_node_id);
+		up_read(&routing_table_lock_lha3);
+		return -ENODEV;
+	}
+	RR("x RESUME_TX id=%d:%08x\n",
+			msg.cli.node_id, msg.cli.port_id);
+	ret = msm_ipc_router_send_control_msg(rt_entry->xprt_info, &msg,
+						hdr->src_node_id);
+	up_read(&routing_table_lock_lha3);
+	if (ret < 0)
+		pr_err("%s: Send Resume_Tx Failed SRC_NODE: %d SRC_PORT: %d DEST_NODE: %d",
+			__func__, hdr->dst_node_id, hdr->dst_port_id,
+			hdr->src_node_id);
+
+	return ret;
+}
+
 int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
 			struct sk_buff_head **data,
 			size_t buf_len)
 {
 	struct rr_packet *pkt;
+	struct sk_buff *head_skb;
 	int ret;
 
 	if (!port_ptr || !data)
@@ -2265,8 +2300,15 @@
 		wake_unlock(&port_ptr->port_rx_wake_lock);
 	*data = pkt->pkt_fragment_q;
 	ret = pkt->length;
-	kfree(pkt);
 	mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
+	kfree(pkt);
+	head_skb = skb_peek(*data);
+	if (!head_skb) {
+		pr_err("%s: Socket Buffer not found", __func__);
+		return -EFAULT;
+	}
+	if (((struct rr_header *)(head_skb->data))->confirm_rx)
+		msm_ipc_router_send_resume_tx((void *)(head_skb->data));
 
 	return ret;
 }