net: rmnet_usb: Add support for aligned QOS header

When QOS is enabled, QOS header of 6 bytes appended to
the network packet.This is making the network packet buffer unaligned.
USB hardware has some penalty with dealing the unaligned buffers Due to
this Bi-Direction throughput is dropped.

Introduce a new QOS header of size 8 bytes. Add a new ioctl to know
which QOS header need to be used.

CRs-Fixed: 583165
Change-Id: I11bb56d2dbbc1262345e091241dcf6f681643e84
Signed-off-by: ChandanaKishori Chiluveru <cchilu@codeaurora.org>
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
index 8e23b4f..928c0c1 100644
--- a/drivers/net/usb/rmnet_usb_data.c
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -25,8 +25,8 @@
 
 #define RMNET_DATA_LEN			2000
 #define RMNET_HEADROOM_W_MUX		(sizeof(struct mux_hdr) + \
-					sizeof(struct QMI_QOS_HDR_S))
-#define RMNET_HEADROOM			sizeof(struct QMI_QOS_HDR_S)
+					sizeof(struct QMI_QOS_ALIGNED_HDR_S))
+#define RMNET_HEADROOM			sizeof(struct QMI_QOS_ALIGNED_HDR_S)
 #define RMNET_TAILROOM			MAX_PAD_BYTES(4);
 
 static unsigned int no_rmnet_devs = 1;
@@ -360,8 +360,13 @@
 	struct QMI_QOS_HDR_S	*qmih;
 
 	if (test_bit(RMNET_MODE_QOS, &dev->data[0])) {
-		qmih = (struct QMI_QOS_HDR_S *)
-		skb_push(skb, sizeof(struct QMI_QOS_HDR_S));
+		if (test_bit(RMNET_MODE_ALIGNED_QOS, &dev->data[0])) {
+			qmih = (struct QMI_QOS_HDR_S *)
+			skb_push(skb, sizeof(struct QMI_QOS_ALIGNED_HDR_S));
+		} else {
+			qmih = (struct QMI_QOS_HDR_S *)
+			skb_push(skb, sizeof(struct QMI_QOS_HDR_S));
+		}
 		qmih->version = 1;
 		qmih->flags = 0;
 		qmih->flow_id = skb->mark;
@@ -538,6 +543,12 @@
 						| RMNET_MODE_LLP_IP));
 		break;
 
+	case RMNET_IOCTL_SET_ALIGNED_QOS_ENABLE:  /* Set QoS Aligned header */
+		set_bit(RMNET_MODE_ALIGNED_QOS, &unet->data[0]);
+		DBG0("[%s] rmnet_ioctl(): set QMI QOS Aligned header enable\n",
+				dev->name);
+		break;
+
 	case RMNET_IOCTL_SET_QOS_ENABLE:	/* Set QoS header enabled*/
 		set_bit(RMNET_MODE_QOS, &unet->data[0]);
 		DBG0("[%s] rmnet_ioctl(): set QMI QOS header enable\n",
diff --git a/include/linux/msm_rmnet.h b/include/linux/msm_rmnet.h
index 01d52b6..03e6e1e 100644
--- a/include/linux/msm_rmnet.h
+++ b/include/linux/msm_rmnet.h
@@ -19,6 +19,7 @@
 #define RMNET_MODE_LLP_ETH  (0x01)
 #define RMNET_MODE_LLP_IP   (0x02)
 #define RMNET_MODE_QOS      (0x04)
+#define RMNET_MODE_ALIGNED_QOS      (0x08)
 #define RMNET_MODE_MASK     (RMNET_MODE_LLP_ETH | \
 			     RMNET_MODE_LLP_IP  | \
 			     RMNET_MODE_QOS)
@@ -42,6 +43,7 @@
 	RMNET_IOCTL_CLOSE            = 0x000089F9, /* Close transport port   */
 	RMNET_IOCTL_FLOW_ENABLE	     = 0x000089FA, /* Flow enable	     */
 	RMNET_IOCTL_FLOW_DISABLE     = 0x000089FB, /* Flow disable	     */
+	RMNET_IOCTL_SET_ALIGNED_QOS_ENABLE = 0x000089FC, /*Set aligned QoS   */
 	RMNET_IOCTL_MAX
 };
 
@@ -53,4 +55,11 @@
 	unsigned long    flow_id;
 };
 
+/* QMI QoS Aligned header definition */
+#define QMI_QOS_ALIGNED_HDR_S  __attribute((__packed__)) qmi_qos_aligned_hdr_s
+struct QMI_QOS_ALIGNED_HDR_S {
+	struct QMI_QOS_HDR_S hdr;
+	unsigned char reserved[2];
+};
+
 #endif /* _MSM_RMNET_H_ */