[][openwrt][mt7988][tops][support v1.1.0]

[Description]
Add support to TOPS v1.1.0 with latest driver and firmware
1. Support TOPS mini network stack
   Refactor codes to improve the reusability of tunnel parameter fetching
   process.
2. Change flow table's tunnel arrangement to align with TOPS mini network
   stack
3. TOPS firmware support reorder Tx/Rx process
   Add some flexibilities to support more applications.
4. Update debug commands
   4.1 Add command to show registered tunnel parameters
   4.2 Update command to register debug tunnel parameters
5. Fix minor bugs
   5.1 coding defects
   5.2 tunnel binding mechanism bugs
6. Support tunnel protocol
   6.1 L2oGRE

[Release-log]
N/A

Change-Id: Idd6b6e0fb0495d21062ededd8b010dc14af317ff
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/8319846
diff --git a/package-21.02/kernel/tops/src/Makefile b/package-21.02/kernel/tops/src/Makefile
index 845f657..86f860d 100644
--- a/package-21.02/kernel/tops/src/Makefile
+++ b/package-21.02/kernel/tops/src/Makefile
@@ -11,6 +11,7 @@
 ccflags-y += -I$(src)/protocol/inc
 
 tops-y += ctrl.o
+tops-y += debugfs.o
 tops-y += firmware.o
 tops-y += init.o
 tops-y += hpdma.o
@@ -19,6 +20,7 @@
 tops-y += mcu.o
 tops-y += netsys.o
 tops-y += net-event.o
+tops-y += tops_params.o
 tops-y += tnl_offload.o
 tops-y += ser.o
 tops-y += tdma.o
@@ -28,7 +30,11 @@
 tops-y += trm.o
 tops-y += wdt.o
 
