diag: Support dynamic switch between USB and PCIe interface

Add support to configure PCIe or USB interface during boot based on
PCIE config definition. Support to dynamic switch between USB and
PCIe by existing IOCTL is added.

Change-Id: I9a51ea5dd6c9d370c7aa0419e9772067f16e9ab6
Signed-off-by: Manoj Prabhu B <bmanoj@codeaurora.org>
diff --git a/drivers/char/diag/Makefile b/drivers/char/diag/Makefile
index 86cc533..7282197 100644
--- a/drivers/char/diag/Makefile
+++ b/drivers/char/diag/Makefile
@@ -3,6 +3,5 @@
 obj-$(CONFIG_USB_QCOM_DIAG_BRIDGE) += diagfwd_hsic.o
 obj-$(CONFIG_USB_QCOM_DIAG_BRIDGE) += diagfwd_smux.o
 obj-$(CONFIG_MSM_MHI) += diagfwd_mhi.o
-obj-$(CONFIG_DIAG_OVER_PCIE) += diag_pcie.o
 obj-$(CONFIG_DIAG_USES_SMD) += diagfwd_smd.o
-diagchar-objs := diagchar_core.o diagchar_hdlc.o diagfwd.o diagfwd_glink.o diagfwd_peripheral.o diagfwd_socket.o diag_mux.o diag_memorydevice.o diag_usb.o diagmem.o diagfwd_cntl.o diag_dci.o diag_masks.o diag_debugfs.o
+diagchar-objs := diagchar_core.o diagchar_hdlc.o diagfwd.o diagfwd_glink.o diagfwd_peripheral.o diagfwd_socket.o diag_mux.o diag_memorydevice.o diag_usb.o diagmem.o diagfwd_cntl.o diag_dci.o diag_masks.o diag_debugfs.o diag_pcie.o
\ No newline at end of file
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index 6e0dba5..19b2b02 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2019, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -44,9 +44,7 @@
 static int diag_dbgfs_table_index;
 static int diag_dbgfs_mempool_index;
 static int diag_dbgfs_usbinfo_index;
-#ifdef CONFIG_DIAG_OVER_PCIE
 static int diag_dbgfs_pcieinfo_index;
-#endif
 static int diag_dbgfs_smdinfo_index;
 static int diag_dbgfs_socketinfo_index;
 static int diag_dbgfs_glinkinfo_index;
@@ -485,7 +483,6 @@
 	return ret;
 }
 
-#ifdef CONFIG_DIAG_OVER_PCIE
 static ssize_t diag_dbgfs_read_pcieinfo(struct file *file, char __user *ubuf,
 				       size_t count, loff_t *ppos)
 {
@@ -545,7 +542,6 @@
 	kfree(buf);
 	return ret;
 }
-#endif
 
 #ifdef CONFIG_DIAG_USES_SMD
 static ssize_t diag_dbgfs_read_smdinfo(struct file *file, char __user *ubuf,
@@ -1146,11 +1142,9 @@
 	.read = diag_dbgfs_read_usbinfo,
 };
 
-#ifdef CONFIG_DIAG_OVER_PCIE
 const struct file_operations diag_dbgfs_pcieinfo_ops = {
 	.read = diag_dbgfs_read_pcieinfo,
 };
-#endif
 
 const struct file_operations diag_dbgfs_dcistats_ops = {
 	.read = diag_dbgfs_read_dcistats,
@@ -1211,12 +1205,10 @@
 	if (!entry)
 		goto err;
 
-#ifdef CONFIG_DIAG_OVER_PCIE
 	entry = debugfs_create_file("pcieinfo", 0444, diag_dbgfs_dent, 0,
 				    &diag_dbgfs_pcieinfo_ops);
 	if (!entry)
 		goto err;
-#endif
 
 	entry = debugfs_create_file("dci_stats", 0444, diag_dbgfs_dent, 0,
 				    &diag_dbgfs_dcistats_ops);
diff --git a/drivers/char/diag/diag_mux.c b/drivers/char/diag/diag_mux.c
index ae59175..e742d08 100644
--- a/drivers/char/diag/diag_mux.c
+++ b/drivers/char/diag/diag_mux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -31,12 +31,6 @@
 #include "diagfwd_peripheral.h"
 #include "diag_ipc_logging.h"
 
-#ifdef CONFIG_DIAG_OVER_PCIE
-#define diag_mux_register_ops diag_pcie_register_ops
-#else
-#define diag_mux_register_ops diag_usb_register_ops
-#endif
-
 struct diag_mux_state_t *diag_mux;
 static struct diag_logger_t usb_logger;
 static struct diag_logger_t md_logger;
@@ -58,7 +52,6 @@
 	.close_peripheral = diag_md_close_peripheral,
 };
 
