msm: ipa: Fix Tos value issue in IPA

Fix TOS mast-filtering rules configured in HW,
the QOS value is set in the upper 3 bits of the
TOS field. The other bits in the TOS field need
to be ignored.

Change-Id: Id55bb101b9f19dae0210d0c0f958a1be68506f75
Signed-off-by: Skylar Chang <chiaweic@codeaurora.org>
diff --git a/drivers/platform/msm/ipa/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_debugfs.c
index aaf5cc0..87ddf59 100644
--- a/drivers/platform/msm/ipa/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_debugfs.c
@@ -346,11 +346,18 @@
 	uint32_t mask[4];
 	int i;
 
-	if (attrib->attrib_mask & IPA_FLT_TOS) {
-		nbytes = scnprintf(buff + cnt, sz - cnt, "tos:%d ",
-				attrib->u.v4.tos);
+
+	if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) {
+		nbytes = scnprintf(buff + cnt, sz - cnt, "tos_value:%d ",
+				attrib->tos_value);
 		cnt += nbytes;
 	}
+	if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) {
+		nbytes = scnprintf(buff + cnt, sz - cnt, "tos_mask:%d ",
+				attrib->tos_mask);
+		cnt += nbytes;
+	}
+
 	if (attrib->attrib_mask & IPA_FLT_PROTOCOL) {
 		nbytes = scnprintf(buff + cnt, sz - cnt, "protocol:%d ",
 				attrib->u.v4.protocol);
diff --git a/drivers/platform/msm/ipa/ipa_rt.c b/drivers/platform/msm/ipa/ipa_rt.c
index 6430c07..5c27c40 100644
--- a/drivers/platform/msm/ipa/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_rt.c
@@ -67,13 +67,31 @@
 	}
 	rule_hdr->u.hdr.pipe_dest_idx = pipe_idx;
 	rule_hdr->u.hdr.system = !ipa_ctx->hdr_tbl_lcl;
-	if (entry->hdr)
+	if (entry->hdr) {
 		rule_hdr->u.hdr.hdr_offset =
 			entry->hdr->offset_entry->offset >> 2;
-	else
+	} else {
 		rule_hdr->u.hdr.hdr_offset = 0;
-
+	}
 	buf += sizeof(struct ipa_rt_rule_hw_hdr);
+	if ((ip == IPA_IP_v4) &&
+		(entry->rule.attrib.attrib_mask & IPA_FLT_TOS)) {
+			entry->rule.attrib.tos_value =
+				(entry->rule.attrib.u.v4.tos << 5);
+			entry->rule.attrib.tos_mask = 0xe0;
+			entry->rule.attrib.attrib_mask &= ~IPA_FLT_TOS;
+			entry->rule.attrib.attrib_mask |= IPA_FLT_TOS_MASKED;
+	}
+
+	if ((ip == IPA_IP_v6) &&
+		(entry->rule.attrib.attrib_mask & IPA_FLT_TC)) {
+			entry->rule.attrib.tos_value =
+				(entry->rule.attrib.u.v6.tc << 5);
+			entry->rule.attrib.tos_mask = 0xe0;
+			entry->rule.attrib.attrib_mask &= ~IPA_FLT_TC;
+			entry->rule.attrib.attrib_mask |= IPA_FLT_TOS_MASKED;
+	}
+
 	if (ipa_generate_hw_rule(ip, &rule->attrib, &buf, &en_rule)) {
 		IPAERR("fail to generate hw rule\n");
 		return -EPERM;
diff --git a/drivers/platform/msm/ipa/ipa_utils.c b/drivers/platform/msm/ipa/ipa_utils.c
index 23de300..21a6dc4 100644
--- a/drivers/platform/msm/ipa/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_utils.c
@@ -237,6 +237,20 @@
 			*buf = ipa_pad_to_32(*buf);
 		}
 
+		if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) {
+			if (ipa_ofst_meq32[ofst_meq32] == -1) {
+				IPAERR("ran out of meq32 eq\n");
+				return -EPERM;
+			}
+			*en_rule |= ipa_ofst_meq32[ofst_meq32];
+			/* 0 => offset of TOS in v4 header */
+			*buf = ipa_write_8(0, *buf);
+			*buf = ipa_write_32((attrib->tos_mask << 16), *buf);
+			*buf = ipa_write_32(attrib->tos_value, *buf);
+			*buf = ipa_pad_to_32(*buf);
+			ofst_meq32++;
+		}
+
 		if (attrib->attrib_mask & IPA_FLT_PROTOCOL) {
 			*en_rule |= IPA_PROTOCOL_EQ;
 			*buf = ipa_write_8(attrib->u.v4.protocol, *buf);
@@ -568,6 +582,20 @@
 			*buf = ipa_pad_to_32(*buf);
 		}
 
+		if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) {
+			if (ipa_ofst_meq32[ofst_meq32] == -1) {
+				IPAERR("ran out of meq32 eq\n");
+				return -EPERM;
+			}
+			*en_rule |= ipa_ofst_meq32[ofst_meq32];
+			/* 0 => offset of TOS in v4 header */
+			*buf = ipa_write_8(0, *buf);
+			*buf = ipa_write_32((attrib->tos_mask << 20), *buf);
+			*buf = ipa_write_32(attrib->tos_value, *buf);
+			*buf = ipa_pad_to_32(*buf);
+			ofst_meq32++;
+		}
+
 		if (attrib->attrib_mask & IPA_FLT_FLOW_LABEL) {
 			*en_rule |= IPA_FLT_FLOW_LABEL;
 			 /* FIXME FL is only 20 bits */
diff --git a/include/linux/msm_ipa.h b/include/linux/msm_ipa.h
index 5151654..b2229d3 100644
--- a/include/linux/msm_ipa.h
+++ b/include/linux/msm_ipa.h
@@ -87,6 +87,7 @@
 #define IPA_FLT_NEXT_HDR       (1ul << 13)
 #define IPA_FLT_META_DATA      (1ul << 14)
 #define IPA_FLT_FRAGMENT       (1ul << 15)
+#define IPA_FLT_TOS_MASKED     (1ul << 16)
 
 /**
  * enum ipa_client_type - names for the various IPA "clients"
@@ -243,6 +244,8 @@
 	uint16_t dst_port_hi;
 	uint8_t type;
 	uint8_t code;
+	uint8_t tos_value;
+	uint8_t tos_mask;
 	uint32_t spi;
 	uint16_t src_port;
 	uint16_t dst_port;