Kaynağa Gözat

msm: ipa: Add support to L2TP over UDP

L2TP over UDP requires new commands to be send to uC
to use the new header length for additition and deletion

Change-Id: I6c642e745386bad5fb7ef63b4167e91ce561e0dd
Armaan Siddiqui 4 yıl önce
ebeveyn
işleme
5cafe9bb19

+ 1 - 1
drivers/platform/msm/ipa/ipa_v3/ipa.c

@@ -2111,7 +2111,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	int retval = 0;
 	u32 pyld_sz;
-	u8 header[128] = { 0 };
+	u8 header[256] = { 0 };
 	u8 *param = NULL;
 	bool is_vlan_mode;
 	struct ipa_ioc_nat_alloc_mem nat_mem;

+ 14 - 3
drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c

@@ -107,6 +107,8 @@ const char *ipa3_hdr_proc_type_name[] = {
 	__stringify(IPA_HDR_PROC_L2TP_HEADER_ADD),
 	__stringify(IPA_HDR_PROC_L2TP_HEADER_REMOVE),
 	__stringify(IPA_HDR_PROC_ETHII_TO_ETHII_EX),
+	__stringify(IPA_HDR_PROC_L2TP_UDP_HEADER_ADD),
+	__stringify(IPA_HDR_PROC_L2TP_UDP_HEADER_REMOVE),
 };
 
 static struct dentry *dent;
@@ -745,6 +747,9 @@ static int ipa3_attrib_dump(struct ipa_rule_attrib *attrib,
 	if (attrib->attrib_mask & IPA_FLT_NEXT_HDR)
 		pr_cont("next_hdr:%d ", attrib->u.v6.next_hdr);
 
+	if (attrib->ext_attrib_mask & IPA_FLT_EXT_NEXT_HDR)
+		pr_err("next_hdr:%d ", attrib->u.v6.next_hdr);
+
 	if (attrib->attrib_mask & IPA_FLT_META_DATA) {
 		pr_cont(
 			"metadata:%x metadata_mask:%x ",
@@ -763,11 +768,16 @@ static int ipa3_attrib_dump(struct ipa_rule_attrib *attrib,
 	if ((attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_ETHER_II) ||
 		(attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_802_3) ||
 		(attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_L2TP) ||
-		(attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_802_1Q)) {
+		(attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_802_1Q) ||
+		(attrib->attrib_mask & IPA_FLT_L2TP_UDP_INNER_MAC_DST_ADDR)) {
 		pr_cont("dst_mac_addr:%pM ", attrib->dst_mac_addr);
 	}
 
-	if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE)
+	if (attrib->ext_attrib_mask & IPA_FLT_EXT_MTU)
+		pr_err("Payload Length:%d ", attrib->payload_length);
+
+	if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE ||
+		attrib->ext_attrib_mask & IPA_FLT_EXT_L2TP_UDP_INNER_ETHER_TYPE)
 		pr_cont("ether_type:%x ", attrib->ether_type);
 
 	if (attrib->attrib_mask & IPA_FLT_VLAN_ID)
@@ -776,7 +786,8 @@ static int ipa3_attrib_dump(struct ipa_rule_attrib *attrib,
 	if (attrib->attrib_mask & IPA_FLT_TCP_SYN)
 		pr_cont("tcp syn ");
 
-	if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP)
+	if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP ||
+		attrib->ext_attrib_mask & IPA_FLT_EXT_L2TP_UDP_TCP_SYN)
 		pr_cont("tcp syn l2tp ");
 
 	if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IP_TYPE)

+ 6 - 2
drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c

@@ -1,12 +1,12 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
  */
 
 #include "ipa_i.h"
 #include "ipahal.h"
 
-static const u32 ipa_hdr_bin_sz[IPA_HDR_BIN_MAX] = { 8, 16, 24, 36, 64};
+static const u32 ipa_hdr_bin_sz[IPA_HDR_BIN_MAX] = { 8, 16, 24, 36, 64, 128};
 static const u32 ipa_hdr_proc_ctx_bin_sz[IPA_HDR_PROC_CTX_BIN_MAX] = { 32, 64};
 
 #define HDR_TYPE_IS_VALID(type) \
@@ -544,6 +544,10 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr, bool user)
 		bin = IPA_HDR_BIN3;
 	else if (hdr->hdr_len <= ipa_hdr_bin_sz[IPA_HDR_BIN4])
 		bin = IPA_HDR_BIN4;
