[][openwrt][mt7988][tops][fix 3 PPE feature issue]

[Description]
Fix tunnel decapsulation can not be bound by PPE and encapsulation
unexpectedly dropped to APMCU issues.

Since HNAT has enabled 3 PPE capability, it will forward ingress packets
to different PPE according to their sport. However, this feature will
cause some problem for tunnel offload because TOPS explicitly overwrites
Fport by CLS HW rather than following ETH/HNAT GDM's configuration.
Furthermore, this overwritten Fport will cause HNAT driver to lookup a
wrong PPE table.

Eventually, the packets that are decap'ed and forwarded by TOPS are sent
to a different PPE which is not HNAT driver expected. Thus, HNAT will find
an invalid entry and not able to bind that flow even though that flow is
actually rate reach in another PPE.

To fix this issue, TOPS CLS rule is updated according to the system's 3
PPE feature is enabled or not. If the feature is not enabled, CLS Fport
rule will set to original PPE0. Otherwise, Fport will be set to PPE1 since
we expect all tunnel packets are coming from GDM2.

The encapsulation also has problem because TOPS MCU will try to find PPE's
flow entry before packet encapsulation taken place. If the flow entry can
not be correctly found, TOPS MCU will forward that packet to APMCU.

[Release-log]
N/A

Change-Id: Ic5b8f33b904318829f6f13e90828b9e7cdc2f9d3
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/8684603
diff --git a/21.02/files/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi b/21.02/files/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi
index 7e96640..48ced19 100644
--- a/21.02/files/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi
+++ b/21.02/files/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi
@@ -381,6 +381,7 @@
 		dma-names = "tnl-sync";
 
 		fe_mem = <&eth>;
+		hnat = <&hnat>;
 	};
 
 	tops-mbox {
diff --git a/feed/kernel/tops/firmware/rebb/mt7988_mgmt/tops-mgmt.img b/feed/kernel/tops/firmware/rebb/mt7988_mgmt/tops-mgmt.img
index 329dbb6..5833d10 100644
--- a/feed/kernel/tops/firmware/rebb/mt7988_mgmt/tops-mgmt.img
+++ b/feed/kernel/tops/firmware/rebb/mt7988_mgmt/tops-mgmt.img
Binary files differ
diff --git a/feed/kernel/tops/firmware/rebb/mt7988_offload/tops-offload.img b/feed/kernel/tops/firmware/rebb/mt7988_offload/tops-offload.img
index 1a7bea5..c57c7da 100644
--- a/feed/kernel/tops/firmware/rebb/mt7988_offload/tops-offload.img
+++ b/feed/kernel/tops/firmware/rebb/mt7988_offload/tops-offload.img
Binary files differ
diff --git a/feed/kernel/tops/src/Makefile b/feed/kernel/tops/src/Makefile
index 929d902..2ad73cd 100644
--- a/feed/kernel/tops/src/Makefile
+++ b/feed/kernel/tops/src/Makefile
@@ -18,6 +18,7 @@
 tops-y += hwspinlock.o
 tops-y += mbox.o
 tops-y += mcu.o
+tops-y += misc.o
 tops-y += netsys.o
 tops-y += net-event.o
 tops-y += tops_params.o
diff --git a/feed/kernel/tops/src/inc/tops/mbox_id.h b/feed/kernel/tops/src/inc/tops/mbox_id.h
index 4ce3f6d..23a14ca 100644
--- a/feed/kernel/tops/src/inc/tops/mbox_id.h
+++ b/feed/kernel/tops/src/inc/tops/mbox_id.h
@@ -37,6 +37,7 @@
 	MBOX_AP2CX_CMD_NET = 1,
 	MBOX_AP2CX_CMD_WDT = 2,
 	MBOX_AP2CX_CMD_TRM = 3,
+	MBOX_AP2CX_CMD_MISC = 4,
 	__MBOX_AP2CX_CMD_MAX = 32,
 };
 
