[][openwrt][mt7988][tops][separate CLS_ENTRY and TOPS_ENTRY dependency]
[Description]
Refactor TOPS CLS_ENTRY and TOPS_ENTRY.
Separate CLS_ENTRY and TOPS_ENTRY implicit mapping relationship.
In previous implementation, 1 protocol can only occupy a CLS_ENTRY and a
CLS_ENTRY is corresponding to a TOPS_ENTRY. 1 TOPS_ENTRY will have a
tunnel offload function inside TOPS firmware.
However, some of the protocol may occupy several CLS_ENTRY such as ESP.
This kind of protocol may use different CLS_ENTRY to distinguish each
session.
This leads to a problem that TOPS firmware can not handle same protocol
with different TOPS_ENTRY.
To solve this problem, the idea of CLS_ENTRY and TOPS_ENTRY is no longer 1
to 1 mapping. CLS_ENTRY is now allocated dynamically and its index is
carried inside tops_tnl_params so that TOPS firmware can map that
CLS_ENTRY to a TOPS_ENTRY which will be corresponding to a tunnel offload
function.
[Release-log]
N/A
Change-Id: I162a899353b9935602d971947d8514ba8d4e7d3e
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7923904
diff --git a/package-21.02/kernel/tops/src/ctrl.c b/package-21.02/kernel/tops/src/ctrl.c
index e425e68..ed1c95b 100644
--- a/package-21.02/kernel/tops/src/ctrl.c
+++ b/package-21.02/kernel/tops/src/ctrl.c
@@ -163,7 +163,7 @@
tnl_params.flag |= TNL_ENCAP_ENABLE;
tnl_params.tops_entry_proto = tnl_type->tops_entry;
- tnl_info = mtk_tops_tnl_info_alloc();
+ tnl_info = mtk_tops_tnl_info_alloc(tnl_type);
if (IS_ERR(tnl_info))
return -ENOMEM;
diff --git a/package-21.02/kernel/tops/src/inc/tunnel.h b/package-21.02/kernel/tops/src/inc/tunnel.h
index 961aa03..387d923 100644
--- a/package-21.02/kernel/tops/src/inc/tunnel.h
+++ b/package-21.02/kernel/tops/src/inc/tunnel.h
@@ -18,6 +18,8 @@
#include <linux/spinlock.h>
#include <linux/types.h>
+#include <pce/cls.h>
+
#include "protocol/l2tp/l2tp.h"
/* tunnel info status */
@@ -107,6 +109,13 @@
TNL_INFO_DEBUG_BIT,
};
+struct tops_cls_entry {
+ struct cls_entry *cls;
+ struct list_head node;
+ refcount_t refcnt;
+ bool updated;
+};
+
/* record outer tunnel header data for HW offloading */
struct tops_tnl_params {
u8 daddr[ETH_ALEN];
@@ -117,6 +126,7 @@
__be16 sport;
u16 protocol;
u8 tops_entry_proto;
+ u8 cls_entry;
u8 flag; /* bit: enum tops_tnl_params_flag */
union {
struct l2tp_param l2tp; /* 4B */
@@ -126,19 +136,26 @@
struct tops_tnl_info {
struct tops_tnl_params tnl_params;
struct tops_tnl_params cache;
+ struct tops_tnl_type *tnl_type;
+ struct tops_cls_entry *tcls;
struct list_head sync_node;
struct hlist_node hlist;
struct net_device *dev;
- struct timer_list taging;
spinlock_t lock;
u32 tnl_idx;
u32 status;
u32 flag; /* bit: enum tops_tnl_info_flag */
- refcount_t refcnt;
} __aligned(16);
struct tops_tnl_type {
const char *type_name;
+ enum tops_entry_type tops_entry;
+
+ int (*cls_entry_setup)(struct tops_tnl_info *tnl_info,
+ struct cls_desc *cdesc);
+ struct list_head tcls_head;
+ bool use_multi_cls;
+
int (*tnl_decap_param_setup)(struct sk_buff *skb,
struct tops_tnl_params *tnl_params);
int (*tnl_encap_param_setup)(struct sk_buff *skb,
@@ -149,14 +166,13 @@
bool (*tnl_info_match)(struct tops_tnl_params *params1,
struct tops_tnl_params *params2);
bool (*tnl_decap_offloadable)(struct sk_buff *skb);
- enum tops_entry_type tops_entry;
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_alloc(void);
+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);
int mtk_tops_tnl_offload_init(struct platform_device *pdev);
diff --git a/package-21.02/kernel/tops/src/protocol/gre/gretap.c b/package-21.02/kernel/tops/src/protocol/gre/gretap.c
index 91a239f..9e937af 100644
--- a/package-21.02/kernel/tops/src/protocol/gre/gretap.c
+++ b/package-21.02/kernel/tops/src/protocol/gre/gretap.c
@@ -8,29 +8,30 @@
#include <net/gre.h>
#include <pce/cls.h>
+#include <pce/netsys.h>
#include <pce/pce.h>
#include "tunnel.h"
-static struct cls_entry gretap_cls_entry = {
- .entry = CLS_ENTRY_GRETAP,
- .cdesc = {
- .fport = 0x3,
- .tport_idx = 0x4,
- .tag_m = 0x3,
- .tag = 0x1,
- .dip_match_m = 0x1,
- .dip_match = 0x1,
- .l4_type_m = 0xFF,
- .l4_type = 0x2F,
- .l4_udp_hdr_nez_m = 0x1,
- .l4_udp_hdr_nez = 0x1,
- .l4_valid_m = 0x7,
- .l4_valid = 0x3,
- .l4_hdr_usr_data_m = 0xFFFF,
- .l4_hdr_usr_data = 0x6558,
- },
-};
+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_decap_param_setup(struct sk_buff *skb,
struct tops_tnl_params *tnl_params)
@@ -171,6 +172,7 @@
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,
@@ -182,24 +184,10 @@
int mtk_tops_gretap_init(void)
{
- int ret;
-
- ret = mtk_tops_tnl_type_register(&gretap_type);
- if (ret)
- return ret;
-
- ret = mtk_pce_cls_entry_register(&gretap_cls_entry);
- if (ret) {
- mtk_tops_tnl_type_unregister(&gretap_type);
- return ret;
- }
-
- return ret;
+ return mtk_tops_tnl_type_register(&gretap_type);
}
void mtk_tops_gretap_deinit(void)
{
- mtk_pce_cls_entry_unregister(&gretap_cls_entry);
-
mtk_tops_tnl_type_unregister(&gretap_type);
}
diff --git a/package-21.02/kernel/tops/src/protocol/l2tp/udp_l2tp_data.c b/package-21.02/kernel/tops/src/protocol/l2tp/udp_l2tp_data.c
index bde94e5..e26dc62 100644
--- a/package-21.02/kernel/tops/src/protocol/l2tp/udp_l2tp_data.c
+++ b/package-21.02/kernel/tops/src/protocol/l2tp/udp_l2tp_data.c
@@ -12,31 +12,31 @@
#include <linux/udp.h>
#include <pce/cls.h>
+#include <pce/netsys.h>
#include <pce/pce.h>
#include "protocol/l2tp/l2tp.h"
#include "protocol/ppp/ppp.h"
#include "tunnel.h"
-static struct cls_entry udp_l2tp_data_cls_entry = {
- .entry = CLS_ENTRY_UDP_L2TP_DATA,
- .cdesc = {
- .fport = 0x3,
- .tport_idx = 0x4,
- .tag_m = 0x3,
- .tag = 0x2,
- .dip_match_m = 0x1,
- .dip_match = 0x1,
- .l4_type_m = 0xFF,
- .l4_type = 0x11,
- .l4_valid_m = 0x7,
- .l4_valid = 0x7,
- .l4_dport_m = 0xFFFF,
- .l4_dport = 1701,
- .l4_hdr_usr_data_m = 0x80030000,
- .l4_hdr_usr_data = 0x00020000,
- },
-};
+static int udp_l2tp_data_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_match(struct udp_l2tp_data_hdr *l2tp)
{
@@ -293,6 +293,7 @@
static struct tops_tnl_type udp_l2tp_data_type = {
.type_name = "udp-l2tp-data",
+ .cls_entry_setup = udp_l2tp_data_cls_entry_setup,
.tnl_decap_param_setup = udp_l2tp_data_tnl_decap_param_setup,
.tnl_encap_param_setup = udp_l2tp_data_tnl_encap_param_setup,
.tnl_debug_param_setup = udp_l2tp_data_tnl_debug_param_setup,
@@ -304,24 +305,10 @@
int mtk_tops_udp_l2tp_data_init(void)
{
- int ret = 0;
-
- ret = mtk_tops_tnl_type_register(&udp_l2tp_data_type);
- if (ret)
- return ret;
-
- ret = mtk_pce_cls_entry_register(&udp_l2tp_data_cls_entry);
- if (ret) {
- mtk_tops_tnl_type_unregister(&udp_l2tp_data_type);
- return ret;
- }
-
- return ret;
+ return mtk_tops_tnl_type_register(&udp_l2tp_data_type);
}
void mtk_tops_udp_l2tp_data_deinit(void)
{
- mtk_pce_cls_entry_unregister(&udp_l2tp_data_cls_entry);
-
mtk_tops_tnl_type_unregister(&udp_l2tp_data_type);
}
diff --git a/package-21.02/kernel/tops/src/tnl_offload.c b/package-21.02/kernel/tops/src/tnl_offload.c
index aa19f75..c3b2cdf 100644
--- a/package-21.02/kernel/tops/src/tnl_offload.c
+++ b/package-21.02/kernel/tops/src/tnl_offload.c
@@ -326,6 +326,258 @@
wake_up_interruptible(&tops_tnl.tnl_sync_wait);
}
+static void mtk_tops_tnl_info_cls_update_idx(struct tops_tnl_info *tnl_info)
+{
+ unsigned long flag;
+
+ tnl_info->tnl_params.cls_entry = tnl_info->tcls->cls->idx;
+ TOPS_NOTICE("cls entry: %u\n", tnl_info->tcls->cls->idx);
+
+ spin_lock_irqsave(&tnl_info->lock, flag);
+ tnl_info->cache.cls_entry = tnl_info->tcls->cls->idx;
+ spin_unlock_irqrestore(&tnl_info->lock, flag);
+}
+
+static void mtk_tops_tnl_info_cls_entry_unprepare(struct tops_tnl_info *tnl_info)
+{
+ struct tops_cls_entry *tcls = tnl_info->tcls;
+
+ pr_notice("cls entry unprepare\n");
+ tnl_info->tcls = NULL;
+
+ if (refcount_dec_and_test(&tcls->refcnt)) {
+ pr_notice("cls entry delete\n");
+ list_del(&tcls->node);
+
+ memset(&tcls->cls->cdesc, 0, sizeof(tcls->cls->cdesc));
+
+ mtk_pce_cls_entry_write(tcls->cls);
+
+ mtk_pce_cls_entry_free(tcls->cls);
+
+ devm_kfree(tops_dev, tcls);
+ }
+}
+
+static struct tops_cls_entry *
+mtk_tops_tnl_info_cls_entry_prepare(struct tops_tnl_info *tnl_info)
+{
+ struct tops_cls_entry *tcls;
+ int ret;
+
+ tcls = devm_kzalloc(tops_dev, sizeof(struct tops_cls_entry), GFP_KERNEL);
+ if (!tcls)
+ return ERR_PTR(-ENOMEM);
+
+ tcls->cls = mtk_pce_cls_entry_alloc();
+ if (IS_ERR(tcls->cls)) {
+ ret = PTR_ERR(tcls->cls);
+ goto free_tcls;
+ }
+
+ INIT_LIST_HEAD(&tcls->node);
+ list_add_tail(&tnl_info->tnl_type->tcls_head, &tcls->node);
+
+ tnl_info->tcls = tcls;
+ refcount_set(&tcls->refcnt, 1);
+
+ return tcls;
+
+free_tcls:
+ devm_kfree(tops_dev, tcls);
+
+ return ERR_PTR(ret);
+}
+
+static int mtk_tops_tnl_info_cls_entry_write(struct tops_tnl_info *tnl_info)
+{
+ int ret;
+
+ if (!tnl_info->tcls)
+ return -EINVAL;
+
+ ret = mtk_pce_cls_entry_write(tnl_info->tcls->cls);
+ if (ret) {
+ mtk_tops_tnl_info_cls_entry_unprepare(tnl_info);
+ return ret;
+ }
+
+ tnl_info->tcls->updated = true;
+
+ mtk_tops_tnl_info_cls_update_idx(tnl_info);
+
+ return 0;
+}
+
+static int mtk_tops_tnl_info_cls_tear_down(struct tops_tnl_info *tnl_info)
+{
+ mtk_tops_tnl_info_cls_entry_unprepare(tnl_info);
+
+ return 0;
+}
+
+/*
+ * check cls entry is updated for tunnel protocols that only use 1 CLS HW entry
+ *
+ * since only tunnel sync task will operate on tcls linked list,
+ * it is safe to access without lock
+ *
+ * return true on updated
+ * return false on need update
+ */
+static bool mtk_tops_tnl_info_cls_single_is_updated(struct tops_tnl_info *tnl_info,
+ struct tops_tnl_type *tnl_type)
+{
+ /*
+ * check tnl_type has already allocate a tops_cls_entry
+ * if not, return false to prepare to allocate a new one
+ */
+ if (list_empty(&tnl_type->tcls_head))
+ return false;
+
+ /*
+ * if tnl_info is not associate to tnl_type's cls entry,
+ * make a reference to tops_cls_entry
+ */
+ if (!tnl_info->tcls) {
+ tnl_info->tcls = list_first_entry(&tnl_type->tcls_head,
+ struct tops_cls_entry,
+ node);
+
+ refcount_inc(&tnl_info->tcls->refcnt);
+ mtk_tops_tnl_info_cls_update_idx(tnl_info);
+ }
+
+ return tnl_info->tcls->updated;
+}
+
+static int mtk_tops_tnl_info_cls_single_setup(struct tops_tnl_info *tnl_info,
+ struct tops_tnl_type *tnl_type)
+{
+ struct tops_cls_entry *tcls;
+ int ret;
+
+ if (mtk_tops_tnl_info_cls_single_is_updated(tnl_info, tnl_type))
+ return 0;
+
+ if (tnl_info->tcls)
+ return mtk_tops_tnl_info_cls_entry_write(tnl_info);
+
+ tcls = mtk_tops_tnl_info_cls_entry_prepare(tnl_info);
+ if (IS_ERR(tcls))
+ return PTR_ERR(tcls);
+
+ ret = tnl_type->cls_entry_setup(tnl_info, &tcls->cls->cdesc);
+ if (ret) {
+ TOPS_ERR("tops cls entry setup failed: %d\n", ret);
+ mtk_tops_tnl_info_cls_entry_unprepare(tnl_info);
+ return ret;
+ }
+
+ return mtk_tops_tnl_info_cls_entry_write(tnl_info);
+}
+
+static struct tops_cls_entry *
+mtk_tops_tnl_info_cls_entry_find(struct tops_tnl_type *tnl_type,
+ struct cls_desc *cdesc)
+{
+ struct tops_cls_entry *tcls;
+
+ list_for_each_entry(tcls, &tnl_type->tcls_head, node)
+ if (!memcmp(&tcls->cls->cdesc, cdesc, sizeof(struct cls_desc)))
+ return tcls;
+
+ return NULL;
+}
+
+static bool mtk_tops_tnl_infO_cls_multi_is_updated(struct tops_tnl_info *tnl_info,
+ struct tops_tnl_type *tnl_type,
+ struct cls_desc *cdesc)
+{
+ struct tops_cls_entry *tcls;
+
+ if (list_empty(&tnl_type->tcls_head))
+ return false;
+
+ if (tnl_info->tcls) {
+ if (!memcmp(cdesc, &tnl_info->tcls->cls->cdesc, sizeof(*cdesc)))
+ return tnl_info->tcls->updated;
+
+ memcpy(&tnl_info->tcls->cls->cdesc, cdesc, sizeof(*cdesc));
+ tnl_info->tcls->updated = false;
+ return false;
+ }
+
+ tcls = mtk_tops_tnl_info_cls_entry_find(tnl_type, cdesc);
+ if (!tcls)
+ return false;
+
+ tnl_info->tcls = tcls;
+ refcount_inc(&tnl_info->tcls->refcnt);
+ mtk_tops_tnl_info_cls_update_idx(tnl_info);
+
+ return tcls->updated;
+}
+
+static int mtk_tops_tnl_info_cls_multi_setup(struct tops_tnl_info *tnl_info,
+ struct tops_tnl_type *tnl_type)
+{
+ struct tops_cls_entry *tcls;
+ struct cls_desc cdesc;
+ int ret;
+
+ memset(&cdesc, 0, sizeof(struct cls_desc));
+
+ /* prepare cls_desc from tnl_type */
+ ret = tnl_type->cls_entry_setup(tnl_info, &cdesc);
+ if (ret) {
+ TOPS_ERR("tops cls entry setup failed: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * check cdesc is already updated, if tnl_info is not associate with a
+ * tcls but we found a tcls has the same cls desc content as cdesc
+ * tnl_info will setup an association with that tcls
+ *
+ * we only go further to this if condition when
+ * a tcls is not yet updated or
+ * tnl_info is not yet associated to a tcls
+ */
+ if (mtk_tops_tnl_infO_cls_multi_is_updated(tnl_info, tnl_type, &cdesc))
+ return 0;
+
+ /* tcls is not yet updated, update this tcls */
+ if (tnl_info->tcls)
+ return mtk_tops_tnl_info_cls_entry_write(tnl_info);
+
+ /* create a new tcls entry and associate with tnl_info */
+ tcls = mtk_tops_tnl_info_cls_entry_prepare(tnl_info);
+ if (IS_ERR(tcls))
+ return PTR_ERR(tcls);
+
+ memcpy(&tcls->cls->cdesc, &cdesc, sizeof(struct cls_desc));
+
+ return mtk_tops_tnl_info_cls_entry_write(tnl_info);
+}
+
+static int mtk_tops_tnl_info_cls_setup(struct tops_tnl_info *tnl_info)
+{
+ struct tops_tnl_type *tnl_type;
+
+ if (tnl_info->tcls && tnl_info->tcls->updated)
+ return 0;
+
+ tnl_type = tnl_info->tnl_type;
+ if (!tnl_type)
+ return -EINVAL;
+
+ if (!tnl_type->use_multi_cls)
+ return mtk_tops_tnl_info_cls_single_setup(tnl_info, tnl_type);
+
+ return mtk_tops_tnl_info_cls_multi_setup(tnl_info, tnl_type);
+}
+
static int mtk_tops_tnl_info_dipfilter_tear_down(struct tops_tnl_info *tnl_info)
{
struct dip_desc dipd;
@@ -461,6 +713,7 @@
lockdep_assert_held(&tnl_info->lock);
tnl_params->flag |= tnl_info->cache.flag;
+ tnl_params->cls_entry = tnl_info->cache.cls_entry;
if (memcmp(&tnl_info->cache, tnl_params, sizeof(struct tops_tnl_params))) {
memcpy(&tnl_info->cache, tnl_params, sizeof(struct tops_tnl_params));
@@ -490,7 +743,8 @@
}
/* tops_tnl.tbl_lock should be acquired before calling this functions */
-static struct tops_tnl_info *mtk_tops_tnl_info_alloc_no_lock(void)
+static struct tops_tnl_info *
+mtk_tops_tnl_info_alloc_no_lock(struct tops_tnl_type *tnl_type)
{
struct tops_tnl_info *tnl_info;
unsigned long flag = 0;
@@ -521,6 +775,8 @@
}
tnl_info_sta_init_no_tnl_lock(tnl_info);
+ tnl_info->tnl_type = tnl_type;
+
INIT_HLIST_NODE(&tnl_info->hlist);
spin_unlock_irqrestore(&tnl_info->lock, flag);
@@ -530,14 +786,14 @@
return tnl_info;
}
-struct tops_tnl_info *mtk_tops_tnl_info_alloc(void)
+struct tops_tnl_info *mtk_tops_tnl_info_alloc(struct tops_tnl_type *tnl_type)
{
struct tops_tnl_info *tnl_info;
unsigned long flag = 0;
spin_lock_irqsave(&tops_tnl.tbl_lock, flag);
- tnl_info = mtk_tops_tnl_info_alloc_no_lock();
+ tnl_info = mtk_tops_tnl_info_alloc_no_lock(tnl_type);
spin_unlock_irqrestore(&tops_tnl.tbl_lock, flag);
@@ -581,6 +837,7 @@
}
static int mtk_tops_tnl_offload(struct sk_buff *skb,
+ struct tops_tnl_type *tnl_type,
struct tops_tnl_params *tnl_params)
{
struct tops_tnl_info *tnl_info;
@@ -600,7 +857,7 @@
goto err_out;
} else if (IS_ERR(tnl_info) && PTR_ERR(tnl_info) == -ENODEV) {
/* not allocate yet */
- tnl_info = mtk_tops_tnl_info_alloc_no_lock();
+ tnl_info = mtk_tops_tnl_info_alloc_no_lock(tnl_type);
}
if (IS_ERR(tnl_info)) {
@@ -611,7 +868,6 @@
spin_lock(&tnl_info->lock);
ret = mtk_tops_tnl_info_setup(skb, tnl_info, tnl_params);
-
spin_unlock(&tnl_info->lock);
err_out:
@@ -707,7 +963,7 @@
tnl_params.tops_entry_proto = tnl_type->tops_entry;
- ret = mtk_tops_tnl_offload(skb, &tnl_params);
+ ret = mtk_tops_tnl_offload(skb, tnl_type, &tnl_params);
/*
* whether success or fail to offload a decapsulation tunnel
@@ -748,7 +1004,7 @@
return ret;
tnl_params.tops_entry_proto = tnl_type->tops_entry;
- return mtk_tops_tnl_offload(skb, &tnl_params);
+ return mtk_tops_tnl_offload(skb, tnl_type, &tnl_params);
}
static struct net_device *mtk_tops_get_tnl_dev(int tnl_idx)
@@ -895,6 +1151,13 @@
return ret;
}
+ ret = mtk_tops_tnl_info_cls_tear_down(tnl_info);
+ if (ret) {
+ TOPS_ERR("tnl sync cls tear down faild: %d\n",
+ ret);
+ return ret;
+ }
+
mtk_tops_tnl_info_free(tnl_info);
return ret;
@@ -936,10 +1199,18 @@
{
int ret;
+ if (setup_pce) {
+ ret = mtk_tops_tnl_info_cls_setup(tnl_info);
+ if (ret) {
+ TOPS_ERR("tnl cls setup failed: %d\n", ret);
+ return ret;
+ }
+ }
+
ret = __mtk_tops_tnl_sync_param_update(tnl_info, is_new_tnl);
if (ret) {
TOPS_ERR("tnl sync failed: %d\n", ret);
- return ret;
+ goto cls_tear_down;
}
tnl_info_sta_updated(tnl_info);
@@ -954,6 +1225,11 @@
}
return ret;
+
+cls_tear_down:
+ mtk_tops_tnl_info_cls_tear_down(tnl_info);
+
+ return ret;
}
static inline int mtk_tops_tnl_sync_param_new(struct tops_tnl_info *tnl_info,
@@ -1255,6 +1531,8 @@
mtk_tops_tnl_info_flush_ppe(tnl_info);
mtk_tops_tnl_info_dipfilter_tear_down(tnl_info);
+
+ mtk_tops_tnl_info_cls_tear_down(tnl_info);
}
spin_unlock_irqrestore(&tops_tnl.tbl_lock, flag);
@@ -1325,6 +1603,7 @@
return -EBUSY;
}
+ INIT_LIST_HEAD(&tnl_type->tcls_head);
tops_tnl.offload_tnl_types[tops_entry] = tnl_type;
tops_tnl.offload_tnl_type_num++;