From cc2f14c1fb9acc74247a4fc2130e7bfcf10fc118 Mon Sep 17 00:00:00 2001
From: Mayank Rana <mrana@codeaurora.org>
Date: Thu, 26 Jun 2014 14:49:18 -0700
Subject: [PATCH] USB: IPA: RNDIS: Add both device and host side parameters

RNDIS IPA driver requires both host and device side different
parameters like max transfer size, number of packets and aggregation
status. This change provides these information to IPA driver by using
RNDIS initialization protocol.

CRs-Fixed: 679074
Change-Id: Ic755d61db79c093d5540a28276b9b428c5ffad92
Signed-off-by: Ravi Gummadidala <rgummadi@codeaurora.org>
Signed-off-by: Mayank Rana <mrana@codeaurora.org>
---
 drivers/net/ethernet/msm/rndis_ipa.c | 46 ++++++++++++++-----------
 drivers/usb/gadget/f_qc_rndis.c      | 28 ++++++++-------
 drivers/usb/gadget/rndis.c           | 27 ++++++++++++++-
 drivers/usb/gadget/rndis.h           |  6 ++++
 drivers/usb/gadget/u_bam_data.c      | 51 +++++++++++++++++++++++-----
 drivers/usb/gadget/u_bam_data.h      |  6 ++--
 include/linux/rndis_ipa.h            | 10 +++---
 7 files changed, 126 insertions(+), 48 deletions(-)

diff --git a/drivers/net/ethernet/msm/rndis_ipa.c b/drivers/net/ethernet/msm/rndis_ipa.c
index eab8360b4312..d327006f71b5 100644
--- a/drivers/net/ethernet/msm/rndis_ipa.c
+++ b/drivers/net/ethernet/msm/rndis_ipa.c
@@ -302,8 +302,8 @@ static void rndis_ipa_dump_skb(struct sk_buff *skb);
 static int rndis_ipa_debugfs_init(struct rndis_ipa_dev *rndis_ipa_ctx);
 static void rndis_ipa_debugfs_destroy(struct rndis_ipa_dev *rndis_ipa_ctx);
 static int rndis_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl,
-		u32 ipa_to_usb_hdl, u32 max_transfer_size,
-		u32 max_packet_number, u32 mtu,
+		u32 ipa_to_usb_hdl, u32 max_xfer_size_bytes_to_dev,
+		u32 max_xfer_size_bytes_to_host, u32 mtu,
 		bool deaggr_enable);
 static int rndis_ipa_set_device_ethernet_addr(u8 *dev_ethaddr,
 		u8 device_ethaddr[]);
