[][openwrt][mt7988][pce][TOPS Alpha release]

[Description]
Add alpha version of PCE(packet classification engine) package
The PCE supports packet classification HW features such as packet header,
partial user data and destination IP match. It also provides support to
setup HW crypto offload essential data.

[Release-log]
N/A

Change-Id: Ia1826dcc6e6969ef65bed6ae3a70ce761799a6b9
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7852682
diff --git a/package-21.02/kernel/pce/src/tport_map.c b/package-21.02/kernel/pce/src/tport_map.c
new file mode 100644
index 0000000..0350be6
--- /dev/null
+++ b/package-21.02/kernel/pce/src/tport_map.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 <linux/device.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
+#include "pce/internal.h"
+#include "pce/tport_map.h"
+
+int mtk_pce_tport_map_ts_config_read(enum ts_config_entry entry,
+				    struct tsc_desc *ts_cfg)
+{
+	struct fe_mem_msg msg;
+	int ret = 0;
+
+	if (!ts_cfg)
+		return -EINVAL;
+
+	if (!(TS_CONFIG_MASK & BIT(entry))) {
+		PCE_ERR("invalid ts config entry: %u\n", entry);
+		return -EPERM;
+	}
+
+	mtk_pce_fe_mem_msg_config(&msg, FE_MEM_CMD_READ, FE_MEM_TYPE_TS_CONFIG, entry);
+	memset(&msg.raw, 0, sizeof(msg.raw));
+
+	ret = mtk_pce_fe_mem_msg_send(&msg);
+	if (ret) {
+		PCE_NOTICE("fe_mem send msg failed: %d\n", ret);
+		return ret;
+	}
+
+	memcpy(ts_cfg, &msg.tdesc, sizeof(*ts_cfg));
+
+	return ret;
+}
+
+int mtk_pce_tport_map_ts_config_write(enum ts_config_entry entry,
+				    struct tsc_desc *ts_cfg)
+{
+	struct fe_mem_msg msg;
+	int ret = 0;
+
+	if (!ts_cfg)
+		return -EINVAL;
+
+	if (!(TS_CONFIG_MASK & BIT(entry))) {
+		PCE_NOTICE("invalid ts config entry: %u\n", entry);
+		return -EPERM;
+	}
+
+	mtk_pce_fe_mem_msg_config(&msg, FE_MEM_CMD_WRITE, FE_MEM_TYPE_TS_CONFIG, entry);
+	memset(&msg.raw, 0, sizeof(msg.raw));
+	memcpy(&msg.raw, ts_cfg, sizeof(struct tsc_desc));
+
+	ret = mtk_pce_fe_mem_msg_send(&msg);
+	if (ret) {
+		PCE_NOTICE("fe_mem send msg failed: %d\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+int mtk_pce_tport_map_ppe_read(enum pse_port ppe, u64 *map)
+{
+	if (!map)
+		return -EINVAL;
+
+	if (!(PSE_PORT_PPE_MASK & BIT(ppe))) {
+		PCE_NOTICE("invalid ppe index: %u\n", ppe);
+		return -EPERM;
+	}
+
+	*map = mtk_pce_ppe_read(ppe, PPE_TPORT_TBL_0);
+	*map |= ((u64)mtk_pce_ppe_read(ppe, PPE_TPORT_TBL_1)) << 32;
+
+	return 0;
+}
+
+static int mtk_pce_tport_map_update_ts_config(enum ts_config_entry entry,
+					      u32 tport_idx,
+					      enum pse_port target)
+{
+	struct tsc_desc ts_cfg;
+	int ret = 0;
+
+	ret = mtk_pce_tport_map_ts_config_read(entry, &ts_cfg);
+	if (ret)
+		return ret;
+
+	if (tport_idx < TPORT_IDX_MAX / 2) {
+		ts_cfg.tport_map_lower &= (~(0xF << (tport_idx * PSE_PER_PORT_BITS)));
+		ts_cfg.tport_map_lower |= (target << (tport_idx * PSE_PER_PORT_BITS));
+	} else {
+		ts_cfg.tport_map_upper &= (~(0xF << (tport_idx * PSE_PER_PORT_BITS)));
+		ts_cfg.tport_map_upper |= (target << (tport_idx * PSE_PER_PORT_BITS));
+	}
+
+	ret = mtk_pce_tport_map_ts_config_write(entry, &ts_cfg);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+static int mtk_pce_tport_map_update_ppe(enum pse_port ppe,
+					u32 tport_idx,
+					enum pse_port target)
+{
+	u32 mask = (PSE_PER_PORT_MASK
+		    << ((tport_idx % (TPORT_IDX_MAX / 2)) * PSE_PER_PORT_BITS));
+	u32 val = ((target & PSE_PER_PORT_MASK)
+		   << ((tport_idx % (TPORT_IDX_MAX / 2)) * PSE_PER_PORT_BITS));
+
+	if (tport_idx < TPORT_IDX_MAX / 2)
+		mtk_pce_ppe_rmw(ppe, PPE_TPORT_TBL_0, mask, val);
+	else
+		mtk_pce_ppe_rmw(ppe, PPE_TPORT_TBL_1, mask, val);
+
+	return 0;
+}
+
+/*
+ * update tport idx mapping
+ * pse_port: the pse port idx that is going to be modified
+ * tport_idx: the tport idx that is going to be modified
+ * target: the next port for packet when the packet is at pse_port with tport_idx
+ */
+int mtk_pce_tport_map_pse_port_update(enum pse_port pse_port,
+				      u32 tport_idx,
+				      enum pse_port target)
+{
+	int ret = 0;
+
+	if (pse_port >= __PSE_PORT_MAX || target >= __PSE_PORT_MAX) {
+		PCE_NOTICE("invalid pse_port: %u, target: %u\n", pse_port, target);
+		return -EPERM;
+	}
+
+	if (tport_idx >= TPORT_IDX_MAX) {
+		PCE_NOTICE("invalid tport_idx: %u\n", tport_idx);
+		return -EPERM;
+	}
+
+	if (TS_CONFIG_MASK & BIT(pse_port))
+		ret = mtk_pce_tport_map_update_ts_config(pse_port, tport_idx, target);
+	else if (PSE_PORT_PPE_MASK & BIT(pse_port))
+		ret = mtk_pce_tport_map_update_ppe(pse_port, tport_idx, target);
+	else
+		ret = -EINVAL;
+
+	if (ret)
+		PCE_ERR("update tport map failed: %d\n", ret);
+
+	return ret;
+}