diff --git a/feed/kernel/tops/src/inc/tops/misc.h b/feed/kernel/tops/src/inc/tops/misc.h
new file mode 100644
index 0000000..ec1ba73
--- /dev/null
+++ b/feed/kernel/tops/src/inc/tops/misc.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Alvin Kuo <alvin.kuo@mediatek.com>
+ */
+
+#ifndef _TOPS_MISC_H_
+#define _TOPS_MISC_H_
+
+#include <linux/platform_device.h>
+
+enum misc_cmd_type {
+	MISC_CMD_TYPE_NULL,
+	MISC_CMD_TYPE_SET_PPE_NUM,
+
+	__MISC_CMD_TYPE_MAX,
+};
+
+int mtk_tops_misc_set_ppe_num(void);
+int mtk_tops_misc_init(struct platform_device *pdev);
+void mtk_tops_misc_deinit(struct platform_device *pdev);
+#endif /* _TOPS_MISC_H_ */
diff --git a/feed/kernel/tops/src/inc/tops/netsys.h b/feed/kernel/tops/src/inc/tops/netsys.h
index b319be4..fb68424 100644
--- a/feed/kernel/tops/src/inc/tops/netsys.h
+++ b/feed/kernel/tops/src/inc/tops/netsys.h
@@ -47,6 +47,7 @@
 #define TDMA_PORT_SHIFT				(0)
 #define TDMA_PORT_MASK				GENMASK(15, 0)
 
+u32 mtk_tops_netsys_ppe_get_num(void);
 u32 mtk_tops_netsys_ppe_get_max_entry_num(u32 ppe_id);
 int mtk_tops_netsys_init(struct platform_device *pdev);
 void mtk_tops_netsys_deinit(struct platform_device *pdev);
diff --git a/feed/kernel/tops/src/init.c b/feed/kernel/tops/src/init.c
index 9944ea2..4495dfb 100644
--- a/feed/kernel/tops/src/init.c
+++ b/feed/kernel/tops/src/init.c
@@ -23,6 +23,7 @@
 #include "tops/internal.h"
 #include "tops/mbox.h"
 #include "tops/mcu.h"
+#include "tops/misc.h"
 #include "tops/netsys.h"
 #include "tops/net-event.h"
 #include "tops/ser.h"
@@ -158,13 +159,20 @@
 		goto err_tdma_deinit;
 	}
 
-	ret = mtk_tops_post_init(pdev);
+	ret = mtk_tops_misc_init(pdev);
 	if (ret)
 		goto err_tnl_offload_deinit;
 
+	ret = mtk_tops_post_init(pdev);
+	if (ret)
+		goto err_misc_deinit;
+
 	TOPS_ERR("init done\n");
 	return ret;
 
+err_misc_deinit:
+	mtk_tops_misc_deinit(pdev);
+
 err_tnl_offload_deinit:
 	mtk_tops_tnl_offload_deinit(pdev);
 
@@ -196,6 +204,8 @@
 
 	mtk_tops_mcu_tear_down(pdev);
 
+	mtk_tops_misc_deinit(pdev);
+
 	mtk_tops_tnl_offload_deinit(pdev);
 
 	mtk_tops_tdma_deinit(pdev);
diff --git a/feed/kernel/tops/src/mcu.c b/feed/kernel/tops/src/mcu.c
index 6e8643a..2150c97 100644
--- a/feed/kernel/tops/src/mcu.c
+++ b/feed/kernel/tops/src/mcu.c
@@ -28,6 +28,7 @@
 #include "tops/internal.h"
 #include "tops/mbox.h"
 #include "tops/mcu.h"
+#include "tops/misc.h"
 #include "tops/netsys.h"
 #include "tops/tdma.h"
 #include "tops/trm.h"