-#ifdef CONFIG_DIAG_OVER_PCIE
 static struct diag_logger_ops pcie_log_ops = {
 	.open = diag_pcie_connect_all,
 	.close = diag_pcie_disconnect_all,
@@ -66,7 +59,6 @@
 	.write = diag_pcie_write,
 	.close_peripheral = NULL
 };
-#endif
 
 int diag_mux_init(void)
 {
@@ -82,18 +74,16 @@
 	md_logger.mode = DIAG_MEMORY_DEVICE_MODE;
 	md_logger.log_ops = &md_log_ops;
 	diag_md_init();
-#ifdef CONFIG_DIAG_OVER_PCIE
 	pcie_logger.mode = DIAG_PCIE_MODE;
 	pcie_logger.log_ops = &pcie_log_ops;
 	diag_mux->pcie_ptr = &pcie_logger;
-#endif
 	/*
 	 * Set USB logging as the default logger. This is the mode
 	 * Diag should be in when it initializes.
 	 */
 	diag_mux->usb_ptr = &usb_logger;
 	diag_mux->md_ptr = &md_logger;
-	switch (driver->transport_set) {
+	switch (driver->pcie_transport_def) {
 	case DIAG_ROUTE_TO_PCIE:
 		diag_mux->logger = &pcie_logger;
 		diag_mux->mode = DIAG_PCIE_MODE;
@@ -113,7 +103,6 @@
 	kfree(diag_mux);
 }
 
-#ifdef CONFIG_DIAG_OVER_PCIE
 int diag_pcie_register_ops(int proc, int ctx, struct diag_mux_ops *ops)
 {
 	int err = 0;
@@ -127,22 +116,13 @@
 	pcie_logger.ops[proc] = ops;
 	err = diag_pcie_register(proc, ctx, ops);
 	if (err) {
-		driver->transport_set = DIAG_ROUTE_TO_USB;
-		diag_mux->logger = &usb_logger;
-		diag_mux->mode = DIAG_USB_MODE;
-		usb_logger.ops[proc] = ops;
-		err = diag_usb_register(proc, ctx, ops);
-		if (err) {
-			pr_err("diag: MUX: unable to register usb operations for proc: %d, err: %d\n",
-					   proc, err);
-			return err;
-		}
 		pr_err("diag: MUX: unable to register pcie operations for proc: %d, err: %d\n",
 			proc, err);
+		return err;
 	}
 	return 0;
 }
-#else
+
 int diag_usb_register_ops(int proc, int ctx, struct diag_mux_ops *ops)
 {
 	int err = 0;
@@ -161,7 +141,6 @@
 	}
 	return 0;
 }
-#endif
 
 int diag_mux_register(int proc, int ctx, struct diag_mux_ops *ops)
 {
@@ -172,9 +151,17 @@
 
 	if (proc < 0 || proc >= NUM_MUX_PROC)
 		return 0;
-	err = diag_mux_register_ops(proc, ctx, ops);
-	if (err)
+	err = diag_pcie_register_ops(proc, ctx, ops);
+	if (err) {
+		pr_err("diag: MUX: unable to register PCIe operations, continuing with USB registrations for proc: %d, err: %d\n",
+		proc, err);
+	}
+	err = diag_usb_register_ops(proc, ctx, ops);
+	if (err) {
+		pr_err("diag: MUX: unable to register USB operations for proc: %d, err: %d\n",
+		proc, err);
 		return err;
+	}
 	md_logger.ops[proc] = ops;
 	err = diag_md_register(proc, ctx, ops);
 	if (err) {
@@ -182,7 +169,6 @@
 		       proc, err);
 		return err;
 	}
-
 	return 0;
 }
 
