diag: Add support for mutiple HSIC instances

On a future target, applications processor will talk to
two MDMs simultaneously. This change will enable multiple
HSIC connections towards this configuration.

Change-Id: If2df9184624e20df13cc76717e593a3b6bb461e5
Signed-off-by: Shalabh Jain <shalabhj@codeaurora.org>
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index d2454f4..fa69f0b 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -18,6 +18,7 @@
 #include <linux/device.h>
 #include <linux/uaccess.h>
 #include <linux/diagchar.h>
+#include <linux/platform_device.h>
 #include <linux/sched.h>
 #ifdef CONFIG_DIAG_OVER_USB
 #include <mach/usbdiag.h>
@@ -141,18 +142,23 @@
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
 void diag_clear_hsic_tbl(void)
 {
-	int i;
+	int i, j;
 
-	driver->num_hsic_buf_tbl_entries = 0;
-	for (i = 0; i < driver->poolsize_hsic_write; i++) {
-		if (driver->hsic_buf_tbl[i].buf) {
-			/* Return the buffer to the pool */
-			diagmem_free(driver, (unsigned char *)
-				(driver->hsic_buf_tbl[i].buf),
-				POOL_TYPE_HSIC);
-			driver->hsic_buf_tbl[i].buf = 0;
+	/* Clear for all active HSIC bridges */
+	for (j = 0; j < MAX_HSIC_CH; j++) {
+		if (diag_hsic[j].hsic_ch) {
+			diag_hsic[j].num_hsic_buf_tbl_entries = 0;
+			for (i = 0; i < diag_hsic[j].poolsize_hsic_write; i++) {
+				if (diag_hsic[j].hsic_buf_tbl[i].buf) {
+					/* Return the buffer to the pool */
+					diagmem_free(driver, (unsigned char *)
+						(diag_hsic[j].hsic_buf_tbl[i].
+						 buf), POOL_TYPE_HSIC);
+					diag_hsic[j].hsic_buf_tbl[i].buf = 0;
+				}
+				diag_hsic[j].hsic_buf_tbl[i].length = 0;
+			}
 		}
-		driver->hsic_buf_tbl[i].length = 0;
 	}
 }
 #else
@@ -298,7 +304,7 @@
 	diagmem_exit(driver, POOL_TYPE_WRITE_STRUCT);
 	for (i = 0; i < driver->num_clients; i++) {
 		if (NULL != diagpriv_data && diagpriv_data->pid ==
-			 driver->client_map[i].pid) {
+						driver->client_map[i].pid) {
 			driver->client_map[i].pid = 0;
 			kfree(diagpriv_data);
 			diagpriv_data = NULL;
@@ -382,7 +388,7 @@
 	uint16_t remote_dev = 0;
 
 	/* Check for MDM processor */
-	if (driver->hsic_inited)
+	if (diag_hsic[HSIC].hsic_inited)
 		remote_dev |= 1 << 0;
 
 	/* Check for QSC processor */
@@ -932,20 +938,22 @@
 		}
 #endif
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
-		spin_lock_irqsave(&driver->hsic_spinlock, spin_lock_flags);
-		for (i = 0; i < driver->poolsize_hsic_write; i++) {
-			hsic_buf_tbl[i].buf = driver->hsic_buf_tbl[i].buf;
-			driver->hsic_buf_tbl[i].buf = 0;
+		spin_lock_irqsave(&diag_hsic[HSIC].hsic_spinlock,
+							spin_lock_flags);
+		for (i = 0; i < diag_hsic[HSIC].poolsize_hsic_write; i++) {
+			hsic_buf_tbl[i].buf =
+					diag_hsic[HSIC].hsic_buf_tbl[i].buf;
+			diag_hsic[HSIC].hsic_buf_tbl[i].buf = 0;
 			hsic_buf_tbl[i].length =
-					driver->hsic_buf_tbl[i].length;
-			driver->hsic_buf_tbl[i].length = 0;
+					diag_hsic[HSIC].hsic_buf_tbl[i].length;
+			diag_hsic[HSIC].hsic_buf_tbl[i].length = 0;
 		}
-		driver->num_hsic_buf_tbl_entries = 0;
-		spin_unlock_irqrestore(&driver->hsic_spinlock,
+		diag_hsic[HSIC].num_hsic_buf_tbl_entries = 0;
+		spin_unlock_irqrestore(&diag_hsic[HSIC].hsic_spinlock,
 					spin_lock_flags);
 
 		remote_token = diag_get_remote(MDM);
-		for (i = 0; i < driver->poolsize_hsic_write; i++) {
+		for (i = 0; i < diag_hsic[HSIC].poolsize_hsic_write; i++) {
 			if (hsic_buf_tbl[i].length > 0) {
 				pr_debug("diag: HSIC copy to user, i: %d, buf: %x, len: %d\n",
 					 i, (unsigned int)hsic_buf_tbl[i].buf,
@@ -1112,7 +1120,7 @@
 				size_t count, loff_t *ppos)
 {
 	int err, ret = 0, pkt_type, token_offset = 0;
-	int remote_proc = 0;
+	int remote_proc = 0, index;
 #ifdef DIAG_DEBUG
 	int length = 0, i;
 #endif
@@ -1127,6 +1135,7 @@
 		return -EIO;
 	}
 #endif /* DIAG over USB */
+	index = 0;
 	/* Get the packet type F3/log/event/Pkt response */
 	err = copy_from_user((&pkt_type), buf, 4);
 	/* First 4 bytes indicate the type of payload - ignore these */
@@ -1193,30 +1202,37 @@
 		}
 #endif
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
-		/* send masks to 9k too */
-		if (driver->hsic_ch && (payload_size > 0) &&
-						(remote_proc == MDM)) {
-			/* wait sending mask updates if HSIC ch not ready */
-			if (driver->in_busy_hsic_write)
-				wait_event_interruptible(driver->wait_q,
-					(driver->in_busy_hsic_write != 1));
-			driver->in_busy_hsic_write = 1;
-			driver->in_busy_hsic_read_on_device = 0;
-			err = diag_bridge_write(
-					driver->user_space_data + token_offset,
-					payload_size);
-			if (err) {
-				pr_err("diag: err sending mask to MDM: %d\n",
-									 err);
-				/*
-				* If the error is recoverable, then clear
-				* the write flag, so we will resubmit a
-				* write on the next frame.  Otherwise, don't
-				* resubmit a write on the next frame.
-				*/
-				if ((-ESHUTDOWN) != err)
-					driver->in_busy_hsic_write = 0;
-			}
+		/* send masks to All 9k */
+		for (index = 0; index < MAX_HSIC_CH; index++) {
+			if (diag_hsic[index].hsic_ch && (payload_size > 0) &&
+							 (remote_proc == MDM)) {
+				/* wait sending mask updates
+				 * if HSIC ch not ready */
+				if (diag_hsic[index].in_busy_hsic_write)
+					wait_event_interruptible(driver->wait_q,
+						(diag_hsic[index].
+						 in_busy_hsic_write != 1));
+				diag_hsic[index].in_busy_hsic_write = 1;
+				diag_hsic[index].in_busy_hsic_read_on_device =
+									0;
+				err = diag_bridge_write(index,
+						driver->user_space_data +
+						token_offset, payload_size);
+				if (err) {
+					pr_err("diag: err sending mask to MDM: %d\n",
+					       err);
+					/*
+					* If the error is recoverable, then
+					* clear the write flag, so we will
+					* resubmit a write on the next frame.
+					* Otherwise, don't resubmit a write
+					* on the next frame.
+					*/
+					if ((-ESHUTDOWN) != err)
+						diag_hsic[index].
+							in_busy_hsic_write = 0;
+				 }
+			 }
 		}
 		if (driver->diag_smux_enabled && (remote_proc == QSC)
 						&& driver->lcid) {
@@ -1540,15 +1556,20 @@
 static int __init diagchar_init(void)
 {
 	dev_t dev;
-	int error;
+	int error, ret;
 
 	pr_debug("diagfwd initializing ..\n");
+	ret = 0;
 	driver = kzalloc(sizeof(struct diagchar_dev) + 5, GFP_KERNEL);
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
 	diag_bridge = kzalloc(MAX_BRIDGES * sizeof(struct diag_bridge_dev),
-								 GFP_KERNEL);
+								GFP_KERNEL);
 	if (!diag_bridge)
-		pr_warning("diag: could not allocate memory for bridge\n");
+		pr_warn("diag: could not allocate memory for bridges\n");
+	diag_hsic = kzalloc(MAX_HSIC_CH * sizeof(struct diag_hsic_dev),
+								GFP_KERNEL);
+	if (!diag_hsic)
+		pr_warn("diag: could not allocate memory for hsic ch\n");
 #endif
 
 	if (driver) {
@@ -1577,6 +1598,12 @@
 		diagfwd_init();
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
 		diagfwd_bridge_init(HSIC);
+		diagfwd_bridge_init(HSIC_2);
+		/* register HSIC device */
+		ret = platform_driver_register(&msm_hsic_ch_driver);
+		if (ret)
+			pr_err("diag: could not register HSIC device, ret: %d\n",
+				ret);
 		diagfwd_bridge_init(SMUX);
 		INIT_WORK(&(driver->diag_disconnect_work),
 						 diag_disconnect_work_fn);