[][openwrt][mt7988][pce][separate CLS entry definition from TOPS_ENTRY]

[Description]
Change CLS entry definition.

Before this patch modification, 1 CLS entry is strictly mapping to a
TOPS_ENTRY which means that 1 tunnel protocol can only occupy 1 CLS entry.
This implementation is based on the assumption of all tunnel protocols
separate different session by destination IP.

This may cause some problem if a tunnel protocol distinguish different
session not by destination IP.

Take IPsec ESP for instance, it use ESP header's SPI field to
differentiate sessions. In this example, ESP will occupy several CLS entry
for several sessions.

In this patch, CLS entry is not strictly mapped to 1 tunnel protocol
anymore.
If a protocol needs to use CLS to forward packets to HW offload engine,
the CLS configuration is now runtime configured instead of setup at boot
up.

Users can use mtk_pce_cls_entry_alloc() to allocate an empty cls_entry.
When they setup the cls_entry structure, they should use
mtk_pce_cls_entry_write() to write the CLS HW.

[Release-log]
N/A

Change-Id: I593be2075c8f27d247cda986ed324a6953a8fc13
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7923903
diff --git a/package-21.02/kernel/pce/src/cls.c b/package-21.02/kernel/pce/src/cls.c
index 847dff8..3c10cf1 100644
--- a/package-21.02/kernel/pce/src/cls.c
+++ b/package-21.02/kernel/pce/src/cls.c
@@ -5,6 +5,8 @@
  * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
  */
 
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
 #include <linux/err.h>
 #include <linux/lockdep.h>
 #include <linux/spinlock.h>
@@ -14,7 +16,8 @@
 #include "pce/netsys.h"
 
 struct cls_hw {
-	struct cls_entry *cls_tbl[FE_MEM_CLS_MAX_INDEX];
+	struct cls_entry cls_tbl[FE_MEM_CLS_MAX_INDEX];
+	DECLARE_BITMAP(cls_used, FE_MEM_CLS_MAX_INDEX);
 	spinlock_t lock;
 };
 
@@ -60,10 +63,15 @@
 
 int mtk_pce_cls_init(struct platform_device *pdev)
 {
+	u32 i;
+
 	spin_lock_init(&cls_hw.lock);
 
 	mtk_pce_cls_clean_up();
 
+	for (i = 0; i < FE_MEM_CLS_MAX_INDEX; i++)
+		cls_hw.cls_tbl[i].idx = i + 1;
+
 	return 0;
 }
 
@@ -72,18 +80,15 @@
 	mtk_pce_cls_clean_up();
 }
 
-/*
- * Read a cls_desc without checking it is in used or not
- * cls_hw.lock should be held before calling this function
- */
-static int __mtk_pce_cls_desc_read(struct cls_desc *cdesc, enum cls_entry_type entry)
+int mtk_pce_cls_desc_read(struct cls_desc *cdesc, u32 idx)
 {
 	struct fe_mem_msg msg;
 	int ret;
 
-	lockdep_assert_held(&cls_hw.lock);
+	if (unlikely(!cdesc || !idx || idx >= FE_MEM_CLS_MAX_INDEX))
+		return -EINVAL;
 
-	mtk_pce_fe_mem_msg_config(&msg, FE_MEM_CMD_READ, FE_MEM_TYPE_CLS, entry);
+	mtk_pce_fe_mem_msg_config(&msg, FE_MEM_CMD_READ, FE_MEM_TYPE_CLS, idx);
 
 	memset(&msg.raw, 0, sizeof(msg.raw));
 
@@ -96,39 +101,14 @@
 	return ret;
 }
 
-/*
- * Read a cls_desc without checking it is in used or not
- * This function is only used for debugging purpose
- */
-int mtk_pce_cls_desc_read(struct cls_desc *cdesc, enum cls_entry_type entry)
-{
-	unsigned long flag;
-	int ret;
-
-	if (unlikely(entry == CLS_ENTRY_NONE || entry >= __CLS_ENTRY_MAX)) {
-		PCE_ERR("invalid cls entry: %u\n", entry);
-		return -EINVAL;
-	}
-
-	spin_lock_irqsave(&cls_hw.lock, flag);
-	ret = __mtk_pce_cls_desc_read(cdesc, entry);
-	spin_unlock_irqrestore(&cls_hw.lock, flag);
-
-	return ret;
-}
-
-/*
- * Write a cls_desc to an entry without checking the entry is occupied
- * cls_hw.lock should be held before calling this function
- */
-static int __mtk_pce_cls_desc_write(struct cls_desc *cdesc,
-				    enum cls_entry_type entry)
+int mtk_pce_cls_desc_write(struct cls_desc *cdesc, u32 idx)
 {
 	struct fe_mem_msg msg;
 
-	lockdep_assert_held(&cls_hw.lock);
+	if (unlikely(!cdesc || !idx || idx >= FE_MEM_CLS_MAX_INDEX))
+		return -EINVAL;
 
-	mtk_pce_fe_mem_msg_config(&msg, FE_MEM_CMD_WRITE, FE_MEM_TYPE_CLS, entry);
+	mtk_pce_fe_mem_msg_config(&msg, FE_MEM_CMD_WRITE, FE_MEM_TYPE_CLS, idx);
 
 	memset(&msg.raw, 0, sizeof(msg.raw));
 	memcpy(&msg.cdesc, cdesc, sizeof(struct cls_desc));
@@ -136,96 +116,51 @@
 	return mtk_pce_fe_mem_msg_send(&msg);
 }
 