@@ -308,6 +294,10 @@
 			diag_mux->pcie_ptr->log_ops->close();
 			diag_mux->logger = diag_mux->md_ptr;
 			diag_mux->md_ptr->log_ops->open();
+		} else if (*req_mode == DIAG_USB_MODE) {
+			diag_mux->pcie_ptr->log_ops->close();
+			diag_mux->logger = diag_mux->usb_ptr;
+			diag_mux->usb_ptr->log_ops->open();
 		} else if (*req_mode == DIAG_MULTI_MODE) {
 			diag_mux->md_ptr->log_ops->open();
 			diag_mux->logger = NULL;
@@ -318,6 +308,10 @@
 			diag_mux->usb_ptr->log_ops->close();
 			diag_mux->logger = diag_mux->md_ptr;
 			diag_mux->md_ptr->log_ops->open();
+		} else if (*req_mode == DIAG_PCIE_MODE) {
+			diag_mux->usb_ptr->log_ops->close();
+			diag_mux->logger = diag_mux->pcie_ptr;
+			diag_mux->pcie_ptr->log_ops->open();
 		} else if (*req_mode == DIAG_MULTI_MODE) {
 			diag_mux->md_ptr->log_ops->open();
 			diag_mux->logger = NULL;
@@ -333,7 +327,8 @@
 			diag_mux->logger = diag_mux->pcie_ptr;
 			diag_mux->pcie_ptr->log_ops->open();
 		} else if (*req_mode == DIAG_MULTI_MODE) {
-			if (driver->transport_set == DIAG_ROUTE_TO_PCIE)
+			if (driver->pcie_transport_def == DIAG_ROUTE_TO_PCIE ||
+				driver->transport_set == DIAG_ROUTE_TO_PCIE)
 				diag_mux->pcie_ptr->log_ops->open();
 			else
 				diag_mux->usb_ptr->log_ops->open();
diff --git a/drivers/char/diag/diag_mux.h b/drivers/char/diag/diag_mux.h
index dac08b3..c822f71 100644
--- a/drivers/char/diag/diag_mux.h
+++ b/drivers/char/diag/diag_mux.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, 2018 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, 2018-2019, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -77,5 +77,4 @@
 int diag_mux_switch_logging(int *new_mode, int *peripheral_mask);
 int diag_pcie_register_ops(int proc, int ctx, struct diag_mux_ops *ops);
 int diag_usb_register_ops(int proc, int ctx, struct diag_mux_ops *ops);
-int diag_mux_register_ops(int proc, int ctx, struct diag_mux_ops *ops);
 #endif
diff --git a/drivers/char/diag/diag_pcie.c b/drivers/char/diag/diag_pcie.c
index 8f53573..bf048c1 100644
--- a/drivers/char/diag/diag_pcie.c
+++ b/drivers/char/diag/diag_pcie.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -85,6 +85,7 @@
 	ureq.mode = IPA_DMA_SYNC;
 	ureq.buf = pcie_info->in_chan_attr.read_buffer;
 	ureq.len = pcie_info->in_chan_attr.read_buffer_size;
+	ureq.transfer_len = 0;
 	bytes_avail = mhi_dev_read_channel(&ureq);
 	if (bytes_avail < 0)
 		return;
@@ -319,7 +320,7 @@
 	pcie_info = &diag_pcie[id];
 
 	if (len > pcie_info->out_chan_attr.max_pkt_size) {
-		DIAG_LOG(DIAG_DEBUG_MUX, "len: %d, max_size: %d\n",
+		DIAG_LOG(DIAG_DEBUG_MUX, "len: %d, max_size: %zu\n",
 			 len, pcie_info->out_chan_attr.max_pkt_size);
 		return diag_pcie_write_ext(pcie_info, buf, len, ctxt);
 	}
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 2e87d51..31a8c3b 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -595,6 +595,7 @@
 	uint32_t cmd_reg_count;
 	struct mutex diagfwd_channel_mutex[NUM_PERIPHERALS];
 	int transport_set;
+	int pcie_transport_def;
 	/* Sizes that reflect memory pool sizes */
 	unsigned int poolsize;
 	unsigned int poolsize_hdlc;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index cb04195..2fc6c58 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -454,8 +454,19 @@
 	session_info = diag_md_session_get_pid(pid);
 	if (!session_info) {
 		mutex_unlock(&driver->md_session_lock);
+		if (driver->pcie_transport_def == DIAG_ROUTE_TO_PCIE)
+			params.req_mode = PCIE_MODE;
+		else
+			params.req_mode = USB_MODE;
+		params.mode_param = 0;
+		params.pd_mask = 0;
+		params.peripheral_mask = DIAG_CON_ALL;
+		mutex_lock(&driver->diagchar_mutex);
+		diag_switch_logging(&params);
+		mutex_unlock(&driver->diagchar_mutex);
 		return;
 	}
+
 	session_mask = session_info->peripheral_mask;
 	mutex_unlock(&driver->md_session_lock);
 
@@ -469,10 +480,12 @@
 	for (i = 0; i < NUM_MD_SESSIONS; i++)
 		if (MD_PERIPHERAL_MASK(i) & session_mask)
 			diag_mux_close_peripheral(DIAG_LOCAL_PROC, i);
+
 	if (driver->transport_set == DIAG_ROUTE_TO_PCIE)
 		params.req_mode = PCIE_MODE;
 	else
 		params.req_mode = USB_MODE;
+
 	params.mode_param = 0;
 	params.pd_mask = 0;
 	params.peripheral_mask = p_mask;
@@ -1554,10 +1567,15 @@
 		req_mode != DIAG_PCIE_MODE)
 		return -EINVAL;
 
-	if (req_mode == DIAG_USB_MODE || req_mode == DIAG_PCIE_MODE) {
-		if (curr_mode == req_mode)
-			return 0;
+	if (curr_mode == req_mode)
+		return 0;
 
+	if ((req_mode ==  DIAG_USB_MODE && curr_mode == DIAG_PCIE_MODE) ||
+		(req_mode == DIAG_PCIE_MODE && curr_mode == DIAG_USB_MODE)) {
+		*change_mode = 1;
+		return 0;
+	} else if ((req_mode == DIAG_USB_MODE || req_mode == DIAG_PCIE_MODE)
+		&& curr_mode == DIAG_MEMORY_DEVICE_MODE) {
 		mutex_lock(&driver->md_session_lock);
 		if (driver->md_session_mode == DIAG_MD_NONE
 		    && driver->md_session_mask == 0 && driver->logging_mask) {
@@ -1607,7 +1625,7 @@
 		/* If all peripherals are being set to USB Mode, call close */
 		if (~change_mask & peripheral_mask) {
 			err = diag_md_peripheral_switch(current->tgid,
-					change_mask, DIAG_USB_MODE);
+					change_mask, req_mode);
 		} else
 			diag_md_session_close(current->tgid);
 		mutex_unlock(&driver->md_session_lock);
@@ -1631,7 +1649,7 @@
 				mutex_unlock(&driver->md_session_lock);
 				return -EINVAL;
 			}
-			if (driver->transport_set == DIAG_ROUTE_TO_PCIE)
+			if (driver->pcie_transport_def == DIAG_ROUTE_TO_PCIE)
 				err = diag_md_peripheral_switch(current->tgid,
 					change_mask, DIAG_PCIE_MODE);
 			else
@@ -1865,6 +1883,15 @@
 	}
 	driver->logging_mode = new_mode;
 	driver->logging_mask = peripheral_mask;
+	if (new_mode == DIAG_PCIE_MODE) {
+		driver->transport_set = DIAG_ROUTE_TO_PCIE;
+		diagmem_setsize(POOL_TYPE_MUX_APPS, itemsize_pcie_apps,
+			poolsize_pcie_apps + 1 + (NUM_PERIPHERALS * 6));
+	} else if (new_mode == DIAG_USB_MODE) {
+		driver->transport_set = DIAG_ROUTE_TO_USB;
+		diagmem_setsize(POOL_TYPE_MUX_APPS, itemsize_usb_apps,
+			poolsize_usb_apps + 1 + (NUM_PERIPHERALS * 6));
+	}
 	DIAG_LOG(DIAG_DEBUG_USERSPACE,
 		"Switch logging to %d mask:%0x\n", new_mode, peripheral_mask);
 
@@ -3952,6 +3979,39 @@
 	return 0;
 }
 