-tops-$(CONFIG_MTK_TOPS_GRETAP) += protocol/gre/gretap.o
-tops-$(CONFIG_MTK_TOPS_UDP_L2TP_DATA) += protocol/l2tp/udp_l2tp_data.o
+tops-y += protocol/mac/eth.o
+tops-y += protocol/mac/ppp.o
+tops-y += protocol/network/ip.o
+tops-y += protocol/transport/udp.o
+tops-$(CONFIG_MTK_TOPS_GRETAP) += protocol/tunnel/gre/gretap.o
+tops-$(CONFIG_MTK_TOPS_L2TP_V2) += protocol/tunnel/l2tp/l2tpv2.o
 
 include $(wildcard $(src)/*.mk)
diff --git a/package-21.02/kernel/tops/src/ctrl.c b/package-21.02/kernel/tops/src/ctrl.c
index ed1c95b..df41715 100644
--- a/package-21.02/kernel/tops/src/ctrl.c
+++ b/package-21.02/kernel/tops/src/ctrl.c
@@ -7,198 +7,12 @@
 
 #include <linux/device.h>
 
-#include "firmware.h"
-#include "hpdma.h"
-#include "internal.h"
-#include "mcu.h"
-#include "netsys.h"
-#include "trm.h"
-#include "tunnel.h"
-#include "wdt.h"
-
-static const char *tops_role_name[__TOPS_ROLE_TYPE_MAX] = {
-	[TOPS_ROLE_TYPE_MGMT] = "tops-mgmt",
-	[TOPS_ROLE_TYPE_CLUSTER] = "tops-offload",
-};
-
-static ssize_t mtk_tops_fw_info_show(struct device *dev,
-				     struct device_attribute *attr,
-				     char *buf)
-{
-	enum tops_role_type rtype;
-	struct tm tm = {0};
-	const char *value;
-	const char *prop;
-	int len = 0;
-	u32 nattr;
-	u32 i;
-
-	for (rtype = TOPS_ROLE_TYPE_MGMT; rtype < __TOPS_ROLE_TYPE_MAX; rtype++) {
-		mtk_tops_fw_get_built_date(rtype, &tm);
-
-		len += snprintf(buf + len, PAGE_SIZE - len,
-				"%s FW information:\n", tops_role_name[rtype]);
-		len += snprintf(buf + len, PAGE_SIZE - len,
-				"Git revision:\t%llx\n",
-				mtk_tops_fw_get_git_commit_id(rtype));
-		len += snprintf(buf + len, PAGE_SIZE - len,
-				"Build date:\t%04ld/%02d/%02d %02d:%02d:%02d\n",
-				tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
-				tm.tm_hour, tm.tm_min, tm.tm_sec);
-
-		nattr = mtk_tops_fw_attr_get_num(rtype);
-
-		for (i = 0; i < nattr; i++) {
-			prop = mtk_tops_fw_attr_get_property(rtype, i);
-			if (!prop)
-				continue;
-
-			value = mtk_tops_fw_attr_get_value(rtype, prop);
-
-			len += snprintf(buf + len, PAGE_SIZE - len,
-					"%s:\t%s\n", prop, value);
-		}
-		len += snprintf(buf + len, PAGE_SIZE - len, "\n");
-	}
-
-	return len;
-}
-
-static int mtk_tops_ctrl_fetch_port(const char *buf, int *ofs, u16 *port)
-{
-	int nchar = 0;
-	int ret;
-	u16 p = 0;
-
-	ret = sscanf(buf + *ofs, "%hu %n", &p, &nchar);
-	if (ret != 1)
-		return -EPERM;
-
-	*port = htons(p);
-
-	*ofs += nchar;
-
-	return nchar;
-}
-
-static int mtk_tops_ctrl_fetch_ip(const char *buf, int *ofs, u32 *ip)
-{
-	int nchar = 0;
-	int ret = 0;
-	u8 tmp[4];
-
-	ret = sscanf(buf + *ofs, "%hhu.%hhu.%hhu.%hhu %n",
-		&tmp[3], &tmp[2], &tmp[1], &tmp[0], &nchar);
-	if (ret != 4)
-		return -EPERM;
-
-	*ip = tmp[0] | tmp[1] << 8 | tmp[2] << 16 | tmp[3] << 24;
-
-	*ofs += nchar;
-
-	return nchar;
-}
-
-static int mtk_tops_ctrl_fetch_mac(const char *buf, int *ofs, u8 *mac)
-{
-	int nchar = 0;
-	int ret = 0;
-
-	ret = sscanf(buf + *ofs, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %n",
-		&mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5], &nchar);
-	if (ret != 6)
-		return -EPERM;
-
-	*ofs += nchar;
-
-	return 0;
-}
-
-static int mtk_tops_ctrl_add_tnl(const char *buf)
-{
-	struct tops_tnl_params tnl_params = {0};
-	struct tops_tnl_info *tnl_info;
-	struct tops_tnl_type *tnl_type;
-	char tnl_type_name[21] = {0};
-	int ofs = 0;
-	int ret = 0;
-
-	ret = sscanf(buf, "%20s %n", tnl_type_name, &ofs);
-	if (ret != 1)
-		return -EPERM;
-
-	tnl_type = mtk_tops_tnl_type_get_by_name(tnl_type_name);
-	if (unlikely(!tnl_type || !tnl_type->tnl_debug_param_setup))
-		return -ENODEV;
-
-	ret = mtk_tops_ctrl_fetch_mac(buf, &ofs, tnl_params.daddr);
-	if (ret < 0)
-		return ret;
-
-	ret = mtk_tops_ctrl_fetch_mac(buf, &ofs, tnl_params.saddr);
-	if (ret < 0)
-		return ret;
-
-	ret = mtk_tops_ctrl_fetch_ip(buf, &ofs, &tnl_params.dip);
-	if (ret < 0)
-		return ret;
-
-	ret = mtk_tops_ctrl_fetch_ip(buf, &ofs, &tnl_params.sip);
-	if (ret < 0)
-		return ret;
-
-	ret = mtk_tops_ctrl_fetch_port(buf, &ofs, &tnl_params.dport);
-	if (ret < 0)
-		return ret;
-
-	ret = mtk_tops_ctrl_fetch_port(buf, &ofs, &tnl_params.sport);
-	if (ret < 0)
-		return ret;
-
-	ret = tnl_type->tnl_debug_param_setup(buf, &ofs, &tnl_params);
-	if (ret < 0)
-		return ret;
-
-	tnl_params.flag |= TNL_DECAP_ENABLE;
-	tnl_params.flag |= TNL_ENCAP_ENABLE;
-	tnl_params.tops_entry_proto = tnl_type->tops_entry;
-
-	tnl_info = mtk_tops_tnl_info_alloc(tnl_type);
-	if (IS_ERR(tnl_info))
-		return -ENOMEM;
-
-	tnl_info->flag |= TNL_INFO_DEBUG;
-	memcpy(&tnl_info->cache, &tnl_params, sizeof(struct tops_tnl_params));
-
-	mtk_tops_tnl_info_hash(tnl_info);
-
-	mtk_tops_tnl_info_submit(tnl_info);
-
-	return 0;
-}
-
-static ssize_t mtk_tops_tnl_store(struct device *dev,
-				  struct device_attribute *attr,
-				  const char *buf,
-				  size_t count)
-{
-	char cmd[21] = {0};
-	int nchar = 0;
-	int ret = 0;
-
-	ret = sscanf(buf, "%20s %n", cmd, &nchar);
-
-	if (ret != 1)
-		return -EPERM;
-
-	if (!strcmp(cmd, "NEW_TNL")) {
-		ret = mtk_tops_ctrl_add_tnl(buf + nchar);
-		if (ret)
-			return ret;
-	}
-
-	return count;
-}
+#include "tops/firmware.h"
+#include "tops/internal.h"
+#include "tops/mcu.h"
+#include "tops/trm.h"
+#include "tops/tunnel.h"
+#include "tops/wdt.h"
 
 static int mtk_tops_trm_fetch_setting(const char *buf,
 				      int *ofs,
@@ -283,14 +97,10 @@
 	return count;
 }
 
-static DEVICE_ATTR_RO(mtk_tops_fw_info);
-static DEVICE_ATTR_WO(mtk_tops_tnl);
 static DEVICE_ATTR_WO(mtk_tops_trm);
 static DEVICE_ATTR_WO(mtk_tops_wdt);
 
 static struct attribute *mtk_tops_attributes[] = {
-	&dev_attr_mtk_tops_fw_info.attr,
-	&dev_attr_mtk_tops_tnl.attr,
 	&dev_attr_mtk_tops_trm.attr,
 	&dev_attr_mtk_tops_wdt.attr,
 	NULL,
diff --git a/package-21.02/kernel/tops/src/debugfs.c b/package-21.02/kernel/tops/src/debugfs.c
new file mode 100644
index 0000000..d2c40cf
--- /dev/null
+++ b/package-21.02/kernel/tops/src/debugfs.c
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Mediatek Inc. All Rights Reserved.
+ *
+ * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
+ */
+
+#include <linux/debugfs.h>
+#include <linux/inet.h>
+#include <linux/uaccess.h>
+
+#include "tops/debugfs.h"
+#include "tops/firmware.h"
+#include "tops/internal.h"
+#include "tops/mcu.h"
+#include "tops/trm.h"
+#include "tops/tunnel.h"
+#include "tops/wdt.h"
+
+static const char *tops_role_name[__TOPS_ROLE_TYPE_MAX] = {
+	[TOPS_ROLE_TYPE_MGMT] = "tops-mgmt",
+	[TOPS_ROLE_TYPE_CLUSTER] = "tops-offload",
+};
+
+static struct dentry *tops_fw_debugfs_root;
+
+static int tops_fw_info_show(struct seq_file *s, void *private)
+{
+	enum tops_role_type rtype;
+	struct tm tm = {0};
+	const char *value;
+	const char *prop;
+	u32 nattr;
+	u32 i;
+
+	for (rtype = TOPS_ROLE_TYPE_MGMT; rtype < __TOPS_ROLE_TYPE_MAX; rtype++) {
+		mtk_tops_fw_get_built_date(rtype, &tm);
+
+		seq_printf(s, "%s FW information:\n", tops_role_name[rtype]);
+		seq_printf(s, "Git revision:\t%llx\n",
+			   mtk_tops_fw_get_git_commit_id(rtype));
+		seq_printf(s, "Build date:\t%04ld/%02d/%02d %02d:%02d:%02d\n",
+			   tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+			   tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+		nattr = mtk_tops_fw_attr_get_num(rtype);
+
+		for (i = 0; i < nattr; i++) {
+			prop = mtk_tops_fw_attr_get_property(rtype, i);
+			if (!prop)
+				continue;
+
+			value = mtk_tops_fw_attr_get_value(rtype, prop);
+
+			seq_printf(s, "%s:\t%s\n", prop, value);
+		}
+		seq_puts(s, "\n");
+	}
+
+	return 0;
+}
+
+static int tops_tnl_show(struct seq_file *s, void *private)
+{
+	struct tops_tnl_info *tnl_info;
+	struct tops_tnl_params *tnl_params;
+	u32 i;
+
+	for (i = 0; i < CONFIG_TOPS_TNL_NUM; i++) {
+		tnl_info = mtk_tops_tnl_info_get_by_idx(i);
+		if (IS_ERR(tnl_info))
+			/* tunnel not enabled */
+			continue;
+
+		tnl_params = &tnl_info->tnl_params;
+		if (!tnl_info->tnl_type || !tnl_info->tnl_type->tnl_param_dump)
+			continue;
+
+		seq_printf(s, "Tunnel Index: %02u\n", i);
+
+		mtk_tops_mac_param_dump(s, &tnl_params->params);
+
+		mtk_tops_network_param_dump(s, &tnl_params->params);
+
+		mtk_tops_transport_param_dump(s, &tnl_params->params);
+
+		tnl_info->tnl_type->tnl_param_dump(s, &tnl_params->params);
+
+		seq_printf(s, "\tTOPS Entry: %02u CLS Entry: %02u CDRT: %02u Flag: 0x%x\n",
+			   tnl_params->tops_entry_proto,
+			   tnl_params->cls_entry,
+			   tnl_params->cdrt,
+			   tnl_params->flag);
+	}
+
+	return 0;
+}
+
+static int tops_tnl_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, tops_tnl_show, file->private_data);
+}
+
+static int tops_tnl_add_new_tnl(const char *buf)
+{
+	struct tops_tnl_params tnl_params;
+	struct tops_params *params;
+	struct tops_tnl_info *tnl_info;
+	struct tops_tnl_type *tnl_type;
+	char proto[DEBUG_PROTO_LEN];
+	int ofs = 0;
+	int ret = 0;
+
+	memset(&tnl_params, 0, sizeof(struct tops_tnl_params));
+	memset(proto, 0, sizeof(proto));
+
+	params = &tnl_params.params;
+
+	ret = mtk_tops_debug_param_setup(buf, &ofs, params);
+	if (ret)
+		return ret;
+
+	ret = mtk_tops_debug_param_proto_peek(buf, ofs, proto);
+	if (ret < 0)
+		return ret;
+
+	ofs += ret;
+
+	tnl_type = mtk_tops_tnl_type_get_by_name(proto);
+	if (!tnl_type || !tnl_type->tnl_debug_param_setup)
+		return -ENODEV;
+
+	ret = tnl_type->tnl_debug_param_setup(buf, &ofs, params);
+	if (ret < 0)
+		return ret;
+
+	tnl_params.flag |= TNL_DECAP_ENABLE;
+	tnl_params.flag |= TNL_ENCAP_ENABLE;
+	tnl_params.tops_entry_proto = tnl_type->tnl_proto_type;
+
+	tnl_info = mtk_tops_tnl_info_alloc(tnl_type);
+	if (IS_ERR(tnl_info))
+		return -ENOMEM;
+
+	tnl_info->flag |= TNL_INFO_DEBUG;
+	memcpy(&tnl_info->cache, &tnl_params, sizeof(struct tops_tnl_params));
+
+	mtk_tops_tnl_info_hash(tnl_info);
+
+	mtk_tops_tnl_info_submit(tnl_info);
+
+	return 0;
+}
+
+static ssize_t tops_tnl_write(struct file *file, const char __user *buffer,
+			      size_t count, loff_t *data)
+{
+	char cmd[21] = {0};
+	char buf[512];
+	int nchar = 0;
+	int ret = 0;
+
+	if (count > sizeof(buf))
+		return -ENOMEM;
+
+	if (copy_from_user(buf, buffer, count))
+		return -EFAULT;
+
+	buf[count] = '\0';
+
+	ret = sscanf(buf, "%20s %n", cmd, &nchar);
+
+	if (ret != 1)
+		return -EPERM;
+
+	if (!strcmp(cmd, "NEW_TNL")) {
+		ret = tops_tnl_add_new_tnl(buf + nchar);
+		if (ret)
+			return ret;
+	} else {
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+DEFINE_SHOW_ATTRIBUTE(tops_fw_info);
+
+static const struct file_operations tops_tnl_fops = {
+	.open = tops_tnl_open,
+	.read = seq_read,
+	.write = tops_tnl_write,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+int mtk_tops_debugfs_init(struct platform_device *pdev)
+{
+	tops_fw_debugfs_root = debugfs_create_dir("fw", tops_debugfs_root);
+
+	debugfs_create_file("firmware_info", 0400, tops_fw_debugfs_root, NULL,
+			    &tops_fw_info_fops);
+
+	debugfs_create_file("tunnel", 0444, tops_fw_debugfs_root, NULL,
+			    &tops_tnl_fops);
+
+	return 0;
+}
+
+void mtk_tops_debugfs_deinit(struct platform_device *pdev)
+{
+	debugfs_remove_recursive(tops_fw_debugfs_root);
+}
diff --git a/package-21.02/kernel/tops/src/firmware.c b/package-21.02/kernel/tops/src/firmware.c
index 646212f..438cbda 100644
--- a/package-21.02/kernel/tops/src/firmware.c
+++ b/package-21.02/kernel/tops/src/firmware.c
@@ -16,9 +16,9 @@
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 
-#include "firmware.h"
-#include "internal.h"
-#include "mcu.h"
+#include "tops/firmware.h"
+#include "tops/internal.h"
+#include "tops/mcu.h"
 
 #define TOPS_MGMT_IMG				"mediatek/tops-mgmt.img"
 #define TOPS_OFFLOAD_IMG			"mediatek/tops-offload.img"
diff --git a/package-21.02/kernel/tops/src/hpdma.c b/package-21.02/kernel/tops/src/hpdma.c
index 18f17e4..4bcae0f 100644
--- a/package-21.02/kernel/tops/src/hpdma.c
+++ b/package-21.02/kernel/tops/src/hpdma.c
@@ -17,11 +17,11 @@
 
 #include <virt-dma.h>
 
-#include "hpdma.h"
-#include "hwspinlock.h"
-#include "internal.h"
-#include "mbox.h"
-#include "mcu.h"
+#include "tops/hpdma.h"
+#include "tops/hwspinlock.h"
+#include "tops/internal.h"
+#include "tops/mbox.h"
+#include "tops/mcu.h"
 
 #define HPDMA_CHAN_NUM			(4)
 
@@ -307,12 +307,9 @@
 	 * axsize can be 1, 2, 4, 8, 16 bytes
 	 * calculate axsize
 	 */
-	while (hvdesc->axsize >= 0 && hvdesc->len % (0x1 << hvdesc->axsize))
+	while (hvdesc->axsize > 0 && hvdesc->len % (0x1 << hvdesc->axsize))
 		hvdesc->axsize--;
 
-	if (hvdesc->axsize < 0)
-		return -EINVAL;
-
 	hvdesc->total_num = hvdesc->len / (0x1 << hvdesc->axsize);
 
 	return 0;
diff --git a/package-21.02/kernel/tops/src/hwspinlock.c b/package-21.02/kernel/tops/src/hwspinlock.c
index 1723cf4..774c56f 100644
--- a/package-21.02/kernel/tops/src/hwspinlock.c
+++ b/package-21.02/kernel/tops/src/hwspinlock.c
@@ -11,7 +11,8 @@
 #include <linux/device.h>
 #include <linux/platform_device.h>
 
-#include "hwspinlock.h"
+#include "tops/hwspinlock.h"
+#include "tops/tops.h"
 
 #define SEMA_ID				(BIT(CORE_AP))
 
diff --git a/package-21.02/kernel/tops/src/inc/ctrl.h b/package-21.02/kernel/tops/src/inc/tops/ctrl.h
similarity index 100%
rename from package-21.02/kernel/tops/src/inc/ctrl.h
rename to package-21.02/kernel/tops/src/inc/tops/ctrl.h
diff --git a/package-21.02/kernel/tops/src/inc/debugfs.h b/package-21.02/kernel/tops/src/inc/tops/debugfs.h
similarity index 61%
rename from package-21.02/kernel/tops/src/inc/debugfs.h
rename to package-21.02/kernel/tops/src/inc/tops/debugfs.h
index ea1847c..e4a6da1 100644
--- a/package-21.02/kernel/tops/src/inc/debugfs.h
+++ b/package-21.02/kernel/tops/src/inc/tops/debugfs.h
@@ -8,6 +8,11 @@
 #ifndef _TOPS_DEBUGFS_H_
 #define _TOPS_DEBUGFS_H_
 
+#include <linux/debugfs.h>
+#include <linux/platform_device.h>
+
 extern struct dentry *tops_debugfs_root;
 
+int mtk_tops_debugfs_init(struct platform_device *pdev);
+void mtk_tops_debugfs_deinit(struct platform_device *pdev);
 #endif /* _TOPS_DEBUGFS_H_ */
diff --git a/package-21.02/kernel/tops/src/inc/firmware.h b/package-21.02/kernel/tops/src/inc/tops/firmware.h
similarity index 100%
rename from package-21.02/kernel/tops/src/inc/firmware.h
rename to package-21.02/kernel/tops/src/inc/tops/firmware.h
diff --git a/package-21.02/kernel/tops/src/inc/hpdma.h b/package-21.02/kernel/tops/src/inc/tops/hpdma.h
similarity index 100%
rename from package-21.02/kernel/tops/src/inc/hpdma.h
rename to package-21.02/kernel/tops/src/inc/tops/hpdma.h
diff --git a/package-21.02/kernel/tops/src/inc/hwspinlock.h b/package-21.02/kernel/tops/src/inc/tops/hwspinlock.h
similarity index 98%
rename from package-21.02/kernel/tops/src/inc/hwspinlock.h
rename to package-21.02/kernel/tops/src/inc/tops/hwspinlock.h
index ee9e343..1ce5004 100644
--- a/package-21.02/kernel/tops/src/inc/hwspinlock.h
+++ b/package-21.02/kernel/tops/src/inc/tops/hwspinlock.h
@@ -10,8 +10,6 @@
 
 #include <linux/types.h>
 
-#include "mbox.h"
-
 #define HWSPINLOCK_SLOT_MAX		16
 
 #define HWSPINLOCK_TOP_BASE		0x10100
diff --git a/package-21.02/kernel/tops/src/inc/internal.h b/package-21.02/kernel/tops/src/inc/tops/internal.h
similarity index 100%
rename from package-21.02/kernel/tops/src/inc/internal.h
rename to package-21.02/kernel/tops/src/inc/tops/internal.h
diff --git a/package-21.02/kernel/tops/src/inc/mbox.h b/package-21.02/kernel/tops/src/inc/tops/mbox.h
similarity index 98%
rename from package-21.02/kernel/tops/src/inc/mbox.h
rename to package-21.02/kernel/tops/src/inc/tops/mbox.h
index 002f2c6..c116162 100644
--- a/package-21.02/kernel/tops/src/inc/mbox.h
+++ b/package-21.02/kernel/tops/src/inc/tops/mbox.h
@@ -10,8 +10,8 @@
 
 #include <linux/list.h>
 
-#include "mbox_id.h"
-#include "tops.h"
+#include "tops/mbox_id.h"
+#include "tops/tops.h"
 
 /* mbox device macros */
 #define MBOX_DEV(core_id, cmd)				\
diff --git a/package-21.02/kernel/tops/src/inc/mbox_id.h b/package-21.02/kernel/tops/src/inc/tops/mbox_id.h
similarity index 100%
rename from package-21.02/kernel/tops/src/inc/mbox_id.h
rename to package-21.02/kernel/tops/src/inc/tops/mbox_id.h
diff --git a/package-21.02/kernel/tops/src/inc/mcu.h b/package-21.02/kernel/tops/src/inc/tops/mcu.h
similarity index 99%
rename from package-21.02/kernel/tops/src/inc/mcu.h
rename to package-21.02/kernel/tops/src/inc/tops/mcu.h
index 7c463eb..df9b059 100644
--- a/package-21.02/kernel/tops/src/inc/mcu.h
+++ b/package-21.02/kernel/tops/src/inc/tops/mcu.h
@@ -18,7 +18,7 @@
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
 
-#include "tops.h"
+#include "tops/tops.h"
 
 struct mcu_state;
 
diff --git a/package-21.02/kernel/tops/src/inc/net-event.h b/package-21.02/kernel/tops/src/inc/tops/net-event.h
similarity index 100%
rename from package-21.02/kernel/tops/src/inc/net-event.h
rename to package-21.02/kernel/tops/src/inc/tops/net-event.h
diff --git a/package-21.02/kernel/tops/src/inc/netsys.h b/package-21.02/kernel/tops/src/inc/tops/netsys.h
similarity index 97%
rename from package-21.02/kernel/tops/src/inc/netsys.h
rename to package-21.02/kernel/tops/src/inc/tops/netsys.h
index 1f51695..b319be4 100644
--- a/package-21.02/kernel/tops/src/inc/netsys.h
+++ b/package-21.02/kernel/tops/src/inc/tops/netsys.h
@@ -12,7 +12,7 @@
 #include <linux/bitfield.h>
 #include <linux/platform_device.h>
 
-#include "tunnel.h"
+#include "tops/tunnel.h"
 
 /* FE BASE */
 #define FE_BASE					(0x0000)
diff --git a/package-21.02/kernel/tops/src/inc/ser.h b/package-21.02/kernel/tops/src/inc/tops/ser.h
similarity index 92%
rename from package-21.02/kernel/tops/src/inc/ser.h
rename to package-21.02/kernel/tops/src/inc/tops/ser.h
index 99f9d3d..72f1f7d 100644
--- a/package-21.02/kernel/tops/src/inc/ser.h
+++ b/package-21.02/kernel/tops/src/inc/tops/ser.h
@@ -12,9 +12,9 @@
 #include <linux/spinlock.h>
 #include <linux/platform_device.h>
 
-#include "net-event.h"
-#include "mcu.h"
-#include "wdt.h"
+#include "tops/net-event.h"
+#include "tops/mcu.h"
+#include "tops/wdt.h"
 
 enum tops_ser_type {
 	TOPS_SER_NETSYS_FE_RST,
diff --git a/package-21.02/kernel/tops/src/inc/tdma.h b/package-21.02/kernel/tops/src/inc/tops/tdma.h
similarity index 100%
rename from package-21.02/kernel/tops/src/inc/tdma.h
rename to package-21.02/kernel/tops/src/inc/tops/tdma.h
diff --git a/package-21.02/kernel/tops/src/inc/tops.h b/package-21.02/kernel/tops/src/inc/tops/tops.h
similarity index 100%
rename from package-21.02/kernel/tops/src/inc/tops.h
rename to package-21.02/kernel/tops/src/inc/tops/tops.h
diff --git a/package-21.02/kernel/tops/src/inc/tops/tops_params.h b/package-21.02/kernel/tops/src/inc/tops/tops_params.h
new file mode 100644
index 0000000..0bdb9b5
--- /dev/null
+++ b/package-21.02/kernel/tops/src/inc/tops/tops_params.h
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
+ */
+
+#ifndef _TOPS_PARAMS_H_
+#define _TOPS_PARAMS_H_
+
+#include <linux/if_ether.h>
+#include <linux/seq_file.h>
+#include <linux/types.h>
+
+#include "tops/protocol/network/ip_params.h"
+#include "tops/protocol/transport/udp_params.h"
+#include "tops/protocol/tunnel/l2tp/l2tp_params.h"
+
+/* tunnel params flags */
+#define TNL_DECAP_ENABLE	(BIT(TNL_PARAMS_DECAP_ENABLE_BIT))
+#define TNL_ENCAP_ENABLE	(BIT(TNL_PARAMS_ENCAP_ENABLE_BIT))
+
+#define DEBUG_PROTO_LEN		(21)
+#define DEBUG_PROTO_ETH		"eth"
+#define DEBUG_PROTO_IP		"ipv4"
+#define DEBUG_PROTO_UDP		"udp"
+#define DEBUG_PROTO_GRETAP	"gretap"
+#define DEBUG_PROTO_L2TP_V2	"l2tpv2"
+
+enum tops_mac_type {
+	TOPS_MAC_NONE,
+	TOPS_MAC_ETH,
+
+	__TOPS_MAC_TYPE_MAX,
+};
+
+enum tops_network_type {
+	TOPS_NETWORK_NONE,
+	TOPS_NETWORK_IPV4,
+
+	__TOPS_NETWORK_TYPE_MAX,
+};
+
+enum tops_transport_type {
+	TOPS_TRANSPORT_NONE,
+	TOPS_TRANSPORT_UDP,
+
+	__TOPS_TRANSPORT_TYPE_MAX,
+};
+
+enum tops_tunnel_type {
+	TOPS_TUNNEL_NONE = 0,
+	TOPS_TUNNEL_GRETAP,
+	TOPS_TUNNEL_PPTP,
+	TOPS_TUNNEL_L2TP_V2,
+	TOPS_TUNNEL_L2TP_V3 = 5,
+	TOPS_TUNNEL_VXLAN,
+	TOPS_TUNNEL_NATT,
+	TOPS_TUNNEL_CAPWAP_CTRL,
+	TOPS_TUNNEL_CAPWAP_DATA,
+	TOPS_TUNNEL_CAPWAP_DTLS = 10,
+	TOPS_TUNNEL_IPSEC_ESP,
+	TOPS_TUNNEL_IPSEC_AH,
+
+	__TOPS_TUNNEL_TYPE_MAX = CONFIG_TOPS_TNL_TYPE_NUM,
+};
+
+enum tops_tnl_params_flag {
+	TNL_PARAMS_DECAP_ENABLE_BIT,
+	TNL_PARAMS_ENCAP_ENABLE_BIT,
+};
+
+struct tops_mac_params {
+	union {
+		struct ethhdr eth;
+	};
+	enum tops_mac_type type;
+};
+
+struct tops_network_params {
+	union {
+		struct tops_ip_params ip;
+	};
+	enum tops_network_type type;
+};
+
+struct tops_transport_params {
+	union {
+		struct tops_udp_params udp;
+	};
+	enum tops_transport_type type;
+};
+
+struct tops_tunnel_params {
+	union {
+		struct tops_l2tp_params l2tp;
+	};
+	enum tops_tunnel_type type;
+};
+
+struct tops_params {
+	struct tops_mac_params mac;
+	struct tops_network_params network;
+	struct tops_transport_params transport;
+	struct tops_tunnel_params tunnel;
+};
+
+/* record outer tunnel header data for HW offloading */
+struct tops_tnl_params {
+	struct tops_params params;
+	u8 tops_entry_proto;
+	u8 cls_entry;
+	u8 cdrt;
+	u8 flag; /* bit: enum tops_tnl_params_flag */
+} __packed __aligned(16);
+
+int
+mtk_tops_encap_param_setup(struct sk_buff *skb,
+			   struct tops_params *params,
+			   int (*tnl_encap_param_setup)(struct sk_buff *skb,
+							struct tops_params *params));
+int
+mtk_tops_decap_param_setup(struct sk_buff *skb,
+			   struct tops_params *params,
+			   int (*tnl_decap_param_setup)(struct sk_buff *skb,
+							struct tops_params *params));
+
+int mtk_tops_transport_decap_param_setup(struct sk_buff *skb,
+					 struct tops_params *params);
+int mtk_tops_network_decap_param_setup(struct sk_buff *skb,
+				       struct tops_params *params);
+int mtk_tops_mac_decap_param_setup(struct sk_buff *skb,
+				       struct tops_params *params);
+
+int mtk_tops_debug_param_proto_peek(const char *buf, int ofs, char *out);
+int mtk_tops_debug_param_setup(const char *buf, int *ofs,
+				   struct tops_params *params);
+void mtk_tops_mac_param_dump(struct seq_file *s, struct tops_params *params);
+void mtk_tops_network_param_dump(struct seq_file *s, struct tops_params *params);
+void mtk_tops_transport_param_dump(struct seq_file *s, struct tops_params *params);
+
+bool mtk_tops_params_match(struct tops_params *p1, struct tops_params *p2);
+#endif /* _TOPS_PARAMS_H_ */
diff --git a/package-21.02/kernel/tops/src/inc/trm-debugfs.h b/package-21.02/kernel/tops/src/inc/tops/trm-debugfs.h
similarity index 100%
rename from package-21.02/kernel/tops/src/inc/trm-debugfs.h
rename to package-21.02/kernel/tops/src/inc/tops/trm-debugfs.h
diff --git a/package-21.02/kernel/tops/src/inc/trm-fs.h b/package-21.02/kernel/tops/src/inc/tops/trm-fs.h
similarity index 100%
rename from package-21.02/kernel/tops/src/inc/trm-fs.h
rename to package-21.02/kernel/tops/src/inc/tops/trm-fs.h
diff --git a/package-21.02/kernel/tops/src/inc/trm-mcu.h b/package-21.02/kernel/tops/src/inc/tops/trm-mcu.h
similarity index 97%
rename from package-21.02/kernel/tops/src/inc/trm-mcu.h
rename to package-21.02/kernel/tops/src/inc/tops/trm-mcu.h
index e3f9e3f..87cf699 100644
--- a/package-21.02/kernel/tops/src/inc/trm-mcu.h
+++ b/package-21.02/kernel/tops/src/inc/tops/trm-mcu.h
@@ -9,7 +9,7 @@
 #ifndef _TOPS_TRM_MCU_H_
 #define _TOPS_TRM_MCU_H_
 
-#include "tops.h"
+#include "tops/tops.h"
 
 #define XCHAL_NUM_AREG                  (32)
 #define CORE_DUMP_FRAM_MAGIC            (0x00BE00BE)
diff --git a/package-21.02/kernel/tops/src/inc/trm.h b/package-21.02/kernel/tops/src/inc/tops/trm.h
similarity index 100%
rename from package-21.02/kernel/tops/src/inc/trm.h
rename to package-21.02/kernel/tops/src/inc/tops/trm.h
diff --git a/package-21.02/kernel/tops/src/inc/tunnel.h b/package-21.02/kernel/tops/src/inc/tops/tunnel.h
similarity index 72%
rename from package-21.02/kernel/tops/src/inc/tunnel.h
rename to package-21.02/kernel/tops/src/inc/tops/tunnel.h
index d00eebe..cbe4dc6 100644
--- a/package-21.02/kernel/tops/src/inc/tunnel.h
+++ b/package-21.02/kernel/tops/src/inc/tops/tunnel.h
@@ -15,12 +15,13 @@
 #include <linux/kthread.h>
 #include <linux/netdevice.h>
 #include <linux/refcount.h>
+#include <linux/seq_file.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 
 #include <pce/cls.h>
 
-#include "protocol/l2tp/l2tp.h"
+#include "tops/tops_params.h"
 
 /* tunnel info status */
 #define TNL_STA_UNINIT		(BIT(TNL_STATUS_UNINIT))
@@ -31,10 +32,6 @@
 #define TNL_STA_DIP_UPDATE	(BIT(TNL_STATUS_DIP_UPDATE))
 #define TNL_STA_DELETING	(BIT(TNL_STATUS_DELETING))
 
-/* tunnel params flags */
-#define TNL_DECAP_ENABLE	(BIT(TNL_PARAMS_DECAP_ENABLE_BIT))
-#define TNL_ENCAP_ENABLE	(BIT(TNL_PARAMS_ENCAP_ENABLE_BIT))
-
 /* tunnel info flags */
 #define TNL_INFO_DEBUG		(BIT(TNL_INFO_DEBUG_BIT))
 
@@ -54,24 +51,6 @@
 	TOPS_CRSN_TNL_ID_END = 0x2F,
 };
 
-enum tops_entry_type {
-	TOPS_ENTRY_NONE = 0,
-	TOPS_ENTRY_GRETAP,
-	TOPS_ENTRY_PPTP,
-	TOPS_ENTRY_IP_L2TP,
-	TOPS_ENTRY_UDP_L2TP_CTRL,
-	TOPS_ENTRY_UDP_L2TP_DATA = 5,
-	TOPS_ENTRY_VXLAN,
-	TOPS_ENTRY_NATT,
-	TOPS_ENTRY_CAPWAP_CTRL,
-	TOPS_ENTRY_CAPWAP_DATA,
-	TOPS_ENTRY_CAPWAP_DTLS = 10,
-	TOPS_ENTRY_IPSEC_ESP,
-	TOPS_ENTRY_IPSEC_AH,
-
-	__TOPS_ENTRY_MAX = CONFIG_TOPS_TNL_NUM,
-};
-
 enum tops_tunnel_mbox_cmd {
 	TOPS_TNL_MBOX_CMD_RESV,
 	TOPS_TNL_START_ADDR_SYNC,
@@ -100,11 +79,6 @@
 	__TNL_STATUS_MAX,
 };
 
-enum tops_tnl_params_flag {
-	TNL_PARAMS_DECAP_ENABLE_BIT,
-	TNL_PARAMS_ENCAP_ENABLE_BIT,
-};
-
 enum tops_tnl_info_flag {
 	TNL_INFO_DEBUG_BIT,
 };
@@ -116,24 +90,6 @@
 	bool updated;
 };
 
-/* record outer tunnel header data for HW offloading */
-struct tops_tnl_params {
-	u8 daddr[ETH_ALEN];
-	u8 saddr[ETH_ALEN];
-	__be32 dip;
-	__be32 sip;
-	__be16 dport;
-	__be16 sport;
-	u16 protocol;
-	u8 tops_entry_proto;
-	u8 cls_entry;
-	u8 cdrt;
-	u8 flag; /* bit: enum tops_tnl_params_flag */
-	union {
-		struct l2tp_param l2tp; /* 4B */
-	} priv;
-} __packed __aligned(16);
-
 struct tops_tnl_info {
 	struct tops_tnl_params tnl_params;
 	struct tops_tnl_params cache;
@@ -157,31 +113,38 @@
  */
 struct tops_tnl_type {
 	const char *type_name;
-	enum tops_entry_type tops_entry;
+	enum tops_tunnel_type tnl_proto_type;
 
 	int (*cls_entry_setup)(struct tops_tnl_info *tnl_info,
 			       struct cls_desc *cdesc);
 	struct list_head tcls_head;
 	bool use_multi_cls;
 
+	/* parameter setup */
 	int (*tnl_decap_param_setup)(struct sk_buff *skb,
-				     struct tops_tnl_params *tnl_params);
+				     struct tops_params *params);
 	int (*tnl_encap_param_setup)(struct sk_buff *skb,
-				     struct tops_tnl_params *tnl_params);
+				     struct tops_params *params);
 	int (*tnl_debug_param_setup)(const char *buf, int *ofs,
-				     struct tops_tnl_params *tnl_params);
+				     struct tops_params *params);
 	int (*tnl_l2_param_update)(struct sk_buff *skb,
-				   struct tops_tnl_params *tnl_params);
-	int (*tnl_dump_param)(char *buf, struct tops_tnl_params *tnl_params);
-	bool (*tnl_info_match)(struct tops_tnl_params *params1,
-			       struct tops_tnl_params *params2);
+				   struct tops_params *params);
+	/* parameter debug dump */
+	void (*tnl_param_dump)(struct seq_file *s, struct tops_params *params);
+	/* check skb content can be offloaded */
 	bool (*tnl_decap_offloadable)(struct sk_buff *skb);