-/*
- * Write a cls_desc to an entry without checking the entry is used by others.
- * The user should check the entry is occupied by themselves or use the standard API
- * mtk_pce_cls_entry_register().
- *
- * This function is only used for debugging purpose
- */
-int mtk_pce_cls_desc_write(struct cls_desc *cdesc, enum cls_entry_type entry)
+int mtk_pce_cls_entry_write(struct cls_entry *cls)
 {
-	unsigned long flag;
-	int ret;
-
-	if (unlikely(!cdesc))
+	if (unlikely(!cls))
 		return -EINVAL;
 
-	spin_lock_irqsave(&cls_hw.lock, flag);
-	ret = __mtk_pce_cls_desc_write(cdesc, entry);
-	spin_unlock_irqrestore(&cls_hw.lock, flag);
-
-	return ret;
+	return mtk_pce_cls_desc_write(&cls->cdesc, cls->idx);
 }
+EXPORT_SYMBOL(mtk_pce_cls_entry_write);
 
-int mtk_pce_cls_entry_register(struct cls_entry *cls)
+struct cls_entry *mtk_pce_cls_entry_alloc(void)
 {
+	struct cls_entry *cls;
 	unsigned long flag;
-	int ret = 0;
-
-	if (unlikely(!cls))
-		return -EINVAL;
-
-	if (unlikely(cls->entry == CLS_ENTRY_NONE || cls->entry >= __CLS_ENTRY_MAX)) {
-		PCE_ERR("invalid cls entry: %u\n", cls->entry);
-		return -EINVAL;
-	}
+	u32 idx;
 
 	spin_lock_irqsave(&cls_hw.lock, flag);
 
-	if (cls_hw.cls_tbl[cls->entry]) {
-		PCE_ERR("cls rules already registered ofr entry: %u\n", cls->entry);
-		ret = -EBUSY;
+	idx = find_first_zero_bit(cls_hw.cls_used, FE_MEM_CLS_MAX_INDEX);
+	if (idx == FE_MEM_CLS_MAX_INDEX) {
+		cls = ERR_PTR(-ENOMEM);
 		goto unlock;
 	}
 
-	ret = __mtk_pce_cls_desc_write(&cls->cdesc, cls->entry);
-	if (ret) {
-		PCE_NOTICE("send cls message failed: %d\n", ret);
-		goto unlock;
-	}
+	set_bit(idx, cls_hw.cls_used);
 
-	cls_hw.cls_tbl[cls->entry] = cls;
+	cls = &cls_hw.cls_tbl[idx];
+
+	memset(&cls->cdesc, 0, sizeof(cls->cdesc));
 
 unlock:
 	spin_unlock_irqrestore(&cls_hw.lock, flag);
 
-	return ret;
+	return cls;
 }
-EXPORT_SYMBOL(mtk_pce_cls_entry_register);
+EXPORT_SYMBOL(mtk_pce_cls_entry_alloc);
 
-void mtk_pce_cls_entry_unregister(struct cls_entry *cls)
+void mtk_pce_cls_entry_free(struct cls_entry *cls)
 {
-	struct cls_desc cdesc;
 	unsigned long flag;
-	int ret = 0;
 
-	if (unlikely(!cls))
+	if (!cls)
 		return;
 
-	if (unlikely(cls->entry == CLS_ENTRY_NONE || cls->entry >= __CLS_ENTRY_MAX)) {
-		PCE_ERR("invalid cls entry: %u\n", cls->entry);
-		return;
-	}
-
 	spin_lock_irqsave(&cls_hw.lock, flag);
-
-	if (cls_hw.cls_tbl[cls->entry] != cls) {
-		PCE_ERR("cls rules is registered by others\n");
-		goto unlock;
-	}
-
-	memset(&cdesc, 0, sizeof(struct cls_desc));
-
-	ret = __mtk_pce_cls_desc_write(&cdesc, cls->entry);
-	if (ret) {
-		PCE_NOTICE("fe send cls message failed: %d\n", ret);
-		goto unlock;
-	}
-
-	cls_hw.cls_tbl[cls->entry] = NULL;
-
-unlock:
+	clear_bit(cls->idx - 1, cls_hw.cls_used);
 	spin_unlock_irqrestore(&cls_hw.lock, flag);
 }
-EXPORT_SYMBOL(mtk_pce_cls_entry_unregister);
+EXPORT_SYMBOL(mtk_pce_cls_entry_free);
diff --git a/package-21.02/kernel/pce/src/debugfs.c b/package-21.02/kernel/pce/src/debugfs.c
index 6e925fd..6596413 100644
--- a/package-21.02/kernel/pce/src/debugfs.c
+++ b/package-21.02/kernel/pce/src/debugfs.c
@@ -100,7 +100,7 @@
 	int ret;
 	u32 i;
 
-	for (i = CLS_ENTRY_NONE + 1; i < FE_MEM_CLS_MAX_INDEX; i++) {
+	for (i = 1; i < FE_MEM_CLS_MAX_INDEX; i++) {
 		ret = mtk_pce_cls_desc_read(&cdesc, i);
 
 		if (ret) {
@@ -399,9 +399,9 @@
 {
 	struct cls_desc cdesc;
 	char buf[512];
-	u32 cls_entry = 0;
 	u32 nchar = 0;
 	u32 ofs = 0;
+	u32 idx = 0;
 	int ret;
 
 	if (count > sizeof(buf))
@@ -414,14 +414,14 @@
 
 	memset(&cdesc, 0, sizeof(struct cls_desc));
 
-	ret = sscanf(buf + ofs, "%u %n\n", &cls_entry, &nchar);
+	ret = sscanf(buf + ofs, "%u %n\n", &idx, &nchar);
 	if (ret != 1)
 		return -EINVAL;
 
 	ofs += nchar;
 
-	if (cls_entry == CLS_ENTRY_NONE || cls_entry > __CLS_ENTRY_MAX) {
-		PCE_ERR("invalid cls entry: %u\n", cls_entry);
+	if (!idx || idx >= FE_MEM_CLS_MAX_INDEX) {
+		PCE_ERR("invalid cls entry: %u\n", idx);
 		return -EINVAL;
 	}
 
@@ -434,7 +434,7 @@
 			return ret;
 	}
 
-	ret = mtk_pce_cls_desc_write(&cdesc, cls_entry);
+	ret = mtk_pce_cls_desc_write(&cdesc, idx);
 	if (ret)
 		return ret;
 
diff --git a/package-21.02/kernel/pce/src/inc/pce/cls.h b/package-21.02/kernel/pce/src/inc/pce/cls.h
index 59d1708..2853c85 100644
--- a/package-21.02/kernel/pce/src/inc/pce/cls.h
+++ b/package-21.02/kernel/pce/src/inc/pce/cls.h
@@ -12,24 +12,6 @@
 
 #include "pce/pce.h"
 
-enum cls_entry_type {
-	CLS_ENTRY_NONE = 0,
-	CLS_ENTRY_GRETAP,
-	CLS_ENTRY_PPTP,
-	CLS_ENTRY_IP_L2TP,
-	CLS_ENTRY_UDP_L2TP_CTRL,
-	CLS_ENTRY_UDP_L2TP_DATA = 5,
-	CLS_ENTRY_VXLAN,
-	CLS_ENTRY_NATT,
-	CLS_ENTRY_CAPWAP_CTRL,
-	CLS_ENTRY_CAPWAP_DATA,
-	CLS_ENTRY_CAPWAP_DTLS = 10,
-	CLS_ENTRY_IPSEC_ESP,
-	CLS_ENTRY_IPSEC_AH,
-
-	__CLS_ENTRY_MAX = FE_MEM_CLS_MAX_INDEX,
-};
-
 #define CLS_DESC_MASK_DATA(cdesc, field, mask, data)			\
 	do {								\
 		(cdesc)->field ## _m = (mask);				\
@@ -39,7 +21,7 @@
 	(cdesc)->field = (data)
 
 struct cls_entry {
-	enum cls_entry_type entry;
+	u32 idx;
 	struct cls_desc cdesc;
 };
 
@@ -49,9 +31,11 @@
 int mtk_pce_cls_init(struct platform_device *pdev);
 void mtk_pce_cls_deinit(struct platform_device *pdev);
 
-int mtk_pce_cls_desc_read(struct cls_desc *cdesc, enum cls_entry_type entry);
-int mtk_pce_cls_desc_write(struct cls_desc *cdesc, enum cls_entry_type entry);
+int mtk_pce_cls_desc_read(struct cls_desc *cdesc, u32 idx);
+int mtk_pce_cls_desc_write(struct cls_desc *cdesc, u32 idx);
+
+int mtk_pce_cls_entry_write(struct cls_entry *cls);
 
-int mtk_pce_cls_entry_register(struct cls_entry *cls);
-void mtk_pce_cls_entry_unregister(struct cls_entry *cls);
+struct cls_entry *mtk_pce_cls_entry_alloc(void);
+void mtk_pce_cls_entry_free(struct cls_entry *cls);
 #endif /* _PCE_CLS_H_ */