@@ -698,8 +698,9 @@ EXPORT_SYMBOL(rndis_ipa_init);
  */
 int rndis_ipa_pipe_connect_notify(u32 usb_to_ipa_hdl,
 			u32 ipa_to_usb_hdl,
-			u32 max_transfer_byte_size,
-			u32 max_packet_number,
+			u32 max_xfer_size_bytes_to_dev,
+			u32 max_packet_number_to_dev,
+			u32 max_xfer_size_bytes_to_host,
 			void *private)
 {
 	struct rndis_ipa_dev *rndis_ipa_ctx = private;
@@ -712,8 +713,11 @@ int rndis_ipa_pipe_connect_notify(u32 usb_to_ipa_hdl,
 
 	RNDIS_IPA_DEBUG("usb_to_ipa_hdl=%d, ipa_to_usb_hdl=%d, private=0x%p\n",
 				usb_to_ipa_hdl, ipa_to_usb_hdl, private);
-	RNDIS_IPA_DEBUG("max_xfer_sz=%d, max_pkt_num=%d\n",
-			max_transfer_byte_size, max_packet_number);
+	RNDIS_IPA_DEBUG("max_xfer_sz_to_dev=%d, max_pkt_num_to_dev=%d\n",
+			max_xfer_size_bytes_to_dev,
+			max_packet_number_to_dev);
+	RNDIS_IPA_DEBUG("max_xfer_sz_to_host=%d\n",
+			max_xfer_size_bytes_to_host);
 
 	next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
 		RNDIS_IPA_CONNECT);
@@ -734,10 +738,14 @@ int rndis_ipa_pipe_connect_notify(u32 usb_to_ipa_hdl,
 	}
 	rndis_ipa_ctx->ipa_to_usb_hdl = ipa_to_usb_hdl;
 	rndis_ipa_ctx->usb_to_ipa_hdl = usb_to_ipa_hdl;
+	if (max_packet_number_to_dev > 1)
+		rndis_ipa_ctx->deaggregation_enable = true;
+	else
+		rndis_ipa_ctx->deaggregation_enable = false;
 	result = rndis_ipa_ep_registers_cfg(usb_to_ipa_hdl,
 			ipa_to_usb_hdl,
-			max_transfer_byte_size,
-			max_packet_number,
+			max_xfer_size_bytes_to_dev,
+			max_xfer_size_bytes_to_host,
 			rndis_ipa_ctx->net->mtu,
 			rndis_ipa_ctx->deaggregation_enable);
 	if (result) {
@@ -1876,12 +1884,10 @@ static bool rm_enabled(struct rndis_ipa_dev *rndis_ipa_ctx)
  *  the USB to IPA end-point
  * @ipa_to_usb_hdl: handle received from ipa_connect which represents
  *  the IPA to USB end-point
- * @max_transfer_byte_size: the maximum size, in bytes, that the device
+ * @max_xfer_size_bytes_to_dev: the maximum size, in bytes, that the device
  *  expects to receive from the host. supplied on REMOTE_NDIS_INITIALIZE_CMPLT.
- * @max_packet_number: The maximum number of
- * concatenated REMOTE_NDIS_PACKET_MSG messages that the device can handle
- * in a single bus transfer to it.
- * This value MUST be at least 1.
+ * @max_xfer_size_bytes_to_host: the maximum size, in bytes, that the host
+ *  expects to receive from the device. supplied on REMOTE_NDIS_INITIALIZE_MSG.
  * @mtu: the netdev MTU size, in bytes
  *
  * USB to IPA pipe:
@@ -1897,8 +1903,8 @@ static bool rm_enabled(struct rndis_ipa_dev *rndis_ipa_ctx)
  */
 static int rndis_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl,
 		u32 ipa_to_usb_hdl,
-		u32 max_transfer_byte_size,
-		u32 max_packet_number,
+		u32 max_xfer_size_bytes_to_dev,
+		u32 max_xfer_size_bytes_to_host,
 		u32 mtu,
 		bool deaggr_enable)
 {
@@ -1913,7 +1919,7 @@ static int rndis_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl,
 		RNDIS_IPA_DEBUG("deaggregation disabled\n");
 	}
 
-	usb_to_ipa_ep_cfg->deaggr.max_packet_len = max_transfer_byte_size;
+	usb_to_ipa_ep_cfg->deaggr.max_packet_len = max_xfer_size_bytes_to_dev;
 	result = ipa_cfg_ep(usb_to_ipa_hdl, usb_to_ipa_ep_cfg);
 	if (result) {
 		pr_err("failed to configure USB to IPA point\n");
@@ -1921,9 +1927,9 @@ static int rndis_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl,
 	}
 	RNDIS_IPA_DEBUG("IPA<-USB end-point configured\n");
 
-	ipa_to_usb_ep_cfg.aggr.aggr_pkt_limit = max_packet_number;
+	ipa_to_usb_ep_cfg.aggr.aggr_pkt_limit = 0;
 	ipa_to_usb_ep_cfg.aggr.aggr_byte_limit =
-		(max_transfer_byte_size - mtu)/1024;
+		(max_xfer_size_bytes_to_host - mtu)/1024;
 	result = ipa_cfg_ep(ipa_to_usb_hdl, &ipa_to_usb_ep_cfg);
 	if (result) {
 		pr_err("failed to configure IPA to USB end-point\n");
@@ -2676,8 +2682,10 @@ static int rndis_ipa_setup_loopback(bool enable,
 	retval = rndis_ipa_pipe_connect_notify(
 			rndis_ipa_ctx->usb_to_ipa_loopback_pipe.ipa_drv_ep_hdl,
 			rndis_ipa_ctx->ipa_to_usb_loopback_pipe.ipa_drv_ep_hdl,
+			BAM_DMA_DATA_FIFO_SIZE,
+			15,
 			BAM_DMA_DATA_FIFO_SIZE - rndis_ipa_ctx->net->mtu,
-			15, rndis_ipa_ctx);
+			rndis_ipa_ctx);
 	if (retval) {
 		RNDIS_IPA_ERROR("connect notify fail");
 		return -ENODEV;
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index 7bdbfed79e2d..7f9a90f3e7a7 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -85,7 +85,7 @@ struct f_rndis_qc {
 	u8				ctrl_id, data_id;
 	u8				ethaddr[ETH_ALEN];
 	u32				vendorID;
-	u8				max_pkt_per_xfer;
+	u8				ul_max_pkt_per_xfer;
 	u8				pkt_alignment_factor;
 	u32				max_pkt_size;
 	const char			*manufacturer;
@@ -587,6 +587,7 @@ static void rndis_qc_command_complete(struct usb_ep *ep,
 	struct f_rndis_qc		*rndis = req->context;
 	int				status;
 	rndis_init_msg_type		*buf;
+	u32		ul_max_xfer_size, dl_max_xfer_size;
 
 	/* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
 	status = rndis_msg_parser(rndis->config, (u8 *) req->buf);
@@ -597,9 +598,10 @@ static void rndis_qc_command_complete(struct usb_ep *ep,
 	buf = (rndis_init_msg_type *)req->buf;
 
 	if (buf->MessageType == RNDIS_MSG_INIT) {
-		rndis->max_pkt_size = buf->MaxTransferSize;
-		pr_debug("MaxTransferSize: %d\n", buf->MaxTransferSize);
-		u_bam_data_set_max_xfer_size(rndis->max_pkt_size);
+		ul_max_xfer_size = rndis_get_ul_max_xfer_size(rndis->config);
+		u_bam_data_set_ul_max_xfer_size(ul_max_xfer_size);
+		dl_max_xfer_size = rndis_get_dl_max_xfer_size(rndis->config);
+		u_bam_data_set_dl_max_xfer_size(dl_max_xfer_size);
 	}
 }
 
@@ -968,8 +970,8 @@ rndis_qc_bind(struct usb_configuration *c, struct usb_function *f)
 		goto fail;
 
 	pr_debug("%s(): max_pkt_per_xfer:%d\n", __func__,
-				rndis->max_pkt_per_xfer);
-	rndis_set_max_pkt_xfer(rndis->config, rndis->max_pkt_per_xfer);
+				rndis->ul_max_pkt_per_xfer);
+	rndis_set_max_pkt_xfer(rndis->config, rndis->ul_max_pkt_per_xfer);
 
 	/* In case of aggregated packets QC device will request
 	 * aliment to 4 (2^2).
@@ -1178,10 +1180,10 @@ rndis_qc_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
 	rndis->manufacturer = manufacturer;
 
 	/* if max_pkt_per_xfer was not configured set to default value */
-	rndis->max_pkt_per_xfer =
+	rndis->ul_max_pkt_per_xfer =
 			max_pkt_per_xfer ? max_pkt_per_xfer :
 			DEFAULT_MAX_PKT_PER_XFER;
-	u_bam_data_set_max_pkt_num(rndis->max_pkt_per_xfer);
+	u_bam_data_set_ul_max_pkt_num(rndis->ul_max_pkt_per_xfer);
 
 	/*
 	 * Check no RNDIS aggregation, and alignment if not mentioned,
@@ -1193,7 +1195,7 @@ rndis_qc_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
 	 * those values will always override default values.
 	 */
 	if ((rndis->pkt_alignment_factor == 0) &&
-			(rndis->max_pkt_per_xfer == 1))
+			(rndis->ul_max_pkt_per_xfer == 1))
 		rndis->pkt_alignment_factor = 0;
 	else
 		rndis->pkt_alignment_factor = pkt_alignment_factor ?
@@ -1288,14 +1290,14 @@ static long rndis_qc_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
 	switch (cmd) {
 	case RNDIS_QC_GET_MAX_PKT_PER_XFER:
 		ret = copy_to_user((void __user *)arg,
-					&rndis->max_pkt_per_xfer,
-					sizeof(rndis->max_pkt_per_xfer));
+					&rndis->ul_max_pkt_per_xfer,
+					sizeof(rndis->ul_max_pkt_per_xfer));
 		if (ret) {
 			pr_err("copying to user space failed\n");
 			ret = -EFAULT;
 		}
-		pr_info("Sent max packets per xfer %d\n",
-				rndis->max_pkt_per_xfer);
+		pr_info("Sent UL max packets per xfer %d\n",
+				rndis->ul_max_pkt_per_xfer);
 		break;
 	case RNDIS_QC_GET_MAX_PKT_SIZE:
 		ret = copy_to_user((void __user *)arg,
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 4880d1c2df4f..d6d4aa3b5ef9 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -615,6 +615,7 @@ static int rndis_init_response(int configNr, rndis_init_msg_type *buf)
 	resp->AFListOffset = cpu_to_le32(0);
 	resp->AFListSize = cpu_to_le32(0);
 
+	params->ul_max_xfer_size = le32_to_cpu(resp->MaxTransferSize);
 	params->resp_avail(params->v);
 	return 0;
 }
@@ -820,7 +821,7 @@ void rndis_set_host_mac(int configNr, const u8 *addr)
  */
 int rndis_msg_parser(u8 configNr, u8 *buf)
 {
-	u32 MsgType, MsgLength;
+	u32 MsgType, MsgLength, major, minor, max_transfer_size;
 	__le32 *tmp;
 	struct rndis_params *params;
 
@@ -845,6 +846,19 @@ int rndis_msg_parser(u8 configNr, u8 *buf)
 	case RNDIS_MSG_INIT:
 		pr_debug("%s: RNDIS_MSG_INIT\n",
 			__func__);
+		tmp++; /* to get RequestID */
+		major = get_unaligned_le32(tmp++);
+		minor = get_unaligned_le32(tmp++);
+		max_transfer_size = get_unaligned_le32(tmp++);
+
+		params->host_rndis_major_ver = major;
+		params->host_rndis_minor_ver = minor;
+		params->dl_max_xfer_size = max_transfer_size;
+
+		pr_debug("%s(): RNDIS Host Major:%d Minor:%d version\n",
+					__func__, major, minor);
+		pr_debug("%s(): UL Max Transfer size:%x\n", __func__,
+					max_transfer_size);
 		params->state = RNDIS_INITIALIZED;
 		return rndis_init_response(configNr,
 					(rndis_init_msg_type *)buf);
@@ -967,6 +981,17 @@ int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed)
 
 	return 0;
 }
+u32 rndis_get_dl_max_xfer_size(u8 configNr)
+{
+	pr_debug("%s:\n", __func__);
+	return rndis_per_dev_params[configNr].dl_max_xfer_size;
+}
+
+u32 rndis_get_ul_max_xfer_size(u8 configNr)
+{
+	pr_debug("%s:\n", __func__);
+	return rndis_per_dev_params[configNr].ul_max_xfer_size;
+}
 
 void rndis_set_max_pkt_xfer(u8 configNr, u8 max_pkt_per_xfer)
 {
diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h
index 92b9c0db31ae..f0133803aa51 100644
--- a/drivers/usb/gadget/rndis.h
+++ b/drivers/usb/gadget/rndis.h
@@ -196,6 +196,10 @@ typedef struct rndis_params
 	void			*v;
 	struct list_head	resp_queue;
 	spinlock_t		lock;
+	u32			host_rndis_major_ver;
+	u32			host_rndis_minor_ver;
+	u32			ul_max_xfer_size;
+	u32			dl_max_xfer_size;
 } rndis_params;
 
 /* RNDIS Message parser and other useless functions */
@@ -208,6 +212,8 @@ int  rndis_set_param_vendor (u8 configNr, u32 vendorID,
 			    const char *vendorDescr);
 int  rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
 void rndis_set_max_pkt_xfer(u8 configNr, u8 max_pkt_per_xfer);
+u32  rndis_get_ul_max_xfer_size(u8 configNr);
+u32  rndis_get_dl_max_xfer_size(u8 configNr);
 void rndis_add_hdr (struct sk_buff *skb);
 int rndis_rm_hdr(struct gether *port, struct sk_buff *skb,
 			struct sk_buff_head *list);
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index efb5b9bff3df..8fc2c561cb73 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -58,8 +58,12 @@ module_param(bam_data_mux_rx_req_size, uint, S_IRUGO | S_IWUSR);
 #define MSM_VENDOR_ID			BIT(16)
 
 struct rndis_data_ch_info {
-	u32 max_transfer_size;
-	u32 max_packets_number;
+	/* this provides downlink (device->host i.e host) side configuration*/
+	u32 dl_max_transfer_size;
+	/* this provides uplink (host->device i.e device) side configuration */
+	u32 ul_max_transfer_size;
+	u32 ul_max_packets_number;
+	bool ul_aggregation_enable;
 	u32 prod_clnt_hdl;
 	u32 cons_clnt_hdl;
 	void *priv;
@@ -992,11 +996,19 @@ static void bam2bam_data_connect_work(struct work_struct *w)
 				d->ipa_params.cons_clnt_hdl;
 			rndis_data.priv = d->ipa_params.priv;
 
+			pr_debug("ul_max_transfer_size:%d\n",
+					rndis_data.ul_max_transfer_size);
+			pr_debug("ul_max_packets_number:%d\n",
+					rndis_data.ul_max_packets_number);
+			pr_debug("dl_max_transfer_size:%d\n",
+					rndis_data.dl_max_transfer_size);
+
 			ret = rndis_ipa_pipe_connect_notify(
 				rndis_data.cons_clnt_hdl,
 				rndis_data.prod_clnt_hdl,
-				rndis_data.max_transfer_size,
-				rndis_data.max_packets_number,
+				rndis_data.ul_max_transfer_size,
+				rndis_data.ul_max_packets_number,
+				rndis_data.dl_max_transfer_size,
 				rndis_data.priv);
 			if (ret) {
 				pr_err("%s: failed to connect IPA: err:%d\n",
@@ -1650,17 +1662,18 @@ static void bam2bam_data_resume_work(struct work_struct *w)
 	}
 }
 
-void u_bam_data_set_max_xfer_size(u32 max_transfer_size)
+void u_bam_data_set_dl_max_xfer_size(u32 max_transfer_size)
 {
+
 	if (!max_transfer_size) {
 		pr_err("%s: invalid parameters\n", __func__);
 		return;
 	}
-
-	rndis_data.max_transfer_size = max_transfer_size;
+	rndis_data.dl_max_transfer_size = max_transfer_size;
+	pr_debug("%s(): dl_max_xfer_size:%d\n", __func__, max_transfer_size);
 }
 
-void u_bam_data_set_max_pkt_num(u32 max_packets_number)
+void u_bam_data_set_ul_max_pkt_num(u8 max_packets_number)
 
 {
 	if (!max_packets_number) {
@@ -1668,5 +1681,25 @@ void u_bam_data_set_max_pkt_num(u32 max_packets_number)
 		return;
 	}
 
-	rndis_data.max_packets_number = max_packets_number;
+	rndis_data.ul_max_packets_number = max_packets_number;
+
+	if (max_packets_number > 1)
+		rndis_data.ul_aggregation_enable = true;
+	else
+		rndis_data.ul_aggregation_enable = false;
+
+	pr_debug("%s(): ul_aggregation enable:%d\n", __func__,
+				rndis_data.ul_aggregation_enable);
+	pr_debug("%s(): ul_max_packets_number:%d\n", __func__,
+				max_packets_number);
+}
+
+void u_bam_data_set_ul_max_xfer_size(u32 max_transfer_size)
+{
+	if (!max_transfer_size) {
+		pr_err("%s: invalid parameters\n", __func__);
+		return;
+	}
+	rndis_data.ul_max_transfer_size = max_transfer_size;
+	pr_debug("%s(): ul_max_xfer_size:%d\n", __func__, max_transfer_size);
 }
diff --git a/drivers/usb/gadget/u_bam_data.h b/drivers/usb/gadget/u_bam_data.h
index 81784a33f5a1..9d0d8a9ce222 100644
--- a/drivers/usb/gadget/u_bam_data.h
+++ b/drivers/usb/gadget/u_bam_data.h
@@ -47,9 +47,11 @@ void bam_data_suspend(u8 port_num);
 
 void bam_data_resume(u8 port_num);
 
-void u_bam_data_set_max_xfer_size(u32 max_transfer_size);
+void u_bam_data_set_dl_max_xfer_size(u32 dl_max_transfer_size);
 
-void u_bam_data_set_max_pkt_num(u32 max_packets_number);
+void u_bam_data_set_ul_max_pkt_num(u8 ul_max_packets_number);
+
+void u_bam_data_set_ul_max_xfer_size(u32 ul_max_xfer_size);
 
 void u_bam_data_start_rndis_ipa(void);
 
diff --git a/include/linux/rndis_ipa.h b/include/linux/rndis_ipa.h
index eeae1d38fe30..14cce939d485 100644
--- a/include/linux/rndis_ipa.h
+++ b/include/linux/rndis_ipa.h
@@ -62,8 +62,9 @@ int rndis_ipa_init(struct ipa_usb_init_params *params);
 
 int rndis_ipa_pipe_connect_notify(u32 usb_to_ipa_hdl,
 			u32 ipa_to_usb_hdl,
-			u32 max_transfer_size,
-			u32 max_packet_number,
+			u32 max_xfer_size_bytes_to_dev,
+			u32 max_packet_number_to_dev,
+			u32 max_xfer_size_bytes_to_host,
 			void *private);
 
 int rndis_ipa_pipe_disconnect_notify(void *private);
@@ -79,8 +80,9 @@ int rndis_ipa_init(struct ipa_usb_init_params *params)
 
 int rndis_ipa_pipe_connect_notify(u32 usb_to_ipa_hdl,
 			u32 ipa_to_usb_hdl,
-			u32 max_transfer_size,
-			u32 max_packet_number,
+			u32 max_xfer_size_bytes_to_dev,
+			u32 max_packet_number_to_dev,
+			u32 max_xfer_size_bytes_to_host,
 			void *private)
 {
 	return 0;
-- 
GitLab