+	/* Starting from IPA4.5, HW supports larger headers. */
+	else if ((hdr->hdr_len <= ipa_hdr_bin_sz[IPA_HDR_BIN5]) &&
+		 (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5))
+		 bin = IPA_HDR_BIN5;
 	else {
 		IPAERR_RL("unexpected hdr len %d\n", hdr->hdr_len);
 		goto bad_hdr_len;

+ 3 - 2
drivers/platform/msm/ipa/ipa_v3/ipa_i.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _IPA3_I_H_
@@ -185,7 +185,8 @@
 #define IPA_HDR_BIN2 2
 #define IPA_HDR_BIN3 3
 #define IPA_HDR_BIN4 4
-#define IPA_HDR_BIN_MAX 5
+#define IPA_HDR_BIN5 5
+#define IPA_HDR_BIN_MAX 6
 
 #define IPA_HDR_PROC_CTX_BIN0 0
 #define IPA_HDR_PROC_CTX_BIN1 1

+ 68 - 7
drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/debugfs.h>
@@ -1541,7 +1541,8 @@ static int ipahal_cp_proc_ctx_to_hw_buff_v3(enum ipa_hdr_proc_type type,
 		ctx->end.type = IPA_PROC_CTX_TLV_TYPE_END;
 		ctx->end.length = 0;
 		ctx->end.value = 0;
-	} else if (type == IPA_HDR_PROC_L2TP_HEADER_ADD) {
+	} else if ((type == IPA_HDR_PROC_L2TP_HEADER_ADD) ||
+		(type == IPA_HDR_PROC_L2TP_UDP_HEADER_ADD)) {
 		struct ipa_hw_hdr_proc_ctx_add_l2tp_hdr_cmd_seq *ctx;
 
 		ctx = (struct ipa_hw_hdr_proc_ctx_add_l2tp_hdr_cmd_seq *)
@@ -1559,8 +1560,14 @@ static int ipahal_cp_proc_ctx_to_hw_buff_v3(enum ipa_hdr_proc_type type,
 			ctx->hdr_add.hdr_addr_hi = 0;
 		ctx->l2tp_params.tlv.type = IPA_PROC_CTX_TLV_TYPE_PROC_CMD;
 		ctx->l2tp_params.tlv.length = 1;
-		ctx->l2tp_params.tlv.value =
-				IPA_HDR_UCP_L2TP_HEADER_ADD;
+		if (type == IPA_HDR_PROC_L2TP_HEADER_ADD)
+			ctx->l2tp_params.tlv.value =
+					IPA_HDR_UCP_L2TP_HEADER_ADD;
+		else
+			ctx->l2tp_params.tlv.value =
+					IPA_HDR_UCP_L2TP_UDP_HEADER_ADD;
+		ctx->l2tp_params.l2tp_params.second_pass =
+			l2tp_params->hdr_add_param.second_pass;
 		ctx->l2tp_params.l2tp_params.eth_hdr_retained =
 			l2tp_params->hdr_add_param.eth_hdr_retained;
 		ctx->l2tp_params.l2tp_params.input_ip_version =
@@ -1591,7 +1598,7 @@ static int ipahal_cp_proc_ctx_to_hw_buff_v3(enum ipa_hdr_proc_type type,
 		ctx->l2tp_params.tlv.type = IPA_PROC_CTX_TLV_TYPE_PROC_CMD;
 		ctx->l2tp_params.tlv.length = 1;
 		ctx->l2tp_params.tlv.value =
-				IPA_HDR_UCP_L2TP_HEADER_REMOVE;
+					IPA_HDR_UCP_L2TP_HEADER_REMOVE;
 		ctx->l2tp_params.l2tp_params.hdr_len_remove =
 			l2tp_params->hdr_remove_param.hdr_len_remove;
 		ctx->l2tp_params.l2tp_params.eth_hdr_retained =
@@ -1612,7 +1619,51 @@ static int ipahal_cp_proc_ctx_to_hw_buff_v3(enum ipa_hdr_proc_type type,
 		ctx->end.type = IPA_PROC_CTX_TLV_TYPE_END;
 		ctx->end.length = 0;
 		ctx->end.value = 0;
-	}  else if (type == IPA_HDR_PROC_ETHII_TO_ETHII_EX) {
+	} else if (type == IPA_HDR_PROC_L2TP_UDP_HEADER_REMOVE) {
+		struct ipa_hw_hdr_proc_ctx_remove_l2tp_hdr_cmd_seq *ctx;
+
+		ctx = (struct ipa_hw_hdr_proc_ctx_remove_l2tp_hdr_cmd_seq *)
+			(base + offset);
+		ctx->hdr_add.tlv.type = IPA_PROC_CTX_TLV_TYPE_HDR_ADD;
+		ctx->hdr_add.tlv.length = 2;
+		if (l2tp_params->hdr_remove_param.eth_hdr_retained) {
+			ctx->hdr_add.tlv.value = hdr_len;
+			hdr_addr = is_hdr_proc_ctx ? phys_base :
+				hdr_base_addr + offset_entry->offset;
+			IPAHAL_DBG("header address 0x%llx length %d\n",
+				hdr_addr, ctx->hdr_add.tlv.value);
+			IPAHAL_CP_PROC_CTX_HEADER_UPDATE(ctx->hdr_add.hdr_addr,
+				ctx->hdr_add.hdr_addr_hi, hdr_addr);
+			if (!is_64)
+				ctx->hdr_add.hdr_addr_hi = 0;
+		} else {
+			ctx->hdr_add.tlv.value = 0;
+		}
+		ctx->l2tp_params.tlv.type = IPA_PROC_CTX_TLV_TYPE_PROC_CMD;
+		ctx->l2tp_params.tlv.length = 1;
+		ctx->l2tp_params.tlv.value =
+				IPA_HDR_UCP_L2TP_UDP_HEADER_REMOVE;
+		ctx->l2tp_params.l2tp_params.hdr_len_remove =
+			l2tp_params->hdr_remove_param.hdr_len_remove;
+		ctx->l2tp_params.l2tp_params.eth_hdr_retained =
+			l2tp_params->hdr_remove_param.eth_hdr_retained;
+		ctx->l2tp_params.l2tp_params.hdr_ofst_pkt_size_valid =
+			l2tp_params->hdr_remove_param.hdr_ofst_pkt_size_valid;
+		ctx->l2tp_params.l2tp_params.hdr_ofst_pkt_size =
+			l2tp_params->hdr_remove_param.hdr_ofst_pkt_size;
+		ctx->l2tp_params.l2tp_params.hdr_endianness =
+			l2tp_params->hdr_remove_param.hdr_endianness;
+		IPAHAL_DBG("hdr ofst valid: %d, hdr ofst pkt size: %d\n",
+			ctx->l2tp_params.l2tp_params.hdr_ofst_pkt_size_valid,
+			ctx->l2tp_params.l2tp_params.hdr_ofst_pkt_size);
+		IPAHAL_DBG("endianness: %d\n",
+			ctx->l2tp_params.l2tp_params.hdr_endianness);
+
+		IPAHAL_DBG("command id %d\n", ctx->l2tp_params.tlv.value);
+		ctx->end.type = IPA_PROC_CTX_TLV_TYPE_END;
+		ctx->end.length = 0;
+		ctx->end.value = 0;
+	} else if (type == IPA_HDR_PROC_ETHII_TO_ETHII_EX) {
 		struct ipa_hw_hdr_proc_ctx_add_hdr_cmd_seq_ex *ctx;
 
 		ctx = (struct ipa_hw_hdr_proc_ctx_add_hdr_cmd_seq_ex *)
@@ -1643,7 +1694,7 @@ static int ipahal_cp_proc_ctx_to_hw_buff_v3(enum ipa_hdr_proc_type type,
 		ctx->end.type = IPA_PROC_CTX_TLV_TYPE_END;
 		ctx->end.length = 0;
 		ctx->end.value = 0;
-	} else {
+	}  else {
 		struct ipa_hw_hdr_proc_ctx_add_hdr_cmd_seq *ctx;
 
 		ctx = (struct ipa_hw_hdr_proc_ctx_add_hdr_cmd_seq *)
@@ -1674,6 +1725,9 @@ static int ipahal_cp_proc_ctx_to_hw_buff_v3(enum ipa_hdr_proc_type type,
 		case IPA_HDR_PROC_802_3_TO_802_3:
 			ctx->cmd.value = IPA_HDR_UCP_802_3_TO_802_3;
 			break;
+		case IPA_HDR_PROC_SET_DSCP:
+			ctx->cmd.value = IPA_HDR_UCP_SET_DSCP;
+			break;
 		default:
 			IPAHAL_ERR("unknown ipa_hdr_proc_type %d", type);
 			WARN_ON(1);
@@ -1716,6 +1770,13 @@ static int ipahal_get_proc_ctx_needed_len_v3(enum ipa_hdr_proc_type type)
 		ret =
 		sizeof(struct ipa_hw_hdr_proc_ctx_remove_l2tp_hdr_cmd_seq);
 		break;
+	case IPA_HDR_PROC_L2TP_UDP_HEADER_ADD:
+		ret = sizeof(struct ipa_hw_hdr_proc_ctx_add_l2tp_hdr_cmd_seq);
+		break;
+	case IPA_HDR_PROC_L2TP_UDP_HEADER_REMOVE:
+		ret =
+		sizeof(struct ipa_hw_hdr_proc_ctx_remove_l2tp_hdr_cmd_seq);
+		break;
 	case IPA_HDR_PROC_ETHII_TO_ETHII_EX:
 		ret = sizeof(struct ipa_hw_hdr_proc_ctx_add_hdr_cmd_seq_ex);
 		break;

+ 194 - 2
drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/ipa.h>
@@ -1032,7 +1032,7 @@ static int ipa_flt_generate_eq(enum ipa_ip_type ipt,
 	 * default "rule" means no attributes set -> map to
 	 * OFFSET_MEQ32_0 with mask of 0 and val of 0 and offset 0
 	 */
-	if (attrib->attrib_mask == 0) {
+	if ((attrib->attrib_mask == 0) && (attrib->ext_attrib_mask == 0)) {
 		eq_atrb->rule_eq_bitmap = 0;
 		eq_atrb->rule_eq_bitmap |= IPA_GET_RULE_EQ_BIT_PTRN(
 			IPA_OFFSET_MEQ32_0);
@@ -1397,6 +1397,54 @@ static int ipa_fltrt_generate_hw_rule_bdy_ip4(u16 *en_rule,
 		ihl_ofst_meq32 += 2;
 	}
 
+	if (attrib->attrib_mask & IPA_FLT_L2TP_UDP_INNER_MAC_DST_ADDR) {
+		if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+			ihl_ofst_meq32) || IPA_IS_RAN_OUT_OF_EQ(
+			ipa3_0_ihl_ofst_meq32, ihl_ofst_meq32 + 1)) {
+			IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+			goto err;
+		}
+		*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+			ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+		*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+			ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32 + 1]);
+		/* populate first ihl meq eq */
+		extra = ipa_write_8(24, extra);
+		rest = ipa_write_8(attrib->dst_mac_addr_mask[3], rest);
+		rest = ipa_write_8(attrib->dst_mac_addr_mask[2], rest);
+		rest = ipa_write_8(attrib->dst_mac_addr_mask[1], rest);
+		rest = ipa_write_8(attrib->dst_mac_addr_mask[0], rest);
+		rest = ipa_write_8(attrib->dst_mac_addr[3], rest);
+		rest = ipa_write_8(attrib->dst_mac_addr[2], rest);
+		rest = ipa_write_8(attrib->dst_mac_addr[1], rest);
+		rest = ipa_write_8(attrib->dst_mac_addr[0], rest);
+		/* populate second ihl meq eq */
+		extra = ipa_write_8(28, extra);
+		rest = ipa_write_16(0, rest);
+		rest = ipa_write_8(attrib->dst_mac_addr_mask[5], rest);
+		rest = ipa_write_8(attrib->dst_mac_addr_mask[4], rest);
+		rest = ipa_write_16(0, rest);
+		rest = ipa_write_8(attrib->dst_mac_addr[5], rest);
+		rest = ipa_write_8(attrib->dst_mac_addr[4], rest);
+		ihl_ofst_meq32 += 2;
+	}
+
+	if (attrib->ext_attrib_mask & IPA_FLT_EXT_L2TP_UDP_INNER_ETHER_TYPE) {
+		if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
+			IPAHAL_ERR("ran out of meq32 eq\n");
+			goto err;
+		}
+		*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+			ipa3_0_ofst_meq32[ofst_meq32]);
+		/* 76 => offset of inner ether type in L2TP over UDP hdr */
+		extra = ipa_write_8(76, extra);
+		rest = ipa_write_16(0, rest);
+		rest = ipa_write_16(attrib->ether_type, rest);
+		rest = ipa_write_16(0, rest);
+		rest = ipa_write_16(attrib->ether_type, rest);
+		ofst_meq32++;
+	}
+
 	if (attrib->attrib_mask & IPA_FLT_TCP_SYN) {
 		if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
 			ihl_ofst_meq32)) {
@@ -1438,6 +1486,21 @@ static int ipa_fltrt_generate_hw_rule_bdy_ip4(u16 *en_rule,
 		rest = ipa_write_32(attrib->meta_data, rest);
 	}
 
+	if (attrib->ext_attrib_mask & IPA_FLT_EXT_MTU) {
+			if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
+					ihl_ofst_rng16)) {
+				IPAHAL_ERR("ran out of ihl_rng16 eq\n");
+				goto err;
+			}
+			*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+				ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
+			/* 130	=> (130 - 128) = 2 offset of length in v4 header */
+			extra = ipa_write_8(130, extra);
+			rest = ipa_write_16(attrib->payload_length, rest);
+			rest = ipa_write_16(0, rest);
+			ihl_ofst_rng16++;
+	}
+
 	if (attrib->attrib_mask & IPA_FLT_SRC_PORT_RANGE) {
 		if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
 				ihl_ofst_rng16)) {
@@ -1551,6 +1614,17 @@ static int ipa_fltrt_generate_hw_rule_bdy_ip6(u16 *en_rule,
 		extra = ipa_write_8(attrib->u.v6.next_hdr, extra);
 	}
 
+	if (attrib->ext_attrib_mask & IPA_FLT_EXT_NEXT_HDR) {
+		*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+			ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+		/* 134  => offset of Next header after v6 header. */
+		extra = ipa_write_8(134, extra);
+		rest = ipa_write_32(0xFF000000, rest);
+		rest = ipa_write_32(attrib->u.v6.next_hdr << 24, rest);
+		extra = ipa_write_8(attrib->u.v6.next_hdr, extra);
+		ihl_ofst_meq32++;
+	}
+
 	if (attrib->attrib_mask & IPA_FLT_TC) {
 		*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_TC_EQ);
 		extra = ipa_write_8(attrib->u.v6.tc, extra);
@@ -1717,6 +1791,124 @@ static int ipa_fltrt_generate_hw_rule_bdy_ip6(u16 *en_rule,
 		ihl_ofst_meq32 += 2;
 	}
 
+	if (attrib->attrib_mask & IPA_FLT_L2TP_UDP_INNER_MAC_DST_ADDR) {
+			if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+				ihl_ofst_meq32) || IPA_IS_RAN_OUT_OF_EQ(
+				ipa3_0_ihl_ofst_meq32, ihl_ofst_meq32 + 1)) {
+				IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+				goto err;
+			}
+			*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+				ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+			*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+				ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32 + 1]);
+			/* populate first ihl meq eq */
+			extra = ipa_write_8(24, extra);
+			rest = ipa_write_8(attrib->dst_mac_addr_mask[3], rest);
+			rest = ipa_write_8(attrib->dst_mac_addr_mask[2], rest);
+			rest = ipa_write_8(attrib->dst_mac_addr_mask[1], rest);
+			rest = ipa_write_8(attrib->dst_mac_addr_mask[0], rest);
+			rest = ipa_write_8(attrib->dst_mac_addr[3], rest);
+			rest = ipa_write_8(attrib->dst_mac_addr[2], rest);
+			rest = ipa_write_8(attrib->dst_mac_addr[1], rest);
+			rest = ipa_write_8(attrib->dst_mac_addr[0], rest);
+			/* populate second ihl meq eq */
+			extra = ipa_write_8(28, extra);
+			rest = ipa_write_16(0, rest);
+			rest = ipa_write_8(attrib->dst_mac_addr_mask[5], rest);
+			rest = ipa_write_8(attrib->dst_mac_addr_mask[4], rest);
+			rest = ipa_write_16(0, rest);
+			rest = ipa_write_8(attrib->dst_mac_addr[5], rest);
+			rest = ipa_write_8(attrib->dst_mac_addr[4], rest);
+			ihl_ofst_meq32 += 2;
+		}
+
+		if (attrib->ext_attrib_mask & IPA_FLT_EXT_L2TP_UDP_INNER_ETHER_TYPE) {
+			if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
+				IPAHAL_ERR("ran out of meq32 eq\n");
+				goto err;
+			}
+			*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+				ipa3_0_ofst_meq32[ofst_meq32]);
+			/* 76 => offset of inner ether type in L2TP over UDP */
+			extra = ipa_write_8(76, extra);
+			rest = ipa_write_16(0, rest);
+			rest = ipa_write_16(attrib->ether_type, rest);
+			rest = ipa_write_16(0, rest);
+			rest = ipa_write_16(attrib->ether_type, rest);
+			ofst_meq32++;
+		}
+
+		if (attrib->ext_attrib_mask & IPA_FLT_EXT_L2TP_UDP_TCP_SYN) {
+			if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+				ihl_ofst_meq32) || IPA_IS_RAN_OUT_OF_EQ(
+				ipa3_0_ihl_ofst_meq32, ihl_ofst_meq32 + 1)) {
+				IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+				goto err;
+			}
+			*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+				ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+			*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+				ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32 + 1]);
+
+			/* populate TCP protocol eq */
+			if (attrib->ether_type == 0x0800) {
+				extra = ipa_write_8(46, extra);
+				rest = ipa_write_32(0xFF0000, rest);
+				rest = ipa_write_32(0x60000, rest);
+			} else {
+				extra = ipa_write_8(42, extra);
+				rest = ipa_write_32(0xFF00, rest);
+				rest = ipa_write_32(0x600, rest);
+			}
+
+			/* populate TCP SYN eq */
+			if (attrib->ether_type == 0x0800) {
+				extra = ipa_write_8(70, extra);
+				rest = ipa_write_32(0x20000, rest);
+				rest = ipa_write_32(0x20000, rest);
+			} else {
+				extra = ipa_write_8(90, extra);
+				rest = ipa_write_32(0x20000, rest);
+				rest = ipa_write_32(0x20000, rest);
+			}
+			ihl_ofst_meq32 += 2;
+		}
+
+		if (attrib->ext_attrib_mask & IPA_FLT_EXT_L2TP_UDP_INNER_NEXT_HDR) {
+			if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+				ihl_ofst_meq32)) {
+				IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+				goto err;
+			}
+			*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+				ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+
+			/* Populate next header */
+			if (attrib->ether_type == 0x0800) {
+				/* 46 => offset of inner next hdr type in
+				 * L2TP over UDP (IPv4).
+				 * 46 = UDP (8) + L2TP (16) + ETH (14) + 8 bytes
+				 * in Ipv4 header.
+				 */
+				extra = ipa_write_8(46, extra);
+				rest = ipa_write_32(0xFF0000, rest);
+				rest = ipa_write_32((attrib->l2tp_udp_next_hdr << 16),
+					rest);
+			} else {
+				/* 42 => offset of inner next hdr type in
+				 * L2TP over UDP (Ipv6).
+				 * 42 = UDP (8) + L2TP (16) + ETH (14) + 4 bytes
+				 * in Ipv6 header.
+				 */
+				extra = ipa_write_8(42, extra);
+				rest = ipa_write_32(0xFF00, rest);
+				rest = ipa_write_32((attrib->l2tp_udp_next_hdr << 8),
+					rest);
+			}
+			ihl_ofst_meq32++;
+		}
+
 	if (attrib->attrib_mask & IPA_FLT_TCP_SYN) {
 		if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
 			ihl_ofst_meq32)) {

+ 14 - 2
drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _IPAHAL_I_H_
@@ -839,9 +839,10 @@ union ipa_pkt_status_hw_v5_0 {
 #define IPA_HDR_UCP_ETHII_TO_ETHII		9
 #define IPA_HDR_UCP_L2TP_HEADER_ADD		10
 #define IPA_HDR_UCP_L2TP_HEADER_REMOVE		11
-#define IPA_HDR_UCP_L2TP_UDP_HEADER_ADD	12
+#define IPA_HDR_UCP_L2TP_UDP_HEADER_ADD		12
 #define IPA_HDR_UCP_L2TP_UDP_HEADER_REMOVE	13
 #define IPA_HDR_UCP_ETHII_TO_ETHII_EX		14
+#define IPA_HDR_UCP_SET_DSCP			16
 
 /* Processing context TLV type */
 #define IPA_PROC_CTX_TLV_TYPE_END 0
@@ -979,4 +980,15 @@ struct ipa_hw_hdr_proc_ctx_add_hdr_cmd_seq_ex {
 	struct ipa_hw_hdr_proc_ctx_tlv end;
 };
 
+/**
+ * struct ipa_hw_hdr_proc_ctx_remove_l2tp_udp_hdr_cmd_seq -
+ * IPA processing context header - process command sequence
+ * @l2tp_params: l2tp params for header removal
+ * @end: tlv end command (cmd.type must be 0)
+ */
+struct ipa_hw_hdr_proc_ctx_remove_l2tp_udp_hdr_cmd_seq {
+	struct ipa_hw_hdr_proc_ctx_l2tp_remove_hdr l2tp_params;
+	struct ipa_hw_hdr_proc_ctx_tlv end;
+};
+
 #endif /* _IPAHAL_I_H_ */