[][openwrt][mt7988][tops][TOPS Alpha release]

[Description]
Add alpha version of TOPS(tunnel offload processor system) and tops-tool
package.

TOPS package supports tunnel protocol HW offload. The support offload
tunnel protocols for Alpha version are L2oGRE and L2TPv2.
Notice that, TOPS only guarantees that inner packets are TCP. It is still
unstable for UDP inner packet flow.

tops-tool package provides several debug features such as logger, coredump
for TOPS.

[Release-log]
N/A

Change-Id: Iab6e4a89bebbe42c967f28e0c9e9c0611673f354
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7852683
diff --git a/package-21.02/kernel/tops/src/ser.c b/package-21.02/kernel/tops/src/ser.c
new file mode 100644
index 0000000..a126185
--- /dev/null
+++ b/package-21.02/kernel/tops/src/ser.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Alvin Kuo <alvin.kuog@mediatek.com>
+ */
+
+#include <linux/err.h>
+#include <linux/workqueue.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+
+#include "internal.h"
+#include "net-event.h"
+#include "ser.h"
+#include "trm.h"
+
+struct tops_ser {
+	struct work_struct work;
+	struct tops_ser_params ser_params;
+	spinlock_t params_lock;
+};
+
+struct tops_ser tops_ser;
+
+static inline void __mtk_tops_ser_cmd_clear(void)
+{
+	memset(&tops_ser.ser_params, 0, sizeof(struct tops_ser_params));
+	tops_ser.ser_params.type = __TOPS_SER_TYPE_MAX;
+}
+
+static inline void mtk_tops_ser_cmd_clear(void)
+{
+	unsigned long flag;
+
+	spin_lock_irqsave(&tops_ser.params_lock, flag);
+
+	__mtk_tops_ser_cmd_clear();
+
+	spin_unlock_irqrestore(&tops_ser.params_lock, flag);
+}
+
+static void mtk_tops_ser_setup_mcmd(struct tops_ser_params *ser_params,
+				    struct mcu_ctrl_cmd *mcmd)
+{
+	memset(mcmd, 0, sizeof(struct mcu_ctrl_cmd));
+
+	switch (ser_params->type) {
+	case TOPS_SER_NETSYS_FE_RST:
+		mcmd->e = MCU_EVENT_TYPE_FE_RESET;
+		break;
+	case TOPS_SER_WDT_TO:
+		mcmd->e = MCU_EVENT_TYPE_WDT_TIMEOUT;
+		break;
+	default:
+		TOPS_ERR("unsupport TOPS SER type: %u\n", ser_params->type);
+		return;
+	}
+
+	if (ser_params->ser_mcmd_setup)
+		ser_params->ser_mcmd_setup(ser_params, mcmd);
+}
+
+static void mtk_tops_ser_reset_callback(void *params)
+{
+	struct tops_ser_params *ser_params = params;
+
+	if (ser_params->ser_callback)
+		ser_params->ser_callback(ser_params);
+}
+
+static void mtk_tops_ser_work(struct work_struct *work)
+{
+	struct tops_ser_params ser_params;
+	struct mcu_ctrl_cmd mcmd;
+	unsigned long flag = 0;
+
+	spin_lock_irqsave(&tops_ser.params_lock, flag);
+
+	while (tops_ser.ser_params.type != __TOPS_SER_TYPE_MAX) {
+		memcpy(&ser_params,
+		       &tops_ser.ser_params,
+		       sizeof(struct tops_ser_params));
+
+		spin_unlock_irqrestore(&tops_ser.params_lock, flag);
+
+		mtk_tops_ser_setup_mcmd(&ser_params, &mcmd);
+
+		if (mtk_tops_mcu_reset(&mcmd,
+				       mtk_tops_ser_reset_callback,
+				       &ser_params)) {
+			TOPS_INFO("SER type: %u failed to recover\n",
+				  ser_params.type);
+			/*
+			 * TODO: check is OK to directly return
+			 * since mcu state machine should handle
+			 * state transition failed?
+			 */
+			mtk_tops_ser_cmd_clear();
+			return;
+		}
+
+		TOPS_INFO("SER type: %u successfully recovered\n", ser_params.type);
+
+		spin_lock_irqsave(&tops_ser.params_lock, flag);
+		/*
+		 * If there isn't queued any other SER cmd that has higher priority
+		 * than current SER command, clear SER command and exit.
+		 * Otherwise let the work perform reset again for high priority SER.
+		 */
+		if (tops_ser.ser_params.type > ser_params.type
+		    || !memcmp(&tops_ser.ser_params, &ser_params,
+			       sizeof(struct tops_ser_params)))
+			__mtk_tops_ser_cmd_clear();
+	}
+
+	spin_unlock_irqrestore(&tops_ser.params_lock, flag);
+}
+
+int mtk_tops_ser(struct tops_ser_params *ser_params)
+{
+	unsigned long flag;
+
+	if (!ser_params)
+		return -EINVAL;
+
+	spin_lock_irqsave(&tops_ser.params_lock, flag);
+
+	/* higher SER type should not override lower SER type */
+	if (tops_ser.ser_params.type != __TOPS_SER_TYPE_MAX
+	    && tops_ser.ser_params.type < ser_params->type)
+		goto unlock;
+
+	memcpy(&tops_ser.ser_params, ser_params, sizeof(*ser_params));
+
+	schedule_work(&tops_ser.work);
+
+unlock:
+	spin_unlock_irqrestore(&tops_ser.params_lock, flag);
+
+	return 0;
+}
+
+int mtk_tops_ser_init(struct platform_device *pdev)
+{
+	INIT_WORK(&tops_ser.work, mtk_tops_ser_work);
+
+	spin_lock_init(&tops_ser.params_lock);
+
+	tops_ser.ser_params.type = __TOPS_SER_TYPE_MAX;
+
+	return 0;
+}
+
+int mtk_tops_ser_deinit(struct platform_device *pdev)
+{
+	return 0;
+}