+	/* match between 2 parameters */
+	bool (*tnl_param_match)(struct tops_params *p, struct tops_params *target);
+	/* recover essential parameters before updating */
+	void (*tnl_param_restore)(struct tops_params *old, struct tops_params *new);
 	bool has_inner_eth;
 };
 
 void mtk_tops_tnl_info_submit_no_tnl_lock(struct tops_tnl_info *tnl_info);
 void mtk_tops_tnl_info_submit(struct tops_tnl_info *tnl_info);
-struct tops_tnl_info *mtk_tops_tnl_info_find(struct tops_tnl_params *tnl_params);
+struct tops_tnl_info *mtk_tops_tnl_info_get_by_idx(u32 tnl_idx);
+struct tops_tnl_info *mtk_tops_tnl_info_find(struct tops_tnl_type *tnl_type,
+					     struct tops_tnl_params *tnl_params);
 struct tops_tnl_info *mtk_tops_tnl_info_alloc(struct tops_tnl_type *tnl_type);
 void mtk_tops_tnl_info_hash(struct tops_tnl_info *tnl_info);
 
diff --git a/package-21.02/kernel/tops/src/inc/wdt.h b/package-21.02/kernel/tops/src/inc/tops/wdt.h
similarity index 95%
rename from package-21.02/kernel/tops/src/inc/wdt.h
rename to package-21.02/kernel/tops/src/inc/tops/wdt.h
index b70bf63..22918a0 100644
--- a/package-21.02/kernel/tops/src/inc/wdt.h
+++ b/package-21.02/kernel/tops/src/inc/tops/wdt.h
@@ -10,7 +10,7 @@
 
 #include <linux/platform_device.h>
 
-#include "tops.h"
+#include "tops/tops.h"
 
 enum wdt_cmd {
 	WDT_CMD_TRIGGER_TIMEOUT,
diff --git a/package-21.02/kernel/tops/src/init.c b/package-21.02/kernel/tops/src/init.c
index 62c7806..478a45a 100644
--- a/package-21.02/kernel/tops/src/init.c
+++ b/package-21.02/kernel/tops/src/init.c
@@ -15,21 +15,22 @@
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 
-#include "ctrl.h"
-#include "firmware.h"
-#include "hpdma.h"
-#include "hwspinlock.h"
-#include "internal.h"
-#include "mbox.h"
-#include "mcu.h"
-#include "netsys.h"
-#include "net-event.h"
-#include "ser.h"
-#include "tdma.h"
-#include "trm-mcu.h"
-#include "trm.h"
-#include "tunnel.h"
-#include "wdt.h"
+#include "tops/ctrl.h"
+#include "tops/debugfs.h"
+#include "tops/firmware.h"
+#include "tops/hpdma.h"
+#include "tops/hwspinlock.h"
+#include "tops/internal.h"
+#include "tops/mbox.h"
+#include "tops/mcu.h"
+#include "tops/netsys.h"
+#include "tops/net-event.h"
+#include "tops/ser.h"
+#include "tops/tdma.h"
+#include "tops/trm-mcu.h"
+#include "tops/trm.h"
+#include "tops/tunnel.h"
+#include "tops/wdt.h"
 
 #define EFUSE_TOPS_POWER_OFF		(0xD08)
 
@@ -79,8 +80,17 @@
 		goto err_ser_deinit;
 	}
 
+	ret = mtk_tops_debugfs_init(pdev);
+	if (ret) {
+		TOPS_ERR("debugfs init failed: %d\n", ret);
+		goto err_wdt_deinit;
+	}
+
 	return ret;
 
+err_wdt_deinit:
+	mtk_tops_wdt_deinit(pdev);
+
 err_ser_deinit:
 	mtk_tops_ser_deinit(pdev);
 