@@ -572,6 +573,8 @@
 {
 	int ret;
 
+	mtk_tops_misc_set_ppe_num();
+
 	mtk_tops_tdma_enable();
 
 	mtk_tops_tnl_offload_recover();
diff --git a/feed/kernel/tops/src/misc.c b/feed/kernel/tops/src/misc.c
new file mode 100644
index 0000000..c61f647
--- /dev/null
+++ b/feed/kernel/tops/src/misc.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Alvin Kuo <alvin.kuo@mediatek.com>
+ */
+
+#include "tops/internal.h"
+#include "tops/misc.h"
+#include "tops/mbox.h"
+#include "tops/netsys.h"
+
+static struct mailbox_dev offload_send_mbox_dev[CORE_OFFLOAD_NUM] = {
+		[CORE_OFFLOAD_0] = MBOX_SEND_OFFLOAD_DEV(0, MISC),
+		[CORE_OFFLOAD_1] = MBOX_SEND_OFFLOAD_DEV(1, MISC),
+		[CORE_OFFLOAD_2] = MBOX_SEND_OFFLOAD_DEV(2, MISC),
+		[CORE_OFFLOAD_3] = MBOX_SEND_OFFLOAD_DEV(3, MISC),
+};
+
+int mtk_tops_misc_set_ppe_num(void)
+{
+	struct mailbox_msg msg = {
+		.msg1 = MISC_CMD_TYPE_SET_PPE_NUM,
+		.msg2 = mtk_tops_netsys_ppe_get_num(),
+	};
+	enum core_id core;
+	int ret;
+
+	for (core = CORE_OFFLOAD_0; core < CORE_OFFLOAD_NUM; core++) {
+		ret = mbox_send_msg_no_wait(&offload_send_mbox_dev[core], &msg);
+		/* TODO: error handle? */
+		if (ret)
+			TOPS_ERR("core offload%u set PPE num failed: %d\n",
+				 core, ret);
+	}
+
+	return ret;
+}
+
+int mtk_tops_misc_init(struct platform_device *pdev)
+{
+	enum core_id core;
+	int ret;
+
+	for (core = CORE_OFFLOAD_0; core < CORE_OFFLOAD_NUM; core++) {
+		ret = register_mbox_dev(MBOX_SEND, &offload_send_mbox_dev[core]);
+		if (ret)
+			goto err_out;
+	}
+
+	return ret;
+
+err_out:
+	for (; core > 0; core--)
+		unregister_mbox_dev(MBOX_SEND, &offload_send_mbox_dev[core - 1]);
+
+	return ret;
+}
+
+void mtk_tops_misc_deinit(struct platform_device *pdev)
+{
+	enum core_id core;
+
+	for (core = CORE_OFFLOAD_0; core < CORE_OFFLOAD_NUM; core++)
+		unregister_mbox_dev(MBOX_SEND, &offload_send_mbox_dev[core]);
+}
diff --git a/feed/kernel/tops/src/netsys.c b/feed/kernel/tops/src/netsys.c
index 50513d8..e1770c9 100644
--- a/feed/kernel/tops/src/netsys.c
+++ b/feed/kernel/tops/src/netsys.c
@@ -32,6 +32,7 @@
 
 struct netsys_hw {
 	void __iomem *base;
+	u32 ppe_num;
 };
 
 static struct netsys_hw netsys;
@@ -111,6 +112,11 @@
 	return 0;
 }
 
+u32 mtk_tops_netsys_ppe_get_num(void)
+{
+	return netsys.ppe_num;
+}
+
 u32 mtk_tops_netsys_ppe_get_max_entry_num(u32 ppe_id)
 {
 	u32 tbl_entry_num;
@@ -132,7 +138,7 @@
 	return PPE_DEFAULT_ENTRY_SIZE << tbl_entry_num;
 }
 
-int mtk_tops_netsys_init(struct platform_device *pdev)
+static int mtk_tops_netsys_base_init(struct platform_device *pdev)
 {
 	struct device_node *fe_mem = NULL;
 	struct resource res;
@@ -144,12 +150,57 @@
 		return -ENODEV;
 	}
 
-	if (of_address_to_resource(fe_mem, 0, &res))
-		return -ENXIO;
+	if (of_address_to_resource(fe_mem, 0, &res)) {
+		ret = -ENXIO;
+		goto out;
+	}
 
 	netsys.base = devm_ioremap(&pdev->dev, res.start, resource_size(&res));