+#ifdef CONFIG_DIAG_OVER_PCIE
+static void diag_init_transport(void)
+{
+	driver->transport_set = DIAG_ROUTE_TO_PCIE;
+	driver->pcie_transport_def = DIAG_ROUTE_TO_PCIE;
+	driver->logging_mode = DIAG_PCIE_MODE;
+	/*
+	 * POOL_TYPE_MUX_APPS is for the buffers in the Diag MUX layer.
+	 * The number of buffers encompasses Diag data generated on
+	 * the Apss processor + 1 for the responses generated
+	 * exclusively on the Apps processor + data from data channels
+	 *(4 channels periperipheral) + data from command channels (2)
+	 */
+	diagmem_setsize(POOL_TYPE_MUX_APPS, itemsize_pcie_apps,
+		poolsize_pcie_apps + 1 + (NUM_PERIPHERALS * 6));
+}
+#else
+static void diag_init_transport(void)
+{
+	driver->transport_set = DIAG_ROUTE_TO_USB;
+	driver->pcie_transport_def = DIAG_ROUTE_TO_USB;
+	driver->logging_mode = DIAG_USB_MODE;
+	/*
+	 * POOL_TYPE_MUX_APPS is for the buffers in the Diag MUX layer.
+	 * The number of buffers encompasses Diag data generated on
+	 * the Apss processor + 1 for the responses generated
+	 * exclusively on the Apps processor + data from data channels
+	 *(4 channels periperipheral) + data from command channels (2)
+	 */
+	diagmem_setsize(POOL_TYPE_MUX_APPS, itemsize_usb_apps,
+		poolsize_usb_apps + 1 + (NUM_PERIPHERALS * 6));
+}
+#endif
 static int __init diagchar_init(void)
 {
 	dev_t dev;
@@ -3965,11 +4025,7 @@
 	kmemleak_not_leak(driver);
 
 	timer_in_progress = 0;
-#ifdef CONFIG_DIAG_OVER_PCIE
-	driver->transport_set = DIAG_ROUTE_TO_PCIE;
-#else
-	driver->transport_set = DIAG_ROUTE_TO_USB;
-#endif
+	diag_init_transport();
 	DIAG_LOG(DIAG_DEBUG_MUX, "Transport type set to %d\n",
 		driver->transport_set);
 	driver->delayed_rsp_id = 0;
@@ -3984,22 +4040,6 @@
 	driver->poolsize_dci = poolsize_dci;
 	driver->poolsize_user = poolsize_user;
 	driver->num_clients = max_clients;
-	if (driver->transport_set == DIAG_ROUTE_TO_PCIE) {
-		driver->logging_mode = DIAG_PCIE_MODE;
-		/*
-		 * POOL_TYPE_MUX_APPS is for the buffers in the Diag MUX layer.
-		 * The number of buffers encompasses Diag data generated on
-		 * the Apss processor + 1 for the responses generated
-		 * exclusively on the Apps processor + data from data channels
-		 *(4 channels periperipheral) + data from command channels (2)
-		 */
-		diagmem_setsize(POOL_TYPE_MUX_APPS, itemsize_pcie_apps,
-			poolsize_pcie_apps + 1 + (NUM_PERIPHERALS * 6));
-	} else {
-		driver->logging_mode = DIAG_USB_MODE;
-		diagmem_setsize(POOL_TYPE_MUX_APPS, itemsize_usb_apps,
-			poolsize_usb_apps + 1 + (NUM_PERIPHERALS * 6));
-	}
 
 	for (i = 0; i < NUM_UPD; i++) {
 		driver->pd_logging_mode[i] = 0;