@@ -165,6 +175,8 @@
 
 static int mtk_tops_remove(struct platform_device *pdev)
 {
+	mtk_tops_debugfs_init(pdev);
+
 	mtk_tops_wdt_deinit(pdev);
 
 	mtk_tops_ser_deinit(pdev);
diff --git a/package-21.02/kernel/tops/src/mbox.c b/package-21.02/kernel/tops/src/mbox.c
index c10cbca..dc902c4 100644
--- a/package-21.02/kernel/tops/src/mbox.c
+++ b/package-21.02/kernel/tops/src/mbox.c
@@ -15,9 +15,9 @@
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
 
-#include "mcu.h"
-#include "mbox.h"
-#include "internal.h"
+#include "tops/mcu.h"
+#include "tops/mbox.h"
+#include "tops/internal.h"
 
 #define MBOX_SEND_TIMEOUT		(2000)
 
diff --git a/package-21.02/kernel/tops/src/mcu.c b/package-21.02/kernel/tops/src/mcu.c
index 30cb032..6e8643a 100644
--- a/package-21.02/kernel/tops/src/mcu.c
+++ b/package-21.02/kernel/tops/src/mcu.c
@@ -22,15 +22,15 @@
 
 #include <pce/pce.h>
 
-#include "ctrl.h"
-#include "firmware.h"
-#include "hpdma.h"
-#include "internal.h"
-#include "mbox.h"
-#include "mcu.h"
-#include "netsys.h"
-#include "tdma.h"
-#include "trm.h"
+#include "tops/ctrl.h"
+#include "tops/firmware.h"
+#include "tops/hpdma.h"
+#include "tops/internal.h"
+#include "tops/mbox.h"
+#include "tops/mcu.h"
+#include "tops/netsys.h"
+#include "tops/tdma.h"
+#include "tops/trm.h"
 
 #define TDMA_TIMEOUT_MAX_CNT			(3)
 #define TDMA_TIMEOUT_DELAY			(100) /* 100ms */
diff --git a/package-21.02/kernel/tops/src/net-event.c b/package-21.02/kernel/tops/src/net-event.c
index 7cc4553..6143a03 100644
--- a/package-21.02/kernel/tops/src/net-event.c
+++ b/package-21.02/kernel/tops/src/net-event.c
@@ -20,13 +20,13 @@
 #include <net/neighbour.h>
 #include <net/route.h>
 
-#include "internal.h"
-#include "netsys.h"
-#include "net-event.h"
-#include "mcu.h"
-#include "ser.h"
-#include "trm.h"
-#include "tunnel.h"
+#include "tops/internal.h"
+#include "tops/netsys.h"
+#include "tops/net-event.h"
+#include "tops/mcu.h"
+#include "tops/ser.h"
+#include "tops/trm.h"
+#include "tops/tunnel.h"
 
 static struct completion wait_fe_reset_done;
 
diff --git a/package-21.02/kernel/tops/src/netsys.c b/package-21.02/kernel/tops/src/netsys.c
index 7deb502..50513d8 100644
--- a/package-21.02/kernel/tops/src/netsys.c
+++ b/package-21.02/kernel/tops/src/netsys.c
@@ -16,12 +16,12 @@
 
 #include <pce/netsys.h>
 
-#include "hpdma.h"
-#include "internal.h"
-#include "mcu.h"
-#include "netsys.h"
-#include "tdma.h"
-#include "trm.h"
+#include "tops/hpdma.h"
+#include "tops/internal.h"
+#include "tops/mcu.h"
+#include "tops/netsys.h"
+#include "tops/tdma.h"
+#include "tops/trm.h"
 
 /* Netsys dump length */
 #define FE_BASE_LEN				(0x2900)
diff --git a/package-21.02/kernel/tops/src/protocol/inc/protocol/l2tp/udp_l2tp_data.h b/package-21.02/kernel/tops/src/protocol/inc/protocol/l2tp/udp_l2tp_data.h
deleted file mode 100644
index 25f9dc3..0000000
--- a/package-21.02/kernel/tops/src/protocol/inc/protocol/l2tp/udp_l2tp_data.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
- *
- * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
- */
-
-#ifndef _TOPS_UDP_L2TP_DATA_H_
-#define _TOPS_UDP_L2TP_DATA_H_
-
-#if defined(CONFIG_MTK_TOPS_UDP_L2TP_DATA)
-int mtk_tops_udp_l2tp_data_init(void);
-void mtk_tops_udp_l2tp_data_deinit(void);
-#else /* !defined(CONFIG_MTK_TOPS_UDP_L2TP_DATA) */
-static inline int mtk_tops_udp_l2tp_data_init(void)
-{
-	return 0;
-}
-
-static inline void mtk_tops_udp_l2tp_data_deinit(void)
-{
-}
-#endif /* defined(CONFIG_MTK_TOPS_UDP_L2TP_DATA) */
-#endif /* _TOPS_UDP_L2TP_DATA_H_ */
diff --git a/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/mac/eth.h b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/mac/eth.h
new file mode 100644
index 0000000..f306230
--- /dev/null
+++ b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/mac/eth.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
+ */
+
+#ifndef _TOPS_ETH_H_
+#define _TOPS_ETH_H_
+
+#include <linux/if_ether.h>
+
+#include "tops/tops_params.h"
+
+int
+mtk_tops_eth_encap_param_setup(
+			struct sk_buff *skb,
+			struct tops_params *params,
+			int (*tnl_encap_param_setup)(struct sk_buff *skb,
+						     struct tops_params *params));
+int mtk_tops_eth_decap_param_setup(struct sk_buff *skb, struct tops_params *params);
+int mtk_tops_eth_debug_param_setup(const char *buf, int *ofs,
+				   struct tops_params *params);
+void mtk_tops_eth_param_dump(struct seq_file *s, struct tops_params *params);
+#endif /* _TOPS_ETH_H_ */
diff --git a/package-21.02/kernel/tops/src/protocol/inc/protocol/ppp/ppp.h b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/mac/ppp.h
similarity index 61%
rename from package-21.02/kernel/tops/src/protocol/inc/protocol/ppp/ppp.h
rename to package-21.02/kernel/tops/src/protocol/inc/tops/protocol/mac/ppp.h
index 274dfde..b5f1cb4 100644
--- a/package-21.02/kernel/tops/src/protocol/inc/protocol/ppp/ppp.h
+++ b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/mac/ppp.h
@@ -2,12 +2,16 @@
 /*
  * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
  *
- * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
+ * Author: Frank-zj Lin <rank-zj.lin@mediatek.com>
  */
 
 #ifndef _TOPS_PPP_H_
 #define _TOPS_PPP_H_
 
+#include <linux/ppp_defs.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+
 /* Limited support: ppp header, no options */
 struct ppp_hdr {
 	u8 addr;
@@ -15,4 +19,5 @@
 	u16 proto;
 };
 
+bool mtk_tops_ppp_valid(struct sk_buff *skb);
 #endif /* _TOPS_PPP_H_ */
diff --git a/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/network/ip.h b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/network/ip.h
new file mode 100644
index 0000000..3182b5d
--- /dev/null
+++ b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/network/ip.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
+ */
+
+#ifndef _TOPS_IP_H_
+#define _TOPS_IP_H_
+
+#include <linux/ip.h>
+#include <uapi/linux/in.h>
+
+#include "tops/protocol/network/ip_params.h"
+#include "tops/tops_params.h"
+
+int mtk_tops_ip_encap_param_setup(
+			struct sk_buff *skb,
+			struct tops_params *params,
+			int (*tnl_encap_param_setup)(struct sk_buff *skb,
+						     struct tops_params *params));
+int mtk_tops_ip_decap_param_setup(struct sk_buff *skb, struct tops_params *params);
+int mtk_tops_ip_debug_param_setup(const char *buf, int *ofs,
+				  struct tops_params *params);
+void mtk_tops_ip_param_dump(struct seq_file *s, struct tops_params *params);
+#endif /* _TOPS_IP_H_ */
diff --git a/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/network/ip_params.h b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/network/ip_params.h
new file mode 100644
index 0000000..9583862
--- /dev/null
+++ b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/network/ip_params.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
+ */
+
+#ifndef _TOPS_IP_PARAMS_H_
+#define _TOPS_IP_PARAMS_H_
+
+#include <linux/types.h>
+
+struct tops_ip_params {
+	__be32 sip;
+	__be32 dip;
+	u8 proto;
+	u8 tos;
+	u8 ttl;
+};
+#endif /* _TOPS_IP_PARAMS_H_ */
diff --git a/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/transport/udp.h b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/transport/udp.h
new file mode 100644
index 0000000..9ee8977
--- /dev/null
+++ b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/transport/udp.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
+ */
+
+#ifndef _TOPS_UDP_H_
+#define _TOPS_UDP_H_
+
+#include "tops/protocol/transport/udp_params.h"
+#include "tops/tops_params.h"
+
+int mtk_tops_udp_encap_param_setup(
+			struct sk_buff *skb,
+			struct tops_params *params,
+			int (*tnl_encap_param_setup)(struct sk_buff *skb,
+						     struct tops_params *params));
+int mtk_tops_udp_decap_param_setup(struct sk_buff *skb, struct tops_params *params);
+int mtk_tops_udp_debug_param_setup(const char *buf, int *ofs,
+				   struct tops_params *params);
+void mtk_tops_udp_param_dump(struct seq_file *s, struct tops_params *params);
+#endif /* _TOPS_UDP_H_ */
diff --git a/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/transport/udp_params.h b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/transport/udp_params.h
new file mode 100644
index 0000000..b66476c
--- /dev/null
+++ b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/transport/udp_params.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
+ */
+
+#ifndef _TOPS_UDP_PARAMS_H_
+#define _TOPS_UDP_PARAMS_H_
+
+#include <linux/types.h>
+#include <linux/udp.h>
+
+struct tops_udp_params {
+	u16 sport;
+	u16 dport;
+};
+#endif /* _TOPS_UDP_PARAMS_H_ */
diff --git a/package-21.02/kernel/tops/src/protocol/inc/protocol/gre/gretap.h b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/tunnel/gre/gretap.h
similarity index 68%
rename from package-21.02/kernel/tops/src/protocol/inc/protocol/gre/gretap.h
rename to package-21.02/kernel/tops/src/protocol/inc/tops/protocol/tunnel/gre/gretap.h
index e308fde..46a68db 100644
--- a/package-21.02/kernel/tops/src/protocol/inc/protocol/gre/gretap.h
+++ b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/tunnel/gre/gretap.h
@@ -8,10 +8,19 @@
 #ifndef _TOPS_GRETAP_H_
 #define _TOPS_GRETAP_H_
 
+#include "tops/tops_params.h"
+
 #if defined(CONFIG_MTK_TOPS_GRETAP)
+int mtk_tops_gretap_decap_param_setup(struct sk_buff *skb, struct tops_params *params);
 int mtk_tops_gretap_init(void);
 void mtk_tops_gretap_deinit(void);
 #else /* !defined(CONFIG_MTK_TOPS_GRETAP) */
+static inline int mtk_tops_gretap_decap_param_setup(struct sk_buff *skb,
+						    struct tops_params *params)
+{
+	return -ENODEV;
+}
+
 static inline int mtk_tops_gretap_init(void)
 {
 	return 0;
diff --git a/package-21.02/kernel/tops/src/protocol/inc/protocol/l2tp/l2tp.h b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/tunnel/l2tp/l2tp_params.h
similarity index 95%
rename from package-21.02/kernel/tops/src/protocol/inc/protocol/l2tp/l2tp.h
rename to package-21.02/kernel/tops/src/protocol/inc/tops/protocol/tunnel/l2tp/l2tp_params.h
index 34449c1..dc266ef 100644
--- a/package-21.02/kernel/tops/src/protocol/inc/protocol/l2tp/l2tp.h
+++ b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/tunnel/l2tp/l2tp_params.h
@@ -18,7 +18,7 @@
 
 #define UDP_L2TP_PORT		1701
 
-struct l2tp_param {
+struct tops_l2tp_params {
 	u16 tid; /* l2tp tunnel id */
 	u16 sid; /* l2tp session id */
 };
@@ -29,5 +29,4 @@
 	u16 tid;
 	u16 sid;
 };
-
 #endif /* _TOPS_L2TP_H_ */
diff --git a/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/tunnel/l2tp/l2tpv2.h b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/tunnel/l2tp/l2tpv2.h
new file mode 100644
index 0000000..a757f11
--- /dev/null
+++ b/package-21.02/kernel/tops/src/protocol/inc/tops/protocol/tunnel/l2tp/l2tpv2.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
+ */
+
+#ifndef _TOPS_L2TP_V2_H_
+#define _TOPS_L2TP_V2_H_
+
+#include "tops/protocol/tunnel/l2tp/l2tp_params.h"
+
+#if defined(CONFIG_MTK_TOPS_L2TP_V2)
+int mtk_tops_l2tpv2_init(void);
+void mtk_tops_l2tpv2_deinit(void);
+#else /* !defined(CONFIG_MTK_TOPS_L2TP_V2) */
+static inline int mtk_tops_l2tpv2_init(void)
+{
+	return 0;
+}
+
+static inline void mtk_tops_l2tpv2_deinit(void)
+{
+}
+#endif /* defined(CONFIG_MTK_TOPS_L2TP_V2) */
+#endif /* _TOPS_L2TP_V2_H_ */
diff --git a/package-21.02/kernel/tops/src/protocol/mac/eth.c b/package-21.02/kernel/tops/src/protocol/mac/eth.c
new file mode 100644
index 0000000..37d4d59
--- /dev/null
+++ b/package-21.02/kernel/tops/src/protocol/mac/eth.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
+ */
+
+#include "tops/internal.h"
+#include "tops/protocol/mac/eth.h"
+#include "tops/protocol/network/ip.h"
+
+#include <mtk_hnat/nf_hnat_mtk.h>
+
+int
+mtk_tops_eth_encap_param_setup(
+			struct sk_buff *skb,
+			struct tops_params *params,
+			int (*tnl_encap_param_setup)(struct sk_buff *skb,
+						     struct tops_params *params))
+{
+	struct ethhdr *eth = eth_hdr(skb);
+
+	params->mac.type = TOPS_MAC_ETH;
+
+	memcpy(&params->mac.eth.h_source, eth->h_source, ETH_ALEN);
+	memcpy(&params->mac.eth.h_dest, eth->h_dest, ETH_ALEN);
+	params->mac.eth.h_proto = htons(ETH_P_IP);
+
+	/*
+	 * either has contrusted ethernet header with IP
+	 * or the packet is going to do xfrm encryption
+	 */
+	if ((ntohs(eth->h_proto) == ETH_P_IP)
+	    || (!skb_hnat_cdrt(skb) && skb_dst(skb) && dst_xfrm(skb_dst(skb)))) {
+		return mtk_tops_ip_encap_param_setup(skb,
+						     params,
+						     tnl_encap_param_setup);
+	}
+
+	TOPS_NOTICE("eth proto not support, proto: 0x%x\n",
+		    ntohs(eth->h_proto));
+
+	return -EINVAL;
+}
+
+int mtk_tops_eth_decap_param_setup(struct sk_buff *skb, struct tops_params *params)
+{
+	struct ethhdr *eth;
+	struct ethhdr ethh;
+	int ret = 0;
+
+	skb_push(skb, sizeof(struct ethhdr));
+	eth = skb_header_pointer(skb, 0, sizeof(struct ethhdr), &ethh);
+	if (unlikely(!eth)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (unlikely(ntohs(eth->h_proto) != ETH_P_IP)) {
+		TOPS_NOTICE("eth proto not support, proto: 0x%x\n",
+			    ntohs(eth->h_proto));
+		ret = -EINVAL;
+		goto out;
+	}
+
+	params->mac.type = TOPS_MAC_ETH;
+
+	memcpy(&params->mac.eth.h_source, eth->h_dest, ETH_ALEN);
+	memcpy(&params->mac.eth.h_dest, eth->h_source, ETH_ALEN);
+	params->mac.eth.h_proto = htons(ETH_P_IP);
+
+out:
+	skb_pull(skb, sizeof(struct ethhdr));
+
+	return ret;
+}
+
+static int tops_eth_debug_param_fetch_mac(const char *buf, int *ofs, u8 *mac)
+{
+	int nchar = 0;
+	int ret;
+
+	ret = sscanf(buf + *ofs, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %n",
+		&mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5], &nchar);
+	if (ret != 6)
+		return -EPERM;
+
+	*ofs += nchar;
+
+	return 0;
+}
+
+int mtk_tops_eth_debug_param_setup(const char *buf, int *ofs,
+				   struct tops_params *params)
+{
+	char proto[DEBUG_PROTO_LEN] = {0};
+	int ret;
+
+	params->mac.type = TOPS_MAC_ETH;
+
+	ret = tops_eth_debug_param_fetch_mac(buf, ofs, params->mac.eth.h_source);
+	if (ret)
+		return ret;
+
+	ret = tops_eth_debug_param_fetch_mac(buf, ofs, params->mac.eth.h_dest);
+	if (ret)
+		return ret;
+
+	ret = mtk_tops_debug_param_proto_peek(buf, *ofs, proto);
+	if (ret < 0)
+		return ret;
+
+	*ofs += ret;
+
+	if (!strcmp(proto, DEBUG_PROTO_IP)) {
+		params->mac.eth.h_proto = htons(ETH_P_IP);
+		ret = mtk_tops_ip_debug_param_setup(buf, ofs, params);
+	} else {
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+void mtk_tops_eth_param_dump(struct seq_file *s, struct tops_params *params)
+{
+	seq_puts(s, "\tMAC Type: Ethernet ");
+	seq_printf(s, "saddr: %pM daddr: %pM\n",
+		   params->mac.eth.h_source, params->mac.eth.h_dest);
+}
diff --git a/package-21.02/kernel/tops/src/protocol/mac/ppp.c b/package-21.02/kernel/tops/src/protocol/mac/ppp.c
new file mode 100644
index 0000000..8b8400b
--- /dev/null
+++ b/package-21.02/kernel/tops/src/protocol/mac/ppp.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Frank-zj Lin <rank-zj.lin@mediatek.com>
+ *         Ren-Ting Wang <ren-ting.wang@mediatek.com>
+ */
+
+#include "tops/protocol/mac/ppp.h"
+
+bool mtk_tops_ppp_valid(struct sk_buff *skb)
+{
+	struct ppp_hdr *ppp;
+	struct ppp_hdr ppph;
+
+	ppp = skb_header_pointer(skb, 0, sizeof(struct ppp_hdr), &ppph);
+
+	if (unlikely(!ppp))
+		return false;
+
+	return (ppp->addr == PPP_ALLSTATIONS &&
+		ppp->ctrl == PPP_UI && ntohs(ppp->proto) == PPP_IP);
+}
diff --git a/package-21.02/kernel/tops/src/protocol/network/ip.c b/package-21.02/kernel/tops/src/protocol/network/ip.c
new file mode 100644
index 0000000..abe7f10
--- /dev/null
+++ b/package-21.02/kernel/tops/src/protocol/network/ip.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
+ */
+
+#include "tops/internal.h"
+#include "tops/protocol/network/ip.h"
+#include "tops/protocol/transport/udp.h"
+
+int mtk_tops_ip_encap_param_setup(
+			struct sk_buff *skb,
+			struct tops_params *params,
+			int (*tnl_encap_param_setup)(struct sk_buff *skb,
+						     struct tops_params *params))
+{
+	struct tops_ip_params *ipp = &params->network.ip;
+	struct iphdr *ip;
+	struct iphdr iph;
+	int ret;
+
+	ip = skb_header_pointer(skb, 0, sizeof(struct iphdr), &iph);
+	if (unlikely(!ip))
+		return -EINVAL;
+
+	if (unlikely(ip->version != IPVERSION)) {
+		TOPS_NOTICE("ip ver: 0x%x invalid\n", ip->version);
+		return -EINVAL;
+	}
+
+	params->network.type = TOPS_NETWORK_IPV4;
+
+	ipp->proto = ip->protocol;
+	ipp->sip = ip->saddr;
+	ipp->dip = ip->daddr;
+	ipp->tos = ip->tos;
+	ipp->ttl = ip->ttl;
+
+	skb_pull(skb, sizeof(struct iphdr));
+
+	switch (ip->protocol) {
+	case IPPROTO_UDP:
+		ret = mtk_tops_udp_encap_param_setup(skb,
+						     params,
+						     tnl_encap_param_setup);
+		break;
+	case IPPROTO_GRE:
+		ret = tnl_encap_param_setup(skb, params);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	};
+
+	skb_push(skb, sizeof(struct iphdr));
+
+	return ret;
+}
+
+int mtk_tops_ip_decap_param_setup(struct sk_buff *skb, struct tops_params *params)
+{
+	struct tops_ip_params *ipp;
+	struct iphdr *ip;
+	struct iphdr iph;
+	int ret;
+
+	skb_push(skb, sizeof(struct iphdr));
+	ip = skb_header_pointer(skb, 0, sizeof(struct iphdr), &iph);
+	if (unlikely(!ip)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (unlikely(ip->version != IPVERSION)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	params->network.type = TOPS_NETWORK_IPV4;
+
+	ipp = &params->network.ip;
+
+	ipp->proto = ip->protocol;
+	ipp->sip = ip->daddr;
+	ipp->dip = ip->saddr;
+	ipp->tos = ip->tos;
+	/*
+	 * if encapsulation parameter is already configured, TTL will remain as
+	 * encapsulation's data
+	 */
+	ipp->ttl = 128;
+
+	ret = mtk_tops_mac_decap_param_setup(skb, params);
+
+out:
+	skb_pull(skb, sizeof(struct iphdr));
+
+	return ret;
+}
+
+static int tops_ip_debug_param_fetch_ip(const char *buf, int *ofs, u32 *ip)
+{
+	int nchar = 0;
+	int ret = 0;
+	u8 tmp[4];
+
+	ret = sscanf(buf + *ofs, "%hhu.%hhu.%hhu.%hhu %n",
+		&tmp[3], &tmp[2], &tmp[1], &tmp[0], &nchar);
+	if (ret != 4)
+		return -EPERM;
+
+	*ip = tmp[3] | tmp[2] << 8 | tmp[1] << 16 | tmp[0] << 24;
+
+	*ofs += nchar;
+
+	return 0;
+}
+
+int mtk_tops_ip_debug_param_setup(const char *buf, int *ofs,
+				  struct tops_params *params)
+{
+	char proto[DEBUG_PROTO_LEN] = {0};
+	int ret;
+
+	params->network.type = TOPS_NETWORK_IPV4;
+
+	ret = tops_ip_debug_param_fetch_ip(buf, ofs, &params->network.ip.sip);
+	if (ret)
+		return ret;
+
+	ret = tops_ip_debug_param_fetch_ip(buf, ofs, &params->network.ip.dip);
+	if (ret)
+		return ret;
+
+	ret = mtk_tops_debug_param_proto_peek(buf, *ofs, proto);
+	if (ret < 0)
+		return ret;
+
+	if (!strcmp(proto, DEBUG_PROTO_UDP)) {
+		params->network.ip.proto = IPPROTO_UDP;
+		*ofs += ret;
+		ret = mtk_tops_udp_debug_param_setup(buf, ofs, params);
+	} else if (!strcmp(proto, DEBUG_PROTO_GRETAP)) {
+		params->network.ip.proto = IPPROTO_GRE;
+		ret = 0;
+	} else {
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+void mtk_tops_ip_param_dump(struct seq_file *s, struct tops_params *params)
+{
+	struct tops_ip_params *ipp = &params->network.ip;
+	u32 sip = params->network.ip.sip;
+	u32 dip = params->network.ip.dip;
+
+	seq_puts(s, "\tNetwork Type: IPv4 ");
+	seq_printf(s, "sip: %pI4 dip: %pI4 protocol: 0x%02x tos: 0x%02x ttl: %03u\n",
+		   &sip, &dip, ipp->proto, ipp->tos, ipp->ttl);
+}
diff --git a/package-21.02/kernel/tops/src/protocol/transport/udp.c b/package-21.02/kernel/tops/src/protocol/transport/udp.c
new file mode 100644
index 0000000..ab653e0
--- /dev/null
+++ b/package-21.02/kernel/tops/src/protocol/transport/udp.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
+ */
+
+#include "tops/protocol/network/ip.h"
+#include "tops/protocol/transport/udp.h"
+
+int mtk_tops_udp_encap_param_setup(
+			struct sk_buff *skb,
+			struct tops_params *params,
+			int (*tnl_encap_param_setup)(struct sk_buff *skb,
+						     struct tops_params *params))
+{
+	struct tops_udp_params *udpp = &params->transport.udp;
+	struct udphdr *udp;
+	struct udphdr udph;
+	int ret;
+
+	udp = skb_header_pointer(skb, 0, sizeof(struct udphdr), &udph);
+	if (unlikely(!udp))
+		return -EINVAL;
+
+	params->transport.type = TOPS_TRANSPORT_UDP;
+
+	udpp->sport = udp->source;
+	udpp->dport = udp->dest;
+
+	skb_pull(skb, sizeof(struct udphdr));
+
+	/* udp must be the end of a tunnel */
+	ret = tnl_encap_param_setup(skb, params);
+
+	skb_push(skb, sizeof(struct udphdr));
+
+	return ret;
+}
+
+int mtk_tops_udp_decap_param_setup(struct sk_buff *skb, struct tops_params *params)
+{
+	struct tops_udp_params *udpp = &params->transport.udp;
+	struct udphdr *udp;
+	struct udphdr udph;
+	int ret;
+
+	skb_push(skb, sizeof(struct udphdr));
+	udp = skb_header_pointer(skb, 0, sizeof(struct udphdr), &udph);
+	if (unlikely(!udp)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	params->transport.type = TOPS_TRANSPORT_UDP;
+
+	udpp->sport = udp->dest;
+	udpp->dport = udp->source;
+
+	ret = mtk_tops_network_decap_param_setup(skb, params);
+
+out:
+	skb_pull(skb, sizeof(struct udphdr));
+
+	return ret;
+}
+
+static int tops_udp_debug_param_fetch_port(const char *buf, int *ofs, u16 *port)
+{
+	int nchar = 0;
+	int ret;
+	u16 p = 0;
+
+	ret = sscanf(buf + *ofs, "%hu %n", &p, &nchar);
+	if (ret != 1)
+		return -EPERM;
+
+	*port = htons(p);
+
+	*ofs += nchar;
+
+	return 0;
+}
+
+int mtk_tops_udp_debug_param_setup(const char *buf, int *ofs,
+				   struct tops_params *params)
+{
+	int ret;
+
+	params->transport.type = TOPS_TRANSPORT_UDP;
+
+	ret = tops_udp_debug_param_fetch_port(buf, ofs, &params->transport.udp.sport);
+	if (ret)
+		return ret;
+
+	ret = tops_udp_debug_param_fetch_port(buf, ofs, &params->transport.udp.dport);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+void mtk_tops_udp_param_dump(struct seq_file *s, struct tops_params *params)
+{
+	struct tops_udp_params *udpp = &params->transport.udp;
+
+	seq_puts(s, "\tTransport Type: UDP ");
+	seq_printf(s, "sport: %05u dport: %05u\n",
+		   ntohs(udpp->sport), ntohs(udpp->dport));
+}
diff --git a/package-21.02/kernel/tops/src/protocol/tunnel/gre/gretap.c b/package-21.02/kernel/tops/src/protocol/tunnel/gre/gretap.c
new file mode 100644
index 0000000..13618ce
--- /dev/null
+++ b/package-21.02/kernel/tops/src/protocol/tunnel/gre/gretap.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
+ */
+
+#include <net/gre.h>
+
+#include <pce/cls.h>
+#include <pce/netsys.h>
+#include <pce/pce.h>
+
+#include "tops/internal.h"
+#include "tops/protocol/tunnel/gre/gretap.h"
+#include "tops/tunnel.h"
+
+static int gretap_cls_entry_setup(struct tops_tnl_info *tnl_info,
+				  struct cls_desc *cdesc)
+{
+	CLS_DESC_DATA(cdesc, fport, PSE_PORT_PPE0);
+	CLS_DESC_DATA(cdesc, tport_idx, 0x4);
+	CLS_DESC_MASK_DATA(cdesc, tag, CLS_DESC_TAG_MASK, CLS_DESC_TAG_MATCH_L4_HDR);
+	CLS_DESC_MASK_DATA(cdesc, dip_match, CLS_DESC_DIP_MATCH, CLS_DESC_DIP_MATCH);
+	CLS_DESC_MASK_DATA(cdesc, l4_type, CLS_DESC_L4_TYPE_MASK, IPPROTO_GRE);
+	CLS_DESC_MASK_DATA(cdesc, l4_udp_hdr_nez,
+			   CLS_DESC_UDPLITE_L4_HDR_NEZ_MASK,
+			   CLS_DESC_UDPLITE_L4_HDR_NEZ_MASK);
+	CLS_DESC_MASK_DATA(cdesc, l4_valid,
+			   CLS_DESC_L4_VALID_MASK,
+			   CLS_DESC_VALID_UPPER_HALF_WORD_BIT |
+			   CLS_DESC_VALID_LOWER_HALF_WORD_BIT);
+	CLS_DESC_MASK_DATA(cdesc, l4_hdr_usr_data, 0x0000FFFF, 0x00006558);
+
+	return 0;
+}
+
+static int gretap_tnl_encap_param_setup(struct sk_buff *skb, struct tops_params *params)
+{
+	params->tunnel.type = TOPS_TUNNEL_GRETAP;
+
+	return 0;
+}
+
+static int gretap_tnl_decap_param_setup(struct sk_buff *skb, struct tops_params *params)
+{
+	struct gre_base_hdr *pgre;
+	struct gre_base_hdr greh;
+	int ret;
+
+	if (!skb->dev->rtnl_link_ops
+	    || strcmp(skb->dev->rtnl_link_ops->kind, "gretap"))
+		return -EAGAIN;
+
+	skb_push(skb, sizeof(struct gre_base_hdr));
+	pgre = skb_header_pointer(skb, 0, sizeof(struct gre_base_hdr), &greh);
+	if (unlikely(!pgre)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (unlikely(ntohs(pgre->protocol) != ETH_P_TEB)) {
+		TOPS_NOTICE("gre: %p protocol unmatched, proto: 0x%x\n",
+			    pgre, ntohs(pgre->protocol));
+		ret = -EINVAL;
+		goto out;
+	}
+
+	params->tunnel.type = TOPS_TUNNEL_GRETAP;
+
+	ret = mtk_tops_network_decap_param_setup(skb, params);
+
+out:
+	skb_pull(skb, sizeof(struct gre_base_hdr));
+
+	return ret;
+}
+
+static int gretap_tnl_debug_param_setup(const char *buf, int *ofs,
+					struct tops_params *params)
+{
+	params->tunnel.type = TOPS_TUNNEL_GRETAP;
+
+	return 0;
+}
+
+static bool gretap_tnl_decap_offloadable(struct sk_buff *skb)
+{
+	struct iphdr *ip = ip_hdr(skb);
+
+	if (ip->protocol != IPPROTO_GRE)
+		return false;
+
+	return true;
+}
+
+static void gretap_tnl_param_dump(struct seq_file *s, struct tops_params *params)
+{
+	seq_puts(s, "\tTunnel Type: GRETAP\n");
+}
+
+static bool gretap_tnl_param_match(struct tops_params *p, struct tops_params *target)
+{
+	return !memcmp(&p->tunnel, &target->tunnel, sizeof(struct tops_tunnel_params));
+}
+
+static struct tops_tnl_type gretap_type = {
+	.type_name = "gretap",
+	.cls_entry_setup = gretap_cls_entry_setup,
+	.tnl_decap_param_setup = gretap_tnl_decap_param_setup,
+	.tnl_encap_param_setup = gretap_tnl_encap_param_setup,
+	.tnl_debug_param_setup = gretap_tnl_debug_param_setup,
+	.tnl_decap_offloadable = gretap_tnl_decap_offloadable,
+	.tnl_param_match = gretap_tnl_param_match,
+	.tnl_param_dump = gretap_tnl_param_dump,
+	.tnl_proto_type = TOPS_TUNNEL_GRETAP,
+	.has_inner_eth = true,
+};
+
+int mtk_tops_gretap_init(void)
+{
+	return mtk_tops_tnl_type_register(&gretap_type);
+}
+
+void mtk_tops_gretap_deinit(void)
+{
+	mtk_tops_tnl_type_unregister(&gretap_type);
+}
diff --git a/package-21.02/kernel/tops/src/protocol/tunnel/l2tp/l2tpv2.c b/package-21.02/kernel/tops/src/protocol/tunnel/l2tp/l2tpv2.c
new file mode 100644
index 0000000..d00d3c0
--- /dev/null
+++ b/package-21.02/kernel/tops/src/protocol/tunnel/l2tp/l2tpv2.c
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Frank-zj Lin <rank-zj.lin@mediatek.com>
+ *         Ren-Ting Wang <ren-ting.wang@mediatek.com>
+ */
+
+#include <linux/netdevice.h>
+
+#include <pce/cls.h>
+#include <pce/netsys.h>
+#include <pce/pce.h>
+
+#include "tops/internal.h"
+#include "tops/protocol/mac/ppp.h"
+#include "tops/protocol/transport/udp.h"
+#include "tops/protocol/tunnel/l2tp/l2tpv2.h"
+#include "tops/tunnel.h"
+
+static int l2tpv2_cls_entry_setup(struct tops_tnl_info *tnl_info,
+				  struct cls_desc *cdesc)
+{
+	CLS_DESC_DATA(cdesc, fport, PSE_PORT_PPE0);
+	CLS_DESC_DATA(cdesc, tport_idx, 0x4);
+	CLS_DESC_MASK_DATA(cdesc, tag, CLS_DESC_TAG_MASK, CLS_DESC_TAG_MATCH_L4_USR);
+	CLS_DESC_MASK_DATA(cdesc, dip_match, CLS_DESC_DIP_MATCH, CLS_DESC_DIP_MATCH);
+	CLS_DESC_MASK_DATA(cdesc, l4_type, CLS_DESC_L4_TYPE_MASK, IPPROTO_UDP);
+	CLS_DESC_MASK_DATA(cdesc, l4_valid,
+			   CLS_DESC_L4_VALID_MASK,
+			   CLS_DESC_VALID_UPPER_HALF_WORD_BIT |
+			   CLS_DESC_VALID_LOWER_HALF_WORD_BIT |
+			   CLS_DESC_VALID_DPORT_BIT);
+	CLS_DESC_MASK_DATA(cdesc, l4_dport, CLS_DESC_L4_DPORT_MASK, 1701);
+	CLS_DESC_MASK_DATA(cdesc, l4_hdr_usr_data, 0x80030000, 0x00020000);
+
+	return 0;
+}
+
+static inline bool l2tpv2_offload_valid(struct sk_buff *skb)
+{
+	struct udp_l2tp_data_hdr *l2tp;
+	struct udp_l2tp_data_hdr l2tph;
+	u16 hdrflags;
+
+	l2tp = skb_header_pointer(skb, 0, sizeof(struct udp_l2tp_data_hdr), &l2tph);
+	if (!l2tp)
+		return false;
+
+	hdrflags = ntohs(l2tp->flag_ver);
+
+	return ((hdrflags & L2TP_HDR_VER_MASK) == L2TP_HDR_VER_2 &&
+		!(hdrflags & L2TP_HDRFLAG_T));
+}
+
+static int l2tpv2_tnl_decap_param_setup(struct sk_buff *skb,
+					struct tops_params *params)
+{
+	struct tops_l2tp_params *l2tpp;
+	struct udp_l2tp_data_hdr *l2tp;
+	struct udp_l2tp_data_hdr l2tph;
+	int ret = 0;
+
+	/* ppp */
+	skb_push(skb, sizeof(struct ppp_hdr));
+	if (unlikely(!mtk_tops_ppp_valid(skb))) {
+		ret = -EINVAL;
+		goto restore_ppp;
+	}
+
+	/* l2tp */
+	skb_push(skb, sizeof(struct udp_l2tp_data_hdr));
+	if (unlikely(!l2tpv2_offload_valid(skb))) {
+		ret = -EINVAL;
+		goto restore_l2tp;
+	}
+
+	l2tp = skb_header_pointer(skb, 0, sizeof(struct udp_l2tp_data_hdr), &l2tph);
+	if (unlikely(!l2tp)) {
+		ret = -EINVAL;
+		goto restore_l2tp;
+	}
+
+	params->tunnel.type = TOPS_TUNNEL_L2TP_V2;
+
+	l2tpp = &params->tunnel.l2tp;
+	l2tpp->tid = l2tp->tid;
+	l2tpp->sid = l2tp->sid;
+
+	ret = mtk_tops_transport_decap_param_setup(skb, params);
+
+restore_l2tp:
+	skb_pull(skb, sizeof(struct udp_l2tp_data_hdr));
+
+restore_ppp:
+	skb_pull(skb, sizeof(struct ppp_hdr));
+
+	return ret;
+}
+
+static int l2tpv2_tnl_encap_param_setup(struct sk_buff *skb,
+					struct tops_params *params)
+{
+	struct tops_l2tp_params *l2tpp;
+	struct udp_l2tp_data_hdr *l2tp;
+	struct udp_l2tp_data_hdr l2tph;
+
+	if (unlikely(!l2tpv2_offload_valid(skb)))
+		return -EINVAL;
+
+	l2tp = skb_header_pointer(skb, 0, sizeof(struct udp_l2tp_data_hdr), &l2tph);
+	if (unlikely(!l2tp))
+		return -EINVAL;
+
+	params->tunnel.type = TOPS_TUNNEL_L2TP_V2;
+
+	l2tpp = &params->tunnel.l2tp;
+	l2tpp->tid = l2tp->tid;
+	l2tpp->sid = l2tp->sid;
+
+	return 0;
+}
+
+static int l2tpv2_tnl_debug_param_setup(const char *buf, int *ofs,
+					struct tops_params *params)
+{
+	struct tops_l2tp_params *l2tpp;
+	int nchar = 0;
+	int ret;
+	u16 tid = 0;
+	u16 sid = 0;
+
+	params->tunnel.type = TOPS_TUNNEL_L2TP_V2;
+	l2tpp = &params->tunnel.l2tp;
+
+	ret = sscanf(buf + *ofs, "%hu %hu %n", &tid, &sid, &nchar);
+	if (ret != 2)
+		return -EINVAL;
+
+	l2tpp->tid = htons(tid);
+	l2tpp->sid = htons(sid);
+
+	*ofs += nchar;
+
+	return 0;
+}
+
+static int l2tpv2_tnl_l2_param_update(struct sk_buff *skb,
+				      struct tops_params *params)
+{
+	struct ethhdr *eth = eth_hdr(skb);
+	struct tops_mac_params *mac = &params->mac;
+
+	memcpy(&mac->eth.h_source, eth->h_source, sizeof(u8) * ETH_ALEN);
+	memcpy(&mac->eth.h_dest, eth->h_dest, sizeof(u8) * ETH_ALEN);
+
+	return 1;
+}
+
+static bool l2tpv2_tnl_decap_offloadable(struct sk_buff *skb)
+{
+	struct iphdr *ip;
+	bool ret = true;
+	u32 ip_len;
+
+	ip = ip_hdr(skb);
+	if (ip->protocol != IPPROTO_UDP)
+		return false;
+
+	ip_len = ip_hdr(skb)->ihl * 4;
+
+	skb_pull(skb, ip_len + sizeof(struct udphdr));
+	if (!l2tpv2_offload_valid(skb)) {
+		ret = false;
+		goto restore_ip_udp;
+	}
+
+	skb_pull(skb, sizeof(struct udp_l2tp_data_hdr));
+	if (!mtk_tops_ppp_valid(skb)) {
+		ret = false;
+		goto restore_l2tp;
+	}
+
+restore_l2tp:
+	skb_push(skb, sizeof(struct udp_l2tp_data_hdr));
+restore_ip_udp:
+	skb_push(skb, ip_len + sizeof(struct udphdr));
+
+	return ret;
+}
+
+static void l2tpv2_tnl_param_dump(struct seq_file *s, struct tops_params *params)
+{
+	struct tops_l2tp_params *l2tpp = &params->tunnel.l2tp;
+
+	seq_puts(s, "\tTunnel Type: L2TPv2 ");
+	seq_printf(s, "tunnel ID: %05u session ID: %05u\n",
+		   ntohs(l2tpp->tid), ntohs(l2tpp->sid));
+}
+
+static struct tops_tnl_type l2tpv2_type = {
+	.type_name = "l2tpv2",
+	.cls_entry_setup = l2tpv2_cls_entry_setup,
+	.tnl_decap_param_setup = l2tpv2_tnl_decap_param_setup,
+	.tnl_encap_param_setup = l2tpv2_tnl_encap_param_setup,
+	.tnl_debug_param_setup = l2tpv2_tnl_debug_param_setup,
+	.tnl_decap_offloadable = l2tpv2_tnl_decap_offloadable,
+	.tnl_l2_param_update = l2tpv2_tnl_l2_param_update,
+	.tnl_param_dump = l2tpv2_tnl_param_dump,
+	.tnl_proto_type = TOPS_TUNNEL_L2TP_V2,
+	.has_inner_eth = false,
+};
+
+int mtk_tops_l2tpv2_init(void)
+{
+	return mtk_tops_tnl_type_register(&l2tpv2_type);
+}
+
+void mtk_tops_l2tpv2_deinit(void)
+{
+	mtk_tops_tnl_type_unregister(&l2tpv2_type);
+}
diff --git a/package-21.02/kernel/tops/src/ser.c b/package-21.02/kernel/tops/src/ser.c
index a126185..0a0fa6c 100644
--- a/package-21.02/kernel/tops/src/ser.c
+++ b/package-21.02/kernel/tops/src/ser.c
@@ -10,10 +10,10 @@
 #include <linux/netdevice.h>
 #include <linux/rtnetlink.h>
 
-#include "internal.h"
-#include "net-event.h"
-#include "ser.h"
-#include "trm.h"
+#include "tops/internal.h"
+#include "tops/net-event.h"
+#include "tops/ser.h"
+#include "tops/trm.h"
 
 struct tops_ser {
 	struct work_struct work;
diff --git a/package-21.02/kernel/tops/src/tdma.c b/package-21.02/kernel/tops/src/tdma.c
index c7053e7..7eff39f 100644
--- a/package-21.02/kernel/tops/src/tdma.c
+++ b/package-21.02/kernel/tops/src/tdma.c
@@ -14,12 +14,12 @@
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
 
-#include "internal.h"
-#include "mbox.h"
-#include "mcu.h"
-#include "tdma.h"
-#include "tops.h"
-#include "trm.h"
+#include "tops/internal.h"
+#include "tops/mbox.h"
+#include "tops/mcu.h"
+#include "tops/tdma.h"
+#include "tops/tops.h"
+#include "tops/trm.h"
 
 /* TDMA dump length */
 #define TDMA_BASE_LEN				(0x400)
diff --git a/package-21.02/kernel/tops/src/tnl_offload.c b/package-21.02/kernel/tops/src/tnl_offload.c
index 268e3ee..714139b 100644
--- a/package-21.02/kernel/tops/src/tnl_offload.c
+++ b/package-21.02/kernel/tops/src/tnl_offload.c
@@ -28,20 +28,20 @@
 #include <pce/netsys.h>
 #include <pce/pce.h>
 
-#include "internal.h"
-#include "mbox.h"
-#include "mcu.h"
-#include "netsys.h"
-#include "protocol/gre/gretap.h"
-#include "protocol/l2tp/udp_l2tp_data.h"
-#include "tunnel.h"
+#include "tops/internal.h"
+#include "tops/mbox.h"
+#include "tops/mcu.h"
+#include "tops/netsys.h"
+#include "tops/protocol/tunnel/gre/gretap.h"
+#include "tops/protocol/tunnel/l2tp/l2tpv2.h"
+#include "tops/tunnel.h"
 
 #define TOPS_PPE_ENTRY_BUCKETS		(64)
 #define TOPS_PPE_ENTRY_BUCKETS_BIT	(6)
 
 struct tops_tnl {
 	/* tunnel types */
-	struct tops_tnl_type *offload_tnl_types[__TOPS_ENTRY_MAX];
+	struct tops_tnl_type *offload_tnl_types[__TOPS_TUNNEL_TYPE_MAX];
 	u32 offload_tnl_type_num;
 	u32 tnl_base_addr;
 
@@ -104,7 +104,7 @@
 		    &&  entry->ipv4_hnapt.tport_id != NR_TDMA_QDMA_TPORT)
 			return;
 
-		bind_tnl_idx = entry->ipv4_hnapt.tops_entry - __TOPS_ENTRY_MAX;
+		bind_tnl_idx = entry->ipv4_hnapt.tops_entry - __TOPS_TUNNEL_TYPE_MAX;
 
 		break;
 	default:
@@ -112,39 +112,39 @@
 	}
 
 	/* unexpected tunnel index */
-	if (bind_tnl_idx >= __TOPS_ENTRY_MAX)
+	if (bind_tnl_idx >= __TOPS_TUNNEL_TYPE_MAX)
 		return;
 
-	if (tnl_idx == __TOPS_ENTRY_MAX || tnl_idx == bind_tnl_idx)
+	if (tnl_idx == __TOPS_TUNNEL_TYPE_MAX || tnl_idx == bind_tnl_idx)
 		memset(entry, 0, sizeof(*entry));
 }
 
 static inline void skb_set_tops_tnl_idx(struct sk_buff *skb, u32 tnl_idx)
 {
-	skb_hnat_tops(skb) = tnl_idx + __TOPS_ENTRY_MAX;
+	skb_hnat_tops(skb) = tnl_idx + __TOPS_TUNNEL_TYPE_MAX;
 }
 
 static inline bool skb_tops_valid(struct sk_buff *skb)
 {
-	return (skb && skb_hnat_tops(skb) < __TOPS_ENTRY_MAX);
+	return (skb && skb_hnat_tops(skb) < __TOPS_TUNNEL_TYPE_MAX);
 }
 
 static inline struct tops_tnl_type *skb_to_tnl_type(struct sk_buff *skb)
 {
-	enum tops_entry_type tops_entry = skb_hnat_tops(skb);
+	enum tops_tunnel_type tnl_proto_type = skb_hnat_tops(skb);
 	struct tops_tnl_type *tnl_type;
 
-	if (unlikely(!tops_entry || tops_entry >= __TOPS_ENTRY_MAX))
+	if (unlikely(!tnl_proto_type || tnl_proto_type >= __TOPS_TUNNEL_TYPE_MAX))
 		return ERR_PTR(-EINVAL);
 
-	tnl_type = tops_tnl.offload_tnl_types[tops_entry];
+	tnl_type = tops_tnl.offload_tnl_types[tnl_proto_type];
 
 	return tnl_type ? tnl_type : ERR_PTR(-ENODEV);
 }
 
 static inline struct tops_tnl_info *skb_to_tnl_info(struct sk_buff *skb)
 {
-	u32 tnl_idx = skb_hnat_tops(skb) - __TOPS_ENTRY_MAX;
+	u32 tnl_idx = skb_hnat_tops(skb) - __TOPS_TUNNEL_TYPE_MAX;
 
 	if (tnl_idx >= CONFIG_TOPS_TNL_NUM)
 		return ERR_PTR(-EINVAL);
@@ -168,7 +168,7 @@
 		return 0;
 
 	/* TODO: check collision possibility? */
-	return (tnl_params->sip ^ tnl_params->dip);
+	return (tnl_params->params.network.ip.sip ^ tnl_params->params.network.ip.dip);
 }
 
 static inline bool tnl_info_decap_is_enable(struct tops_tnl_info *tnl_info)
@@ -404,6 +404,10 @@
 			ret = PTR_ERR(cdrt);
 			goto free_tcls;
 		}
+		if (unlikely(!cdrt->cls)) {
+			ret = -ENODEV;
+			goto free_tcls;
+		}
 
 		tcls->cls = cdrt->cls;
 	}
@@ -593,7 +597,7 @@
 		if (IS_ERR(cdrt)) {
 			TOPS_ERR("no cdrt idx: %u related CDRT found\n",
 				 tnl_params->cdrt);
-			return ret;
+			return PTR_ERR(cdrt);
 		}
 
 		memcpy(&cdesc, &cdrt->cls->cdesc, sizeof(struct cls_desc));
@@ -657,7 +661,7 @@
 
 	memset(&dipd, 0, sizeof(struct dip_desc));
 
-	dipd.ipv4 = be32_to_cpu(tnl_info->tnl_params.sip);
+	dipd.ipv4 = be32_to_cpu(tnl_info->tnl_params.params.network.ip.sip);
 	dipd.tag = DIPFILTER_IPV4;
 
 	return mtk_pce_dipfilter_entry_del(&dipd);
@@ -670,7 +674,7 @@
 	/* setup dipfilter */
 	memset(&dipd, 0, sizeof(struct dip_desc));
 
-	dipd.ipv4 = be32_to_cpu(tnl_info->tnl_params.sip);
+	dipd.ipv4 = be32_to_cpu(tnl_info->tnl_params.params.network.ip.sip);
 	dipd.tag = DIPFILTER_IPV4;
 
 	return mtk_pce_dipfilter_entry_add(&dipd);
@@ -731,69 +735,92 @@
 	spin_unlock_irqrestore(&tops_tnl.tbl_lock, flag);
 }
 
+struct tops_tnl_info *mtk_tops_tnl_info_get_by_idx(u32 tnl_idx)
+{
+	if (tnl_idx >= CONFIG_TOPS_TNL_NUM)
+		return ERR_PTR(-EINVAL);
+
+	if (!test_bit(tnl_idx, tops_tnl.tnl_used))
+		return ERR_PTR(-EACCES);
+
+	return &tops_tnl.tnl_infos[tnl_idx];
+}
+
 static bool mtk_tops_tnl_info_match(struct tops_tnl_type *tnl_type,
 				    struct tops_tnl_info *tnl_info,
-				    struct tops_tnl_params *match_data)
+				    struct tops_params *target)
 {
+	struct tops_params *p = &tnl_info->cache.params;
 	unsigned long flag = 0;
 	bool match;
 
 	spin_lock_irqsave(&tnl_info->lock, flag);
 
-	match = tnl_type->tnl_info_match(&tnl_info->cache, match_data);
+	match = (p->tunnel.type == target->tunnel.type
+		 && mtk_tops_params_match(p, target)
+		 && tnl_type->tnl_param_match(p, target));
 
 	spin_unlock_irqrestore(&tnl_info->lock, flag);
 
 	return match;
 }
 
-struct tops_tnl_info *mtk_tops_tnl_info_find(struct tops_tnl_params *tnl_params)
+struct tops_tnl_info *mtk_tops_tnl_info_find(struct tops_tnl_type *tnl_type,
+					     struct tops_tnl_params *tnl_params)
 {
 	struct tops_tnl_info *tnl_info;
-	struct tops_tnl_type *tnl_type;
 
 	lockdep_assert_held(&tops_tnl.tbl_lock);
 
 	if (unlikely(!tnl_params->tops_entry_proto
-		     || tnl_params->tops_entry_proto >= __TOPS_ENTRY_MAX))
-		return ERR_PTR(-EINVAL);
-
-	tnl_type = tops_tnl.offload_tnl_types[tnl_params->tops_entry_proto];
-	if (unlikely(!tnl_type))
+		     || tnl_params->tops_entry_proto >= __TOPS_TUNNEL_TYPE_MAX))
 		return ERR_PTR(-EINVAL);
 
-	if (unlikely(!tnl_type->tnl_info_match))
-		return ERR_PTR(-ENXIO);
-
 	hash_for_each_possible(tops_tnl.ht,
 			       tnl_info,
 			       hlist,
 			       tnl_params_hash(tnl_params))
-		if (mtk_tops_tnl_info_match(tnl_type, tnl_info, tnl_params))
+		if (mtk_tops_tnl_info_match(tnl_type, tnl_info, &tnl_params->params))
 			return tnl_info;
 
 	return ERR_PTR(-ENODEV);
 }
 
+static inline void mtk_tops_tnl_info_preserve(struct tops_tnl_type *tnl_type,
+					      struct tops_tnl_params *old,
+					      struct tops_tnl_params *new)
+{
+	new->flag |= old->flag;
+	new->cls_entry = old->cls_entry;
+	if (old->cdrt)
+		new->cdrt = old->cdrt;
+
+	/* we can only get ttl from encapsulation */
+	if (new->params.network.ip.ttl == 128 && old->params.network.ip.ttl != 0)
+		new->params.network.ip.ttl = old->params.network.ip.ttl;
+
+	if (tnl_type->tnl_param_restore)
+		tnl_type->tnl_param_restore(&old->params, &new->params);
+}
+
 /* tnl_info->lock should be held before calling this function */
 static int mtk_tops_tnl_info_setup(struct sk_buff *skb,
+				   struct tops_tnl_type *tnl_type,
 				   struct tops_tnl_info *tnl_info,
 				   struct tops_tnl_params *tnl_params)
 {
+	bool has_diff = false;
+
 	if (unlikely(!skb || !tnl_info || !tnl_params))
 		return -EPERM;
 
 	lockdep_assert_held(&tnl_info->lock);
 
-	/* manually preserve essential data among encapsulation and decapsulation */
-	tnl_params->flag |= tnl_info->cache.flag;
-	tnl_params->cls_entry = tnl_info->cache.cls_entry;
-	if (tnl_info->cache.cdrt)
-		tnl_params->cdrt = tnl_info->cache.cdrt;
-
-	if (memcmp(&tnl_info->cache, tnl_params, sizeof(struct tops_tnl_params))) {
-		memcpy(&tnl_info->cache, tnl_params, sizeof(struct tops_tnl_params));
+	mtk_tops_tnl_info_preserve(tnl_type, &tnl_info->cache, tnl_params);
 
+	has_diff = memcmp(&tnl_info->cache, tnl_params, sizeof(*tnl_params));
+	if (has_diff) {
+		memcpy(&tnl_info->cache, tnl_params, sizeof(*tnl_params));
 		mtk_tops_tnl_info_hash_no_lock(tnl_info);
 	}
 
@@ -801,20 +828,21 @@
 		/* the net_device is used to forward pkt to decap'ed inf when Rx */
 		tnl_info->dev = skb->dev;
 		if (!tnl_info_decap_is_enable(tnl_info)) {
+			has_diff = true;
 			tnl_info_decap_enable(tnl_info);
-
-			mtk_tops_tnl_info_submit_no_tnl_lock(tnl_info);
 		}
 	} else if (skb_hnat_is_encap(skb)) {
 		/* set skb_hnat_tops(skb) to tunnel index for ppe binding */
 		skb_set_tops_tnl_idx(skb, tnl_info->tnl_idx);
 		if (!tnl_info_encap_is_enable(tnl_info)) {
+			has_diff = true;
 			tnl_info_encap_enable(tnl_info);
-
-			mtk_tops_tnl_info_submit_no_tnl_lock(tnl_info);
 		}
 	}
 
+	if (has_diff)
+		mtk_tops_tnl_info_submit_no_tnl_lock(tnl_info);
+
 	return 0;
 }
 
@@ -926,7 +954,7 @@
 	/* prepare tnl_info */
 	spin_lock_irqsave(&tops_tnl.tbl_lock, flag);
 
-	tnl_info = mtk_tops_tnl_info_find(tnl_params);
+	tnl_info = mtk_tops_tnl_info_find(tnl_type, tnl_params);
 	if (IS_ERR(tnl_info) && PTR_ERR(tnl_info) != -ENODEV) {
 		/* error */
 		ret = PTR_ERR(tnl_info);
@@ -943,7 +971,7 @@
 	}
 
 	spin_lock(&tnl_info->lock);
-	ret = mtk_tops_tnl_info_setup(skb, tnl_info, tnl_params);
+	ret = mtk_tops_tnl_info_setup(skb, tnl_type, tnl_info, tnl_params);
 	spin_unlock(&tnl_info->lock);
 
 err_out:
@@ -968,7 +996,7 @@
 
 	spin_lock_irqsave(&tnl_info->lock, flag);
 
-	ret = tnl_type->tnl_l2_param_update(skb, &tnl_info->cache);
+	ret = tnl_type->tnl_l2_param_update(skb, &tnl_info->cache.params);
 	/* tnl params need to be updated */
 	if (ret == 1) {
 		mtk_tops_tnl_info_submit_no_tnl_lock(tnl_info);
@@ -1003,8 +1031,8 @@
 		return false;
 
 	/* TODO: may can be optimized */
-	for (i = TOPS_ENTRY_GRETAP, cnt = 0;
-	     i < __TOPS_ENTRY_MAX && cnt < tops_tnl.offload_tnl_type_num;
+	for (i = TOPS_TUNNEL_GRETAP, cnt = 0;
+	     i < __TOPS_TUNNEL_TYPE_MAX && cnt < tops_tnl.offload_tnl_type_num;
 	     i++) {
 		tnl_type = tops_tnl.offload_tnl_types[i];
 		if (unlikely(!tnl_type))
@@ -1013,7 +1041,7 @@
 		cnt++;
 		if (tnl_type->tnl_decap_offloadable
 		    && tnl_type->tnl_decap_offloadable(skb)) {
-			skb_hnat_tops(skb) = tnl_type->tops_entry;
+			skb_hnat_tops(skb) = tnl_type->tnl_proto_type;
 			return true;
 		}
 	}
@@ -1043,7 +1071,7 @@
 		return PTR_ERR(tnl_type);
 	}
 
-	if (unlikely(!tnl_type->tnl_decap_param_setup)) {
+	if (unlikely(!tnl_type->tnl_decap_param_setup || !tnl_type->tnl_param_match)) {
 		skb_mark_unbind(skb);
 		return -ENODEV;
 	}
@@ -1054,7 +1082,9 @@
 	if (tnl_type->has_inner_eth)
 		skb_push(skb, sizeof(struct ethhdr));
 
-	ret = tnl_type->tnl_decap_param_setup(skb, &tnl_params);
+	ret = mtk_tops_decap_param_setup(skb,
+					 &tnl_params.params,
+					 tnl_type->tnl_decap_param_setup);
 
 	/* pull ethernet header to restore skb->data to ip start */
 	if (tnl_type->has_inner_eth)
@@ -1065,7 +1095,7 @@
 		return ret;
 	}
 
-	tnl_params.tops_entry_proto = tnl_type->tops_entry;
+	tnl_params.tops_entry_proto = tnl_type->tnl_proto_type;
 	tnl_params.cdrt = skb_hnat_cdrt(skb);
 
 	ret = mtk_tops_tnl_offload(skb, tnl_type, &tnl_params);
@@ -1091,15 +1121,18 @@
 	if (IS_ERR(tnl_type))
 		return PTR_ERR(tnl_type);
 
-	if (unlikely(!tnl_type->tnl_encap_param_setup))
+	if (unlikely(!tnl_type->tnl_encap_param_setup || !tnl_type->tnl_param_match))
 		return -ENODEV;
 
 	memset(&tnl_params, 0, sizeof(struct tops_tnl_params));
 
-	ret = tnl_type->tnl_encap_param_setup(skb, &tnl_params);
+	ret = mtk_tops_encap_param_setup(skb,
+					 &tnl_params.params,
+					 tnl_type->tnl_encap_param_setup);
 	if (unlikely(ret))
 		return ret;
-	tnl_params.tops_entry_proto = tnl_type->tops_entry;
+
+	tnl_params.tops_entry_proto = tnl_type->tnl_proto_type;
 	tnl_params.cdrt = skb_hnat_cdrt(skb);
 
 	return mtk_tops_tnl_offload(skb, tnl_type, &tnl_params);
@@ -1535,7 +1568,7 @@
 			if (!entry_hnat_is_bound(entry))
 				continue;
 
-			tnl_flush_ppe_entry(entry, __TOPS_ENTRY_MAX);
+			tnl_flush_ppe_entry(entry, __TOPS_TUNNEL_TYPE_MAX);
 		}
 	}
 	hnat_cache_ebl(1);
@@ -1672,7 +1705,7 @@
 {
 	mtk_tops_gretap_init();
 
-	mtk_tops_udp_l2tp_data_init();
+	mtk_tops_l2tpv2_init();
 
 	return 0;
 }
@@ -1681,19 +1714,19 @@
 {
 	mtk_tops_gretap_deinit();
 
-	mtk_tops_udp_l2tp_data_deinit();
+	mtk_tops_l2tpv2_deinit();
 }
 
 struct tops_tnl_type *mtk_tops_tnl_type_get_by_name(const char *name)
 {
-	enum tops_entry_type tops_entry = TOPS_ENTRY_NONE + 1;
+	enum tops_tunnel_type tnl_proto_type = TOPS_TUNNEL_NONE + 1;
 	struct tops_tnl_type *tnl_type;
 
 	if (unlikely(!name))
 		return ERR_PTR(-EPERM);
 
-	for (; tops_entry < __TOPS_ENTRY_MAX; tops_entry++) {
-		tnl_type = tops_tnl.offload_tnl_types[tops_entry];
+	for (; tnl_proto_type < __TOPS_TUNNEL_TYPE_MAX; tnl_proto_type++) {
+		tnl_type = tops_tnl.offload_tnl_types[tnl_proto_type];
 		if (tnl_type && !strcmp(name, tnl_type->type_name))
 			break;
 	}
@@ -1703,24 +1736,25 @@
 
 int mtk_tops_tnl_type_register(struct tops_tnl_type *tnl_type)
 {
-	enum tops_entry_type tops_entry = tnl_type->tops_entry;
+	enum tops_tunnel_type tnl_proto_type = tnl_type->tnl_proto_type;
 
-	if (unlikely(tops_entry == TOPS_ENTRY_NONE
-		     || tops_entry >= __TOPS_ENTRY_MAX)) {
-		TOPS_ERR("invalid tops_entry: %u\n", tops_entry);
+	if (unlikely(tnl_proto_type == TOPS_TUNNEL_NONE
+		     || tnl_proto_type >= __TOPS_TUNNEL_TYPE_MAX)) {
+		TOPS_ERR("invalid tnl_proto_type: %u\n", tnl_proto_type);
 		return -EINVAL;
 	}
 
 	if (unlikely(!tnl_type))
 		return -EINVAL;
 
-	if (tops_tnl.offload_tnl_types[tops_entry]) {
-		TOPS_ERR("offload tnl type is already registered: %u\n", tops_entry);
+	if (tops_tnl.offload_tnl_types[tnl_proto_type]) {
+		TOPS_ERR("offload tnl type is already registered: %u\n",
+			 tnl_proto_type);
 		return -EBUSY;
 	}
 
 	INIT_LIST_HEAD(&tnl_type->tcls_head);
-	tops_tnl.offload_tnl_types[tops_entry] = tnl_type;
+	tops_tnl.offload_tnl_types[tnl_proto_type] = tnl_type;
 	tops_tnl.offload_tnl_type_num++;
 
 	return 0;
@@ -1728,22 +1762,22 @@
 
 void mtk_tops_tnl_type_unregister(struct tops_tnl_type *tnl_type)
 {
-	enum tops_entry_type tops_entry = tnl_type->tops_entry;
+	enum tops_tunnel_type tnl_proto_type = tnl_type->tnl_proto_type;
 
-	if (unlikely(tops_entry == TOPS_ENTRY_NONE
-		     || tops_entry >= __TOPS_ENTRY_MAX)) {
-		TOPS_ERR("invalid tops_entry: %u\n", tops_entry);
+	if (unlikely(tnl_proto_type == TOPS_TUNNEL_NONE
+		     || tnl_proto_type >= __TOPS_TUNNEL_TYPE_MAX)) {
+		TOPS_ERR("invalid tnl_proto_type: %u\n", tnl_proto_type);
 		return;
 	}
 
 	if (unlikely(!tnl_type))
 		return;
 
-	if (tops_tnl.offload_tnl_types[tops_entry] != tnl_type) {
+	if (tops_tnl.offload_tnl_types[tnl_proto_type] != tnl_type) {
 		TOPS_ERR("offload tnl type is registered by others\n");
 		return;
 	}
 
-	tops_tnl.offload_tnl_types[tops_entry] = NULL;
+	tops_tnl.offload_tnl_types[tnl_proto_type] = NULL;
 	tops_tnl.offload_tnl_type_num--;
 }
diff --git a/package-21.02/kernel/tops/src/tops_params.c b/package-21.02/kernel/tops/src/tops_params.c
new file mode 100644
index 0000000..c23a44a
--- /dev/null
+++ b/package-21.02/kernel/tops/src/tops_params.c
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
+ */
+
+#include "tops/tops_params.h"
+
+#include "tops/protocol/mac/eth.h"
+#include "tops/protocol/network/ip.h"
+#include "tops/protocol/transport/udp.h"
+
+int
+mtk_tops_encap_param_setup(struct sk_buff *skb,
+			   struct tops_params *params,
+			   int (*tnl_encap_param_setup)(struct sk_buff *skb,
+							struct tops_params *params))
+{
+	return mtk_tops_eth_encap_param_setup(skb, params, tnl_encap_param_setup);
+}
+
+int
+mtk_tops_decap_param_setup(struct sk_buff *skb,
+			   struct tops_params *params,
+			   int (*tnl_decap_param_setup)(struct sk_buff *skb,
+							struct tops_params *params))
+{
+	return tnl_decap_param_setup(skb, params);
+}
+
+int mtk_tops_transport_decap_param_setup(struct sk_buff *skb,
+					 struct tops_params *params)
+{
+	return mtk_tops_udp_decap_param_setup(skb, params);
+}
+
+int mtk_tops_network_decap_param_setup(struct sk_buff *skb,
+				       struct tops_params *params)
+{
+	/* TODO: IPv6 */
+	return mtk_tops_ip_decap_param_setup(skb, params);
+}
+
+int mtk_tops_mac_decap_param_setup(struct sk_buff *skb,
+				   struct tops_params *params)
+{
+	return mtk_tops_eth_decap_param_setup(skb, params);
+}
+
+int mtk_tops_debug_param_proto_peek(const char *buf, int ofs, char *proto)
+{
+	int nchar = 0;
+	int ret;
+
+	if (!proto)
+		return -EINVAL;
+
+	ret = sscanf(buf + ofs, "%20s %n", proto, &nchar);
+	if (ret != 1)
+		return -EPERM;
+
+	return nchar;
+}
+
+int mtk_tops_debug_param_setup(const char *buf, int *ofs,
+				   struct tops_params *params)
+{
+	char proto[DEBUG_PROTO_LEN];
+	int ret;
+
+	memset(proto, 0, sizeof(proto));
+
+	ret = mtk_tops_debug_param_proto_peek(buf, *ofs, proto);
+	if (ret < 0)
+		return ret;
+
+	*ofs += ret;
+
+	if (!strcmp(proto, DEBUG_PROTO_ETH))
+		return mtk_tops_eth_debug_param_setup(buf, ofs, params);
+
+	/* not support mac protocols other than Ethernet */
+	return -EINVAL;
+}
+
+void mtk_tops_mac_param_dump(struct seq_file *s, struct tops_params *params)
+{
+	if (params->mac.type == TOPS_MAC_ETH)
+		mtk_tops_eth_param_dump(s, params);
+}
+
+void mtk_tops_network_param_dump(struct seq_file *s, struct tops_params *params)
+{
+	if (params->network.type == TOPS_NETWORK_IPV4)
+		mtk_tops_ip_param_dump(s, params);
+}
+
+void mtk_tops_transport_param_dump(struct seq_file *s, struct tops_params *params)
+{
+	if (params->transport.type == TOPS_TRANSPORT_UDP)
+		mtk_tops_udp_param_dump(s, params);
+}
+
+static bool tops_transport_params_match(struct tops_transport_params *t1,
+					struct tops_transport_params *t2)
+{
+	return !memcmp(t1, t2, sizeof(*t1));
+}
+
+static bool tops_network_params_match(struct tops_network_params *n1,
+				      struct tops_network_params *n2)
+{
+	if (n1->type != n2->type)
+		return false;
+
+	if (n1->type == TOPS_NETWORK_IPV4)
+		return (n1->ip.sip == n2->ip.sip
+			&& n1->ip.dip == n2->ip.dip
+			&& n1->ip.proto == n2->ip.proto
+			&& n1->ip.tos == n2->ip.tos);
+
+	/* TODO: support IPv6 */
+	return false;
+}
+
+bool mtk_tops_params_match(struct tops_params *p1, struct tops_params *p2)
+{
+	return (tops_network_params_match(&p1->network, &p2->network)
+		&& tops_transport_params_match(&p1->transport, &p2->transport));
+}
diff --git a/package-21.02/kernel/tops/src/trm-debugfs.c b/package-21.02/kernel/tops/src/trm-debugfs.c
index 66c64f3..2566b6e 100644
--- a/package-21.02/kernel/tops/src/trm-debugfs.c
+++ b/package-21.02/kernel/tops/src/trm-debugfs.c
@@ -8,11 +8,11 @@
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
 
-#include "debugfs.h"
-#include "internal.h"
-#include "tops.h"
-#include "trm-debugfs.h"
-#include "trm.h"
+#include "tops/debugfs.h"
+#include "tops/internal.h"
+#include "tops/tops.h"
+#include "tops/trm-debugfs.h"
+#include "tops/trm.h"
 
 struct dentry *trm_debugfs_root;
 
diff --git a/package-21.02/kernel/tops/src/trm-fs.c b/package-21.02/kernel/tops/src/trm-fs.c
index 81ae77a..130a569 100644
--- a/package-21.02/kernel/tops/src/trm-fs.c
+++ b/package-21.02/kernel/tops/src/trm-fs.c
@@ -11,10 +11,10 @@
 #include <linux/err.h>
 #include <linux/relay.h>
 
-#include "trm-debugfs.h"
-#include "trm-fs.h"
-#include "trm-mcu.h"
-#include "trm.h"
+#include "tops/trm-debugfs.h"
+#include "tops/trm-fs.h"
+#include "tops/trm-mcu.h"
+#include "tops/trm.h"
 
 #define RLY_RETRY_NUM				3
 
diff --git a/package-21.02/kernel/tops/src/trm-mcu.c b/package-21.02/kernel/tops/src/trm-mcu.c
index b475dc0..e7a8268 100644
--- a/package-21.02/kernel/tops/src/trm-mcu.c
+++ b/package-21.02/kernel/tops/src/trm-mcu.c
@@ -12,12 +12,12 @@
 #include <linux/io.h>
 #include <linux/of.h>
 
-#include "internal.h"
-#include "mcu.h"
-#include "trm-debugfs.h"
-#include "trm-fs.h"
-#include "trm-mcu.h"
-#include "trm.h"
+#include "tops/internal.h"
+#include "tops/mcu.h"
+#include "tops/trm-debugfs.h"
+#include "tops/trm-fs.h"
+#include "tops/trm-mcu.h"
+#include "tops/trm.h"
 
 #define TOPS_OCD_RETRY_TIMES		(3)
 
diff --git a/package-21.02/kernel/tops/src/trm.c b/package-21.02/kernel/tops/src/trm.c
index a3f959f..0b61f87 100644
--- a/package-21.02/kernel/tops/src/trm.c
+++ b/package-21.02/kernel/tops/src/trm.c
@@ -17,13 +17,13 @@
 #include <linux/relay.h>
 #include <linux/types.h>
 
-#include "internal.h"
-#include "mbox.h"
-#include "mcu.h"
-#include "netsys.h"
-#include "trm-fs.h"
-#include "trm-mcu.h"
-#include "trm.h"
+#include "tops/internal.h"
+#include "tops/mbox.h"
+#include "tops/mcu.h"
+#include "tops/netsys.h"
+#include "tops/trm-fs.h"
+#include "tops/trm-mcu.h"
+#include "tops/trm.h"
 
 #define TRM_HDR_LEN				(sizeof(struct trm_header))
 
@@ -75,6 +75,7 @@
 	memset(trm_hdr, 0, TRM_HDR_LEN);
 
 	strncpy(trm_hdr->info.name, trm_cfg->name, TRM_CONFIG_NAME_MAX_LEN);
+	trm_hdr->info.name[TRM_CONFIG_NAME_MAX_LEN - 1] = '\0';
 	trm_hdr->info.start_addr = trm_cfg->addr + trm_cfg->offset;
 	trm_hdr->info.size = size;
 	trm_hdr->info.dump_time = dump_time;
diff --git a/package-21.02/kernel/tops/src/wdt.c b/package-21.02/kernel/tops/src/wdt.c
index 5d450c5..b632d4e 100644
--- a/package-21.02/kernel/tops/src/wdt.c
+++ b/package-21.02/kernel/tops/src/wdt.c
@@ -8,11 +8,11 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 
-#include "internal.h"
-#include "mbox.h"
-#include "ser.h"
-#include "trm.h"
-#include "wdt.h"
+#include "tops/internal.h"
+#include "tops/mbox.h"
+#include "tops/ser.h"
+#include "tops/trm.h"
+#include "tops/wdt.h"
 
 #define WDT_IRQ_STATUS			0x0140B0
 #define TOP_WDT_MODE			0x012000