-	if (!netsys.base)
-		return -ENOMEM;
+	if (!netsys.base) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+out:
+	of_node_put(fe_mem);
+
+	return ret;
+}
+
+static int mtk_tops_netsys_ppe_num_init(struct platform_device *pdev)
+{
+	struct device_node *hnat = NULL;
+	u32 val = 0;
+	int ret = 0;
+
+	hnat = of_parse_phandle(pdev->dev.of_node, "hnat", 0);
+	if (!hnat) {
+		TOPS_ERR("can not find hnat node\n");
+		return -ENODEV;
+	}
+
+	ret = of_property_read_u32(hnat, "mtketh-ppe-num", &val);
+	if (ret)
+		netsys.ppe_num = 1;
+	else
+		netsys.ppe_num = val;
+
+	of_node_put(hnat);
+
+	return 0;
+}
+
+int mtk_tops_netsys_init(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = mtk_tops_netsys_base_init(pdev);
+	if (ret)
+		return ret;
+
+	ret = mtk_tops_netsys_ppe_num_init(pdev);
+	if (ret)
+		return ret;
 
 	ret = mtk_trm_hw_config_register(TRM_NETSYS, &netsys_trm_hw_cfg);
 	if (ret)
diff --git a/feed/kernel/tops/src/protocol/tunnel/gre/gretap.c b/feed/kernel/tops/src/protocol/tunnel/gre/gretap.c
index 584367f..576d15c 100644
--- a/feed/kernel/tops/src/protocol/tunnel/gre/gretap.c
+++ b/feed/kernel/tops/src/protocol/tunnel/gre/gretap.c
@@ -12,13 +12,26 @@
 #include <pce/pce.h>
 
 #include "tops/internal.h"
+#include "tops/netsys.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);
+	/*
+	 * If the system only has 1 PPE,
+	 * packets from any GDM will default forward to PPE0 first
+	 * If the system has 3 PPE,
+	 * packets from GDM1 will forward to PPE0
+	 * packets from GDM2 will forward to PPE1
+	 * packets from GDM3 will forward to PPE2
+	 */
+	if (mtk_tops_netsys_ppe_get_num() == 1)
+		CLS_DESC_DATA(cdesc, fport, PSE_PORT_PPE0);
+	else
+		CLS_DESC_DATA(cdesc, fport, PSE_PORT_PPE1);
+
 	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);
diff --git a/feed/kernel/tops/src/protocol/tunnel/l2tp/l2tpv2.c b/feed/kernel/tops/src/protocol/tunnel/l2tp/l2tpv2.c
index ac5a929..a066202 100644
--- a/feed/kernel/tops/src/protocol/tunnel/l2tp/l2tpv2.c
+++ b/feed/kernel/tops/src/protocol/tunnel/l2tp/l2tpv2.c
@@ -17,6 +17,7 @@
 #include <pce/pce.h>
 
 #include "tops/internal.h"
+#include "tops/netsys.h"
 #include "tops/protocol/mac/ppp.h"
 #include "tops/protocol/transport/udp.h"
 #include "tops/protocol/tunnel/l2tp/l2tpv2.h"
@@ -25,7 +26,19 @@
 static int l2tpv2_cls_entry_setup(struct tops_tnl_info *tnl_info,
 				  struct cls_desc *cdesc)
 {
-	CLS_DESC_DATA(cdesc, fport, PSE_PORT_PPE0);
+	/*
+	 * If the system only has 1 PPE,
+	 * packets from any GDM will default forward to PPE0 first
+	 * If the system has 3 PPE,
+	 * packets from GDM1 will forward to PPE0
+	 * packets from GDM2 will forward to PPE1
+	 * packets from GDM3 will forward to PPE2
+	 */
+	if (mtk_tops_netsys_ppe_get_num() == 1)
+		CLS_DESC_DATA(cdesc, fport, PSE_PORT_PPE0);
+	else
+		CLS_DESC_DATA(cdesc, fport, PSE_PORT_PPE1);
+
 	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);
diff --git a/feed/kernel/tops/src/protocol/tunnel/pptp/pptp.c b/feed/kernel/tops/src/protocol/tunnel/pptp/pptp.c
index 8bc46fe..098852f 100644
--- a/feed/kernel/tops/src/protocol/tunnel/pptp/pptp.c
+++ b/feed/kernel/tops/src/protocol/tunnel/pptp/pptp.c
@@ -16,6 +16,7 @@
 #include <pce/netsys.h>
 #include <pce/pce.h>
 
+#include "tops/netsys.h"
 #include "tops/protocol/mac/ppp.h"
 #include "tops/protocol/tunnel/pptp/pptp.h"
 #include "tops/seq_gen.h"
@@ -24,7 +25,19 @@
 static int pptp_cls_entry_setup(struct tops_tnl_info *tnl_info,
 				struct cls_desc *cdesc)
 {
-	CLS_DESC_DATA(cdesc, fport, PSE_PORT_PPE0);
+	/*
+	 * If the system only has 1 PPE,
+	 * packets from any GDM will default forward to PPE0 first
+	 * If the system has 3 PPE,
+	 * packets from GDM1 will forward to PPE0
+	 * packets from GDM2 will forward to PPE1
+	 * packets from GDM3 will forward to PPE2
+	 */
+	if (mtk_tops_netsys_ppe_get_num() == 1)
+		CLS_DESC_DATA(cdesc, fport, PSE_PORT_PPE0);
+	else
+		CLS_DESC_DATA(cdesc, fport, PSE_PORT_PPE1);
+
 	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);