[rdkb][common][bsp][Refactor and sync kernel from openwrt]
[Description]
76cd4287 [mt7986][trng][change trng version]
37641870 [openwrt][mt7987][bsp][Add support for the mt7987 platform]
73fe5221 [kernel][mt7987][hnat][Refactor fqos flag assignment when HQoS is enabled for the NETSYSv3.1]
b4d8a1ed [kernel][common][eth][Add nf hw offload]
9872cf38 [kernel][mt7987][eth][Switch to real clock driver for the ETH]
e49e90e7 [set trng clock is ao]
[Release-log]
Change-Id: I47177c3ac8287a95f5bff802123e5bdb068fb009
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-mt7986.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-mt7986.c
index 2238414..a47a9ea 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-mt7986.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-mt7986.c
@@ -488,6 +488,16 @@
.ops = &mtk_clk_gate_ops_setclr, \
}
+#define GATE_INFRA0_FLAGS(_id, _name, _parent, _shift, _flags) { \
+ .id = _id, \
+ .name = _name, \
+ .parent_name = _parent, \
+ .regs = &infra0_cg_regs, \
+ .shift = _shift, \
+ .flags = _flags, \
+ .ops = &mtk_clk_gate_ops_setclr, \
+ }
+
static const struct mtk_gate infra_clks[] __initconst = {
/* INFRA0 */
GATE_INFRA0(CK_INFRA_PWM_HCK, "infra_pwm_hck", "infra_66m_mck", 1),
@@ -506,7 +516,7 @@
GATE_INFRA0(CK_INFRA_AP_DMA_CK, "infra_ap_dma", "infra_66m_mck", 16),
GATE_INFRA0(CK_INFRA_SEJ_CK, "infra_sej", "infra_66m_mck", 24),
GATE_INFRA0(CK_INFRA_SEJ_13M_CK, "infra_sej_13m", "infra_ck_f26m", 25),
- GATE_INFRA0(CK_INFRA_TRNG_CK, "infra_trng", "infra_hd_133m", 26),
+ GATE_INFRA0_FLAGS(CK_INFRA_TRNG_CK, "infra_trng", "infra_hd_133m", 26, CLK_IS_CRITICAL),
/* INFRA1 */
GATE_INFRA1(CK_INFRA_THERM_CK, "infra_therm", "infra_ck_f26m", 0),
GATE_INFRA1(CK_INFRA_I2CO_CK, "infra_i2co", "infra_i2cs", 1),
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
index 20141da..ab68eac 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
@@ -1145,6 +1145,10 @@
atomic64_add(bytes, &counter[dir].bytes);
atomic64_add(packets, &counter[dir].packets);
}
+
+ /* avoid compiler warnings */
+ if (tuple.dst.protonum == IPPROTO_TCP)
+ nf_conntrack_tcp_established(ct);
}
}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
index 0a5be88..8804b72 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
@@ -1018,7 +1018,7 @@
!mtk_tnl_decap_offload) {
skb->dev->netdev_ops->ndo_flow_offload_check(&hw_path);
- if (hw_path.flags & FLOW_OFFLOAD_PATH_TNL)
+ if (hw_path.flags & BIT(DEV_PATH_TNL))
skb_hnat_alg(skb) = 1;
}
@@ -1168,7 +1168,7 @@
struct neighbour *neigh = NULL;
struct dst_entry *dst = skb_dst(skb);
- if (hw_path->flags & FLOW_OFFLOAD_PATH_PPPOE)
+ if (hw_path->flags & BIT(DEV_PATH_PPPOE))
return 0;
rcu_read_lock_bh();
@@ -1206,7 +1206,7 @@
struct rtable *rt = (struct rtable *)dst;
struct net_device *dev = (__force struct net_device *)out;
- if (hw_path->flags & FLOW_OFFLOAD_PATH_PPPOE)
+ if (hw_path->flags & BIT(DEV_PATH_PPPOE))
return 0;
if (!skb_hnat_cdrt(skb) && dst && dst_xfrm(dst))
@@ -1294,8 +1294,8 @@
struct foe_entry ppe_fill_info_blk(struct foe_entry entry,
struct flow_offload_hw_path *hw_path)
{
- entry.bfib1.psn = (hw_path->flags & FLOW_OFFLOAD_PATH_PPPOE) ? 1 : 0;
- entry.bfib1.vlan_layer += (hw_path->flags & FLOW_OFFLOAD_PATH_VLAN) ? 1 : 0;
+ entry.bfib1.psn = (hw_path->flags & BIT(DEV_PATH_PPPOE)) ? 1 : 0;
+ entry.bfib1.vlan_layer += (hw_path->flags & BIT(DEV_PATH_VLAN)) ? 1 : 0;
entry.bfib1.vpm = (entry.bfib1.vlan_layer) ? 1 : 0;
entry.bfib1.cah = 1;
entry.bfib1.time_stamp = (hnat_priv->data->version == MTK_HNAT_V2 ||
@@ -1390,7 +1390,7 @@
{
struct dst_entry *dst = skb_dst(skb);
- if ((skb_hnat_tops(skb) && !(hw_path->flags & FLOW_OFFLOAD_PATH_TNL))) {
+ if ((skb_hnat_tops(skb) && !(hw_path->flags & BIT(DEV_PATH_TNL)))) {
if (!tnl_toggle)
return -1;
@@ -2042,17 +2042,11 @@
MTK_HNAT_V3) ?
skb->mark & 0x7f : skb->mark & 0xf;
#if defined(CONFIG_MEDIATEK_NETSYS_V3)
- if ((IS_HQOS_UL_MODE && IS_WAN(dev)) ||
- (IS_HQOS_DL_MODE &&
- IS_LAN_GRP(dev)) ||
- (IS_PPPQ_MODE &&
- IS_PPPQ_PATH(dev, skb)))
- entry.ipv4_hnapt.tport_id = NR_QDMA_TPORT;
- else
- entry.ipv4_hnapt.tport_id = 0;
-#else
- entry.ipv4_hnapt.iblk2.fqos = 1;
+ entry.ipv4_hnapt.tport_id =
+ HQOS_FLAG(dev, skb, entry.ipv4_hnapt.iblk2.qid);
#endif
+ entry.ipv4_hnapt.iblk2.fqos =
+ HQOS_FLAG(dev, skb, entry.ipv4_hnapt.iblk2.qid);
}
entry.ipv4_hnapt.bfib1.udp =
@@ -2114,7 +2108,7 @@
/* Fill Layer2 Info.*/
entry = ppe_fill_L2_info(entry, hw_path);
- if ((skb_hnat_tops(skb) && hw_path->flags & FLOW_OFFLOAD_PATH_TNL) ||
+ if ((skb_hnat_tops(skb) && hw_path->flags & BIT(DEV_PATH_TNL)) ||
(!skb_hnat_cdrt(skb) && skb_hnat_is_encrypt(skb) &&
skb_dst(skb) && dst_xfrm(skb_dst(skb))))
goto hnat_entry_skip_bind;
@@ -2259,13 +2253,13 @@
if (FROM_EXT(skb) || skb_hnat_sport(skb) == NR_QDMA_PORT)
entry.ipv4_hnapt.iblk2.fqos = 0;
- else
+ else {
#if defined(CONFIG_MEDIATEK_NETSYS_V3)
entry.ipv4_hnapt.tport_id = HQOS_FLAG(dev, skb, qid) ?
NR_QDMA_TPORT : 0;
-#else
- entry.ipv4_hnapt.iblk2.fqos = HQOS_FLAG(dev, skb, qid) ? 1 : 0;
#endif
+ entry.ipv4_hnapt.iblk2.fqos = HQOS_FLAG(dev, skb, qid) ? 1 : 0;
+ }
} else {
entry.ipv4_hnapt.iblk2.fqos = 0;
}
@@ -2312,7 +2306,7 @@
if (FROM_EXT(skb) || skb_hnat_sport(skb) == NR_QDMA_PORT)
entry.ipv6_5t_route.iblk2.fqos = 0;
- else
+ else {
#if defined(CONFIG_MEDIATEK_NETSYS_V3)
switch (entry.bfib1.pkt_type) {
case IPV4_MAP_E:
@@ -2330,9 +2324,9 @@
HQOS_FLAG(dev, skb, qid) ? NR_QDMA_TPORT : 0;
break;
}
-#else
- entry.ipv6_5t_route.iblk2.fqos = HQOS_FLAG(dev, skb, qid) ? 1 : 0;
#endif
+ entry.ipv6_5t_route.iblk2.fqos = HQOS_FLAG(dev, skb, qid) ? 1 : 0;
+ }
} else {
entry.ipv6_5t_route.iblk2.fqos = 0;
}
@@ -2551,6 +2545,7 @@
entry.ipv4_hnapt.winfo.wcid = skb_hnat_wc_id(skb);
#if defined(CONFIG_MEDIATEK_NETSYS_V3)
entry.ipv4_hnapt.tport_id = IS_HQOS_DL_MODE ? NR_QDMA_TPORT : 0;
+ entry.ipv4_hnapt.iblk2.fqos = IS_HQOS_DL_MODE ? 1 : 0;
entry.ipv4_hnapt.iblk2.rxid = skb_hnat_rx_id(skb);
entry.ipv4_hnapt.iblk2.winfoi = 1;
entry.ipv4_hnapt.winfo_pao.usr_info =
@@ -2609,6 +2604,7 @@
entry.ipv6_hnapt.winfo_pao.hf = skb_hnat_hf(skb);
entry.ipv6_hnapt.winfo_pao.amsdu = skb_hnat_amsdu(skb);
entry.ipv6_hnapt.tport_id = IS_HQOS_DL_MODE ? NR_QDMA_TPORT : 0;
+ entry.ipv6_hnapt.iblk2.fqos = IS_HQOS_DL_MODE ? 1 : 0;
} else if (IS_L2_BRIDGE(&entry)) {
entry.l2_bridge.iblk2.dp = gmac_no;
entry.l2_bridge.iblk2.rxid = skb_hnat_rx_id(skb);
@@ -2625,6 +2621,7 @@
entry.l2_bridge.winfo_pao.is_sp = skb_hnat_is_sp(skb);
entry.l2_bridge.winfo_pao.hf = skb_hnat_hf(skb);
entry.l2_bridge.winfo_pao.amsdu = skb_hnat_amsdu(skb);
+ entry.l2_bridge.iblk2.fqos = IS_HQOS_DL_MODE ? 1 : 0;
#endif
} else {
entry.ipv6_5t_route.iblk2.fqos = 0;
@@ -2641,6 +2638,7 @@
entry.ipv4_mape.winfo.bssid = skb_hnat_bss_id(skb);
entry.ipv4_mape.winfo.wcid = skb_hnat_wc_id(skb);
entry.ipv4_mape.tport_id = IS_HQOS_DL_MODE ? NR_QDMA_TPORT : 0;
+ entry.ipv4_mape.iblk2.fqos = IS_HQOS_DL_MODE ? 1 : 0;
entry.ipv4_mape.iblk2.rxid = skb_hnat_rx_id(skb);
entry.ipv4_mape.iblk2.winfoi = 1;
entry.ipv4_mape.winfo_pao.usr_info =
@@ -2662,6 +2660,7 @@
entry.ipv6_5t_route.winfo.bssid = skb_hnat_bss_id(skb);
entry.ipv6_5t_route.winfo.wcid = skb_hnat_wc_id(skb);
entry.ipv6_5t_route.tport_id = IS_HQOS_DL_MODE ? NR_QDMA_TPORT : 0;
+ entry.ipv6_5t_route.iblk2.fqos = IS_HQOS_DL_MODE ? 1 : 0;
entry.ipv6_5t_route.iblk2.rxid = skb_hnat_rx_id(skb);
entry.ipv6_5t_route.iblk2.winfoi = 1;
entry.ipv6_5t_route.winfo_pao.usr_info =
@@ -3281,7 +3280,7 @@
out->netdev_ops->ndo_flow_offload_check(&hw_path);
out = (IS_GMAC1_MODE) ? hw_path.virt_dev : hw_path.dev;
- if (hw_path.flags & FLOW_OFFLOAD_PATH_TNL && mtk_tnl_encap_offload) {
+ if (hw_path.flags & BIT(DEV_PATH_TNL) && mtk_tnl_encap_offload) {
if (ntohs(skb->protocol) == ETH_P_IP &&
ip_hdr(skb)->protocol == IPPROTO_TCP) {
skb_hnat_set_tops(skb, hw_path.tnl_type + 1);
@@ -3309,7 +3308,7 @@
if (is_virt_dev
&& !(skb_hnat_tops(skb) && skb_hnat_is_encap(skb)
- && (hw_path.flags & FLOW_OFFLOAD_PATH_TNL)))
+ && (hw_path.flags & BIT(DEV_PATH_TNL))))
return 0;
if (debug_level >= 7)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_stag.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_stag.c
index 5f64105..4398bae 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_stag.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_stag.c
@@ -39,7 +39,7 @@
int port_index;
u16 dsa_tag;
- if (hw_path->flags & FLOW_OFFLOAD_PATH_VLAN)
+ if (hw_path->flags & BIT(DEV_PATH_VLAN))
ndev = hw_path->dev;
else
ndev = (struct net_device *)netdev;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-ethernet-add-ppe-for-netsys1.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-ethernet-add-ppe-for-netsys1.patch
new file mode 100644
index 0000000..dd0473d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-ethernet-add-ppe-for-netsys1.patch
@@ -0,0 +1,1929 @@
+From 2ee245f821d960dd389a5c3dd97dc1057aa05554 Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Tue, 4 Jun 2024 09:14:34 +0800
+Subject: [PATCH 01/24] ethernet add ppe for netsys1
+
+---
+ drivers/net/ethernet/mediatek/Makefile | 3 +-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 25 +-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 19 +-
+ drivers/net/ethernet/mediatek/mtk_ppe.c | 514 +++++++
+ drivers/net/ethernet/mediatek/mtk_ppe.h | 288 ++++
+ .../net/ethernet/mediatek/mtk_ppe_debugfs.c | 214 +++
+ .../net/ethernet/mediatek/mtk_ppe_offload.c | 535 ++++++++
+ drivers/net/ethernet/mediatek/mtk_ppe_regs.h | 144 ++
+ 8 files changed, 1739 insertions(+), 3 deletions(-)
+ create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe.c
+ create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe.h
+ create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
+ create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+ create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe_regs.h
+
+diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile
+old mode 100644
+new mode 100755
+index 634640d..5f342f4
+--- a/drivers/net/ethernet/mediatek/Makefile
++++ b/drivers/net/ethernet/mediatek/Makefile
+@@ -4,5 +4,6 @@
+ #
+
+ obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o
+-mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_usxgmii.o mtk_eth_path.o mtk_eth_dbg.o mtk_eth_reset.o mtk_eth_ptp.o
++mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_usxgmii.o mtk_eth_path.o mtk_eth_dbg.o mtk_eth_reset.o mtk_eth_ptp.o \
++ mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o
+ obj-$(CONFIG_NET_MEDIATEK_HNAT) += mtk_hnat/
+diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+old mode 100644
+new mode 100755
+index 697a197..edc4ecf
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -4010,6 +4010,7 @@ static int mtk_open(struct net_device *dev)
+ struct mtk_phylink_priv *phylink_priv = &mac->phylink_priv;
+ struct device_node *phy_node;
+ const char *mac_addr;
++ u32 gdm_config = MTK_GDMA_TO_PDMA;
+ u32 id = mtk_mac2xgmii_id(eth, mac->id);
+ int err, i;
+
+@@ -4102,7 +4103,10 @@ static int mtk_open(struct net_device *dev)
+ regmap_write(eth->sgmii->pcs[id].regmap,
+ SGMSYS_QPHY_PWR_STATE_CTRL, 0);
+
+- mtk_gdm_config(eth, mac->id, MTK_GDMA_TO_PDMA);
++ if (eth->soc->offload_version && mtk_ppe_start(ð->ppe) == 0)
++ gdm_config = MTK_GDMA_TO_PPE;
++
++ mtk_gdm_config(eth, mac->id, gdm_config);
+
+ return 0;
+ }
+@@ -4189,6 +4193,9 @@ static int mtk_stop(struct net_device *dev)
+
+ mtk_dma_free(eth);
+
++ if (eth->soc->offload_version)
++ mtk_ppe_stop(ð->ppe);
++
+ return 0;
+ }
+
+@@ -5109,6 +5116,7 @@ static const struct net_device_ops mtk_netdev_ops = {
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = mtk_poll_controller,
+ #endif
++ .ndo_setup_tc = mtk_eth_setup_tc,
+ };
+
+ static void mux_poll(struct work_struct *work)
+@@ -5741,6 +5749,17 @@ static int mtk_probe(struct platform_device *pdev)
+ goto err_free_dev;
+ }
+
++ if (eth->soc->offload_version) {
++ err = mtk_ppe_init(ð->ppe, eth->dev,
++ eth->base + MTK_ETH_PPE_BASE);
++ if (err)
++ goto err_free_dev;
++
++ err = mtk_eth_offload_init(eth);
++ if (err)
++ goto err_free_dev;
++ }
++
+ for (i = 0; i < MTK_MAX_DEVS; i++) {
+ if (!eth->netdev[i])
+ continue;
+@@ -5842,6 +5861,7 @@ static const struct mtk_soc_data mt2701_data = {
+ .required_clks = MT7623_CLKS_BITMAP,
+ .required_pctl = true,
+ .has_sram = false,
++ .offload_version = 1,
+ .rss_num = 0,
+ .txrx = {
+ .txd_size = sizeof(struct mtk_tx_dma),
+@@ -5862,6 +5882,7 @@ static const struct mtk_soc_data mt7621_data = {
+ .required_clks = MT7621_CLKS_BITMAP,
+ .required_pctl = false,
+ .has_sram = false,
++ .offload_version = 1,
+ .rss_num = 0,
+ .txrx = {
+ .txd_size = sizeof(struct mtk_tx_dma),
+@@ -5883,6 +5904,7 @@ static const struct mtk_soc_data mt7622_data = {
+ .required_clks = MT7622_CLKS_BITMAP,
+ .required_pctl = false,
+ .has_sram = false,
++ .offload_version = 2,
+ .rss_num = 0,
+ .txrx = {
+ .txd_size = sizeof(struct mtk_tx_dma),
+@@ -5903,6 +5925,7 @@ static const struct mtk_soc_data mt7623_data = {
+ .required_clks = MT7623_CLKS_BITMAP,
+ .required_pctl = true,
+ .has_sram = false,
++ .offload_version = 1,
+ .rss_num = 0,
+ .txrx = {
+ .txd_size = sizeof(struct mtk_tx_dma),
+diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+old mode 100644
+new mode 100755
+index 9fae48f..54b2c7c
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -15,6 +15,8 @@
+ #include <linux/refcount.h>
+ #include <linux/phylink.h>
+ #include <linux/ptp_clock_kernel.h>
++#include <linux/rhashtable.h>
++#include "mtk_ppe.h"
+
+ #define MTK_QDMA_PAGE_SIZE 2048
+ #define MTK_MAX_RX_LENGTH 1536
+@@ -46,7 +48,8 @@
+ NETIF_F_HW_VLAN_CTAG_TX | \
+ NETIF_F_SG | NETIF_F_TSO | \
+ NETIF_F_TSO6 | \
+- NETIF_F_IPV6_CSUM)
++ NETIF_F_IPV6_CSUM |\
++ NETIF_F_HW_TC)
+ #define MTK_SET_FEATURES (NETIF_F_LRO | \
+ NETIF_F_HW_VLAN_CTAG_RX)
+ #define MTK_HW_FEATURES_MT7628 (NETIF_F_SG | NETIF_F_RXCSUM)
+@@ -133,6 +136,7 @@
+ #define MTK_GDMA_UCS_EN BIT(20)
+ #define MTK_GDMA_STRP_CRC BIT(16)
+ #define MTK_GDMA_TO_PDMA 0x0
++#define MTK_GDMA_TO_PPE 0x4444
+ #define MTK_GDMA_DROP_ALL 0x7777
+
+ /* GDM Egress Control Register */
+@@ -686,6 +690,12 @@
+ #define RX_DMA_TCI(_x) ((_x) & (VLAN_PRIO_MASK | VLAN_VID_MASK))
+ #define RX_DMA_VPID(_x) (((_x) >> 16) & 0xffff)
+
++/* QDMA descriptor rxd4 */
++#define MTK_RXD4_FOE_ENTRY GENMASK(13, 0)
++#define MTK_RXD4_PPE_CPU_REASON GENMASK(18, 14)
++#define MTK_RXD4_SRC_PORT GENMASK(21, 19)
++#define MTK_RXD4_ALG GENMASK(31, 22)
++
+ /* QDMA descriptor rxd4 */
+ #define RX_DMA_L4_VALID BIT(24)
+ #define RX_DMA_L4_VALID_PDMA BIT(30) /* when PDMA is used */
+@@ -1737,6 +1747,7 @@ struct mtk_soc_data {
+ u64 caps;
+ u64 required_clks;
+ bool required_pctl;
++ u8 offload_version;
+ netdev_features_t hw_features;
+ bool has_sram;
+ struct {
+@@ -1947,6 +1958,9 @@ struct mtk_eth {
+ int ip_align;
+ spinlock_t syscfg0_lock;
+ struct notifier_block netdevice_notifier;
++
++ struct mtk_ppe ppe;
++ struct rhashtable flow_table;
+ };
+
+ /* struct mtk_mac - the structure that holds the info about the MACs of the
+@@ -2026,6 +2040,9 @@ struct phylink_pcs *mtk_usxgmii_select_pcs(struct mtk_usxgmii *ss, int id);
+ int mtk_usxgmii_init(struct mtk_eth *eth, struct device_node *r);
+ int mtk_toprgu_init(struct mtk_eth *eth, struct device_node *r);
+
++int mtk_eth_offload_init(struct mtk_eth *eth);
++int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
++ void *type_data);
+ void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
+ u32 mtk_rss_indr_table(struct mtk_rss_params *rss_params, int index);
+ #endif /* MTK_ETH_H */
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
+new file mode 100644
+index 0000000..6965d98
+--- /dev/null
++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
+@@ -0,0 +1,513 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
++
++#include <linux/kernel.h>
++#include <linux/io.h>
++#include <linux/iopoll.h>
++#include <linux/etherdevice.h>
++#include <linux/platform_device.h>
++#include "mtk_ppe.h"
++#include "mtk_ppe_regs.h"
++
++static void ppe_w32(struct mtk_ppe *ppe, u32 reg, u32 val)
++{
++ writel(val, ppe->base + reg);
++}
++
++static u32 ppe_r32(struct mtk_ppe *ppe, u32 reg)
++{
++ return readl(ppe->base + reg);
++}
++
++static u32 ppe_m32(struct mtk_ppe *ppe, u32 reg, u32 mask, u32 set)
++{
++ u32 val;
++
++ val = ppe_r32(ppe, reg);
++ val &= ~mask;
++ val |= set;
++ ppe_w32(ppe, reg, val);
++
++ return val;
++}
++
++static u32 ppe_set(struct mtk_ppe *ppe, u32 reg, u32 val)
++{
++ return ppe_m32(ppe, reg, 0, val);
++}
++
++static u32 ppe_clear(struct mtk_ppe *ppe, u32 reg, u32 val)
++{
++ return ppe_m32(ppe, reg, val, 0);
++}
++
++static int mtk_ppe_wait_busy(struct mtk_ppe *ppe)
++{
++ int ret;
++ u32 val;
++
++ ret = readl_poll_timeout(ppe->base + MTK_PPE_GLO_CFG, val,
++ !(val & MTK_PPE_GLO_CFG_BUSY),
++ 20, MTK_PPE_WAIT_TIMEOUT_US);
++
++ if (ret)
++ dev_err(ppe->dev, "PPE table busy");
++
++ return ret;
++}
++
++static void mtk_ppe_cache_clear(struct mtk_ppe *ppe)
++{
++ ppe_set(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_CLEAR);
++ ppe_clear(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_CLEAR);
++}
++
++static void mtk_ppe_cache_enable(struct mtk_ppe *ppe, bool enable)
++{
++ mtk_ppe_cache_clear(ppe);
++
++ ppe_m32(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_EN,
++ enable * MTK_PPE_CACHE_CTL_EN);
++}
++
++static u32 mtk_ppe_hash_entry(struct mtk_foe_entry *e)
++{
++ u32 hv1, hv2, hv3;
++ u32 hash;
++
++ switch (FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, e->ib1)) {
++ case MTK_PPE_PKT_TYPE_BRIDGE:
++ hv1 = e->bridge.src_mac_lo;
++ hv1 ^= ((e->bridge.src_mac_hi & 0xffff) << 16);
++ hv2 = e->bridge.src_mac_hi >> 16;
++ hv2 ^= e->bridge.dest_mac_lo;
++ hv3 = e->bridge.dest_mac_hi;
++ break;
++ case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
++ case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
++ hv1 = e->ipv4.orig.ports;
++ hv2 = e->ipv4.orig.dest_ip;
++ hv3 = e->ipv4.orig.src_ip;
++ break;
++ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T:
++ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T:
++ hv1 = e->ipv6.src_ip[3] ^ e->ipv6.dest_ip[3];
++ hv1 ^= e->ipv6.ports;
++
++ hv2 = e->ipv6.src_ip[2] ^ e->ipv6.dest_ip[2];
++ hv2 ^= e->ipv6.dest_ip[0];
++
++ hv3 = e->ipv6.src_ip[1] ^ e->ipv6.dest_ip[1];
++ hv3 ^= e->ipv6.src_ip[0];
++ break;
++ case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
++ case MTK_PPE_PKT_TYPE_IPV6_6RD:
++ default:
++ WARN_ON_ONCE(1);
++ return MTK_PPE_HASH_MASK;
++ }
++
++ hash = (hv1 & hv2) | ((~hv1) & hv3);
++ hash = (hash >> 24) | ((hash & 0xffffff) << 8);
++ hash ^= hv1 ^ hv2 ^ hv3;
++ hash ^= hash >> 16;
++ hash <<= 1;
++ hash &= MTK_PPE_ENTRIES - 1;
++
++ return hash;
++}
++
++static inline struct mtk_foe_mac_info *
++mtk_foe_entry_l2(struct mtk_foe_entry *entry)
++{
++ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
++
++ if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE)
++ return &entry->ipv6.l2;
++
++ return &entry->ipv4.l2;
++}
++
++static inline u32 *
++mtk_foe_entry_ib2(struct mtk_foe_entry *entry)
++{
++ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
++
++ if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE)
++ return &entry->ipv6.ib2;
++
++ return &entry->ipv4.ib2;
++}
++
++int mtk_foe_entry_prepare(struct mtk_foe_entry *entry, int type, int l4proto,
++ u8 pse_port, u8 *src_mac, u8 *dest_mac)
++{
++ struct mtk_foe_mac_info *l2;
++ u32 ports_pad, val;
++
++ memset(entry, 0, sizeof(*entry));
++
++ val = FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND) |
++ FIELD_PREP(MTK_FOE_IB1_PACKET_TYPE, type) |
++ FIELD_PREP(MTK_FOE_IB1_UDP, l4proto == IPPROTO_UDP) |
++ MTK_FOE_IB1_BIND_TTL |
++ MTK_FOE_IB1_BIND_CACHE;
++ entry->ib1 = val;
++
++ val = FIELD_PREP(MTK_FOE_IB2_PORT_MG, 0x3f) |
++ FIELD_PREP(MTK_FOE_IB2_PORT_AG, 0x1f) |
++ FIELD_PREP(MTK_FOE_IB2_DEST_PORT, pse_port);
++
++ if (is_multicast_ether_addr(dest_mac))
++ val |= MTK_FOE_IB2_MULTICAST;
++
++ ports_pad = 0xa5a5a500 | (l4proto & 0xff);
++ if (type == MTK_PPE_PKT_TYPE_IPV4_ROUTE)
++ entry->ipv4.orig.ports = ports_pad;
++ if (type == MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T)
++ entry->ipv6.ports = ports_pad;
++
++ if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) {
++ entry->ipv6.ib2 = val;
++ l2 = &entry->ipv6.l2;
++ } else {
++ entry->ipv4.ib2 = val;
++ l2 = &entry->ipv4.l2;
++ }
++
++ l2->dest_mac_hi = get_unaligned_be32(dest_mac);
++ l2->dest_mac_lo = get_unaligned_be16(dest_mac + 4);
++ l2->src_mac_hi = get_unaligned_be32(src_mac);
++ l2->src_mac_lo = get_unaligned_be16(src_mac + 4);
++
++ if (type >= MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T)
++ l2->etype = ETH_P_IPV6;
++ else
++ l2->etype = ETH_P_IP;
++
++ return 0;
++}
++
++int mtk_foe_entry_set_pse_port(struct mtk_foe_entry *entry, u8 port)
++{
++ u32 *ib2 = mtk_foe_entry_ib2(entry);
++ u32 val;
++
++ val = *ib2;
++ val &= ~MTK_FOE_IB2_DEST_PORT;
++ val |= FIELD_PREP(MTK_FOE_IB2_DEST_PORT, port);
++ *ib2 = val;
++
++ return 0;
++}
++
++int mtk_foe_entry_set_ipv4_tuple(struct mtk_foe_entry *entry, bool egress,
++ __be32 src_addr, __be16 src_port,
++ __be32 dest_addr, __be16 dest_port)
++{
++ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
++ struct mtk_ipv4_tuple *t;
++
++ switch (type) {
++ case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
++ if (egress) {
++ t = &entry->ipv4.new;
++ break;
++ }
++ fallthrough;
++ case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
++ case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
++ t = &entry->ipv4.orig;
++ break;
++ case MTK_PPE_PKT_TYPE_IPV6_6RD:
++ entry->ipv6_6rd.tunnel_src_ip = be32_to_cpu(src_addr);
++ entry->ipv6_6rd.tunnel_dest_ip = be32_to_cpu(dest_addr);
++ return 0;
++ default:
++ WARN_ON_ONCE(1);
++ return -EINVAL;
++ }
++
++ t->src_ip = be32_to_cpu(src_addr);
++ t->dest_ip = be32_to_cpu(dest_addr);
++
++ if (type == MTK_PPE_PKT_TYPE_IPV4_ROUTE)
++ return 0;
++
++ t->src_port = be16_to_cpu(src_port);
++ t->dest_port = be16_to_cpu(dest_port);
++
++ return 0;
++}
++
++int mtk_foe_entry_set_ipv6_tuple(struct mtk_foe_entry *entry,
++ __be32 *src_addr, __be16 src_port,
++ __be32 *dest_addr, __be16 dest_port)
++{
++ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
++ u32 *src, *dest;
++ int i;
++
++ switch (type) {
++ case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
++ src = entry->dslite.tunnel_src_ip;
++ dest = entry->dslite.tunnel_dest_ip;
++ break;
++ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T:
++ case MTK_PPE_PKT_TYPE_IPV6_6RD:
++ entry->ipv6.src_port = be16_to_cpu(src_port);
++ entry->ipv6.dest_port = be16_to_cpu(dest_port);
++ fallthrough;
++ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T:
++ src = entry->ipv6.src_ip;
++ dest = entry->ipv6.dest_ip;
++ break;
++ default:
++ WARN_ON_ONCE(1);
++ return -EINVAL;
++ }
++
++ for (i = 0; i < 4; i++)
++ src[i] = be32_to_cpu(src_addr[i]);
++ for (i = 0; i < 4; i++)
++ dest[i] = be32_to_cpu(dest_addr[i]);
++
++ return 0;
++}
++
++int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port)
++{
++ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
++
++ l2->etype = BIT(port);
++
++ if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_LAYER))
++ entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1);
++ else
++ l2->etype |= BIT(8);
++
++ entry->ib1 &= ~MTK_FOE_IB1_BIND_VLAN_TAG;
++
++ return 0;
++}
++
++int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid)
++{
++ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
++
++ switch (FIELD_GET(MTK_FOE_IB1_BIND_VLAN_LAYER, entry->ib1)) {
++ case 0:
++ entry->ib1 |= MTK_FOE_IB1_BIND_VLAN_TAG |
++ FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1);
++ l2->vlan1 = vid;
++ return 0;
++ case 1:
++ if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_TAG)) {
++ l2->vlan1 = vid;
++ l2->etype |= BIT(8);
++ } else {
++ l2->vlan2 = vid;
++ entry->ib1 += FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1);
++ }
++ return 0;
++ default:
++ return -ENOSPC;
++ }
++}
++
++int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid)
++{
++ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
++
++ if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_LAYER) ||
++ (entry->ib1 & MTK_FOE_IB1_BIND_VLAN_TAG))
++ l2->etype = ETH_P_PPP_SES;
++
++ entry->ib1 |= MTK_FOE_IB1_BIND_PPPOE;
++ l2->pppoe_id = sid;
++
++ return 0;
++}
++
++static inline bool mtk_foe_entry_usable(struct mtk_foe_entry *entry)
++{
++ return !(entry->ib1 & MTK_FOE_IB1_STATIC) &&
++ FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1) != MTK_FOE_STATE_BIND;
++}
++
++int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
++ u16 timestamp)
++{
++ struct mtk_foe_entry *hwe;
++ u32 hash;
++
++ timestamp &= MTK_FOE_IB1_BIND_TIMESTAMP;
++ entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP;
++ entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP, timestamp);
++
++ hash = mtk_ppe_hash_entry(entry);
++ hwe = &ppe->foe_table[hash];
++ if (!mtk_foe_entry_usable(hwe)) {
++ hwe++;
++ hash++;
++
++ if (!mtk_foe_entry_usable(hwe))
++ return -ENOSPC;
++ }
++
++ memcpy(&hwe->data, &entry->data, sizeof(hwe->data));
++ wmb();
++ hwe->ib1 = entry->ib1;
++
++ dma_wmb();
++
++ mtk_ppe_cache_clear(ppe);
++
++ return hash;
++}
++
++int mtk_ppe_init(struct mtk_ppe *ppe, struct device *dev, void __iomem *base)
++{
++ struct mtk_foe_entry *foe;
++
++ /* need to allocate a separate device, since it PPE DMA access is
++ * not coherent.
++ */
++ ppe->base = base;
++ ppe->dev = dev;
++ ppe->version = eth->soc->offload_version;
++
++ foe = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*foe),
++ &ppe->foe_phys, GFP_KERNEL);
++ if (!foe)
++ return -ENOMEM;
++
++ ppe->foe_table = foe;
++
++ mtk_ppe_debugfs_init(ppe);
++
++ return 0;
++}
++
++static void mtk_ppe_init_foe_table(struct mtk_ppe *ppe)
++{
++ static const u8 skip[] = { 12, 25, 38, 51, 76, 89, 102 };
++ int i, k;
++
++ memset(ppe->foe_table, 0, MTK_PPE_ENTRIES * sizeof(*ppe->foe_table));
++
++ if (!IS_ENABLED(CONFIG_SOC_MT7621))
++ return;
++
++ /* skip all entries that cross the 1024 byte boundary */
++ for (i = 0; i < MTK_PPE_ENTRIES; i += 128)
++ for (k = 0; k < ARRAY_SIZE(skip); k++)
++ ppe->foe_table[i + skip[k]].ib1 |= MTK_FOE_IB1_STATIC;
++}
++
++int mtk_ppe_start(struct mtk_ppe *ppe)
++{
++ u32 val;
++
++ mtk_ppe_init_foe_table(ppe);
++ ppe_w32(ppe, MTK_PPE_TB_BASE, ppe->foe_phys);
++
++ val = MTK_PPE_TB_CFG_ENTRY_80B |
++ MTK_PPE_TB_CFG_AGE_NON_L4 |
++ MTK_PPE_TB_CFG_AGE_UNBIND |
++ MTK_PPE_TB_CFG_AGE_TCP |
++ MTK_PPE_TB_CFG_AGE_UDP |
++ MTK_PPE_TB_CFG_AGE_TCP_FIN |
++ FIELD_PREP(MTK_PPE_TB_CFG_SEARCH_MISS,
++ MTK_PPE_SEARCH_MISS_ACTION_FORWARD_BUILD) |
++ FIELD_PREP(MTK_PPE_TB_CFG_KEEPALIVE,
++ MTK_PPE_KEEPALIVE_DISABLE) |
++ FIELD_PREP(MTK_PPE_TB_CFG_HASH_MODE, 1) |
++ FIELD_PREP(MTK_PPE_TB_CFG_SCAN_MODE,
++ MTK_PPE_SCAN_MODE_CHECK_AGE) |
++ FIELD_PREP(MTK_PPE_TB_CFG_ENTRY_NUM,
++ MTK_PPE_ENTRIES_SHIFT);
++ ppe_w32(ppe, MTK_PPE_TB_CFG, val);
++
++ ppe_w32(ppe, MTK_PPE_IP_PROTO_CHK,
++ MTK_PPE_IP_PROTO_CHK_IPV4 | MTK_PPE_IP_PROTO_CHK_IPV6);
++
++ mtk_ppe_cache_enable(ppe, true);
++
++ val = MTK_PPE_FLOW_CFG_IP4_TCP_FRAG |
++ MTK_PPE_FLOW_CFG_IP4_UDP_FRAG |
++ MTK_PPE_FLOW_CFG_IP6_3T_ROUTE |
++ MTK_PPE_FLOW_CFG_IP6_5T_ROUTE |
++ MTK_PPE_FLOW_CFG_IP6_6RD |
++ MTK_PPE_FLOW_CFG_IP4_NAT |
++ MTK_PPE_FLOW_CFG_IP4_NAPT |
++ MTK_PPE_FLOW_CFG_IP4_DSLITE |
++ MTK_PPE_FLOW_CFG_L2_BRIDGE |
++ MTK_PPE_FLOW_CFG_IP4_NAT_FRAG;
++ ppe_w32(ppe, MTK_PPE_FLOW_CFG, val);
++
++ val = FIELD_PREP(MTK_PPE_UNBIND_AGE_MIN_PACKETS, 1000) |
++ FIELD_PREP(MTK_PPE_UNBIND_AGE_DELTA, 3);
++ ppe_w32(ppe, MTK_PPE_UNBIND_AGE, val);
++
++ val = FIELD_PREP(MTK_PPE_BIND_AGE0_DELTA_UDP, 30) |
++ FIELD_PREP(MTK_PPE_BIND_AGE0_DELTA_NON_L4, 1);
++ ppe_w32(ppe, MTK_PPE_BIND_AGE0, val);
++
++ val = FIELD_PREP(MTK_PPE_BIND_AGE1_DELTA_TCP_FIN, 1) |
++ FIELD_PREP(MTK_PPE_BIND_AGE1_DELTA_TCP, 30);
++ ppe_w32(ppe, MTK_PPE_BIND_AGE1, val);
++
++ val = MTK_PPE_BIND_LIMIT0_QUARTER | MTK_PPE_BIND_LIMIT0_HALF;
++ ppe_w32(ppe, MTK_PPE_BIND_LIMIT0, val);
++
++ val = MTK_PPE_BIND_LIMIT1_FULL |
++ FIELD_PREP(MTK_PPE_BIND_LIMIT1_NON_L4, 1);
++ ppe_w32(ppe, MTK_PPE_BIND_LIMIT1, val);
++
++ val = FIELD_PREP(MTK_PPE_BIND_RATE_BIND, 30) |
++ FIELD_PREP(MTK_PPE_BIND_RATE_PREBIND, 1);
++ ppe_w32(ppe, MTK_PPE_BIND_RATE, val);
++
++ /* enable PPE */
++ val = MTK_PPE_GLO_CFG_EN |
++ MTK_PPE_GLO_CFG_IP4_L4_CS_DROP |
++ MTK_PPE_GLO_CFG_IP4_CS_DROP |
++ MTK_PPE_GLO_CFG_MCAST_TB_EN |
++ MTK_PPE_GLO_CFG_FLOW_DROP_UPDATE;
++ ppe_w32(ppe, MTK_PPE_GLO_CFG, val);
++
++ ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT, 0);
++
++ return 0;
++}
++
++int mtk_ppe_stop(struct mtk_ppe *ppe)
++{
++ u32 val;
++ int i;
++
++ for (i = 0; i < MTK_PPE_ENTRIES; i++)
++ ppe->foe_table[i].ib1 = FIELD_PREP(MTK_FOE_IB1_STATE,
++ MTK_FOE_STATE_INVALID);
++
++ mtk_ppe_cache_enable(ppe, false);
++
++ /* disable aging */
++ val = MTK_PPE_TB_CFG_AGE_NON_L4 |
++ MTK_PPE_TB_CFG_AGE_UNBIND |
++ MTK_PPE_TB_CFG_AGE_TCP |
++ MTK_PPE_TB_CFG_AGE_UDP |
++ MTK_PPE_TB_CFG_AGE_TCP_FIN |
++ MTK_PPE_TB_CFG_SCAN_MODE;
++ ppe_clear(ppe, MTK_PPE_TB_CFG, val);
++
++ if (mtk_ppe_wait_busy(ppe))
++ return -ETIMEDOUT;
++
++ /* disable offload engine */
++ ppe_clear(ppe, MTK_PPE_GLO_CFG, MTK_PPE_GLO_CFG_EN);
++ ppe_w32(ppe, MTK_PPE_FLOW_CFG, 0);
++
++ return 0;
++}
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
+new file mode 100644
+index 0000000..242fb8f
+--- /dev/null
++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
+@@ -0,0 +1,287 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
++
++#ifndef __MTK_PPE_H
++#define __MTK_PPE_H
++
++#include <linux/kernel.h>
++#include <linux/bitfield.h>
++
++#define MTK_ETH_PPE_BASE 0xc00
++
++#define MTK_PPE_ENTRIES_SHIFT 3
++#define MTK_PPE_ENTRIES (1024 << MTK_PPE_ENTRIES_SHIFT)
++#define MTK_PPE_HASH_MASK (MTK_PPE_ENTRIES - 1)
++#define MTK_PPE_WAIT_TIMEOUT_US 1000000
++
++#define MTK_FOE_IB1_UNBIND_TIMESTAMP GENMASK(7, 0)
++#define MTK_FOE_IB1_UNBIND_PACKETS GENMASK(23, 8)
++#define MTK_FOE_IB1_UNBIND_PREBIND BIT(24)
++
++#define MTK_FOE_IB1_BIND_TIMESTAMP GENMASK(14, 0)
++#define MTK_FOE_IB1_BIND_KEEPALIVE BIT(15)
++#define MTK_FOE_IB1_BIND_VLAN_LAYER GENMASK(18, 16)
++#define MTK_FOE_IB1_BIND_PPPOE BIT(19)
++#define MTK_FOE_IB1_BIND_VLAN_TAG BIT(20)
++#define MTK_FOE_IB1_BIND_PKT_SAMPLE BIT(21)
++#define MTK_FOE_IB1_BIND_CACHE BIT(22)
++#define MTK_FOE_IB1_BIND_TUNNEL_DECAP BIT(23)
++#define MTK_FOE_IB1_BIND_TTL BIT(24)
++
++#define MTK_FOE_IB1_PACKET_TYPE GENMASK(27, 25)
++#define MTK_FOE_IB1_STATE GENMASK(29, 28)
++#define MTK_FOE_IB1_UDP BIT(30)
++#define MTK_FOE_IB1_STATIC BIT(31)
++
++enum {
++ MTK_PPE_PKT_TYPE_IPV4_HNAPT = 0,
++ MTK_PPE_PKT_TYPE_IPV4_ROUTE = 1,
++ MTK_PPE_PKT_TYPE_BRIDGE = 2,
++ MTK_PPE_PKT_TYPE_IPV4_DSLITE = 3,
++ MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T = 4,
++ MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T = 5,
++ MTK_PPE_PKT_TYPE_IPV6_6RD = 7,
++};
++
++#define MTK_FOE_IB2_QID GENMASK(3, 0)
++#define MTK_FOE_IB2_PSE_QOS BIT(4)
++#define MTK_FOE_IB2_DEST_PORT GENMASK(7, 5)
++#define MTK_FOE_IB2_MULTICAST BIT(8)
++
++#define MTK_FOE_IB2_WHNAT_QID2 GENMASK(13, 12)
++#define MTK_FOE_IB2_WHNAT_DEVIDX BIT(16)
++#define MTK_FOE_IB2_WHNAT_NAT BIT(17)
++
++#define MTK_FOE_IB2_PORT_MG GENMASK(17, 12)
++
++#define MTK_FOE_IB2_PORT_AG GENMASK(23, 18)
++
++#define MTK_FOE_IB2_DSCP GENMASK(31, 24)
++
++#define MTK_FOE_VLAN2_WHNAT_BSS GEMMASK(5, 0)
++#define MTK_FOE_VLAN2_WHNAT_WCID GENMASK(13, 6)
++#define MTK_FOE_VLAN2_WHNAT_RING GENMASK(15, 14)
++
++enum {
++ MTK_FOE_STATE_INVALID,
++ MTK_FOE_STATE_UNBIND,
++ MTK_FOE_STATE_BIND,
++ MTK_FOE_STATE_FIN
++};
++
++struct mtk_foe_mac_info {
++ u16 vlan1;
++ u16 etype;
++
++ u32 dest_mac_hi;
++
++ u16 vlan2;
++ u16 dest_mac_lo;
++
++ u32 src_mac_hi;
++
++ u16 pppoe_id;
++ u16 src_mac_lo;
++};
++
++struct mtk_foe_bridge {
++ u32 dest_mac_hi;
++
++ u16 src_mac_lo;
++ u16 dest_mac_lo;
++
++ u32 src_mac_hi;
++
++ u32 ib2;
++
++ u32 _rsv[5];
++
++ u32 udf_tsid;
++ struct mtk_foe_mac_info l2;
++};
++
++struct mtk_ipv4_tuple {
++ u32 src_ip;
++ u32 dest_ip;
++ union {
++ struct {
++ u16 dest_port;
++ u16 src_port;
++ };
++ struct {
++ u8 protocol;
++ u8 _pad[3]; /* fill with 0xa5a5a5 */
++ };
++ u32 ports;
++ };
++};
++
++struct mtk_foe_ipv4 {
++ struct mtk_ipv4_tuple orig;
++
++ u32 ib2;
++
++ struct mtk_ipv4_tuple new;
++
++ u16 timestamp;
++ u16 _rsv0[3];
++
++ u32 udf_tsid;
++
++ struct mtk_foe_mac_info l2;
++};
++
++struct mtk_foe_ipv4_dslite {
++ struct mtk_ipv4_tuple ip4;
++
++ u32 tunnel_src_ip[4];
++ u32 tunnel_dest_ip[4];
++
++ u8 flow_label[3];
++ u8 priority;
++
++ u32 udf_tsid;
++
++ u32 ib2;
++
++ struct mtk_foe_mac_info l2;
++};
++
++struct mtk_foe_ipv6 {
++ u32 src_ip[4];
++ u32 dest_ip[4];
++
++ union {
++ struct {
++ u8 protocol;
++ u8 _pad[3]; /* fill with 0xa5a5a5 */
++ }; /* 3-tuple */
++ struct {
++ u16 dest_port;
++ u16 src_port;
++ }; /* 5-tuple */
++ u32 ports;
++ };
++
++ u32 _rsv[3];
++
++ u32 udf;
++
++ u32 ib2;
++ struct mtk_foe_mac_info l2;
++};
++
++struct mtk_foe_ipv6_6rd {
++ u32 src_ip[4];
++ u32 dest_ip[4];
++ u16 dest_port;
++ u16 src_port;
++
++ u32 tunnel_src_ip;
++ u32 tunnel_dest_ip;
++
++ u16 hdr_csum;
++ u8 dscp;
++ u8 ttl;
++
++ u8 flag;
++ u8 pad;
++ u8 per_flow_6rd_id;
++ u8 pad2;
++
++ u32 ib2;
++ struct mtk_foe_mac_info l2;
++};
++
++struct mtk_foe_entry {
++ u32 ib1;
++
++ union {
++ struct mtk_foe_bridge bridge;
++ struct mtk_foe_ipv4 ipv4;
++ struct mtk_foe_ipv4_dslite dslite;
++ struct mtk_foe_ipv6 ipv6;
++ struct mtk_foe_ipv6_6rd ipv6_6rd;
++ u32 data[19];
++ };
++};
++
++enum {
++ MTK_PPE_CPU_REASON_TTL_EXCEEDED = 0x02,
++ MTK_PPE_CPU_REASON_OPTION_HEADER = 0x03,
++ MTK_PPE_CPU_REASON_NO_FLOW = 0x07,
++ MTK_PPE_CPU_REASON_IPV4_FRAG = 0x08,
++ MTK_PPE_CPU_REASON_IPV4_DSLITE_FRAG = 0x09,
++ MTK_PPE_CPU_REASON_IPV4_DSLITE_NO_TCP_UDP = 0x0a,
++ MTK_PPE_CPU_REASON_IPV6_6RD_NO_TCP_UDP = 0x0b,
++ MTK_PPE_CPU_REASON_TCP_FIN_SYN_RST = 0x0c,
++ MTK_PPE_CPU_REASON_UN_HIT = 0x0d,
++ MTK_PPE_CPU_REASON_HIT_UNBIND = 0x0e,
++ MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED = 0x0f,
++ MTK_PPE_CPU_REASON_HIT_BIND_TCP_FIN = 0x10,
++ MTK_PPE_CPU_REASON_HIT_TTL_1 = 0x11,
++ MTK_PPE_CPU_REASON_HIT_BIND_VLAN_VIOLATION = 0x12,
++ MTK_PPE_CPU_REASON_KEEPALIVE_UC_OLD_HDR = 0x13,
++ MTK_PPE_CPU_REASON_KEEPALIVE_MC_NEW_HDR = 0x14,
++ MTK_PPE_CPU_REASON_KEEPALIVE_DUP_OLD_HDR = 0x15,
++ MTK_PPE_CPU_REASON_HIT_BIND_FORCE_CPU = 0x16,
++ MTK_PPE_CPU_REASON_TUNNEL_OPTION_HEADER = 0x17,
++ MTK_PPE_CPU_REASON_MULTICAST_TO_CPU = 0x18,
++ MTK_PPE_CPU_REASON_MULTICAST_TO_GMAC1_CPU = 0x19,
++ MTK_PPE_CPU_REASON_HIT_PRE_BIND = 0x1a,
++ MTK_PPE_CPU_REASON_PACKET_SAMPLING = 0x1b,
++ MTK_PPE_CPU_REASON_EXCEED_MTU = 0x1c,
++ MTK_PPE_CPU_REASON_PPE_BYPASS = 0x1e,
++ MTK_PPE_CPU_REASON_INVALID = 0x1f,
++};
++
++struct mtk_ppe {
++ struct device *dev;
++ void __iomem *base;
++ int version;
++
++ struct mtk_foe_entry *foe_table;
++ dma_addr_t foe_phys;
++
++ void *acct_table;
++};
++
++int mtk_ppe_init(struct mtk_ppe *ppe, struct device *dev, void __iomem *base);
++int mtk_ppe_start(struct mtk_ppe *ppe);
++int mtk_ppe_stop(struct mtk_ppe *ppe);
++
++static inline void
++mtk_foe_entry_clear(struct mtk_ppe *ppe, u16 hash)
++{
++ ppe->foe_table[hash].ib1 = 0;
++ dma_wmb();
++}
++
++static inline int
++mtk_foe_entry_timestamp(struct mtk_ppe *ppe, u16 hash)
++{
++ u32 ib1 = READ_ONCE(ppe->foe_table[hash].ib1);
++
++ if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND)
++ return -1;
++
++ return FIELD_GET(MTK_FOE_IB1_BIND_TIMESTAMP, ib1);
++}
++
++int mtk_foe_entry_prepare(struct mtk_foe_entry *entry, int type, int l4proto,
++ u8 pse_port, u8 *src_mac, u8 *dest_mac);
++int mtk_foe_entry_set_pse_port(struct mtk_foe_entry *entry, u8 port);
++int mtk_foe_entry_set_ipv4_tuple(struct mtk_foe_entry *entry, bool orig,
++ __be32 src_addr, __be16 src_port,
++ __be32 dest_addr, __be16 dest_port);
++int mtk_foe_entry_set_ipv6_tuple(struct mtk_foe_entry *entry,
++ __be32 *src_addr, __be16 src_port,
++ __be32 *dest_addr, __be16 dest_port);
++int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port);
++int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid);
++int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid);
++int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
++ u16 timestamp);
++int mtk_ppe_debugfs_init(struct mtk_ppe *ppe);
++
++#endif
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
+new file mode 100644
+index 0000000..d4b4823
+--- /dev/null
++++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
+@@ -0,0 +1,214 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
++
++#include <linux/kernel.h>
++#include <linux/debugfs.h>
++#include "mtk_eth_soc.h"
++
++struct mtk_flow_addr_info
++{
++ void *src, *dest;
++ u16 *src_port, *dest_port;
++ bool ipv6;
++};
++
++static const char *mtk_foe_entry_state_str(int state)
++{
++ static const char * const state_str[] = {
++ [MTK_FOE_STATE_INVALID] = "INV",
++ [MTK_FOE_STATE_UNBIND] = "UNB",
++ [MTK_FOE_STATE_BIND] = "BND",
++ [MTK_FOE_STATE_FIN] = "FIN",
++ };
++
++ if (state >= ARRAY_SIZE(state_str) || !state_str[state])
++ return "UNK";
++
++ return state_str[state];
++}
++
++static const char *mtk_foe_pkt_type_str(int type)
++{
++ static const char * const type_str[] = {
++ [MTK_PPE_PKT_TYPE_IPV4_HNAPT] = "IPv4 5T",
++ [MTK_PPE_PKT_TYPE_IPV4_ROUTE] = "IPv4 3T",
++ [MTK_PPE_PKT_TYPE_BRIDGE] = "L2",
++ [MTK_PPE_PKT_TYPE_IPV4_DSLITE] = "DS-LITE",
++ [MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T] = "IPv6 3T",
++ [MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T] = "IPv6 5T",
++ [MTK_PPE_PKT_TYPE_IPV6_6RD] = "6RD",
++ };
++
++ if (type >= ARRAY_SIZE(type_str) || !type_str[type])
++ return "UNKNOWN";
++
++ return type_str[type];
++}
++
++static void
++mtk_print_addr(struct seq_file *m, u32 *addr, bool ipv6)
++{
++ u32 n_addr[4];
++ int i;
++
++ if (!ipv6) {
++ seq_printf(m, "%pI4h", addr);
++ return;
++ }
++
++ for (i = 0; i < ARRAY_SIZE(n_addr); i++)
++ n_addr[i] = htonl(addr[i]);
++ seq_printf(m, "%pI6", n_addr);
++}
++
++static void
++mtk_print_addr_info(struct seq_file *m, struct mtk_flow_addr_info *ai)
++{
++ mtk_print_addr(m, ai->src, ai->ipv6);
++ if (ai->src_port)
++ seq_printf(m, ":%d", *ai->src_port);
++ seq_printf(m, "->");
++ mtk_print_addr(m, ai->dest, ai->ipv6);
++ if (ai->dest_port)
++ seq_printf(m, ":%d", *ai->dest_port);
++}
++
++static int
++mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind)
++{
++ struct mtk_ppe *ppe = m->private;
++ int i;
++
++ for (i = 0; i < MTK_PPE_ENTRIES; i++) {
++ struct mtk_foe_entry *entry = &ppe->foe_table[i];
++ struct mtk_foe_mac_info *l2;
++ struct mtk_flow_addr_info ai = {};
++ unsigned char h_source[ETH_ALEN];
++ unsigned char h_dest[ETH_ALEN];
++ int type, state;
++ u32 ib2;
++
++
++ state = FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1);
++ if (!state)
++ continue;
++
++ if (bind && state != MTK_FOE_STATE_BIND)
++ continue;
++
++ type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
++ seq_printf(m, "%05x %s %7s", i,
++ mtk_foe_entry_state_str(state),
++ mtk_foe_pkt_type_str(type));
++
++ switch (type) {
++ case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
++ case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
++ ai.src_port = &entry->ipv4.orig.src_port;
++ ai.dest_port = &entry->ipv4.orig.dest_port;
++ fallthrough;
++ case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
++ ai.src = &entry->ipv4.orig.src_ip;
++ ai.dest = &entry->ipv4.orig.dest_ip;
++ break;
++ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T:
++ ai.src_port = &entry->ipv6.src_port;
++ ai.dest_port = &entry->ipv6.dest_port;
++ fallthrough;
++ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T:
++ case MTK_PPE_PKT_TYPE_IPV6_6RD:
++ ai.src = &entry->ipv6.src_ip;
++ ai.dest = &entry->ipv6.dest_ip;
++ ai.ipv6 = true;
++ break;
++ }
++
++ seq_printf(m, " orig=");
++ mtk_print_addr_info(m, &ai);
++
++ switch (type) {
++ case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
++ case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
++ ai.src_port = &entry->ipv4.new.src_port;
++ ai.dest_port = &entry->ipv4.new.dest_port;
++ fallthrough;
++ case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
++ ai.src = &entry->ipv4.new.src_ip;
++ ai.dest = &entry->ipv4.new.dest_ip;
++ seq_printf(m, " new=");
++ mtk_print_addr_info(m, &ai);
++ break;
++ }
++
++ if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) {
++ l2 = &entry->ipv6.l2;
++ ib2 = entry->ipv6.ib2;
++ } else {
++ l2 = &entry->ipv4.l2;
++ ib2 = entry->ipv4.ib2;
++ }
++
++ *((__be32 *)h_source) = htonl(l2->src_mac_hi);
++ *((__be16 *)&h_source[4]) = htons(l2->src_mac_lo);
++ *((__be32 *)h_dest) = htonl(l2->dest_mac_hi);
++ *((__be16 *)&h_dest[4]) = htons(l2->dest_mac_lo);
++
++ seq_printf(m, " eth=%pM->%pM etype=%04x"
++ " vlan=%d,%d ib1=%08x ib2=%08x\n",
++ h_source, h_dest, ntohs(l2->etype),
++ l2->vlan1, l2->vlan2, entry->ib1, ib2);
++ }
++
++ return 0;
++}
++
++static int
++mtk_ppe_debugfs_foe_show_all(struct seq_file *m, void *private)
++{
++ return mtk_ppe_debugfs_foe_show(m, private, false);
++}
++
++static int
++mtk_ppe_debugfs_foe_show_bind(struct seq_file *m, void *private)
++{
++ return mtk_ppe_debugfs_foe_show(m, private, true);
++}
++
++static int
++mtk_ppe_debugfs_foe_open_all(struct inode *inode, struct file *file)
++{
++ return single_open(file, mtk_ppe_debugfs_foe_show_all,
++ inode->i_private);
++}
++
++static int
++mtk_ppe_debugfs_foe_open_bind(struct inode *inode, struct file *file)
++{
++ return single_open(file, mtk_ppe_debugfs_foe_show_bind,
++ inode->i_private);
++}
++
++int mtk_ppe_debugfs_init(struct mtk_ppe *ppe)
++{
++ static const struct file_operations fops_all = {
++ .open = mtk_ppe_debugfs_foe_open_all,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++ };
++
++ static const struct file_operations fops_bind = {
++ .open = mtk_ppe_debugfs_foe_open_bind,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++ };
++
++ struct dentry *root;
++
++ root = debugfs_create_dir("mtk_ppe", NULL);
++ debugfs_create_file("entries", S_IRUGO, root, ppe, &fops_all);
++ debugfs_create_file("bind", S_IRUGO, root, ppe, &fops_bind);
++
++ return 0;
++}
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+new file mode 100644
+index 0000000..1380ef0
+--- /dev/null
++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+@@ -0,0 +1,535 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (C) 2020 Felix Fietkau <nbd@nbd.name>
++ */
++
++#include <linux/if_ether.h>
++#include <linux/rhashtable.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <net/flow_offload.h>
++#include <net/pkt_cls.h>
++#include <net/dsa.h>
++#include "mtk_eth_soc.h"
++
++struct mtk_flow_data {
++ struct ethhdr eth;
++
++ union {
++ struct {
++ __be32 src_addr;
++ __be32 dst_addr;
++ } v4;
++
++ struct {
++ struct in6_addr src_addr;
++ struct in6_addr dst_addr;
++ } v6;
++ };
++
++ __be16 src_port;
++ __be16 dst_port;
++
++ struct {
++ u16 id;
++ __be16 proto;
++ u8 num;
++ } vlan;
++ struct {
++ u16 sid;
++ u8 num;
++ } pppoe;
++};
++
++struct mtk_flow_entry {
++ struct rhash_head node;
++ unsigned long cookie;
++ u16 hash;
++};
++
++static const struct rhashtable_params mtk_flow_ht_params = {
++ .head_offset = offsetof(struct mtk_flow_entry, node),
++ .key_offset = offsetof(struct mtk_flow_entry, cookie),
++ .key_len = sizeof(unsigned long),
++ .automatic_shrinking = true,
++};
++
++static u32
++mtk_eth_timestamp(struct mtk_eth *eth)
++{
++ return mtk_r32(eth, 0x0010) & MTK_FOE_IB1_BIND_TIMESTAMP;
++}
++
++static int
++mtk_flow_set_ipv4_addr(struct mtk_foe_entry *foe, struct mtk_flow_data *data,
++ bool egress)
++{
++ return mtk_foe_entry_set_ipv4_tuple(foe, egress,
++ data->v4.src_addr, data->src_port,
++ data->v4.dst_addr, data->dst_port);
++}
++
++static int
++mtk_flow_set_ipv6_addr(struct mtk_foe_entry *foe, struct mtk_flow_data *data)
++{
++ return mtk_foe_entry_set_ipv6_tuple(foe,
++ data->v6.src_addr.s6_addr32, data->src_port,
++ data->v6.dst_addr.s6_addr32, data->dst_port);
++}
++
++static void
++mtk_flow_offload_mangle_eth(const struct flow_action_entry *act, void *eth)
++{
++ void *dest = eth + act->mangle.offset;
++ const void *src = &act->mangle.val;
++
++ if (act->mangle.offset > 8)
++ return;
++
++ if (act->mangle.mask == 0xffff) {
++ src += 2;
++ dest += 2;
++ }
++
++ memcpy(dest, src, act->mangle.mask ? 2 : 4);
++}
++
++
++static int
++mtk_flow_mangle_ports(const struct flow_action_entry *act,
++ struct mtk_flow_data *data)
++{
++ u32 val = ntohl(act->mangle.val);
++
++ switch (act->mangle.offset) {
++ case 0:
++ if (act->mangle.mask == ~htonl(0xffff))
++ data->dst_port = cpu_to_be16(val);
++ else
++ data->src_port = cpu_to_be16(val >> 16);
++ break;
++ case 2:
++ data->dst_port = cpu_to_be16(val);
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int
++mtk_flow_mangle_ipv4(const struct flow_action_entry *act,
++ struct mtk_flow_data *data)
++{
++ __be32 *dest;
++
++ switch (act->mangle.offset) {
++ case offsetof(struct iphdr, saddr):
++ dest = &data->v4.src_addr;
++ break;
++ case offsetof(struct iphdr, daddr):
++ dest = &data->v4.dst_addr;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ memcpy(dest, &act->mangle.val, sizeof(u32));
++
++ return 0;
++}
++
++static int
++mtk_flow_get_dsa_port(struct net_device **dev)
++{
++#if IS_ENABLED(CONFIG_NET_DSA)
++ struct dsa_port *dp;
++
++ dp = dsa_port_from_netdev(*dev);
++ if (IS_ERR(dp))
++ return -ENODEV;
++
++ if (dp->cpu_dp->tag_ops->proto != DSA_TAG_PROTO_MTK)
++ return -ENODEV;
++
++ *dev = dp->cpu_dp->master;
++
++ return dp->index;
++#else
++ return -ENODEV;
++#endif
++}
++
++static int
++mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
++ struct net_device *dev)
++{
++ int pse_port, dsa_port;
++
++ dsa_port = mtk_flow_get_dsa_port(&dev);
++ if (dsa_port >= 0)
++ mtk_foe_entry_set_dsa(foe, dsa_port);
++
++ if (dev == eth->netdev[0])
++ pse_port = PSE_GDM1_PORT;
++ else if (dev == eth->netdev[1])
++ pse_port = PSE_GDM2_PORT;
++ else
++ return -EOPNOTSUPP;
++
++ mtk_foe_entry_set_pse_port(foe, pse_port);
++
++ return 0;
++}
++
++static int
++mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
++{
++ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
++ struct flow_action_entry *act;
++ struct mtk_flow_data data = {};
++ struct mtk_foe_entry foe;
++ struct net_device *odev = NULL;
++ struct mtk_flow_entry *entry;
++ int offload_type = 0;
++ u16 addr_type = 0;
++ u32 timestamp;
++ u8 l4proto = 0;
++ int err = 0;
++ int hash;
++ int i;
++
++ if (rhashtable_lookup(ð->flow_table, &f->cookie, mtk_flow_ht_params))
++ return -EEXIST;
++
++ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_META)) {
++ struct flow_match_meta match;
++
++ flow_rule_match_meta(rule, &match);
++ } else {
++ return -EOPNOTSUPP;
++ }
++
++ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
++ struct flow_match_control match;
++
++ flow_rule_match_control(rule, &match);
++ addr_type = match.key->addr_type;
++ } else {
++ return -EOPNOTSUPP;
++ }
++
++ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
++ struct flow_match_basic match;
++
++ flow_rule_match_basic(rule, &match);
++ l4proto = match.key->ip_proto;
++ } else {
++ return -EOPNOTSUPP;
++ }
++
++ flow_action_for_each(i, act, &rule->action) {
++ switch (act->id) {
++ case FLOW_ACTION_MANGLE:
++ if (act->mangle.htype == FLOW_ACT_MANGLE_HDR_TYPE_ETH)
++ mtk_flow_offload_mangle_eth(act, &data.eth);
++ break;
++ case FLOW_ACTION_REDIRECT:
++ odev = act->dev;
++ break;
++ case FLOW_ACTION_CSUM:
++ break;
++ case FLOW_ACTION_VLAN_PUSH:
++ if (data.vlan.num == 1 ||
++ act->vlan.proto != htons(ETH_P_8021Q))
++ return -EOPNOTSUPP;
++
++ data.vlan.id = act->vlan.vid;
++ data.vlan.proto = act->vlan.proto;
++ data.vlan.num++;
++ break;
++ case FLOW_ACTION_VLAN_POP:
++ break;
++ case FLOW_ACTION_PPPOE_PUSH:
++ if (data.pppoe.num == 1)
++ return -EOPNOTSUPP;
++
++ data.pppoe.sid = act->pppoe.sid;
++ data.pppoe.num++;
++ break;
++ default:
++ return -EOPNOTSUPP;
++ }
++ }
++
++ switch (addr_type) {
++ case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
++ offload_type = MTK_PPE_PKT_TYPE_IPV4_HNAPT;
++ break;
++ case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
++ offload_type = MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T;
++ break;
++ default:
++ return -EOPNOTSUPP;
++ }
++
++ if (!is_valid_ether_addr(data.eth.h_source) ||
++ !is_valid_ether_addr(data.eth.h_dest))
++ return -EINVAL;
++
++ err = mtk_foe_entry_prepare(&foe, offload_type, l4proto, 0,
++ data.eth.h_source,
++ data.eth.h_dest);
++ if (err)
++ return err;
++
++ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
++ struct flow_match_ports ports;
++
++ flow_rule_match_ports(rule, &ports);
++ data.src_port = ports.key->src;
++ data.dst_port = ports.key->dst;
++ } else {
++ return -EOPNOTSUPP;
++ }
++
++ if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
++ struct flow_match_ipv4_addrs addrs;
++
++ flow_rule_match_ipv4_addrs(rule, &addrs);
++
++ data.v4.src_addr = addrs.key->src;
++ data.v4.dst_addr = addrs.key->dst;
++
++ mtk_flow_set_ipv4_addr(&foe, &data, false);
++ }
++
++ if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
++ struct flow_match_ipv6_addrs addrs;
++
++ flow_rule_match_ipv6_addrs(rule, &addrs);
++
++ data.v6.src_addr = addrs.key->src;
++ data.v6.dst_addr = addrs.key->dst;
++
++ mtk_flow_set_ipv6_addr(&foe, &data);
++ }
++
++ flow_action_for_each(i, act, &rule->action) {
++ if (act->id != FLOW_ACTION_MANGLE)
++ continue;
++
++ switch (act->mangle.htype) {
++ case FLOW_ACT_MANGLE_HDR_TYPE_TCP:
++ case FLOW_ACT_MANGLE_HDR_TYPE_UDP:
++ err = mtk_flow_mangle_ports(act, &data);
++ break;
++ case FLOW_ACT_MANGLE_HDR_TYPE_IP4:
++ err = mtk_flow_mangle_ipv4(act, &data);
++ break;
++ case FLOW_ACT_MANGLE_HDR_TYPE_ETH:
++ /* handled earlier */
++ break;
++ default:
++ return -EOPNOTSUPP;
++ }
++
++ if (err)
++ return err;
++ }
++
++ if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
++ err = mtk_flow_set_ipv4_addr(&foe, &data, true);
++ if (err)
++ return err;
++ }
++
++ if (data.vlan.num == 1) {
++ if (data.vlan.proto != htons(ETH_P_8021Q))
++ return -EOPNOTSUPP;
++
++ mtk_foe_entry_set_vlan(&foe, data.vlan.id);
++ }
++ if (data.pppoe.num == 1)
++ mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid);
++
++ err = mtk_flow_set_output_device(eth, &foe, odev);
++ if (err)
++ return err;
++
++ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
++ if (!entry)
++ return -ENOMEM;
++
++ entry->cookie = f->cookie;
++ timestamp = mtk_eth_timestamp(eth);
++ hash = mtk_foe_entry_commit(ð->ppe, &foe, timestamp);
++ if (hash < 0) {
++ err = hash;
++ goto free;
++ }
++
++ entry->hash = hash;
++ err = rhashtable_insert_fast(ð->flow_table, &entry->node,
++ mtk_flow_ht_params);
++ if (err < 0)
++ goto clear_flow;
++
++ return 0;
++clear_flow:
++ mtk_foe_entry_clear(ð->ppe, hash);
++free:
++ kfree(entry);
++ return err;
++}
++
++static int
++mtk_flow_offload_destroy(struct mtk_eth *eth, struct flow_cls_offload *f)
++{
++ struct mtk_flow_entry *entry;
++
++ entry = rhashtable_lookup(ð->flow_table, &f->cookie,
++ mtk_flow_ht_params);
++ if (!entry)
++ return -ENOENT;
++
++ mtk_foe_entry_clear(ð->ppe, entry->hash);
++ rhashtable_remove_fast(ð->flow_table, &entry->node,
++ mtk_flow_ht_params);
++ kfree(entry);
++
++ return 0;
++}
++
++static int
++mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f)
++{
++ struct mtk_flow_entry *entry;
++ int timestamp;
++ u32 idle;
++
++ entry = rhashtable_lookup(ð->flow_table, &f->cookie,
++ mtk_flow_ht_params);
++ if (!entry)
++ return -ENOENT;
++
++ timestamp = mtk_foe_entry_timestamp(ð->ppe, entry->hash);
++ if (timestamp < 0)
++ return -ETIMEDOUT;
++
++ idle = mtk_eth_timestamp(eth) - timestamp;
++ f->stats.lastused = jiffies - idle * HZ;
++
++ return 0;
++}
++
++static DEFINE_MUTEX(mtk_flow_offload_mutex);
++
++static int
++mtk_eth_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv)
++{
++ struct flow_cls_offload *cls = type_data;
++ struct net_device *dev = cb_priv;
++ struct mtk_mac *mac = netdev_priv(dev);
++ struct mtk_eth *eth = mac->hw;
++ int err;
++
++ if (!tc_can_offload(dev))
++ return -EOPNOTSUPP;
++
++ if (type != TC_SETUP_CLSFLOWER)
++ return -EOPNOTSUPP;
++
++ mutex_lock(&mtk_flow_offload_mutex);
++ switch (cls->command) {
++ case FLOW_CLS_REPLACE:
++ err = mtk_flow_offload_replace(eth, cls);
++ break;
++ case FLOW_CLS_DESTROY:
++ err = mtk_flow_offload_destroy(eth, cls);
++ break;
++ case FLOW_CLS_STATS:
++ err = mtk_flow_offload_stats(eth, cls);
++ break;
++ default:
++ err = -EOPNOTSUPP;
++ break;
++ }
++ mutex_unlock(&mtk_flow_offload_mutex);
++
++ return err;
++}
++
++static int
++mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f)
++{
++ struct mtk_mac *mac = netdev_priv(dev);
++ struct mtk_eth *eth = mac->hw;
++ static LIST_HEAD(block_cb_list);
++ struct flow_block_cb *block_cb;
++ flow_setup_cb_t *cb;
++ int err = 0;
++
++ if (!eth->ppe.foe_table)
++ return -EOPNOTSUPP;
++
++ if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
++ return -EOPNOTSUPP;
++
++ cb = mtk_eth_setup_tc_block_cb;
++ f->driver_block_list = &block_cb_list;
++
++ switch (f->command) {
++ case FLOW_BLOCK_BIND:
++ block_cb = flow_block_cb_lookup(f->block, cb, dev);
++ if (block_cb) {
++ flow_block_cb_incref(block_cb);
++ goto unlock;
++ }
++ block_cb = flow_block_cb_alloc(cb, dev, dev, NULL);
++ if (IS_ERR(block_cb)) {
++ err = PTR_ERR(block_cb);
++ goto unlock;
++ }
++
++ flow_block_cb_add(block_cb, f);
++ list_add_tail(&block_cb->driver_list, &block_cb_list);
++ break;
++ case FLOW_BLOCK_UNBIND:
++ block_cb = flow_block_cb_lookup(f->block, cb, dev);
++ if (!block_cb) {
++ err = -ENOENT;
++ goto unlock;
++ }
++
++ if (flow_block_cb_decref(block_cb)) {
++ flow_block_cb_remove(block_cb, f);
++ list_del(&block_cb->driver_list);
++ }
++ break;
++ default:
++ err = -EOPNOTSUPP;
++ break;
++ }
++
++unlock:
++ return err;
++}
++
++int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
++ void *type_data)
++{
++ if (type == TC_SETUP_FT)
++ return mtk_eth_setup_tc_block(dev, type_data);
++
++ return -EOPNOTSUPP;
++}
++
++int mtk_eth_offload_init(struct mtk_eth *eth)
++{
++ if (!eth->ppe.foe_table)
++ return 0;
++
++ return rhashtable_init(ð->flow_table, &mtk_flow_ht_params);
++}
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_regs.h b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
+new file mode 100644
+index 0000000..0c45ea0
+--- /dev/null
++++ b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
+@@ -0,0 +1,144 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
++
++#ifndef __MTK_PPE_REGS_H
++#define __MTK_PPE_REGS_H
++
++#define MTK_PPE_GLO_CFG 0x200
++#define MTK_PPE_GLO_CFG_EN BIT(0)
++#define MTK_PPE_GLO_CFG_TSID_EN BIT(1)
++#define MTK_PPE_GLO_CFG_IP4_L4_CS_DROP BIT(2)
++#define MTK_PPE_GLO_CFG_IP4_CS_DROP BIT(3)
++#define MTK_PPE_GLO_CFG_TTL0_DROP BIT(4)
++#define MTK_PPE_GLO_CFG_PPE_BSWAP BIT(5)
++#define MTK_PPE_GLO_CFG_PSE_HASH_OFS BIT(6)
++#define MTK_PPE_GLO_CFG_MCAST_TB_EN BIT(7)
++#define MTK_PPE_GLO_CFG_FLOW_DROP_KA BIT(8)
++#define MTK_PPE_GLO_CFG_FLOW_DROP_UPDATE BIT(9)
++#define MTK_PPE_GLO_CFG_UDP_LITE_EN BIT(10)
++#define MTK_PPE_GLO_CFG_UDP_LEN_DROP BIT(11)
++#define MTK_PPE_GLO_CFG_MCAST_ENTRIES GNEMASK(13, 12)
++#define MTK_PPE_GLO_CFG_BUSY BIT(31)
++
++#define MTK_PPE_FLOW_CFG 0x204
++#define MTK_PPE_FLOW_CFG_IP4_TCP_FRAG BIT(6)
++#define MTK_PPE_FLOW_CFG_IP4_UDP_FRAG BIT(7)
++#define MTK_PPE_FLOW_CFG_IP6_3T_ROUTE BIT(8)
++#define MTK_PPE_FLOW_CFG_IP6_5T_ROUTE BIT(9)
++#define MTK_PPE_FLOW_CFG_IP6_6RD BIT(10)
++#define MTK_PPE_FLOW_CFG_IP4_NAT BIT(12)
++#define MTK_PPE_FLOW_CFG_IP4_NAPT BIT(13)
++#define MTK_PPE_FLOW_CFG_IP4_DSLITE BIT(14)
++#define MTK_PPE_FLOW_CFG_L2_BRIDGE BIT(15)
++#define MTK_PPE_FLOW_CFG_IP_PROTO_BLACKLIST BIT(16)
++#define MTK_PPE_FLOW_CFG_IP4_NAT_FRAG BIT(17)
++#define MTK_PPE_FLOW_CFG_IP4_HASH_FLOW_LABEL BIT(18)
++#define MTK_PPE_FLOW_CFG_IP4_HASH_GRE_KEY BIT(19)
++#define MTK_PPE_FLOW_CFG_IP6_HASH_GRE_KEY BIT(20)
++
++#define MTK_PPE_IP_PROTO_CHK 0x208
++#define MTK_PPE_IP_PROTO_CHK_IPV4 GENMASK(15, 0)
++#define MTK_PPE_IP_PROTO_CHK_IPV6 GENMASK(31, 16)
++
++#define MTK_PPE_TB_CFG 0x21c
++#define MTK_PPE_TB_CFG_ENTRY_NUM GENMASK(2, 0)
++#define MTK_PPE_TB_CFG_ENTRY_80B BIT(3)
++#define MTK_PPE_TB_CFG_SEARCH_MISS GENMASK(5, 4)
++#define MTK_PPE_TB_CFG_AGE_PREBIND BIT(6)
++#define MTK_PPE_TB_CFG_AGE_NON_L4 BIT(7)
++#define MTK_PPE_TB_CFG_AGE_UNBIND BIT(8)
++#define MTK_PPE_TB_CFG_AGE_TCP BIT(9)
++#define MTK_PPE_TB_CFG_AGE_UDP BIT(10)
++#define MTK_PPE_TB_CFG_AGE_TCP_FIN BIT(11)
++#define MTK_PPE_TB_CFG_KEEPALIVE GENMASK(13, 12)
++#define MTK_PPE_TB_CFG_HASH_MODE GENMASK(15, 14)
++#define MTK_PPE_TB_CFG_SCAN_MODE GENMASK(17, 16)
++#define MTK_PPE_TB_CFG_HASH_DEBUG GENMASK(19, 18)
++
++enum {
++ MTK_PPE_SCAN_MODE_DISABLED,
++ MTK_PPE_SCAN_MODE_CHECK_AGE,
++ MTK_PPE_SCAN_MODE_KEEPALIVE_AGE,
++};
++
++enum {
++ MTK_PPE_KEEPALIVE_DISABLE,
++ MTK_PPE_KEEPALIVE_UNICAST_CPU,
++ MTK_PPE_KEEPALIVE_DUP_CPU = 3,
++};
++
++enum {
++ MTK_PPE_SEARCH_MISS_ACTION_DROP,
++ MTK_PPE_SEARCH_MISS_ACTION_FORWARD = 2,
++ MTK_PPE_SEARCH_MISS_ACTION_FORWARD_BUILD = 3,
++};
++
++#define MTK_PPE_TB_BASE 0x220
++
++#define MTK_PPE_TB_USED 0x224
++#define MTK_PPE_TB_USED_NUM GENMASK(13, 0)
++
++#define MTK_PPE_BIND_RATE 0x228
++#define MTK_PPE_BIND_RATE_BIND GENMASK(15, 0)
++#define MTK_PPE_BIND_RATE_PREBIND GENMASK(31, 16)
++
++#define MTK_PPE_BIND_LIMIT0 0x22c
++#define MTK_PPE_BIND_LIMIT0_QUARTER GENMASK(13, 0)
++#define MTK_PPE_BIND_LIMIT0_HALF GENMASK(29, 16)
++
++#define MTK_PPE_BIND_LIMIT1 0x230
++#define MTK_PPE_BIND_LIMIT1_FULL GENMASK(13, 0)
++#define MTK_PPE_BIND_LIMIT1_NON_L4 GENMASK(23, 16)
++
++#define MTK_PPE_KEEPALIVE 0x234
++#define MTK_PPE_KEEPALIVE_TIME GENMASK(15, 0)
++#define MTK_PPE_KEEPALIVE_TIME_TCP GENMASK(23, 16)
++#define MTK_PPE_KEEPALIVE_TIME_UDP GENMASK(31, 24)
++
++#define MTK_PPE_UNBIND_AGE 0x238
++#define MTK_PPE_UNBIND_AGE_MIN_PACKETS GENMASK(31, 16)
++#define MTK_PPE_UNBIND_AGE_DELTA GENMASK(7, 0)
++
++#define MTK_PPE_BIND_AGE0 0x23c
++#define MTK_PPE_BIND_AGE0_DELTA_NON_L4 GENMASK(30, 16)
++#define MTK_PPE_BIND_AGE0_DELTA_UDP GENMASK(14, 0)
++
++#define MTK_PPE_BIND_AGE1 0x240
++#define MTK_PPE_BIND_AGE1_DELTA_TCP_FIN GENMASK(30, 16)
++#define MTK_PPE_BIND_AGE1_DELTA_TCP GENMASK(14, 0)
++
++#define MTK_PPE_HASH_SEED 0x244
++
++#define MTK_PPE_DEFAULT_CPU_PORT 0x248
++#define MTK_PPE_DEFAULT_CPU_PORT_MASK(_n) (GENMASK(2, 0) << ((_n) * 4))
++
++#define MTK_PPE_MTU_DROP 0x308
++
++#define MTK_PPE_VLAN_MTU0 0x30c
++#define MTK_PPE_VLAN_MTU0_NONE GENMASK(13, 0)
++#define MTK_PPE_VLAN_MTU0_1TAG GENMASK(29, 16)
++
++#define MTK_PPE_VLAN_MTU1 0x310
++#define MTK_PPE_VLAN_MTU1_2TAG GENMASK(13, 0)
++#define MTK_PPE_VLAN_MTU1_3TAG GENMASK(29, 16)
++
++#define MTK_PPE_VPM_TPID 0x318
++
++#define MTK_PPE_CACHE_CTL 0x320
++#define MTK_PPE_CACHE_CTL_EN BIT(0)
++#define MTK_PPE_CACHE_CTL_LOCK_CLR BIT(4)
++#define MTK_PPE_CACHE_CTL_REQ BIT(8)
++#define MTK_PPE_CACHE_CTL_CLEAR BIT(9)
++#define MTK_PPE_CACHE_CTL_CMD GENMASK(13, 12)
++
++#define MTK_PPE_MIB_CFG 0x334
++#define MTK_PPE_MIB_CFG_EN BIT(0)
++#define MTK_PPE_MIB_CFG_RD_CLR BIT(1)
++
++#define MTK_PPE_MIB_TB_BASE 0x338
++
++#define MTK_PPE_MIB_CACHE_CTL 0x350
++#define MTK_PPE_MIB_CACHE_CTL_EN BIT(0)
++#define MTK_PPE_MIB_CACHE_CTL_FLUSH BIT(2)
++
++#endif
+--
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3003-add-wed.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3003-add-wed.patch
index bfb726a..79672d4 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3003-add-wed.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3003-add-wed.patch
@@ -35,7 +35,7 @@
create mode 100644 include/linux/soc/mediatek/mtk_wed.h
diff --git a/arch/arm64/boot/dts/mediatek/mt7622.dtsi b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
-index 753a97a..e46566a 100644
+index 9eeecff..3224350 100644
--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
@@ -338,7 +338,7 @@
@@ -47,7 +47,7 @@
interface-type = "ace";
reg = <0x5000 0x1000>;
};
-@@ -921,6 +921,11 @@
+@@ -920,6 +920,11 @@
};
};
@@ -59,7 +59,7 @@
ethsys: syscon@1b000000 {
compatible = "mediatek,mt7622-ethsys",
"syscon";
-@@ -939,6 +944,26 @@
+@@ -938,6 +943,26 @@
#dma-cells = <1>;
};
@@ -84,9 +84,9 @@
+ };
+
eth: ethernet@1b100000 {
- compatible = "mediatek,mt7622-eth",
- "mediatek,mt2701-eth",
-@@ -965,6 +990,11 @@
+ compatible = "mediatek,mt7622-eth";
+ reg = <0 0x1b100000 0 0x20000>;
+@@ -962,6 +987,11 @@
power-domains = <&scpsys MT7622_POWER_DOMAIN_ETHSYS>;
mediatek,ethsys = <ðsys>;
mediatek,sgmiisys = <&sgmiisys>;
@@ -134,7 +134,7 @@
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
old mode 100755
new mode 100644
-index 24b5593..15966b8
+index fe6ede6..4ae4a3b
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -22,11 +22,13 @@
@@ -151,7 +151,7 @@
#if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE)
#include "mtk_hnat/nf_hnat_mtk.h"
-@@ -2388,6 +2390,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+@@ -2505,6 +2507,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
struct net_device *netdev = NULL;
dma_addr_t dma_addr = DMA_MAPPING_ERROR;
u64 addr64 = 0;
@@ -159,7 +159,7 @@
int mac = 0;
idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size);
-@@ -2476,6 +2479,17 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+@@ -2602,6 +2605,17 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
skb_checksum_none_assert(skb);
skb->protocol = eth_type_trans(skb, netdev);
@@ -177,7 +177,7 @@
if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_RX_V2)) {
if (trxd.rxd3 & RX_DMA_VTAG_V2)
-@@ -4293,7 +4307,7 @@ static int mtk_stop(struct net_device *dev)
+@@ -4445,7 +4459,7 @@ static int mtk_stop(struct net_device *dev)
mtk_dma_free(eth);
if (eth->soc->offload_version)
@@ -186,7 +186,7 @@
return 0;
}
-@@ -5710,6 +5724,22 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5908,6 +5922,22 @@ static int mtk_probe(struct platform_device *pdev)
}
}
@@ -209,7 +209,7 @@
if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
for (i = 0; i < MTK_PDMA_IRQ_NUM; i++)
eth->irq_pdma[i] = platform_get_irq(pdev, i);
-@@ -5726,7 +5756,8 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5924,7 +5954,8 @@ static int mtk_probe(struct platform_device *pdev)
if (eth->irq_fe[i] < 0) {
dev_err(&pdev->dev, "no IRQ%d resource found\n", i);
@@ -219,7 +219,7 @@
}
}
-@@ -5734,12 +5765,15 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5932,12 +5963,15 @@ static int mtk_probe(struct platform_device *pdev)
eth->clks[i] = devm_clk_get(eth->dev,
mtk_clks_source_name[i]);
if (IS_ERR(eth->clks[i])) {
@@ -238,7 +238,7 @@
}
eth->clks[i] = NULL;
}
-@@ -5750,7 +5784,7 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5948,7 +5982,7 @@ static int mtk_probe(struct platform_device *pdev)
err = mtk_hw_init(eth, MTK_TYPE_COLD_RESET);
if (err)
@@ -247,7 +247,7 @@
eth->hwlro = MTK_HAS_CAPS(eth->soc->caps, MTK_HWLRO);
-@@ -5879,14 +5913,15 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -6075,14 +6109,15 @@ static int mtk_probe(struct platform_device *pdev)
}
if (eth->soc->offload_version) {
@@ -268,7 +268,7 @@
}
for (i = 0; i < MTK_MAX_DEVS; i++) {
-@@ -5896,7 +5931,7 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -6092,7 +6127,7 @@ static int mtk_probe(struct platform_device *pdev)
err = register_netdev(eth->netdev[i]);
if (err) {
dev_err(eth->dev, "error bringing up device\n");
@@ -277,7 +277,7 @@
} else
netif_info(eth, probe, eth->netdev[i],
"mediatek frame engine at 0x%08lx, irq %d\n",
-@@ -5946,12 +5981,15 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -6141,12 +6176,15 @@ static int mtk_probe(struct platform_device *pdev)
return 0;
@@ -294,7 +294,7 @@
return err;
}
-@@ -5971,6 +6009,7 @@ static int mtk_remove(struct platform_device *pdev)
+@@ -6166,6 +6204,7 @@ static int mtk_remove(struct platform_device *pdev)
phylink_disconnect_phy(mac->phylink);
}
@@ -302,7 +302,7 @@
mtk_hw_deinit(eth);
for (i = 0; i < MTK_TX_NAPI_NUM; i++) {
-@@ -6002,6 +6041,7 @@ static const struct mtk_soc_data mt2701_data = {
+@@ -6196,6 +6235,7 @@ static const struct mtk_soc_data mt2701_data = {
.required_pctl = true,
.has_sram = false,
.offload_version = 1,
@@ -310,7 +310,7 @@
.rss_num = 0,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma),
-@@ -6023,6 +6063,7 @@ static const struct mtk_soc_data mt7621_data = {
+@@ -6217,6 +6257,7 @@ static const struct mtk_soc_data mt7621_data = {
.required_pctl = false,
.has_sram = false,
.offload_version = 1,
@@ -318,7 +318,7 @@
.rss_num = 0,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma),
-@@ -6045,6 +6086,7 @@ static const struct mtk_soc_data mt7622_data = {
+@@ -6239,6 +6280,7 @@ static const struct mtk_soc_data mt7622_data = {
.required_pctl = false,
.has_sram = false,
.offload_version = 2,
@@ -326,7 +326,7 @@
.rss_num = 0,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma),
-@@ -6066,6 +6108,7 @@ static const struct mtk_soc_data mt7623_data = {
+@@ -6260,6 +6302,7 @@ static const struct mtk_soc_data mt7623_data = {
.required_pctl = true,
.has_sram = false,
.offload_version = 1,
@@ -337,10 +337,10 @@
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
old mode 100755
new mode 100644
-index c9fb783..b8fd0c9
+index f9d1f91..01672eb
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -638,6 +638,9 @@
+@@ -619,6 +619,9 @@
#define RX_DMA_SPORT_MASK 0x7
#define RX_DMA_SPORT_MASK_V2 0xf
@@ -350,7 +350,7 @@
/* QDMA descriptor txd4 */
#define TX_DMA_CHKSUM (0x7 << 29)
#define TX_DMA_TSO BIT(28)
-@@ -1739,6 +1742,7 @@ struct mtk_reg_map {
+@@ -1809,6 +1812,7 @@ struct mtk_reg_map {
* the target SoC
* @required_pctl A bool value to show whether the SoC requires
* the extra setup for those pins used by GMAC.
@@ -358,7 +358,7 @@
* @txd_size Tx DMA descriptor size.
* @rxd_size Rx DMA descriptor size.
* @rx_dma_l4_valid Rx DMA valid register mask.
-@@ -1753,6 +1757,7 @@ struct mtk_soc_data {
+@@ -1823,6 +1827,7 @@ struct mtk_soc_data {
u64 required_clks;
bool required_pctl;
u8 offload_version;
@@ -366,18 +366,18 @@
netdev_features_t hw_features;
bool has_sram;
struct {
-@@ -1964,7 +1969,7 @@ struct mtk_eth {
+@@ -2115,7 +2120,7 @@ struct mtk_eth {
+ spinlock_t syscfg0_lock;
struct notifier_block netdevice_notifier;
- struct timer_list mtk_dma_monitor_timer;
- struct mtk_ppe ppe;
+ struct mtk_ppe *ppe;
struct rhashtable flow_table;
};
-@@ -2021,6 +2026,14 @@ extern const struct of_device_id of_mtk_match[];
- extern u32 mtk_hwlro_stats_ebl;
- extern u32 dbg_show_level;
+@@ -2178,6 +2183,14 @@ extern u32 (*mtk_get_tnl_netsys_params)(struct sk_buff *skb);
+ extern struct net_device *(*mtk_get_tnl_dev)(u8 tops_crsn);
+ extern void (*mtk_set_tops_crsn)(struct sk_buff *skb, u8 tops_crsn);
+static inline struct mtk_foe_entry *
+mtk_foe_get_entry(struct mtk_ppe *ppe, u16 hash)
@@ -2957,7 +2957,7 @@
+
+#endif
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
-index 2d1aa35..85d582c 100644
+index 6c0860b..5020ccd 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -849,6 +849,7 @@ enum net_device_path_type {
@@ -2965,10 +2965,10 @@
DEV_PATH_PPPOE,
DEV_PATH_DSA,
+ DEV_PATH_MTK_WDMA,
- };
-
- struct net_device_path {
-@@ -874,6 +875,12 @@ struct net_device_path {
+ DEV_PATH_DSLITE,
+ DEV_PATH_6RD,
+ DEV_PATH_TNL,
+@@ -877,6 +878,12 @@ struct net_device_path {
int port;
u16 proto;
} dsa;
@@ -3119,7 +3119,7 @@
+
+#endif
diff --git a/net/core/dev.c b/net/core/dev.c
-index e9dd11e..64d3e41 100644
+index 7d29e7b..906d101 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -758,6 +758,10 @@ int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
@@ -3134,5 +3134,5 @@
if (!path)
return -1;
--
-2.18.0
+2.45.2
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/640-netfilter-nf_flow_table-add-hardware-offload-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/640-netfilter-nf_flow_table-add-hardware-offload-support.patch
deleted file mode 100644
index 88d2cb1..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/640-netfilter-nf_flow_table-add-hardware-offload-support.patch
+++ /dev/null
@@ -1,564 +0,0 @@
-From: Pablo Neira Ayuso <pablo@netfilter.org>
-Date: Thu, 11 Jan 2018 16:32:00 +0100
-Subject: [PATCH] netfilter: nf_flow_table: add hardware offload support
-
-This patch adds the infrastructure to offload flows to hardware, in case
-the nic/switch comes with built-in flow tables capabilities.
-
-If the hardware comes with no hardware flow tables or they have
-limitations in terms of features, the existing infrastructure falls back
-to the software flow table implementation.
-
-The software flow table garbage collector skips entries that resides in
-the hardware, so the hardware will be responsible for releasing this
-flow table entry too via flow_offload_dead().
-
-Hardware configuration, either to add or to delete entries, is done from
-the hardware offload workqueue, to ensure this is done from user context
-given that we may sleep when grabbing the mdio mutex.
-
-Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
----
- create mode 100644 net/netfilter/nf_flow_table_hw.c
-
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -931,6 +931,13 @@ struct devlink;
- struct tlsdev_ops;
-
-
-+struct flow_offload;
-+
-+enum flow_offload_type {
-+ FLOW_OFFLOAD_ADD = 0,
-+ FLOW_OFFLOAD_DEL,
-+};
-+
- /*
- * This structure defines the management hooks for network devices.
- * The following hooks can be defined; unless noted otherwise, they are
-@@ -1163,6 +1170,10 @@ struct tlsdev_ops;
- * int (*ndo_bridge_dellink)(struct net_device *dev, struct nlmsghdr *nlh,
- * u16 flags);
- *
-+ * int (*ndo_flow_offload)(enum flow_offload_type type,
-+ * struct flow_offload *flow);
-+ * Adds/deletes flow entry to/from net device flowtable.
-+ *
- * int (*ndo_change_carrier)(struct net_device *dev, bool new_carrier);
- * Called to change device carrier. Soft-devices (like dummy, team, etc)
- * which do not represent real hardware may define this to allow their
-@@ -1410,6 +1421,8 @@ struct net_device_ops {
- int (*ndo_bridge_dellink)(struct net_device *dev,
- struct nlmsghdr *nlh,
- u16 flags);
-+ int (*ndo_flow_offload)(enum flow_offload_type type,
-+ struct flow_offload *flow);
- int (*ndo_change_carrier)(struct net_device *dev,
- bool new_carrier);
- int (*ndo_get_phys_port_id)(struct net_device *dev,
---- a/include/net/netfilter/nf_flow_table.h
-+++ b/include/net/netfilter/nf_flow_table.h
-@@ -21,11 +21,17 @@ struct nf_flowtable_type {
- struct module *owner;
- };
-
-+enum nf_flowtable_flags {
-+ NF_FLOWTABLE_F_HW = 0x1,
-+};
-+
- struct nf_flowtable {
- struct list_head list;
- struct rhashtable rhashtable;
- const struct nf_flowtable_type *type;
-+ u32 flags;
- struct delayed_work gc_work;
-+ possible_net_t ft_net;
- };
-
- enum flow_offload_tuple_dir {
-@@ -71,6 +77,7 @@ struct flow_offload_tuple_rhash {
- #define FLOW_OFFLOAD_DNAT 0x2
- #define FLOW_OFFLOAD_DYING 0x4
- #define FLOW_OFFLOAD_TEARDOWN 0x8
-+#define FLOW_OFFLOAD_HW 0x10
-
- struct flow_offload {
- struct flow_offload_tuple_rhash tuplehash[FLOW_OFFLOAD_DIR_MAX];
-@@ -123,6 +130,22 @@ unsigned int nf_flow_offload_ip_hook(voi
- unsigned int nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
- const struct nf_hook_state *state);
-
-+void nf_flow_offload_hw_add(struct net *net, struct flow_offload *flow,
-+ struct nf_conn *ct);
-+void nf_flow_offload_hw_del(struct net *net, struct flow_offload *flow);
-+
-+struct nf_flow_table_hw {
-+ struct module *owner;
-+ void (*add)(struct net *net, struct flow_offload *flow,
-+ struct nf_conn *ct);
-+ void (*del)(struct net *net, struct flow_offload *flow);
-+};
-+
-+int nf_flow_table_hw_register(const struct nf_flow_table_hw *offload);
-+void nf_flow_table_hw_unregister(const struct nf_flow_table_hw *offload);
-+
-+extern struct work_struct nf_flow_offload_hw_work;
-+
- #define MODULE_ALIAS_NF_FLOWTABLE(family) \
- MODULE_ALIAS("nf-flowtable-" __stringify(family))
-
---- a/include/uapi/linux/netfilter/nf_tables.h
-+++ b/include/uapi/linux/netfilter/nf_tables.h
-@@ -1516,6 +1516,7 @@ enum nft_object_attributes {
- * @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32)
- * @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32)
- * @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64)
-+ * @NFTA_FLOWTABLE_FLAGS: flags (NLA_U32)
- */
- enum nft_flowtable_attributes {
- NFTA_FLOWTABLE_UNSPEC,
-@@ -1525,6 +1526,7 @@ enum nft_flowtable_attributes {
- NFTA_FLOWTABLE_USE,
- NFTA_FLOWTABLE_HANDLE,
- NFTA_FLOWTABLE_PAD,
-+ NFTA_FLOWTABLE_FLAGS,
- __NFTA_FLOWTABLE_MAX
- };
- #define NFTA_FLOWTABLE_MAX (__NFTA_FLOWTABLE_MAX - 1)
---- a/net/netfilter/Kconfig
-+++ b/net/netfilter/Kconfig
-@@ -710,6 +710,15 @@ config NF_FLOW_TABLE
-
- To compile it as a module, choose M here.
-
-+config NF_FLOW_TABLE_HW
-+ tristate "Netfilter flow table hardware offload module"
-+ depends on NF_FLOW_TABLE
-+ help
-+ This option adds hardware offload support for the flow table core
-+ infrastructure.
-+
-+ To compile it as a module, choose M here.
-+
- config NETFILTER_XTABLES
- tristate "Netfilter Xtables support (required for ip_tables)"
- default m if NETFILTER_ADVANCED=n
---- a/net/netfilter/Makefile
-+++ b/net/netfilter/Makefile
-@@ -123,6 +123,7 @@ obj-$(CONFIG_NF_FLOW_TABLE) += nf_flow_t
- nf_flow_table-objs := nf_flow_table_core.o nf_flow_table_ip.o
-
- obj-$(CONFIG_NF_FLOW_TABLE_INET) += nf_flow_table_inet.o
-+obj-$(CONFIG_NF_FLOW_TABLE_HW) += nf_flow_table_hw.o
-
- # generic X tables
- obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
---- a/net/netfilter/nf_flow_table_core.c
-+++ b/net/netfilter/nf_flow_table_core.c
-@@ -261,10 +261,16 @@ static inline bool nf_flow_has_expired(c
- return nf_flow_timeout_delta(flow->timeout) <= 0;
- }
-
-+static inline bool nf_flow_in_hw(const struct flow_offload *flow)
-+{
-+ return flow->flags & FLOW_OFFLOAD_HW;
-+}
-+
- static void flow_offload_del(struct nf_flowtable *flow_table,
- struct flow_offload *flow)
- {
- struct flow_offload_entry *e;
-+ struct net *net = read_pnet(&flow_table->ft_net);
-
- rhashtable_remove_fast(&flow_table->rhashtable,
- &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].node,
-@@ -284,6 +290,9 @@ static void flow_offload_del(struct nf_f
- if (!(flow->flags & FLOW_OFFLOAD_TEARDOWN))
- flow_offload_fixup_ct_state(e->ct);
-
-+ if (nf_flow_in_hw(flow))
-+ nf_flow_offload_hw_del(net, flow);
-+
- flow_offload_free(flow);
- }
-
-@@ -374,6 +383,9 @@ static void nf_flow_offload_gc_step(stru
- if (!teardown)
- nf_ct_offload_timeout(flow);
-
-+ if (nf_flow_in_hw(flow) && !teardown)
-+ return;
-+
- if (nf_flow_has_expired(flow) || teardown)
- flow_offload_del(flow_table, flow);
- }
-@@ -503,10 +515,43 @@ int nf_flow_dnat_port(const struct flow_
- }
- EXPORT_SYMBOL_GPL(nf_flow_dnat_port);
-
-+static const struct nf_flow_table_hw __rcu *nf_flow_table_hw_hook __read_mostly;
-+
-+static int nf_flow_offload_hw_init(struct nf_flowtable *flow_table)
-+{
-+ const struct nf_flow_table_hw *offload;
-+
-+ if (!rcu_access_pointer(nf_flow_table_hw_hook))
-+ request_module("nf-flow-table-hw");
-+
-+ rcu_read_lock();
-+ offload = rcu_dereference(nf_flow_table_hw_hook);
-+ if (!offload)
-+ goto err_no_hw_offload;
-+
-+ if (!try_module_get(offload->owner))
-+ goto err_no_hw_offload;
-+
-+ rcu_read_unlock();
-+
-+ return 0;
-+
-+err_no_hw_offload:
-+ rcu_read_unlock();
-+
-+ return -EOPNOTSUPP;
-+}
-+
- int nf_flow_table_init(struct nf_flowtable *flowtable)
- {
- int err;
-
-+ if (flowtable->flags & NF_FLOWTABLE_F_HW) {
-+ err = nf_flow_offload_hw_init(flowtable);
-+ if (err)
-+ return err;
-+ }
-+
- INIT_DEFERRABLE_WORK(&flowtable->gc_work, nf_flow_offload_work_gc);
-
- err = rhashtable_init(&flowtable->rhashtable,
-@@ -547,6 +592,8 @@ static void nf_flow_table_iterate_cleanu
- {
- nf_flow_table_iterate(flowtable, nf_flow_table_do_cleanup, dev);
- flush_delayed_work(&flowtable->gc_work);
-+ if (flowtable->flags & NF_FLOWTABLE_F_HW)
-+ flush_work(&nf_flow_offload_hw_work);
- }
-
- void nf_flow_table_cleanup(struct net_device *dev)
-@@ -560,6 +607,26 @@ void nf_flow_table_cleanup(struct net_de
- }
- EXPORT_SYMBOL_GPL(nf_flow_table_cleanup);
-
-+struct work_struct nf_flow_offload_hw_work;
-+EXPORT_SYMBOL_GPL(nf_flow_offload_hw_work);
-+
-+/* Give the hardware workqueue the chance to remove entries from hardware.*/
-+static void nf_flow_offload_hw_free(struct nf_flowtable *flowtable)
-+{
-+ const struct nf_flow_table_hw *offload;
-+
-+ flush_work(&nf_flow_offload_hw_work);
-+
-+ rcu_read_lock();
-+ offload = rcu_dereference(nf_flow_table_hw_hook);
-+ if (!offload) {
-+ rcu_read_unlock();
-+ return;
-+ }
-+ module_put(offload->owner);
-+ rcu_read_unlock();
-+}
-+
- void nf_flow_table_free(struct nf_flowtable *flow_table)
- {
- mutex_lock(&flowtable_lock);
-@@ -569,9 +636,58 @@ void nf_flow_table_free(struct nf_flowta
- nf_flow_table_iterate(flow_table, nf_flow_table_do_cleanup, NULL);
- nf_flow_table_iterate(flow_table, nf_flow_offload_gc_step, flow_table);
- rhashtable_destroy(&flow_table->rhashtable);
-+ if (flow_table->flags & NF_FLOWTABLE_F_HW)
-+ nf_flow_offload_hw_free(flow_table);
- }
- EXPORT_SYMBOL_GPL(nf_flow_table_free);
-
-+/* Must be called from user context. */
-+void nf_flow_offload_hw_add(struct net *net, struct flow_offload *flow,
-+ struct nf_conn *ct)
-+{
-+ const struct nf_flow_table_hw *offload;
-+
-+ rcu_read_lock();
-+ offload = rcu_dereference(nf_flow_table_hw_hook);
-+ if (offload)
-+ offload->add(net, flow, ct);
-+ rcu_read_unlock();
-+}
-+EXPORT_SYMBOL_GPL(nf_flow_offload_hw_add);
-+
-+/* Must be called from user context. */
-+void nf_flow_offload_hw_del(struct net *net, struct flow_offload *flow)
-+{
-+ const struct nf_flow_table_hw *offload;
-+
-+ rcu_read_lock();
-+ offload = rcu_dereference(nf_flow_table_hw_hook);
-+ if (offload)
-+ offload->del(net, flow);
-+ rcu_read_unlock();
-+}
-+EXPORT_SYMBOL_GPL(nf_flow_offload_hw_del);
-+
-+int nf_flow_table_hw_register(const struct nf_flow_table_hw *offload)
-+{
-+ if (rcu_access_pointer(nf_flow_table_hw_hook))
-+ return -EBUSY;
-+
-+ rcu_assign_pointer(nf_flow_table_hw_hook, offload);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(nf_flow_table_hw_register);
-+
-+void nf_flow_table_hw_unregister(const struct nf_flow_table_hw *offload)
-+{
-+ WARN_ON(rcu_access_pointer(nf_flow_table_hw_hook) != offload);
-+ rcu_assign_pointer(nf_flow_table_hw_hook, NULL);
-+
-+ synchronize_rcu();
-+}
-+EXPORT_SYMBOL_GPL(nf_flow_table_hw_unregister);
-+
- static int nf_flow_table_netdev_event(struct notifier_block *this,
- unsigned long event, void *ptr)
- {
---- /dev/null
-+++ b/net/netfilter/nf_flow_table_hw.c
-@@ -0,0 +1,169 @@
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/netfilter.h>
-+#include <linux/rhashtable.h>
-+#include <linux/netdevice.h>
-+#include <net/netfilter/nf_flow_table.h>
-+#include <net/netfilter/nf_conntrack.h>
-+#include <net/netfilter/nf_conntrack_core.h>
-+#include <net/netfilter/nf_conntrack_tuple.h>
-+
-+static DEFINE_SPINLOCK(flow_offload_hw_pending_list_lock);
-+static LIST_HEAD(flow_offload_hw_pending_list);
-+
-+static DEFINE_MUTEX(nf_flow_offload_hw_mutex);
-+
-+struct flow_offload_hw {
-+ struct list_head list;
-+ enum flow_offload_type type;
-+ struct flow_offload *flow;
-+ struct nf_conn *ct;
-+ possible_net_t flow_hw_net;
-+};
-+
-+static int do_flow_offload_hw(struct net *net, struct flow_offload *flow,
-+ int type)
-+{
-+ struct net_device *indev;
-+ int ret, ifindex;
-+
-+ ifindex = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.iifidx;
-+ indev = dev_get_by_index(net, ifindex);
-+ if (WARN_ON(!indev))
-+ return 0;
-+
-+ mutex_lock(&nf_flow_offload_hw_mutex);
-+ ret = indev->netdev_ops->ndo_flow_offload(type, flow);
-+ mutex_unlock(&nf_flow_offload_hw_mutex);
-+
-+ dev_put(indev);
-+
-+ return ret;
-+}
-+
-+static void flow_offload_hw_work_add(struct flow_offload_hw *offload)
-+{
-+ struct net *net;
-+ int ret;
-+
-+ if (nf_ct_is_dying(offload->ct))
-+ return;
-+
-+ net = read_pnet(&offload->flow_hw_net);
-+ ret = do_flow_offload_hw(net, offload->flow, FLOW_OFFLOAD_ADD);
-+ if (ret >= 0)
-+ offload->flow->flags |= FLOW_OFFLOAD_HW;
-+}
-+
-+static void flow_offload_hw_work_del(struct flow_offload_hw *offload)
-+{
-+ struct net *net = read_pnet(&offload->flow_hw_net);
-+
-+ do_flow_offload_hw(net, offload->flow, FLOW_OFFLOAD_DEL);
-+}
-+
-+static void flow_offload_hw_work(struct work_struct *work)
-+{
-+ struct flow_offload_hw *offload, *next;
-+ LIST_HEAD(hw_offload_pending);
-+
-+ spin_lock_bh(&flow_offload_hw_pending_list_lock);
-+ list_replace_init(&flow_offload_hw_pending_list, &hw_offload_pending);
-+ spin_unlock_bh(&flow_offload_hw_pending_list_lock);
-+
-+ list_for_each_entry_safe(offload, next, &hw_offload_pending, list) {
-+ switch (offload->type) {
-+ case FLOW_OFFLOAD_ADD:
-+ flow_offload_hw_work_add(offload);
-+ break;
-+ case FLOW_OFFLOAD_DEL:
-+ flow_offload_hw_work_del(offload);
-+ break;
-+ }
-+ if (offload->ct)
-+ nf_conntrack_put(&offload->ct->ct_general);
-+ list_del(&offload->list);
-+ kfree(offload);
-+ }
-+}
-+
-+static void flow_offload_queue_work(struct flow_offload_hw *offload)
-+{
-+ spin_lock_bh(&flow_offload_hw_pending_list_lock);
-+ list_add_tail(&offload->list, &flow_offload_hw_pending_list);
-+ spin_unlock_bh(&flow_offload_hw_pending_list_lock);
-+
-+ schedule_work(&nf_flow_offload_hw_work);
-+}
-+
-+static void flow_offload_hw_add(struct net *net, struct flow_offload *flow,
-+ struct nf_conn *ct)
-+{
-+ struct flow_offload_hw *offload;
-+
-+ offload = kmalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC);
-+ if (!offload)
-+ return;
-+
-+ nf_conntrack_get(&ct->ct_general);
-+ offload->type = FLOW_OFFLOAD_ADD;
-+ offload->ct = ct;
-+ offload->flow = flow;
-+ write_pnet(&offload->flow_hw_net, net);
-+
-+ flow_offload_queue_work(offload);
-+}
-+
-+static void flow_offload_hw_del(struct net *net, struct flow_offload *flow)
-+{
-+ struct flow_offload_hw *offload;
-+
-+ offload = kmalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC);
-+ if (!offload)
-+ return;
-+
-+ offload->type = FLOW_OFFLOAD_DEL;
-+ offload->ct = NULL;
-+ offload->flow = flow;
-+ write_pnet(&offload->flow_hw_net, net);
-+
-+ flow_offload_queue_work(offload);
-+}
-+
-+static const struct nf_flow_table_hw flow_offload_hw = {
-+ .add = flow_offload_hw_add,
-+ .del = flow_offload_hw_del,
-+ .owner = THIS_MODULE,
-+};
-+
-+static int __init nf_flow_table_hw_module_init(void)
-+{
-+ INIT_WORK(&nf_flow_offload_hw_work, flow_offload_hw_work);
-+ nf_flow_table_hw_register(&flow_offload_hw);
-+
-+ return 0;
-+}
-+
-+static void __exit nf_flow_table_hw_module_exit(void)
-+{
-+ struct flow_offload_hw *offload, *next;
-+ LIST_HEAD(hw_offload_pending);
-+
-+ nf_flow_table_hw_unregister(&flow_offload_hw);
-+ cancel_work_sync(&nf_flow_offload_hw_work);
-+
-+ list_for_each_entry_safe(offload, next, &hw_offload_pending, list) {
-+ if (offload->ct)
-+ nf_conntrack_put(&offload->ct->ct_general);
-+ list_del(&offload->list);
-+ kfree(offload);
-+ }
-+}
-+
-+module_init(nf_flow_table_hw_module_init);
-+module_exit(nf_flow_table_hw_module_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
-+MODULE_ALIAS("nf-flow-table-hw");
---- a/net/netfilter/nf_tables_api.c
-+++ b/net/netfilter/nf_tables_api.c
-@@ -5758,6 +5758,13 @@ static int nf_tables_flowtable_parse_hoo
- if (err < 0)
- return err;
-
-+ for (i = 0; i < n; i++) {
-+ if (flowtable->data.flags & NF_FLOWTABLE_F_HW &&
-+ !dev_array[i]->netdev_ops->ndo_flow_offload) {
-+ return -EOPNOTSUPP;
-+ }
-+ }
-+
- ops = kcalloc(n, sizeof(struct nf_hook_ops), GFP_KERNEL);
- if (!ops)
- return -ENOMEM;
-@@ -5888,10 +5895,19 @@ static int nf_tables_newflowtable(struct
- }
-
- flowtable->data.type = type;
-+ write_pnet(&flowtable->data.ft_net, net);
-+
- err = type->init(&flowtable->data);
- if (err < 0)
- goto err3;
-
-+ if (nla[NFTA_FLOWTABLE_FLAGS]) {
-+ flowtable->data.flags =
-+ ntohl(nla_get_be32(nla[NFTA_FLOWTABLE_FLAGS]));
-+ if (flowtable->data.flags & ~NF_FLOWTABLE_F_HW)
-+ goto err4;
-+ }
-+
- err = nf_tables_flowtable_parse_hook(&ctx, nla[NFTA_FLOWTABLE_HOOK],
- flowtable);
- if (err < 0)
-@@ -6017,7 +6033,8 @@ static int nf_tables_fill_flowtable_info
- nla_put_string(skb, NFTA_FLOWTABLE_NAME, flowtable->name) ||
- nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)) ||
- nla_put_be64(skb, NFTA_FLOWTABLE_HANDLE, cpu_to_be64(flowtable->handle),
-- NFTA_FLOWTABLE_PAD))
-+ NFTA_FLOWTABLE_PAD) ||
-+ nla_put_be32(skb, NFTA_FLOWTABLE_FLAGS, htonl(flowtable->data.flags)))
- goto nla_put_failure;
-
- nest = nla_nest_start_noflag(skb, NFTA_FLOWTABLE_HOOK);
---- a/net/netfilter/nft_flow_offload.c
-+++ b/net/netfilter/nft_flow_offload.c
-@@ -128,6 +128,9 @@ static void nft_flow_offload_eval(const
- if (ret < 0)
- goto err_flow_add;
-
-+ if (flowtable->flags & NF_FLOWTABLE_F_HW)
-+ nf_flow_offload_hw_add(nft_net(pkt), flow, ct);
-+
- dst_release(route.tuple[!dir].dst);
- return;
-
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/641-netfilter-nf_flow_table-support-hw-offload-through-v.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/641-netfilter-nf_flow_table-support-hw-offload-through-v.patch
deleted file mode 100644
index d766ca9..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/641-netfilter-nf_flow_table-support-hw-offload-through-v.patch
+++ /dev/null
@@ -1,306 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Thu, 15 Mar 2018 20:46:31 +0100
-Subject: [PATCH] netfilter: nf_flow_table: support hw offload through
- virtual interfaces
-
-There are hardware offload devices that support offloading VLANs and
-PPPoE devices. Additionally, it is useful to be able to offload packets
-routed through bridge interfaces as well.
-Add support for finding the path to the offload device through these
-virtual interfaces, while collecting useful parameters for the offload
-device, like VLAN ID/protocol, PPPoE session and Ethernet MAC address.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/include/linux/netdevice.h
-+++ b/include/linux/netdevice.h
-@@ -932,6 +932,7 @@ struct tlsdev_ops;
-
-
- struct flow_offload;
-+struct flow_offload_hw_path;
-
- enum flow_offload_type {
- FLOW_OFFLOAD_ADD = 0,
-@@ -1170,8 +1171,15 @@ enum flow_offload_type {
- * int (*ndo_bridge_dellink)(struct net_device *dev, struct nlmsghdr *nlh,
- * u16 flags);
- *
-+ * int (*ndo_flow_offload_check)(struct flow_offload_hw_path *path);
-+ * For virtual devices like bridges, vlan, and pppoe, fill in the
-+ * underlying network device that can be used for offloading connections.
-+ * Return an error if offloading is not supported.
-+ *
- * int (*ndo_flow_offload)(enum flow_offload_type type,
-- * struct flow_offload *flow);
-+ * struct flow_offload *flow,
-+ * struct flow_offload_hw_path *src,
-+ * struct flow_offload_hw_path *dest);
- * Adds/deletes flow entry to/from net device flowtable.
- *
- * int (*ndo_change_carrier)(struct net_device *dev, bool new_carrier);
-@@ -1421,8 +1429,11 @@ struct net_device_ops {
- int (*ndo_bridge_dellink)(struct net_device *dev,
- struct nlmsghdr *nlh,
- u16 flags);
-+ int (*ndo_flow_offload_check)(struct flow_offload_hw_path *path);
- int (*ndo_flow_offload)(enum flow_offload_type type,
-- struct flow_offload *flow);
-+ struct flow_offload *flow,
-+ struct flow_offload_hw_path *src,
-+ struct flow_offload_hw_path *dest);
- int (*ndo_change_carrier)(struct net_device *dev,
- bool new_carrier);
- int (*ndo_get_phys_port_id)(struct net_device *dev,
---- a/include/net/netfilter/nf_flow_table.h
-+++ b/include/net/netfilter/nf_flow_table.h
-@@ -88,6 +88,21 @@ struct flow_offload {
- };
- };
-
-+#define FLOW_OFFLOAD_PATH_ETHERNET BIT(0)
-+#define FLOW_OFFLOAD_PATH_VLAN BIT(1)
-+#define FLOW_OFFLOAD_PATH_PPPOE BIT(2)
-+
-+struct flow_offload_hw_path {
-+ struct net_device *dev;
-+ u32 flags;
-+
-+ u8 eth_src[ETH_ALEN];
-+ u8 eth_dest[ETH_ALEN];
-+ u16 vlan_proto;
-+ u16 vlan_id;
-+ u16 pppoe_sid;
-+};
-+
- #define NF_FLOW_TIMEOUT (30 * HZ)
-
- struct nf_flow_route {
---- a/net/netfilter/nf_flow_table_hw.c
-+++ b/net/netfilter/nf_flow_table_hw.c
-@@ -19,48 +19,77 @@ struct flow_offload_hw {
- enum flow_offload_type type;
- struct flow_offload *flow;
- struct nf_conn *ct;
-- possible_net_t flow_hw_net;
-+
-+ struct flow_offload_hw_path src;
-+ struct flow_offload_hw_path dest;
- };
-
--static int do_flow_offload_hw(struct net *net, struct flow_offload *flow,
-- int type)
-+static void flow_offload_check_ethernet(struct flow_offload_tuple *tuple,
-+ struct dst_entry *dst,
-+ struct flow_offload_hw_path *path)
- {
-- struct net_device *indev;
-- int ret, ifindex;
-+ struct net_device *dev = path->dev;
-+ struct neighbour *n;
-
-- ifindex = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.iifidx;
-- indev = dev_get_by_index(net, ifindex);
-- if (WARN_ON(!indev))
-- return 0;
--
-- mutex_lock(&nf_flow_offload_hw_mutex);
-- ret = indev->netdev_ops->ndo_flow_offload(type, flow);
-- mutex_unlock(&nf_flow_offload_hw_mutex);
-+ if (dev->type != ARPHRD_ETHER)
-+ return;
-
-- dev_put(indev);
-+ memcpy(path->eth_src, path->dev->dev_addr, ETH_ALEN);
-+ n = dst_neigh_lookup(dst, &tuple->src_v4);
-+ if (!n)
-+ return;
-
-- return ret;
-+ memcpy(path->eth_dest, n->ha, ETH_ALEN);
-+ path->flags |= FLOW_OFFLOAD_PATH_ETHERNET;
-+ neigh_release(n);
- }
-
--static void flow_offload_hw_work_add(struct flow_offload_hw *offload)
-+static int flow_offload_check_path(struct net *net,
-+ struct flow_offload_tuple *tuple,
-+ struct dst_entry *dst,
-+ struct flow_offload_hw_path *path)
- {
-- struct net *net;
-- int ret;
-+ struct net_device *dev;
-
-- if (nf_ct_is_dying(offload->ct))
-- return;
-+ dev = dev_get_by_index_rcu(net, tuple->iifidx);
-+ if (!dev)
-+ return -ENOENT;
-+
-+ path->dev = dev;
-+ flow_offload_check_ethernet(tuple, dst, path);
-
-- net = read_pnet(&offload->flow_hw_net);
-- ret = do_flow_offload_hw(net, offload->flow, FLOW_OFFLOAD_ADD);
-- if (ret >= 0)
-- offload->flow->flags |= FLOW_OFFLOAD_HW;
-+ if (dev->netdev_ops->ndo_flow_offload_check)
-+ return dev->netdev_ops->ndo_flow_offload_check(path);
-+
-+ return 0;
- }
-
--static void flow_offload_hw_work_del(struct flow_offload_hw *offload)
-+static int do_flow_offload_hw(struct flow_offload_hw *offload)
- {
-- struct net *net = read_pnet(&offload->flow_hw_net);
-+ struct net_device *src_dev = offload->src.dev;
-+ struct net_device *dest_dev = offload->dest.dev;
-+ int ret;
-+
-+ ret = src_dev->netdev_ops->ndo_flow_offload(offload->type,
-+ offload->flow,
-+ &offload->src,
-+ &offload->dest);
-+
-+ /* restore devices in case the driver mangled them */
-+ offload->src.dev = src_dev;
-+ offload->dest.dev = dest_dev;
-
-- do_flow_offload_hw(net, offload->flow, FLOW_OFFLOAD_DEL);
-+ return ret;
-+}
-+
-+static void flow_offload_hw_free(struct flow_offload_hw *offload)
-+{
-+ dev_put(offload->src.dev);
-+ dev_put(offload->dest.dev);
-+ if (offload->ct)
-+ nf_conntrack_put(&offload->ct->ct_general);
-+ list_del(&offload->list);
-+ kfree(offload);
- }
-
- static void flow_offload_hw_work(struct work_struct *work)
-@@ -73,18 +102,22 @@ static void flow_offload_hw_work(struct
- spin_unlock_bh(&flow_offload_hw_pending_list_lock);
-
- list_for_each_entry_safe(offload, next, &hw_offload_pending, list) {
-+ mutex_lock(&nf_flow_offload_hw_mutex);
- switch (offload->type) {
- case FLOW_OFFLOAD_ADD:
-- flow_offload_hw_work_add(offload);
-+ if (nf_ct_is_dying(offload->ct))
-+ break;
-+
-+ if (do_flow_offload_hw(offload) >= 0)
-+ offload->flow->flags |= FLOW_OFFLOAD_HW;
- break;
- case FLOW_OFFLOAD_DEL:
-- flow_offload_hw_work_del(offload);
-+ do_flow_offload_hw(offload);
- break;
- }
-- if (offload->ct)
-- nf_conntrack_put(&offload->ct->ct_general);
-- list_del(&offload->list);
-- kfree(offload);
-+ mutex_unlock(&nf_flow_offload_hw_mutex);
-+
-+ flow_offload_hw_free(offload);
- }
- }
-
-@@ -97,20 +130,56 @@ static void flow_offload_queue_work(stru
- schedule_work(&nf_flow_offload_hw_work);
- }
-
-+static struct flow_offload_hw *
-+flow_offload_hw_prepare(struct net *net, struct flow_offload *flow)
-+{
-+ struct flow_offload_hw_path src = {};
-+ struct flow_offload_hw_path dest = {};
-+ struct flow_offload_tuple *tuple_s, *tuple_d;
-+ struct flow_offload_hw *offload = NULL;
-+
-+ rcu_read_lock_bh();
-+
-+ tuple_s = &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple;
-+ tuple_d = &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple;
-+
-+ if (flow_offload_check_path(net, tuple_s, tuple_d->dst_cache, &src))
-+ goto out;
-+
-+ if (flow_offload_check_path(net, tuple_d, tuple_s->dst_cache, &dest))
-+ goto out;
-+
-+ if (!src.dev->netdev_ops->ndo_flow_offload)
-+ goto out;
-+
-+ offload = kzalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC);
-+ if (!offload)
-+ goto out;
-+
-+ dev_hold(src.dev);
-+ dev_hold(dest.dev);
-+ offload->src = src;
-+ offload->dest = dest;
-+ offload->flow = flow;
-+
-+out:
-+ rcu_read_unlock_bh();
-+
-+ return offload;
-+}
-+
- static void flow_offload_hw_add(struct net *net, struct flow_offload *flow,
- struct nf_conn *ct)
- {
- struct flow_offload_hw *offload;
-
-- offload = kmalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC);
-+ offload = flow_offload_hw_prepare(net, flow);
- if (!offload)
- return;
-
- nf_conntrack_get(&ct->ct_general);
- offload->type = FLOW_OFFLOAD_ADD;
- offload->ct = ct;
-- offload->flow = flow;
-- write_pnet(&offload->flow_hw_net, net);
-
- flow_offload_queue_work(offload);
- }
-@@ -119,14 +188,11 @@ static void flow_offload_hw_del(struct n
- {
- struct flow_offload_hw *offload;
-
-- offload = kmalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC);
-+ offload = flow_offload_hw_prepare(net, flow);
- if (!offload)
- return;
-
- offload->type = FLOW_OFFLOAD_DEL;
-- offload->ct = NULL;
-- offload->flow = flow;
-- write_pnet(&offload->flow_hw_net, net);
-
- flow_offload_queue_work(offload);
- }
-@@ -153,12 +219,8 @@ static void __exit nf_flow_table_hw_modu
- nf_flow_table_hw_unregister(&flow_offload_hw);
- cancel_work_sync(&nf_flow_offload_hw_work);
-
-- list_for_each_entry_safe(offload, next, &hw_offload_pending, list) {
-- if (offload->ct)
-- nf_conntrack_put(&offload->ct->ct_general);
-- list_del(&offload->list);
-- kfree(offload);
-- }
-+ list_for_each_entry_safe(offload, next, &hw_offload_pending, list)
-+ flow_offload_hw_free(offload);
- }
-
- module_init(nf_flow_table_hw_module_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/645-netfilter-nf_flow_table-rework-hardware-offload-time.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/645-netfilter-nf_flow_table-rework-hardware-offload-time.patch
deleted file mode 100644
index f4efbcd..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/645-netfilter-nf_flow_table-rework-hardware-offload-time.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sun, 25 Mar 2018 21:10:55 +0200
-Subject: [PATCH] netfilter: nf_flow_table: rework hardware offload timeout
- handling
-
-Some offload implementations send keepalive packets + explicit
-notifications of TCP FIN/RST packets. In this case it is more convenient
-to simply let the driver update flow->timeout handling and use the
-regular flow offload gc step.
-
-For drivers that manage their own lifetime, a separate flag can be set
-to avoid gc timeouts.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/include/net/netfilter/nf_flow_table.h
-+++ b/include/net/netfilter/nf_flow_table.h
-@@ -78,6 +78,7 @@ struct flow_offload_tuple_rhash {
- #define FLOW_OFFLOAD_DYING 0x4
- #define FLOW_OFFLOAD_TEARDOWN 0x8
- #define FLOW_OFFLOAD_HW 0x10
-+#define FLOW_OFFLOAD_KEEP 0x20
-
- struct flow_offload {
- struct flow_offload_tuple_rhash tuplehash[FLOW_OFFLOAD_DIR_MAX];
---- a/net/netfilter/nf_flow_table_core.c
-+++ b/net/netfilter/nf_flow_table_core.c
-@@ -383,7 +383,7 @@ static void nf_flow_offload_gc_step(stru
- if (!teardown)
- nf_ct_offload_timeout(flow);
-
-- if (nf_flow_in_hw(flow) && !teardown)
-+ if ((flow->flags & FLOW_OFFLOAD_KEEP) && !teardown)
- return;
-
- if (nf_flow_has_expired(flow) || teardown)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/646-netfilter-nf_flow_table-rework-private-driver-data.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/646-netfilter-nf_flow_table-rework-private-driver-data.patch
deleted file mode 100644
index 235f2a3..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/646-netfilter-nf_flow_table-rework-private-driver-data.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Fri, 27 Apr 2018 14:42:14 +0200
-Subject: [PATCH] netfilter: nf_flow_table: rework private driver data
-
-Move the timeout out of the union, since it can be shared between the
-driver and the stack. Add a private pointer that the driver can use to
-point to its own data structures
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/include/net/netfilter/nf_flow_table.h
-+++ b/include/net/netfilter/nf_flow_table.h
-@@ -83,9 +83,10 @@ struct flow_offload_tuple_rhash {
- struct flow_offload {
- struct flow_offload_tuple_rhash tuplehash[FLOW_OFFLOAD_DIR_MAX];
- u32 flags;
-+ u32 timeout;
- union {
- /* Your private driver data here. */
-- u32 timeout;
-+ void *priv;
- };
- };
-
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/647-netfilter-flow-acct.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/647-netfilter-flow-acct.patch
deleted file mode 100644
index 9f7ca61..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/647-netfilter-flow-acct.patch
+++ /dev/null
@@ -1,70 +0,0 @@
---- a/include/net/netfilter/nf_flow_table.h
-+++ b/include/net/netfilter/nf_flow_table.h
-@@ -163,6 +163,8 @@ struct nf_flow_table_hw {
- int nf_flow_table_hw_register(const struct nf_flow_table_hw *offload);
- void nf_flow_table_hw_unregister(const struct nf_flow_table_hw *offload);
-
-+void nf_flow_table_acct(struct flow_offload *flow, struct sk_buff *skb, int dir);
-+
- extern struct work_struct nf_flow_offload_hw_work;
-
- #define MODULE_ALIAS_NF_FLOWTABLE(family) \
---- a/net/netfilter/nf_flow_table_core.c
-+++ b/net/netfilter/nf_flow_table_core.c
-@@ -13,6 +13,7 @@
- #include <net/netfilter/nf_conntrack_core.h>
- #include <net/netfilter/nf_conntrack_l4proto.h>
- #include <net/netfilter/nf_conntrack_tuple.h>
-+#include <net/netfilter/nf_conntrack_acct.h>
-
- struct flow_offload_entry {
- struct flow_offload flow;
-@@ -177,6 +178,22 @@ void flow_offload_free(struct flow_offlo
- }
- EXPORT_SYMBOL_GPL(flow_offload_free);
-
-+void nf_flow_table_acct(struct flow_offload *flow, struct sk_buff *skb, int dir)
-+{
-+ struct flow_offload_entry *entry;
-+ struct nf_conn_acct *acct;
-+
-+ entry = container_of(flow, struct flow_offload_entry, flow);
-+ acct = nf_conn_acct_find(entry->ct);
-+ if (acct) {
-+ struct nf_conn_counter *counter = acct->counter;
-+
-+ atomic64_inc(&counter[dir].packets);
-+ atomic64_add(skb->len, &counter[dir].bytes);
-+ }
-+}
-+EXPORT_SYMBOL_GPL(nf_flow_table_acct);
-+
- static u32 flow_offload_hash(const void *data, u32 len, u32 seed)
- {
- const struct flow_offload_tuple *tuple = data;
---- a/net/netfilter/nf_flow_table_ip.c
-+++ b/net/netfilter/nf_flow_table_ip.c
-@@ -12,6 +12,7 @@
- #include <net/ip6_route.h>
- #include <net/neighbour.h>
- #include <net/netfilter/nf_flow_table.h>
-+
- /* For layer 4 checksum field offset. */
- #include <linux/tcp.h>
- #include <linux/udp.h>
-@@ -288,6 +289,7 @@ nf_flow_offload_ip_hook(void *priv, stru
- skb->dev = outdev;
- nexthop = rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr);
- skb_dst_set_noref(skb, &rt->dst);
-+ nf_flow_table_acct(flow, skb, dir);
- neigh_xmit(NEIGH_ARP_TABLE, outdev, &nexthop, skb);
-
- return NF_STOLEN;
-@@ -518,6 +520,7 @@ nf_flow_offload_ipv6_hook(void *priv, st
- skb->dev = outdev;
- nexthop = rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6);
- skb_dst_set_noref(skb, &rt->dst);
-+ nf_flow_table_acct(flow, skb, dir);
- neigh_xmit(NEIGH_ND_TABLE, outdev, nexthop, skb);
-
- return NF_STOLEN;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/650-netfilter-add-xt_OFFLOAD-target.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/650-netfilter-add-xt_OFFLOAD-target.patch
deleted file mode 100644
index 8d9fec0..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/650-netfilter-add-xt_OFFLOAD-target.patch
+++ /dev/null
@@ -1,589 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Tue, 20 Feb 2018 15:56:02 +0100
-Subject: [PATCH] netfilter: add xt_OFFLOAD target
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
- create mode 100644 net/netfilter/xt_OFFLOAD.c
-
---- a/net/ipv4/netfilter/Kconfig
-+++ b/net/ipv4/netfilter/Kconfig
-@@ -56,8 +56,6 @@ config NF_TABLES_ARP
- help
- This option enables the ARP support for nf_tables.
-
--endif # NF_TABLES
--
- config NF_FLOW_TABLE_IPV4
- tristate "Netfilter flow table IPv4 module"
- depends on NF_FLOW_TABLE
-@@ -66,6 +64,8 @@ config NF_FLOW_TABLE_IPV4
-
- To compile it as a module, choose M here.
-
-+endif # NF_TABLES
-+
- config NF_DUP_IPV4
- tristate "Netfilter IPv4 packet duplication to alternate destination"
- depends on !NF_CONNTRACK || NF_CONNTRACK
---- a/net/ipv6/netfilter/Kconfig
-+++ b/net/ipv6/netfilter/Kconfig
-@@ -45,7 +45,6 @@ config NFT_FIB_IPV6
- multicast or blackhole.
-
- endif # NF_TABLES_IPV6
--endif # NF_TABLES
-
- config NF_FLOW_TABLE_IPV6
- tristate "Netfilter flow table IPv6 module"
-@@ -55,6 +54,8 @@ config NF_FLOW_TABLE_IPV6
-
- To compile it as a module, choose M here.
-
-+endif # NF_TABLES
-+
- config NF_DUP_IPV6
- tristate "Netfilter IPv6 packet duplication to alternate destination"
- depends on !NF_CONNTRACK || NF_CONNTRACK
---- a/net/netfilter/Kconfig
-+++ b/net/netfilter/Kconfig
-@@ -689,8 +689,6 @@ config NFT_FIB_NETDEV
-
- endif # NF_TABLES_NETDEV
-
--endif # NF_TABLES
--
- config NF_FLOW_TABLE_INET
- tristate "Netfilter flow table mixed IPv4/IPv6 module"
- depends on NF_FLOW_TABLE
-@@ -699,11 +697,12 @@ config NF_FLOW_TABLE_INET
-
- To compile it as a module, choose M here.
-
-+endif # NF_TABLES
-+
- config NF_FLOW_TABLE
- tristate "Netfilter flow table module"
- depends on NETFILTER_INGRESS
- depends on NF_CONNTRACK
-- depends on NF_TABLES
- help
- This option adds the flow table core infrastructure.
-
-@@ -992,6 +991,15 @@ config NETFILTER_XT_TARGET_NOTRACK
- depends on NETFILTER_ADVANCED
- select NETFILTER_XT_TARGET_CT
-
-+config NETFILTER_XT_TARGET_FLOWOFFLOAD
-+ tristate '"FLOWOFFLOAD" target support'
-+ depends on NF_FLOW_TABLE
-+ depends on NETFILTER_INGRESS
-+ help
-+ This option adds a `FLOWOFFLOAD' target, which uses the nf_flow_offload
-+ module to speed up processing of packets by bypassing the usual
-+ netfilter chains
-+
- config NETFILTER_XT_TARGET_RATEEST
- tristate '"RATEEST" target support'
- depends on NETFILTER_ADVANCED
---- a/net/netfilter/Makefile
-+++ b/net/netfilter/Makefile
-@@ -141,6 +141,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIF
- obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
- obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o
- obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o
-+obj-$(CONFIG_NETFILTER_XT_TARGET_FLOWOFFLOAD) += xt_FLOWOFFLOAD.o
- obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o
- obj-$(CONFIG_NETFILTER_XT_TARGET_HMARK) += xt_HMARK.o
- obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
---- /dev/null
-+++ b/net/netfilter/xt_FLOWOFFLOAD.c
-@@ -0,0 +1,427 @@
-+/*
-+ * Copyright (C) 2018 Felix Fietkau <nbd@nbd.name>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/netfilter.h>
-+#include <linux/netfilter/xt_FLOWOFFLOAD.h>
-+#include <net/ip.h>
-+#include <net/netfilter/nf_conntrack.h>
-+#include <net/netfilter/nf_conntrack_extend.h>
-+#include <net/netfilter/nf_conntrack_helper.h>
-+#include <net/netfilter/nf_flow_table.h>
-+
-+static struct nf_flowtable nf_flowtable;
-+static HLIST_HEAD(hooks);
-+static DEFINE_SPINLOCK(hooks_lock);
-+static struct delayed_work hook_work;
-+
-+struct xt_flowoffload_hook {
-+ struct hlist_node list;
-+ struct nf_hook_ops ops;
-+ struct net *net;
-+ bool registered;
-+ bool used;
-+};
-+
-+static unsigned int
-+xt_flowoffload_net_hook(void *priv, struct sk_buff *skb,
-+ const struct nf_hook_state *state)
-+{
-+ switch (skb->protocol) {
-+ case htons(ETH_P_IP):
-+ return nf_flow_offload_ip_hook(priv, skb, state);
-+ case htons(ETH_P_IPV6):
-+ return nf_flow_offload_ipv6_hook(priv, skb, state);
-+ }
-+
-+ return NF_ACCEPT;
-+}
-+
-+int nf_flow_table_iterate(struct nf_flowtable *flow_table,
-+ void (*iter)(struct flow_offload *flow, void *data),
-+ void *data);
-+
-+static int
-+xt_flowoffload_create_hook(struct net_device *dev)
-+{
-+ struct xt_flowoffload_hook *hook;
-+ struct nf_hook_ops *ops;
-+
-+ hook = kzalloc(sizeof(*hook), GFP_ATOMIC);
-+ if (!hook)
-+ return -ENOMEM;
-+
-+ ops = &hook->ops;
-+ ops->pf = NFPROTO_NETDEV;
-+ ops->hooknum = NF_NETDEV_INGRESS;
-+ ops->priority = 10;
-+ ops->priv = &nf_flowtable;
-+ ops->hook = xt_flowoffload_net_hook;
-+ ops->dev = dev;
-+
-+ hlist_add_head(&hook->list, &hooks);
-+ mod_delayed_work(system_power_efficient_wq, &hook_work, 0);
-+
-+ return 0;
-+}
-+
-+static struct xt_flowoffload_hook *
-+flow_offload_lookup_hook(struct net_device *dev)
-+{
-+ struct xt_flowoffload_hook *hook;
-+
-+ hlist_for_each_entry(hook, &hooks, list) {
-+ if (hook->ops.dev == dev)
-+ return hook;
-+ }
-+
-+ return NULL;
-+}
-+
-+static void
-+xt_flowoffload_check_device(struct net_device *dev)
-+{
-+ struct xt_flowoffload_hook *hook;
-+
-+ spin_lock_bh(&hooks_lock);
-+ hook = flow_offload_lookup_hook(dev);
-+ if (hook)
-+ hook->used = true;
-+ else
-+ xt_flowoffload_create_hook(dev);
-+ spin_unlock_bh(&hooks_lock);
-+}
-+
-+static void
-+xt_flowoffload_register_hooks(void)
-+{
-+ struct xt_flowoffload_hook *hook;
-+
-+restart:
-+ hlist_for_each_entry(hook, &hooks, list) {
-+ if (hook->registered)
-+ continue;
-+
-+ hook->registered = true;
-+ hook->net = dev_net(hook->ops.dev);
-+ spin_unlock_bh(&hooks_lock);
-+ nf_register_net_hook(hook->net, &hook->ops);
-+ spin_lock_bh(&hooks_lock);
-+ goto restart;
-+ }
-+
-+}
-+
-+static void
-+xt_flowoffload_cleanup_hooks(void)
-+{
-+ struct xt_flowoffload_hook *hook;
-+
-+restart:
-+ hlist_for_each_entry(hook, &hooks, list) {
-+ if (hook->used || !hook->registered)
-+ continue;
-+
-+ hlist_del(&hook->list);
-+ spin_unlock_bh(&hooks_lock);
-+ nf_unregister_net_hook(hook->net, &hook->ops);
-+ kfree(hook);
-+ spin_lock_bh(&hooks_lock);
-+ goto restart;
-+ }
-+
-+}
-+
-+static void
-+xt_flowoffload_check_hook(struct flow_offload *flow, void *data)
-+{
-+ struct flow_offload_tuple *tuple = &flow->tuplehash[0].tuple;
-+ struct xt_flowoffload_hook *hook;
-+ bool *found = data;
-+ struct rtable *rt = (struct rtable *)tuple->dst_cache;
-+
-+ spin_lock_bh(&hooks_lock);
-+ hlist_for_each_entry(hook, &hooks, list) {
-+ if (hook->ops.dev->ifindex != tuple->iifidx &&
-+ hook->ops.dev->ifindex != rt->dst.dev->ifindex)
-+ continue;
-+
-+ hook->used = true;
-+ *found = true;
-+ }
-+ spin_unlock_bh(&hooks_lock);
-+}
-+
-+static void
-+xt_flowoffload_hook_work(struct work_struct *work)
-+{
-+ struct xt_flowoffload_hook *hook;
-+ bool found = false;
-+ int err;
-+
-+ spin_lock_bh(&hooks_lock);
-+ xt_flowoffload_register_hooks();
-+ hlist_for_each_entry(hook, &hooks, list)
-+ hook->used = false;
-+ spin_unlock_bh(&hooks_lock);
-+
-+ err = nf_flow_table_iterate(&nf_flowtable, xt_flowoffload_check_hook,
-+ &found);
-+ if (err && err != -EAGAIN)
-+ goto out;
-+
-+ spin_lock_bh(&hooks_lock);
-+ xt_flowoffload_cleanup_hooks();
-+ spin_unlock_bh(&hooks_lock);
-+
-+out:
-+ if (found)
-+ queue_delayed_work(system_power_efficient_wq, &hook_work, HZ);
-+}
-+
-+static bool
-+xt_flowoffload_skip(struct sk_buff *skb, int family)
-+{
-+ if (skb_sec_path(skb))
-+ return true;
-+
-+ if (family == NFPROTO_IPV4) {
-+ const struct ip_options *opt = &(IPCB(skb)->opt);
-+
-+ if (unlikely(opt->optlen))
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+static struct dst_entry *
-+xt_flowoffload_dst(const struct nf_conn *ct, enum ip_conntrack_dir dir,
-+ const struct xt_action_param *par, int ifindex)
-+{
-+ struct dst_entry *dst = NULL;
-+ struct flowi fl;
-+
-+ memset(&fl, 0, sizeof(fl));
-+ switch (xt_family(par)) {
-+ case NFPROTO_IPV4:
-+ fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip;
-+ fl.u.ip4.flowi4_oif = ifindex;
-+ break;
-+ case NFPROTO_IPV6:
-+ fl.u.ip6.saddr = ct->tuplehash[dir].tuple.dst.u3.in6;
-+ fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6;
-+ fl.u.ip6.flowi6_oif = ifindex;
-+ break;
-+ }
-+
-+ nf_route(xt_net(par), &dst, &fl, false, xt_family(par));
-+
-+ return dst;
-+}
-+
-+static int
-+xt_flowoffload_route(struct sk_buff *skb, const struct nf_conn *ct,
-+ const struct xt_action_param *par,
-+ struct nf_flow_route *route, enum ip_conntrack_dir dir)
-+{
-+ struct dst_entry *this_dst, *other_dst;
-+
-+ this_dst = xt_flowoffload_dst(ct, !dir, par, xt_out(par)->ifindex);
-+ other_dst = xt_flowoffload_dst(ct, dir, par, xt_in(par)->ifindex);
-+
-+ route->tuple[dir].dst = this_dst;
-+ route->tuple[!dir].dst = other_dst;
-+
-+ if (!this_dst || !other_dst)
-+ return -ENOENT;
-+
-+ if (dst_xfrm(this_dst) || dst_xfrm(other_dst))
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
-+static unsigned int
-+flowoffload_tg(struct sk_buff *skb, const struct xt_action_param *par)
-+{
-+ const struct xt_flowoffload_target_info *info = par->targinfo;
-+ struct tcphdr _tcph, *tcph = NULL;
-+ enum ip_conntrack_info ctinfo;
-+ enum ip_conntrack_dir dir;
-+ struct nf_flow_route route;
-+ struct flow_offload *flow = NULL;
-+ struct nf_conn *ct;
-+ struct net *net;
-+
-+ if (xt_flowoffload_skip(skb, xt_family(par)))
-+ return XT_CONTINUE;
-+
-+ ct = nf_ct_get(skb, &ctinfo);
-+ if (ct == NULL)
-+ return XT_CONTINUE;
-+
-+ switch (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum) {
-+ case IPPROTO_TCP:
-+ if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED)
-+ return XT_CONTINUE;
-+
-+ tcph = skb_header_pointer(skb, par->thoff,
-+ sizeof(_tcph), &_tcph);
-+ if (unlikely(!tcph || tcph->fin || tcph->rst))
-+ return XT_CONTINUE;
-+ break;
-+ case IPPROTO_UDP:
-+ break;
-+ default:
-+ return XT_CONTINUE;
-+ }
-+
-+ if (nf_ct_ext_exist(ct, NF_CT_EXT_HELPER) ||
-+ ct->status & IPS_SEQ_ADJUST)
-+ return XT_CONTINUE;
-+
-+ if (!nf_ct_is_confirmed(ct))
-+ return XT_CONTINUE;
-+
-+ if (!xt_in(par) || !xt_out(par))
-+ return XT_CONTINUE;
-+
-+ if (test_and_set_bit(IPS_OFFLOAD_BIT, &ct->status))
-+ return XT_CONTINUE;
-+
-+ dir = CTINFO2DIR(ctinfo);
-+
-+ if (xt_flowoffload_route(skb, ct, par, &route, dir) == 0)
-+ flow = flow_offload_alloc(ct, &route);
-+
-+ dst_release(route.tuple[dir].dst);
-+ dst_release(route.tuple[!dir].dst);
-+
-+ if (!flow)
-+ goto err_flow_route;
-+
-+ if (tcph) {
-+ ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
-+ ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
-+ }
-+
-+ if (flow_offload_add(&nf_flowtable, flow) < 0)
-+ goto err_flow_add;
-+
-+ xt_flowoffload_check_device(xt_in(par));
-+ xt_flowoffload_check_device(xt_out(par));
-+
-+ net = read_pnet(&nf_flowtable.ft_net);
-+ if (!net)
-+ write_pnet(&nf_flowtable.ft_net, xt_net(par));
-+
-+ if (info->flags & XT_FLOWOFFLOAD_HW)
-+ nf_flow_offload_hw_add(xt_net(par), flow, ct);
-+
-+ return XT_CONTINUE;
-+
-+err_flow_add:
-+ flow_offload_free(flow);
-+err_flow_route:
-+ clear_bit(IPS_OFFLOAD_BIT, &ct->status);
-+ return XT_CONTINUE;
-+}
-+
-+
-+static int flowoffload_chk(const struct xt_tgchk_param *par)
-+{
-+ struct xt_flowoffload_target_info *info = par->targinfo;
-+
-+ if (info->flags & ~XT_FLOWOFFLOAD_MASK)
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
-+static struct xt_target offload_tg_reg __read_mostly = {
-+ .family = NFPROTO_UNSPEC,
-+ .name = "FLOWOFFLOAD",
-+ .revision = 0,
-+ .targetsize = sizeof(struct xt_flowoffload_target_info),
-+ .usersize = sizeof(struct xt_flowoffload_target_info),
-+ .checkentry = flowoffload_chk,
-+ .target = flowoffload_tg,
-+ .me = THIS_MODULE,
-+};
-+
-+static int xt_flowoffload_table_init(struct nf_flowtable *table)
-+{
-+ table->flags = NF_FLOWTABLE_F_HW;
-+ nf_flow_table_init(table);
-+ return 0;
-+}
-+
-+static void xt_flowoffload_table_cleanup(struct nf_flowtable *table)
-+{
-+ nf_flow_table_free(table);
-+}
-+
-+static int flow_offload_netdev_event(struct notifier_block *this,
-+ unsigned long event, void *ptr)
-+{
-+ struct xt_flowoffload_hook *hook = NULL;
-+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-+
-+ if (event != NETDEV_UNREGISTER)
-+ return NOTIFY_DONE;
-+
-+ spin_lock_bh(&hooks_lock);
-+ hook = flow_offload_lookup_hook(dev);
-+ if (hook) {
-+ hlist_del(&hook->list);
-+ }
-+ spin_unlock_bh(&hooks_lock);
-+ if (hook) {
-+ nf_unregister_net_hook(hook->net, &hook->ops);
-+ kfree(hook);
-+ }
-+
-+ nf_flow_table_cleanup(dev);
-+
-+ return NOTIFY_DONE;
-+}
-+
-+static struct notifier_block flow_offload_netdev_notifier = {
-+ .notifier_call = flow_offload_netdev_event,
-+};
-+
-+static int __init xt_flowoffload_tg_init(void)
-+{
-+ int ret;
-+
-+ register_netdevice_notifier(&flow_offload_netdev_notifier);
-+
-+ INIT_DELAYED_WORK(&hook_work, xt_flowoffload_hook_work);
-+
-+ ret = xt_flowoffload_table_init(&nf_flowtable);
-+ if (ret)
-+ return ret;
-+
-+ ret = xt_register_target(&offload_tg_reg);
-+ if (ret)
-+ xt_flowoffload_table_cleanup(&nf_flowtable);
-+
-+ return ret;
-+}
-+
-+static void __exit xt_flowoffload_tg_exit(void)
-+{
-+ xt_unregister_target(&offload_tg_reg);
-+ xt_flowoffload_table_cleanup(&nf_flowtable);
-+ unregister_netdevice_notifier(&flow_offload_netdev_notifier);
-+}
-+
-+MODULE_LICENSE("GPL");
-+module_init(xt_flowoffload_tg_init);
-+module_exit(xt_flowoffload_tg_exit);
---- a/net/netfilter/nf_flow_table_core.c
-+++ b/net/netfilter/nf_flow_table_core.c
-@@ -7,7 +7,6 @@
- #include <linux/netdevice.h>
- #include <net/ip.h>
- #include <net/ip6_route.h>
--#include <net/netfilter/nf_tables.h>
- #include <net/netfilter/nf_flow_table.h>
- #include <net/netfilter/nf_conntrack.h>
- #include <net/netfilter/nf_conntrack_core.h>
-@@ -351,8 +350,7 @@ flow_offload_lookup(struct nf_flowtable
- }
- EXPORT_SYMBOL_GPL(flow_offload_lookup);
-
--static int
--nf_flow_table_iterate(struct nf_flowtable *flow_table,
-+int nf_flow_table_iterate(struct nf_flowtable *flow_table,
- void (*iter)(struct flow_offload *flow, void *data),
- void *data)
- {
-@@ -385,6 +383,7 @@ nf_flow_table_iterate(struct nf_flowtabl
-
- return err;
- }
-+EXPORT_SYMBOL_GPL(nf_flow_table_iterate);
-
- static void nf_flow_offload_gc_step(struct flow_offload *flow, void *data)
- {
---- /dev/null
-+++ b/include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h
-@@ -0,0 +1,17 @@
-+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-+#ifndef _XT_FLOWOFFLOAD_H
-+#define _XT_FLOWOFFLOAD_H
-+
-+#include <linux/types.h>
-+
-+enum {
-+ XT_FLOWOFFLOAD_HW = 1 << 0,
-+
-+ XT_FLOWOFFLOAD_MASK = XT_FLOWOFFLOAD_HW
-+};
-+
-+struct xt_flowoffload_target_info {
-+ __u32 flags;
-+};
-+
-+#endif /* _XT_FLOWOFFLOAD_H */
---- a/include/net/netfilter/nf_flow_table.h
-+++ b/include/net/netfilter/nf_flow_table.h
-@@ -133,6 +133,10 @@ static inline void flow_offload_dead(str
- flow->flags |= FLOW_OFFLOAD_DYING;
- }
-
-+int nf_flow_table_iterate(struct nf_flowtable *flow_table,
-+ void (*iter)(struct flow_offload *flow, void *data),
-+ void *data);
-+
- int nf_flow_snat_port(const struct flow_offload *flow,
- struct sk_buff *skb, unsigned int thoff,
- u8 protocol, enum flow_offload_tuple_dir dir);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-mt7622-backport-nf-hw-offload-framework-and-upstream.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1718-v5.15-net-netfilter-add-nf-hw-offload.patch
similarity index 73%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-mt7622-backport-nf-hw-offload-framework-and-upstream.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1718-v5.15-net-netfilter-add-nf-hw-offload.patch
index 8f28900..f162e51 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-mt7622-backport-nf-hw-offload-framework-and-upstream.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1718-v5.15-net-netfilter-add-nf-hw-offload.patch
@@ -1,18 +1,9 @@
From 3a4256932000744357ba358140fd2895756060e6 Mon Sep 17 00:00:00 2001
From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
-Date: Tue, 15 Oct 2024 15:23:05 +0800
-Subject: [PATCH 01/24] mt7622 backport nf hw offload framework and upstream
- hnat plus xt-FLOWOFFLOAD update v2
+Date: Tue, 4 Jun 2024 09:14:34 +0800
+Subject: net netfilter add nf hw offload
---
- drivers/net/ethernet/mediatek/Makefile | 3 +-
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 25 +-
- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 19 +-
- drivers/net/ethernet/mediatek/mtk_ppe.c | 513 +++++++
- drivers/net/ethernet/mediatek/mtk_ppe.h | 287 ++++
- .../net/ethernet/mediatek/mtk_ppe_debugfs.c | 214 +++
- .../net/ethernet/mediatek/mtk_ppe_offload.c | 535 ++++++++
- drivers/net/ethernet/mediatek/mtk_ppe_regs.h | 144 ++
drivers/net/ppp/ppp_generic.c | 22 +
drivers/net/ppp/pppoe.c | 24 +
include/linux/netdevice.h | 60 +
@@ -47,1924 +38,11 @@
net/netfilter/nf_flow_table_ip.c | 447 +++---
net/netfilter/nf_flow_table_offload.c | 1199 +++++++++++++++++
net/netfilter/xt_FLOWOFFLOAD.c | 780 +++++++++++
- 42 files changed, 4981 insertions(+), 452 deletions(-)
- mode change 100644 => 100755 drivers/net/ethernet/mediatek/Makefile
- mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_eth_soc.c
- mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_eth_soc.h
- create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe.c
- create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe.h
- create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
- create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe_offload.c
- create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe_regs.h
+ 34 files changed, 3244 insertions(+), 499 deletions(-)
create mode 100644 include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h
create mode 100644 net/netfilter/nf_flow_table_offload.c
create mode 100644 net/netfilter/xt_FLOWOFFLOAD.c
-diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile
-old mode 100644
-new mode 100755
-index 2f14aa1..0a3b977
---- a/drivers/net/ethernet/mediatek/Makefile
-+++ b/drivers/net/ethernet/mediatek/Makefile
-@@ -4,5 +4,6 @@
- #
-
- obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o
--mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_usxgmii.o mtk_eth_path.o mtk_eth_dbg.o mtk_eth_reset.o mtk_eth_ptp.o
-+mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_usxgmii.o mtk_eth_path.o mtk_eth_dbg.o mtk_eth_reset.o mtk_eth_ptp.o \
-+ mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o
- obj-$(CONFIG_NET_MEDIATEK_HNAT) += mtk_hnat/
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-old mode 100644
-new mode 100755
-index e3040fb..088ff2d
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -4307,6 +4307,7 @@ static int mtk_open(struct net_device *dev)
- struct mtk_phylink_priv *phylink_priv = &mac->phylink_priv;
- struct device_node *phy_node;
- const char *mac_addr;
-+ u32 gdm_config = MTK_GDMA_TO_PDMA;
- u32 id = mtk_mac2xgmii_id(eth, mac->id);
- int err, i;
-
-@@ -4407,7 +4408,10 @@ static int mtk_open(struct net_device *dev)
- regmap_write(eth->sgmii->pcs[id].regmap,
- SGMSYS_QPHY_PWR_STATE_CTRL, 0);
-
-- mtk_gdm_config(eth, mac->id, MTK_GDMA_TO_PDMA);
-+ if (eth->soc->offload_version && mtk_ppe_start(ð->ppe) == 0)
-+ gdm_config = MTK_GDMA_TO_PPE;
-+
-+ mtk_gdm_config(eth, mac->id, gdm_config);
-
- return 0;
- }
-@@ -4541,6 +4545,9 @@ static int mtk_stop(struct net_device *dev)
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_HWTSTAMP))
- ptp_clock_unregister(eth->ptp_clock);
-
-+ if (eth->soc->offload_version)
-+ mtk_ppe_stop(ð->ppe);
-+
- return 0;
- }
-
-@@ -5577,6 +5584,7 @@ static const struct net_device_ops mtk_netdev_ops = {
- #ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = mtk_poll_controller,
- #endif
-+ .ndo_setup_tc = mtk_eth_setup_tc,
- };
-
- static void mux_poll(struct work_struct *work)
-@@ -6221,6 +6229,17 @@ static int mtk_probe(struct platform_device *pdev)
- goto err_free_dev;
- }
-
-+ if (eth->soc->offload_version) {
-+ err = mtk_ppe_init(ð->ppe, eth->dev,
-+ eth->base + MTK_ETH_PPE_BASE);
-+ if (err)
-+ goto err_free_dev;
-+
-+ err = mtk_eth_offload_init(eth);
-+ if (err)
-+ goto err_free_dev;
-+ }
-+
- for (i = 0; i < MTK_MAX_DEVS; i++) {
- if (!eth->netdev[i])
- continue;
-@@ -6331,6 +6350,7 @@ static const struct mtk_soc_data mt2701_data = {
- .required_clks = MT7623_CLKS_BITMAP,
- .required_pctl = true,
- .has_sram = false,
-+ .offload_version = 1,
- .rss_num = 0,
- .txrx = {
- .txd_size = sizeof(struct mtk_tx_dma),
-@@ -6351,6 +6371,7 @@ static const struct mtk_soc_data mt7621_data = {
- .required_clks = MT7621_CLKS_BITMAP,
- .required_pctl = false,
- .has_sram = false,
-+ .offload_version = 1,
- .rss_num = 0,
- .txrx = {
- .txd_size = sizeof(struct mtk_tx_dma),
-@@ -6372,6 +6393,7 @@ static const struct mtk_soc_data mt7622_data = {
- .required_clks = MT7622_CLKS_BITMAP,
- .required_pctl = false,
- .has_sram = false,
-+ .offload_version = 2,
- .rss_num = 0,
- .txrx = {
- .txd_size = sizeof(struct mtk_tx_dma),
-@@ -6392,6 +6414,7 @@ static const struct mtk_soc_data mt7623_data = {
- .required_clks = MT7623_CLKS_BITMAP,
- .required_pctl = true,
- .has_sram = false,
-+ .offload_version = 1,
- .rss_num = 0,
- .txrx = {
- .txd_size = sizeof(struct mtk_tx_dma),
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-old mode 100644
-new mode 100755
-index 02feeaf..8ca9c0c
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -16,6 +16,8 @@
- #include <linux/refcount.h>
- #include <linux/phylink.h>
- #include <linux/ptp_clock_kernel.h>
-+#include <linux/rhashtable.h>
-+#include "mtk_ppe.h"
-
- #define MTK_QDMA_PAGE_SIZE 2048
- #define MTK_MAX_RX_LENGTH 1536
-@@ -51,7 +53,8 @@
- NETIF_F_HW_VLAN_CTAG_TX | \
- NETIF_F_SG | NETIF_F_TSO | \
- NETIF_F_TSO6 | \
-- NETIF_F_IPV6_CSUM)
-+ NETIF_F_IPV6_CSUM |\
-+ NETIF_F_HW_TC)
- #define MTK_SET_FEATURES (NETIF_F_LRO | \
- NETIF_F_HW_VLAN_CTAG_RX)
- #define MTK_HW_FEATURES_MT7628 (NETIF_F_SG | NETIF_F_RXCSUM)
-@@ -149,6 +152,7 @@
- #define MTK_GDMA_UCS_EN BIT(20)
- #define MTK_GDMA_STRP_CRC BIT(16)
- #define MTK_GDMA_TO_PDMA 0x0
-+#define MTK_GDMA_TO_PPE 0x4444
- #define MTK_GDMA_DROP_ALL 0x7777
-
- /* GDM Egress Control Register */
-@@ -725,6 +729,12 @@
- #define RX_DMA_TCI(_x) ((_x) & (VLAN_PRIO_MASK | VLAN_VID_MASK))
- #define RX_DMA_VPID(_x) (((_x) >> 16) & 0xffff)
-
-+/* QDMA descriptor rxd4 */
-+#define MTK_RXD4_FOE_ENTRY GENMASK(13, 0)
-+#define MTK_RXD4_PPE_CPU_REASON GENMASK(18, 14)
-+#define MTK_RXD4_SRC_PORT GENMASK(21, 19)
-+#define MTK_RXD4_ALG GENMASK(31, 22)
-+
- /* QDMA descriptor rxd4 */
- #define RX_DMA_L4_VALID BIT(24)
- #define RX_DMA_L4_VALID_PDMA BIT(30) /* when PDMA is used */
-@@ -1967,6 +1977,7 @@ struct mtk_soc_data {
- u64 caps;
- u64 required_clks;
- bool required_pctl;
-+ u8 offload_version;
- netdev_features_t hw_features;
- bool has_sram;
- struct {
-@@ -2263,6 +2274,9 @@ struct mtk_eth {
- int ip_align;
- spinlock_t syscfg0_lock;
- struct notifier_block netdevice_notifier;
-+
-+ struct mtk_ppe ppe;
-+ struct rhashtable flow_table;
- };
-
- /* struct mtk_mac - the structure that holds the info about the MACs of the
-@@ -2348,6 +2362,9 @@ struct phylink_pcs *mtk_usxgmii_select_pcs(struct mtk_usxgmii *ss, unsigned int
- int mtk_usxgmii_init(struct mtk_eth *eth, struct device_node *r);
- int mtk_toprgu_init(struct mtk_eth *eth, struct device_node *r);
-
-+int mtk_eth_offload_init(struct mtk_eth *eth);
-+int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
-+ void *type_data);
- void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
- u32 mtk_rss_indr_table(struct mtk_rss_params *rss_params, int index);
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
-new file mode 100644
-index 0000000..8a1437b
---- /dev/null
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
-@@ -0,0 +1,513 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
-+
-+#include <linux/kernel.h>
-+#include <linux/io.h>
-+#include <linux/iopoll.h>
-+#include <linux/etherdevice.h>
-+#include <linux/platform_device.h>
-+#include "mtk_ppe.h"
-+#include "mtk_ppe_regs.h"
-+
-+static void ppe_w32(struct mtk_ppe *ppe, u32 reg, u32 val)
-+{
-+ writel(val, ppe->base + reg);
-+}
-+
-+static u32 ppe_r32(struct mtk_ppe *ppe, u32 reg)
-+{
-+ return readl(ppe->base + reg);
-+}
-+
-+static u32 ppe_m32(struct mtk_ppe *ppe, u32 reg, u32 mask, u32 set)
-+{
-+ u32 val;
-+
-+ val = ppe_r32(ppe, reg);
-+ val &= ~mask;
-+ val |= set;
-+ ppe_w32(ppe, reg, val);
-+
-+ return val;
-+}
-+
-+static u32 ppe_set(struct mtk_ppe *ppe, u32 reg, u32 val)
-+{
-+ return ppe_m32(ppe, reg, 0, val);
-+}
-+
-+static u32 ppe_clear(struct mtk_ppe *ppe, u32 reg, u32 val)
-+{
-+ return ppe_m32(ppe, reg, val, 0);
-+}
-+
-+static int mtk_ppe_wait_busy(struct mtk_ppe *ppe)
-+{
-+ int ret;
-+ u32 val;
-+
-+ ret = readl_poll_timeout(ppe->base + MTK_PPE_GLO_CFG, val,
-+ !(val & MTK_PPE_GLO_CFG_BUSY),
-+ 20, MTK_PPE_WAIT_TIMEOUT_US);
-+
-+ if (ret)
-+ dev_err(ppe->dev, "PPE table busy");
-+
-+ return ret;
-+}
-+
-+static void mtk_ppe_cache_clear(struct mtk_ppe *ppe)
-+{
-+ ppe_set(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_CLEAR);
-+ ppe_clear(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_CLEAR);
-+}
-+
-+static void mtk_ppe_cache_enable(struct mtk_ppe *ppe, bool enable)
-+{
-+ mtk_ppe_cache_clear(ppe);
-+
-+ ppe_m32(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_EN,
-+ enable * MTK_PPE_CACHE_CTL_EN);
-+}
-+
-+static u32 mtk_ppe_hash_entry(struct mtk_foe_entry *e)
-+{
-+ u32 hv1, hv2, hv3;
-+ u32 hash;
-+
-+ switch (FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, e->ib1)) {
-+ case MTK_PPE_PKT_TYPE_BRIDGE:
-+ hv1 = e->bridge.src_mac_lo;
-+ hv1 ^= ((e->bridge.src_mac_hi & 0xffff) << 16);
-+ hv2 = e->bridge.src_mac_hi >> 16;
-+ hv2 ^= e->bridge.dest_mac_lo;
-+ hv3 = e->bridge.dest_mac_hi;
-+ break;
-+ case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
-+ case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
-+ hv1 = e->ipv4.orig.ports;
-+ hv2 = e->ipv4.orig.dest_ip;
-+ hv3 = e->ipv4.orig.src_ip;
-+ break;
-+ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T:
-+ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T:
-+ hv1 = e->ipv6.src_ip[3] ^ e->ipv6.dest_ip[3];
-+ hv1 ^= e->ipv6.ports;
-+
-+ hv2 = e->ipv6.src_ip[2] ^ e->ipv6.dest_ip[2];
-+ hv2 ^= e->ipv6.dest_ip[0];
-+
-+ hv3 = e->ipv6.src_ip[1] ^ e->ipv6.dest_ip[1];
-+ hv3 ^= e->ipv6.src_ip[0];
-+ break;
-+ case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
-+ case MTK_PPE_PKT_TYPE_IPV6_6RD:
-+ default:
-+ WARN_ON_ONCE(1);
-+ return MTK_PPE_HASH_MASK;
-+ }
-+
-+ hash = (hv1 & hv2) | ((~hv1) & hv3);
-+ hash = (hash >> 24) | ((hash & 0xffffff) << 8);
-+ hash ^= hv1 ^ hv2 ^ hv3;
-+ hash ^= hash >> 16;
-+ hash <<= 1;
-+ hash &= MTK_PPE_ENTRIES - 1;
-+
-+ return hash;
-+}
-+
-+static inline struct mtk_foe_mac_info *
-+mtk_foe_entry_l2(struct mtk_foe_entry *entry)
-+{
-+ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
-+
-+ if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE)
-+ return &entry->ipv6.l2;
-+
-+ return &entry->ipv4.l2;
-+}
-+
-+static inline u32 *
-+mtk_foe_entry_ib2(struct mtk_foe_entry *entry)
-+{
-+ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
-+
-+ if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE)
-+ return &entry->ipv6.ib2;
-+
-+ return &entry->ipv4.ib2;
-+}
-+
-+int mtk_foe_entry_prepare(struct mtk_foe_entry *entry, int type, int l4proto,
-+ u8 pse_port, u8 *src_mac, u8 *dest_mac)
-+{
-+ struct mtk_foe_mac_info *l2;
-+ u32 ports_pad, val;
-+
-+ memset(entry, 0, sizeof(*entry));
-+
-+ val = FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND) |
-+ FIELD_PREP(MTK_FOE_IB1_PACKET_TYPE, type) |
-+ FIELD_PREP(MTK_FOE_IB1_UDP, l4proto == IPPROTO_UDP) |
-+ MTK_FOE_IB1_BIND_TTL |
-+ MTK_FOE_IB1_BIND_CACHE;
-+ entry->ib1 = val;
-+
-+ val = FIELD_PREP(MTK_FOE_IB2_PORT_MG, 0x3f) |
-+ FIELD_PREP(MTK_FOE_IB2_PORT_AG, 0x1f) |
-+ FIELD_PREP(MTK_FOE_IB2_DEST_PORT, pse_port);
-+
-+ if (is_multicast_ether_addr(dest_mac))
-+ val |= MTK_FOE_IB2_MULTICAST;
-+
-+ ports_pad = 0xa5a5a500 | (l4proto & 0xff);
-+ if (type == MTK_PPE_PKT_TYPE_IPV4_ROUTE)
-+ entry->ipv4.orig.ports = ports_pad;
-+ if (type == MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T)
-+ entry->ipv6.ports = ports_pad;
-+
-+ if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) {
-+ entry->ipv6.ib2 = val;
-+ l2 = &entry->ipv6.l2;
-+ } else {
-+ entry->ipv4.ib2 = val;
-+ l2 = &entry->ipv4.l2;
-+ }
-+
-+ l2->dest_mac_hi = get_unaligned_be32(dest_mac);
-+ l2->dest_mac_lo = get_unaligned_be16(dest_mac + 4);
-+ l2->src_mac_hi = get_unaligned_be32(src_mac);
-+ l2->src_mac_lo = get_unaligned_be16(src_mac + 4);
-+
-+ if (type >= MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T)
-+ l2->etype = ETH_P_IPV6;
-+ else
-+ l2->etype = ETH_P_IP;
-+
-+ return 0;
-+}
-+
-+int mtk_foe_entry_set_pse_port(struct mtk_foe_entry *entry, u8 port)
-+{
-+ u32 *ib2 = mtk_foe_entry_ib2(entry);
-+ u32 val;
-+
-+ val = *ib2;
-+ val &= ~MTK_FOE_IB2_DEST_PORT;
-+ val |= FIELD_PREP(MTK_FOE_IB2_DEST_PORT, port);
-+ *ib2 = val;
-+
-+ return 0;
-+}
-+
-+int mtk_foe_entry_set_ipv4_tuple(struct mtk_foe_entry *entry, bool egress,
-+ __be32 src_addr, __be16 src_port,
-+ __be32 dest_addr, __be16 dest_port)
-+{
-+ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
-+ struct mtk_ipv4_tuple *t;
-+
-+ switch (type) {
-+ case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
-+ if (egress) {
-+ t = &entry->ipv4.new;
-+ break;
-+ }
-+ fallthrough;
-+ case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
-+ case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
-+ t = &entry->ipv4.orig;
-+ break;
-+ case MTK_PPE_PKT_TYPE_IPV6_6RD:
-+ entry->ipv6_6rd.tunnel_src_ip = be32_to_cpu(src_addr);
-+ entry->ipv6_6rd.tunnel_dest_ip = be32_to_cpu(dest_addr);
-+ return 0;
-+ default:
-+ WARN_ON_ONCE(1);
-+ return -EINVAL;
-+ }
-+
-+ t->src_ip = be32_to_cpu(src_addr);
-+ t->dest_ip = be32_to_cpu(dest_addr);
-+
-+ if (type == MTK_PPE_PKT_TYPE_IPV4_ROUTE)
-+ return 0;
-+
-+ t->src_port = be16_to_cpu(src_port);
-+ t->dest_port = be16_to_cpu(dest_port);
-+
-+ return 0;
-+}
-+
-+int mtk_foe_entry_set_ipv6_tuple(struct mtk_foe_entry *entry,
-+ __be32 *src_addr, __be16 src_port,
-+ __be32 *dest_addr, __be16 dest_port)
-+{
-+ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
-+ u32 *src, *dest;
-+ int i;
-+
-+ switch (type) {
-+ case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
-+ src = entry->dslite.tunnel_src_ip;
-+ dest = entry->dslite.tunnel_dest_ip;
-+ break;
-+ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T:
-+ case MTK_PPE_PKT_TYPE_IPV6_6RD:
-+ entry->ipv6.src_port = be16_to_cpu(src_port);
-+ entry->ipv6.dest_port = be16_to_cpu(dest_port);
-+ fallthrough;
-+ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T:
-+ src = entry->ipv6.src_ip;
-+ dest = entry->ipv6.dest_ip;
-+ break;
-+ default:
-+ WARN_ON_ONCE(1);
-+ return -EINVAL;
-+ }
-+
-+ for (i = 0; i < 4; i++)
-+ src[i] = be32_to_cpu(src_addr[i]);
-+ for (i = 0; i < 4; i++)
-+ dest[i] = be32_to_cpu(dest_addr[i]);
-+
-+ return 0;
-+}
-+
-+int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port)
-+{
-+ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
-+
-+ l2->etype = BIT(port);
-+
-+ if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_LAYER))
-+ entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1);
-+ else
-+ l2->etype |= BIT(8);
-+
-+ entry->ib1 &= ~MTK_FOE_IB1_BIND_VLAN_TAG;
-+
-+ return 0;
-+}
-+
-+int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid)
-+{
-+ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
-+
-+ switch (FIELD_GET(MTK_FOE_IB1_BIND_VLAN_LAYER, entry->ib1)) {
-+ case 0:
-+ entry->ib1 |= MTK_FOE_IB1_BIND_VLAN_TAG |
-+ FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1);
-+ l2->vlan1 = vid;
-+ return 0;
-+ case 1:
-+ if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_TAG)) {
-+ l2->vlan1 = vid;
-+ l2->etype |= BIT(8);
-+ } else {
-+ l2->vlan2 = vid;
-+ entry->ib1 += FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1);
-+ }
-+ return 0;
-+ default:
-+ return -ENOSPC;
-+ }
-+}
-+
-+int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid)
-+{
-+ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
-+
-+ if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_LAYER) ||
-+ (entry->ib1 & MTK_FOE_IB1_BIND_VLAN_TAG))
-+ l2->etype = ETH_P_PPP_SES;
-+
-+ entry->ib1 |= MTK_FOE_IB1_BIND_PPPOE;
-+ l2->pppoe_id = sid;
-+
-+ return 0;
-+}
-+
-+static inline bool mtk_foe_entry_usable(struct mtk_foe_entry *entry)
-+{
-+ return !(entry->ib1 & MTK_FOE_IB1_STATIC) &&
-+ FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1) != MTK_FOE_STATE_BIND;
-+}
-+
-+int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
-+ u16 timestamp)
-+{
-+ struct mtk_foe_entry *hwe;
-+ u32 hash;
-+
-+ timestamp &= MTK_FOE_IB1_BIND_TIMESTAMP;
-+ entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP;
-+ entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP, timestamp);
-+
-+ hash = mtk_ppe_hash_entry(entry);
-+ hwe = &ppe->foe_table[hash];
-+ if (!mtk_foe_entry_usable(hwe)) {
-+ hwe++;
-+ hash++;
-+
-+ if (!mtk_foe_entry_usable(hwe))
-+ return -ENOSPC;
-+ }
-+
-+ memcpy(&hwe->data, &entry->data, sizeof(hwe->data));
-+ wmb();
-+ hwe->ib1 = entry->ib1;
-+
-+ dma_wmb();
-+
-+ mtk_ppe_cache_clear(ppe);
-+
-+ return hash;
-+}
-+
-+int mtk_ppe_init(struct mtk_ppe *ppe, struct device *dev, void __iomem *base)
-+{
-+ struct mtk_foe_entry *foe;
-+
-+ /* need to allocate a separate device, since it PPE DMA access is
-+ * not coherent.
-+ */
-+ ppe->base = base;
-+ ppe->dev = dev;
-+ ppe->version = eth->soc->offload_version;
-+
-+ foe = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*foe),
-+ &ppe->foe_phys, GFP_KERNEL);
-+ if (!foe)
-+ return -ENOMEM;
-+
-+ ppe->foe_table = foe;
-+
-+ mtk_ppe_debugfs_init(ppe);
-+
-+ return 0;
-+}
-+
-+static void mtk_ppe_init_foe_table(struct mtk_ppe *ppe)
-+{
-+ static const u8 skip[] = { 12, 25, 38, 51, 76, 89, 102 };
-+ int i, k;
-+
-+ memset(ppe->foe_table, 0, MTK_PPE_ENTRIES * sizeof(*ppe->foe_table));
-+
-+ if (!IS_ENABLED(CONFIG_SOC_MT7621))
-+ return;
-+
-+ /* skip all entries that cross the 1024 byte boundary */
-+ for (i = 0; i < MTK_PPE_ENTRIES; i += 128)
-+ for (k = 0; k < ARRAY_SIZE(skip); k++)
-+ ppe->foe_table[i + skip[k]].ib1 |= MTK_FOE_IB1_STATIC;
-+}
-+
-+int mtk_ppe_start(struct mtk_ppe *ppe)
-+{
-+ u32 val;
-+
-+ mtk_ppe_init_foe_table(ppe);
-+ ppe_w32(ppe, MTK_PPE_TB_BASE, ppe->foe_phys);
-+
-+ val = MTK_PPE_TB_CFG_ENTRY_80B |
-+ MTK_PPE_TB_CFG_AGE_NON_L4 |
-+ MTK_PPE_TB_CFG_AGE_UNBIND |
-+ MTK_PPE_TB_CFG_AGE_TCP |
-+ MTK_PPE_TB_CFG_AGE_UDP |
-+ MTK_PPE_TB_CFG_AGE_TCP_FIN |
-+ FIELD_PREP(MTK_PPE_TB_CFG_SEARCH_MISS,
-+ MTK_PPE_SEARCH_MISS_ACTION_FORWARD_BUILD) |
-+ FIELD_PREP(MTK_PPE_TB_CFG_KEEPALIVE,
-+ MTK_PPE_KEEPALIVE_DISABLE) |
-+ FIELD_PREP(MTK_PPE_TB_CFG_HASH_MODE, 1) |
-+ FIELD_PREP(MTK_PPE_TB_CFG_SCAN_MODE,
-+ MTK_PPE_SCAN_MODE_CHECK_AGE) |
-+ FIELD_PREP(MTK_PPE_TB_CFG_ENTRY_NUM,
-+ MTK_PPE_ENTRIES_SHIFT);
-+ ppe_w32(ppe, MTK_PPE_TB_CFG, val);
-+
-+ ppe_w32(ppe, MTK_PPE_IP_PROTO_CHK,
-+ MTK_PPE_IP_PROTO_CHK_IPV4 | MTK_PPE_IP_PROTO_CHK_IPV6);
-+
-+ mtk_ppe_cache_enable(ppe, true);
-+
-+ val = MTK_PPE_FLOW_CFG_IP4_TCP_FRAG |
-+ MTK_PPE_FLOW_CFG_IP4_UDP_FRAG |
-+ MTK_PPE_FLOW_CFG_IP6_3T_ROUTE |
-+ MTK_PPE_FLOW_CFG_IP6_5T_ROUTE |
-+ MTK_PPE_FLOW_CFG_IP6_6RD |
-+ MTK_PPE_FLOW_CFG_IP4_NAT |
-+ MTK_PPE_FLOW_CFG_IP4_NAPT |
-+ MTK_PPE_FLOW_CFG_IP4_DSLITE |
-+ MTK_PPE_FLOW_CFG_L2_BRIDGE |
-+ MTK_PPE_FLOW_CFG_IP4_NAT_FRAG;
-+ ppe_w32(ppe, MTK_PPE_FLOW_CFG, val);
-+
-+ val = FIELD_PREP(MTK_PPE_UNBIND_AGE_MIN_PACKETS, 1000) |
-+ FIELD_PREP(MTK_PPE_UNBIND_AGE_DELTA, 3);
-+ ppe_w32(ppe, MTK_PPE_UNBIND_AGE, val);
-+
-+ val = FIELD_PREP(MTK_PPE_BIND_AGE0_DELTA_UDP, 30) |
-+ FIELD_PREP(MTK_PPE_BIND_AGE0_DELTA_NON_L4, 1);
-+ ppe_w32(ppe, MTK_PPE_BIND_AGE0, val);
-+
-+ val = FIELD_PREP(MTK_PPE_BIND_AGE1_DELTA_TCP_FIN, 1) |
-+ FIELD_PREP(MTK_PPE_BIND_AGE1_DELTA_TCP, 30);
-+ ppe_w32(ppe, MTK_PPE_BIND_AGE1, val);
-+
-+ val = MTK_PPE_BIND_LIMIT0_QUARTER | MTK_PPE_BIND_LIMIT0_HALF;
-+ ppe_w32(ppe, MTK_PPE_BIND_LIMIT0, val);
-+
-+ val = MTK_PPE_BIND_LIMIT1_FULL |
-+ FIELD_PREP(MTK_PPE_BIND_LIMIT1_NON_L4, 1);
-+ ppe_w32(ppe, MTK_PPE_BIND_LIMIT1, val);
-+
-+ val = FIELD_PREP(MTK_PPE_BIND_RATE_BIND, 30) |
-+ FIELD_PREP(MTK_PPE_BIND_RATE_PREBIND, 1);
-+ ppe_w32(ppe, MTK_PPE_BIND_RATE, val);
-+
-+ /* enable PPE */
-+ val = MTK_PPE_GLO_CFG_EN |
-+ MTK_PPE_GLO_CFG_IP4_L4_CS_DROP |
-+ MTK_PPE_GLO_CFG_IP4_CS_DROP |
-+ MTK_PPE_GLO_CFG_MCAST_TB_EN |
-+ MTK_PPE_GLO_CFG_FLOW_DROP_UPDATE;
-+ ppe_w32(ppe, MTK_PPE_GLO_CFG, val);
-+
-+ ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT, 0);
-+
-+ return 0;
-+}
-+
-+int mtk_ppe_stop(struct mtk_ppe *ppe)
-+{
-+ u32 val;
-+ int i;
-+
-+ for (i = 0; i < MTK_PPE_ENTRIES; i++)
-+ ppe->foe_table[i].ib1 = FIELD_PREP(MTK_FOE_IB1_STATE,
-+ MTK_FOE_STATE_INVALID);
-+
-+ mtk_ppe_cache_enable(ppe, false);
-+
-+ /* disable aging */
-+ val = MTK_PPE_TB_CFG_AGE_NON_L4 |
-+ MTK_PPE_TB_CFG_AGE_UNBIND |
-+ MTK_PPE_TB_CFG_AGE_TCP |
-+ MTK_PPE_TB_CFG_AGE_UDP |
-+ MTK_PPE_TB_CFG_AGE_TCP_FIN |
-+ MTK_PPE_TB_CFG_SCAN_MODE;
-+ ppe_clear(ppe, MTK_PPE_TB_CFG, val);
-+
-+ if (mtk_ppe_wait_busy(ppe))
-+ return -ETIMEDOUT;
-+
-+ /* disable offload engine */
-+ ppe_clear(ppe, MTK_PPE_GLO_CFG, MTK_PPE_GLO_CFG_EN);
-+ ppe_w32(ppe, MTK_PPE_FLOW_CFG, 0);
-+
-+ return 0;
-+}
-diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
-new file mode 100644
-index 0000000..4787447
---- /dev/null
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
-@@ -0,0 +1,287 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
-+
-+#ifndef __MTK_PPE_H
-+#define __MTK_PPE_H
-+
-+#include <linux/kernel.h>
-+#include <linux/bitfield.h>
-+
-+#define MTK_ETH_PPE_BASE 0xc00
-+
-+#define MTK_PPE_ENTRIES_SHIFT 3
-+#define MTK_PPE_ENTRIES (1024 << MTK_PPE_ENTRIES_SHIFT)
-+#define MTK_PPE_HASH_MASK (MTK_PPE_ENTRIES - 1)
-+#define MTK_PPE_WAIT_TIMEOUT_US 1000000
-+
-+#define MTK_FOE_IB1_UNBIND_TIMESTAMP GENMASK(7, 0)
-+#define MTK_FOE_IB1_UNBIND_PACKETS GENMASK(23, 8)
-+#define MTK_FOE_IB1_UNBIND_PREBIND BIT(24)
-+
-+#define MTK_FOE_IB1_BIND_TIMESTAMP GENMASK(14, 0)
-+#define MTK_FOE_IB1_BIND_KEEPALIVE BIT(15)
-+#define MTK_FOE_IB1_BIND_VLAN_LAYER GENMASK(18, 16)
-+#define MTK_FOE_IB1_BIND_PPPOE BIT(19)
-+#define MTK_FOE_IB1_BIND_VLAN_TAG BIT(20)
-+#define MTK_FOE_IB1_BIND_PKT_SAMPLE BIT(21)
-+#define MTK_FOE_IB1_BIND_CACHE BIT(22)
-+#define MTK_FOE_IB1_BIND_TUNNEL_DECAP BIT(23)
-+#define MTK_FOE_IB1_BIND_TTL BIT(24)
-+
-+#define MTK_FOE_IB1_PACKET_TYPE GENMASK(27, 25)
-+#define MTK_FOE_IB1_STATE GENMASK(29, 28)
-+#define MTK_FOE_IB1_UDP BIT(30)
-+#define MTK_FOE_IB1_STATIC BIT(31)
-+
-+enum {
-+ MTK_PPE_PKT_TYPE_IPV4_HNAPT = 0,
-+ MTK_PPE_PKT_TYPE_IPV4_ROUTE = 1,
-+ MTK_PPE_PKT_TYPE_BRIDGE = 2,
-+ MTK_PPE_PKT_TYPE_IPV4_DSLITE = 3,
-+ MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T = 4,
-+ MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T = 5,
-+ MTK_PPE_PKT_TYPE_IPV6_6RD = 7,
-+};
-+
-+#define MTK_FOE_IB2_QID GENMASK(3, 0)
-+#define MTK_FOE_IB2_PSE_QOS BIT(4)
-+#define MTK_FOE_IB2_DEST_PORT GENMASK(7, 5)
-+#define MTK_FOE_IB2_MULTICAST BIT(8)
-+
-+#define MTK_FOE_IB2_WHNAT_QID2 GENMASK(13, 12)
-+#define MTK_FOE_IB2_WHNAT_DEVIDX BIT(16)
-+#define MTK_FOE_IB2_WHNAT_NAT BIT(17)
-+
-+#define MTK_FOE_IB2_PORT_MG GENMASK(17, 12)
-+
-+#define MTK_FOE_IB2_PORT_AG GENMASK(23, 18)
-+
-+#define MTK_FOE_IB2_DSCP GENMASK(31, 24)
-+
-+#define MTK_FOE_VLAN2_WHNAT_BSS GEMMASK(5, 0)
-+#define MTK_FOE_VLAN2_WHNAT_WCID GENMASK(13, 6)
-+#define MTK_FOE_VLAN2_WHNAT_RING GENMASK(15, 14)
-+
-+enum {
-+ MTK_FOE_STATE_INVALID,
-+ MTK_FOE_STATE_UNBIND,
-+ MTK_FOE_STATE_BIND,
-+ MTK_FOE_STATE_FIN
-+};
-+
-+struct mtk_foe_mac_info {
-+ u16 vlan1;
-+ u16 etype;
-+
-+ u32 dest_mac_hi;
-+
-+ u16 vlan2;
-+ u16 dest_mac_lo;
-+
-+ u32 src_mac_hi;
-+
-+ u16 pppoe_id;
-+ u16 src_mac_lo;
-+};
-+
-+struct mtk_foe_bridge {
-+ u32 dest_mac_hi;
-+
-+ u16 src_mac_lo;
-+ u16 dest_mac_lo;
-+
-+ u32 src_mac_hi;
-+
-+ u32 ib2;
-+
-+ u32 _rsv[5];
-+
-+ u32 udf_tsid;
-+ struct mtk_foe_mac_info l2;
-+};
-+
-+struct mtk_ipv4_tuple {
-+ u32 src_ip;
-+ u32 dest_ip;
-+ union {
-+ struct {
-+ u16 dest_port;
-+ u16 src_port;
-+ };
-+ struct {
-+ u8 protocol;
-+ u8 _pad[3]; /* fill with 0xa5a5a5 */
-+ };
-+ u32 ports;
-+ };
-+};
-+
-+struct mtk_foe_ipv4 {
-+ struct mtk_ipv4_tuple orig;
-+
-+ u32 ib2;
-+
-+ struct mtk_ipv4_tuple new;
-+
-+ u16 timestamp;
-+ u16 _rsv0[3];
-+
-+ u32 udf_tsid;
-+
-+ struct mtk_foe_mac_info l2;
-+};
-+
-+struct mtk_foe_ipv4_dslite {
-+ struct mtk_ipv4_tuple ip4;
-+
-+ u32 tunnel_src_ip[4];
-+ u32 tunnel_dest_ip[4];
-+
-+ u8 flow_label[3];
-+ u8 priority;
-+
-+ u32 udf_tsid;
-+
-+ u32 ib2;
-+
-+ struct mtk_foe_mac_info l2;
-+};
-+
-+struct mtk_foe_ipv6 {
-+ u32 src_ip[4];
-+ u32 dest_ip[4];
-+
-+ union {
-+ struct {
-+ u8 protocol;
-+ u8 _pad[3]; /* fill with 0xa5a5a5 */
-+ }; /* 3-tuple */
-+ struct {
-+ u16 dest_port;
-+ u16 src_port;
-+ }; /* 5-tuple */
-+ u32 ports;
-+ };
-+
-+ u32 _rsv[3];
-+
-+ u32 udf;
-+
-+ u32 ib2;
-+ struct mtk_foe_mac_info l2;
-+};
-+
-+struct mtk_foe_ipv6_6rd {
-+ u32 src_ip[4];
-+ u32 dest_ip[4];
-+ u16 dest_port;
-+ u16 src_port;
-+
-+ u32 tunnel_src_ip;
-+ u32 tunnel_dest_ip;
-+
-+ u16 hdr_csum;
-+ u8 dscp;
-+ u8 ttl;
-+
-+ u8 flag;
-+ u8 pad;
-+ u8 per_flow_6rd_id;
-+ u8 pad2;
-+
-+ u32 ib2;
-+ struct mtk_foe_mac_info l2;
-+};
-+
-+struct mtk_foe_entry {
-+ u32 ib1;
-+
-+ union {
-+ struct mtk_foe_bridge bridge;
-+ struct mtk_foe_ipv4 ipv4;
-+ struct mtk_foe_ipv4_dslite dslite;
-+ struct mtk_foe_ipv6 ipv6;
-+ struct mtk_foe_ipv6_6rd ipv6_6rd;
-+ u32 data[19];
-+ };
-+};
-+
-+enum {
-+ MTK_PPE_CPU_REASON_TTL_EXCEEDED = 0x02,
-+ MTK_PPE_CPU_REASON_OPTION_HEADER = 0x03,
-+ MTK_PPE_CPU_REASON_NO_FLOW = 0x07,
-+ MTK_PPE_CPU_REASON_IPV4_FRAG = 0x08,
-+ MTK_PPE_CPU_REASON_IPV4_DSLITE_FRAG = 0x09,
-+ MTK_PPE_CPU_REASON_IPV4_DSLITE_NO_TCP_UDP = 0x0a,
-+ MTK_PPE_CPU_REASON_IPV6_6RD_NO_TCP_UDP = 0x0b,
-+ MTK_PPE_CPU_REASON_TCP_FIN_SYN_RST = 0x0c,
-+ MTK_PPE_CPU_REASON_UN_HIT = 0x0d,
-+ MTK_PPE_CPU_REASON_HIT_UNBIND = 0x0e,
-+ MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED = 0x0f,
-+ MTK_PPE_CPU_REASON_HIT_BIND_TCP_FIN = 0x10,
-+ MTK_PPE_CPU_REASON_HIT_TTL_1 = 0x11,
-+ MTK_PPE_CPU_REASON_HIT_BIND_VLAN_VIOLATION = 0x12,
-+ MTK_PPE_CPU_REASON_KEEPALIVE_UC_OLD_HDR = 0x13,
-+ MTK_PPE_CPU_REASON_KEEPALIVE_MC_NEW_HDR = 0x14,
-+ MTK_PPE_CPU_REASON_KEEPALIVE_DUP_OLD_HDR = 0x15,
-+ MTK_PPE_CPU_REASON_HIT_BIND_FORCE_CPU = 0x16,
-+ MTK_PPE_CPU_REASON_TUNNEL_OPTION_HEADER = 0x17,
-+ MTK_PPE_CPU_REASON_MULTICAST_TO_CPU = 0x18,
-+ MTK_PPE_CPU_REASON_MULTICAST_TO_GMAC1_CPU = 0x19,
-+ MTK_PPE_CPU_REASON_HIT_PRE_BIND = 0x1a,
-+ MTK_PPE_CPU_REASON_PACKET_SAMPLING = 0x1b,
-+ MTK_PPE_CPU_REASON_EXCEED_MTU = 0x1c,
-+ MTK_PPE_CPU_REASON_PPE_BYPASS = 0x1e,
-+ MTK_PPE_CPU_REASON_INVALID = 0x1f,
-+};
-+
-+struct mtk_ppe {
-+ struct device *dev;
-+ void __iomem *base;
-+ int version;
-+
-+ struct mtk_foe_entry *foe_table;
-+ dma_addr_t foe_phys;
-+
-+ void *acct_table;
-+};
-+
-+int mtk_ppe_init(struct mtk_ppe *ppe, struct device *dev, void __iomem *base);
-+int mtk_ppe_start(struct mtk_ppe *ppe);
-+int mtk_ppe_stop(struct mtk_ppe *ppe);
-+
-+static inline void
-+mtk_foe_entry_clear(struct mtk_ppe *ppe, u16 hash)
-+{
-+ ppe->foe_table[hash].ib1 = 0;
-+ dma_wmb();
-+}
-+
-+static inline int
-+mtk_foe_entry_timestamp(struct mtk_ppe *ppe, u16 hash)
-+{
-+ u32 ib1 = READ_ONCE(ppe->foe_table[hash].ib1);
-+
-+ if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND)
-+ return -1;
-+
-+ return FIELD_GET(MTK_FOE_IB1_BIND_TIMESTAMP, ib1);
-+}
-+
-+int mtk_foe_entry_prepare(struct mtk_foe_entry *entry, int type, int l4proto,
-+ u8 pse_port, u8 *src_mac, u8 *dest_mac);
-+int mtk_foe_entry_set_pse_port(struct mtk_foe_entry *entry, u8 port);
-+int mtk_foe_entry_set_ipv4_tuple(struct mtk_foe_entry *entry, bool orig,
-+ __be32 src_addr, __be16 src_port,
-+ __be32 dest_addr, __be16 dest_port);
-+int mtk_foe_entry_set_ipv6_tuple(struct mtk_foe_entry *entry,
-+ __be32 *src_addr, __be16 src_port,
-+ __be32 *dest_addr, __be16 dest_port);
-+int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port);
-+int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid);
-+int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid);
-+int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
-+ u16 timestamp);
-+int mtk_ppe_debugfs_init(struct mtk_ppe *ppe);
-+
-+#endif
-diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
-new file mode 100644
-index 0000000..d4b4823
---- /dev/null
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
-@@ -0,0 +1,214 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
-+
-+#include <linux/kernel.h>
-+#include <linux/debugfs.h>
-+#include "mtk_eth_soc.h"
-+
-+struct mtk_flow_addr_info
-+{
-+ void *src, *dest;
-+ u16 *src_port, *dest_port;
-+ bool ipv6;
-+};
-+
-+static const char *mtk_foe_entry_state_str(int state)
-+{
-+ static const char * const state_str[] = {
-+ [MTK_FOE_STATE_INVALID] = "INV",
-+ [MTK_FOE_STATE_UNBIND] = "UNB",
-+ [MTK_FOE_STATE_BIND] = "BND",
-+ [MTK_FOE_STATE_FIN] = "FIN",
-+ };
-+
-+ if (state >= ARRAY_SIZE(state_str) || !state_str[state])
-+ return "UNK";
-+
-+ return state_str[state];
-+}
-+
-+static const char *mtk_foe_pkt_type_str(int type)
-+{
-+ static const char * const type_str[] = {
-+ [MTK_PPE_PKT_TYPE_IPV4_HNAPT] = "IPv4 5T",
-+ [MTK_PPE_PKT_TYPE_IPV4_ROUTE] = "IPv4 3T",
-+ [MTK_PPE_PKT_TYPE_BRIDGE] = "L2",
-+ [MTK_PPE_PKT_TYPE_IPV4_DSLITE] = "DS-LITE",
-+ [MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T] = "IPv6 3T",
-+ [MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T] = "IPv6 5T",
-+ [MTK_PPE_PKT_TYPE_IPV6_6RD] = "6RD",
-+ };
-+
-+ if (type >= ARRAY_SIZE(type_str) || !type_str[type])
-+ return "UNKNOWN";
-+
-+ return type_str[type];
-+}
-+
-+static void
-+mtk_print_addr(struct seq_file *m, u32 *addr, bool ipv6)
-+{
-+ u32 n_addr[4];
-+ int i;
-+
-+ if (!ipv6) {
-+ seq_printf(m, "%pI4h", addr);
-+ return;
-+ }
-+
-+ for (i = 0; i < ARRAY_SIZE(n_addr); i++)
-+ n_addr[i] = htonl(addr[i]);
-+ seq_printf(m, "%pI6", n_addr);
-+}
-+
-+static void
-+mtk_print_addr_info(struct seq_file *m, struct mtk_flow_addr_info *ai)
-+{
-+ mtk_print_addr(m, ai->src, ai->ipv6);
-+ if (ai->src_port)
-+ seq_printf(m, ":%d", *ai->src_port);
-+ seq_printf(m, "->");
-+ mtk_print_addr(m, ai->dest, ai->ipv6);
-+ if (ai->dest_port)
-+ seq_printf(m, ":%d", *ai->dest_port);
-+}
-+
-+static int
-+mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind)
-+{
-+ struct mtk_ppe *ppe = m->private;
-+ int i;
-+
-+ for (i = 0; i < MTK_PPE_ENTRIES; i++) {
-+ struct mtk_foe_entry *entry = &ppe->foe_table[i];
-+ struct mtk_foe_mac_info *l2;
-+ struct mtk_flow_addr_info ai = {};
-+ unsigned char h_source[ETH_ALEN];
-+ unsigned char h_dest[ETH_ALEN];
-+ int type, state;
-+ u32 ib2;
-+
-+
-+ state = FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1);
-+ if (!state)
-+ continue;
-+
-+ if (bind && state != MTK_FOE_STATE_BIND)
-+ continue;
-+
-+ type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
-+ seq_printf(m, "%05x %s %7s", i,
-+ mtk_foe_entry_state_str(state),
-+ mtk_foe_pkt_type_str(type));
-+
-+ switch (type) {
-+ case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
-+ case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
-+ ai.src_port = &entry->ipv4.orig.src_port;
-+ ai.dest_port = &entry->ipv4.orig.dest_port;
-+ fallthrough;
-+ case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
-+ ai.src = &entry->ipv4.orig.src_ip;
-+ ai.dest = &entry->ipv4.orig.dest_ip;
-+ break;
-+ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T:
-+ ai.src_port = &entry->ipv6.src_port;
-+ ai.dest_port = &entry->ipv6.dest_port;
-+ fallthrough;
-+ case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T:
-+ case MTK_PPE_PKT_TYPE_IPV6_6RD:
-+ ai.src = &entry->ipv6.src_ip;
-+ ai.dest = &entry->ipv6.dest_ip;
-+ ai.ipv6 = true;
-+ break;
-+ }
-+
-+ seq_printf(m, " orig=");
-+ mtk_print_addr_info(m, &ai);
-+
-+ switch (type) {
-+ case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
-+ case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
-+ ai.src_port = &entry->ipv4.new.src_port;
-+ ai.dest_port = &entry->ipv4.new.dest_port;
-+ fallthrough;
-+ case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
-+ ai.src = &entry->ipv4.new.src_ip;
-+ ai.dest = &entry->ipv4.new.dest_ip;
-+ seq_printf(m, " new=");
-+ mtk_print_addr_info(m, &ai);
-+ break;
-+ }
-+
-+ if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) {
-+ l2 = &entry->ipv6.l2;
-+ ib2 = entry->ipv6.ib2;
-+ } else {
-+ l2 = &entry->ipv4.l2;
-+ ib2 = entry->ipv4.ib2;
-+ }
-+
-+ *((__be32 *)h_source) = htonl(l2->src_mac_hi);
-+ *((__be16 *)&h_source[4]) = htons(l2->src_mac_lo);
-+ *((__be32 *)h_dest) = htonl(l2->dest_mac_hi);
-+ *((__be16 *)&h_dest[4]) = htons(l2->dest_mac_lo);
-+
-+ seq_printf(m, " eth=%pM->%pM etype=%04x"
-+ " vlan=%d,%d ib1=%08x ib2=%08x\n",
-+ h_source, h_dest, ntohs(l2->etype),
-+ l2->vlan1, l2->vlan2, entry->ib1, ib2);
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+mtk_ppe_debugfs_foe_show_all(struct seq_file *m, void *private)
-+{
-+ return mtk_ppe_debugfs_foe_show(m, private, false);
-+}
-+
-+static int
-+mtk_ppe_debugfs_foe_show_bind(struct seq_file *m, void *private)
-+{
-+ return mtk_ppe_debugfs_foe_show(m, private, true);
-+}
-+
-+static int
-+mtk_ppe_debugfs_foe_open_all(struct inode *inode, struct file *file)
-+{
-+ return single_open(file, mtk_ppe_debugfs_foe_show_all,
-+ inode->i_private);
-+}
-+
-+static int
-+mtk_ppe_debugfs_foe_open_bind(struct inode *inode, struct file *file)
-+{
-+ return single_open(file, mtk_ppe_debugfs_foe_show_bind,
-+ inode->i_private);
-+}
-+
-+int mtk_ppe_debugfs_init(struct mtk_ppe *ppe)
-+{
-+ static const struct file_operations fops_all = {
-+ .open = mtk_ppe_debugfs_foe_open_all,
-+ .read = seq_read,
-+ .llseek = seq_lseek,
-+ .release = single_release,
-+ };
-+
-+ static const struct file_operations fops_bind = {
-+ .open = mtk_ppe_debugfs_foe_open_bind,
-+ .read = seq_read,
-+ .llseek = seq_lseek,
-+ .release = single_release,
-+ };
-+
-+ struct dentry *root;
-+
-+ root = debugfs_create_dir("mtk_ppe", NULL);
-+ debugfs_create_file("entries", S_IRUGO, root, ppe, &fops_all);
-+ debugfs_create_file("bind", S_IRUGO, root, ppe, &fops_bind);
-+
-+ return 0;
-+}
-diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-new file mode 100644
-index 0000000..1380ef0
---- /dev/null
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-@@ -0,0 +1,535 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/*
-+ * Copyright (C) 2020 Felix Fietkau <nbd@nbd.name>
-+ */
-+
-+#include <linux/if_ether.h>
-+#include <linux/rhashtable.h>
-+#include <linux/ip.h>
-+#include <linux/ipv6.h>
-+#include <net/flow_offload.h>
-+#include <net/pkt_cls.h>
-+#include <net/dsa.h>
-+#include "mtk_eth_soc.h"
-+
-+struct mtk_flow_data {
-+ struct ethhdr eth;
-+
-+ union {
-+ struct {
-+ __be32 src_addr;
-+ __be32 dst_addr;
-+ } v4;
-+
-+ struct {
-+ struct in6_addr src_addr;
-+ struct in6_addr dst_addr;
-+ } v6;
-+ };
-+
-+ __be16 src_port;
-+ __be16 dst_port;
-+
-+ struct {
-+ u16 id;
-+ __be16 proto;
-+ u8 num;
-+ } vlan;
-+ struct {
-+ u16 sid;
-+ u8 num;
-+ } pppoe;
-+};
-+
-+struct mtk_flow_entry {
-+ struct rhash_head node;
-+ unsigned long cookie;
-+ u16 hash;
-+};
-+
-+static const struct rhashtable_params mtk_flow_ht_params = {
-+ .head_offset = offsetof(struct mtk_flow_entry, node),
-+ .key_offset = offsetof(struct mtk_flow_entry, cookie),
-+ .key_len = sizeof(unsigned long),
-+ .automatic_shrinking = true,
-+};
-+
-+static u32
-+mtk_eth_timestamp(struct mtk_eth *eth)
-+{
-+ return mtk_r32(eth, 0x0010) & MTK_FOE_IB1_BIND_TIMESTAMP;
-+}
-+
-+static int
-+mtk_flow_set_ipv4_addr(struct mtk_foe_entry *foe, struct mtk_flow_data *data,
-+ bool egress)
-+{
-+ return mtk_foe_entry_set_ipv4_tuple(foe, egress,
-+ data->v4.src_addr, data->src_port,
-+ data->v4.dst_addr, data->dst_port);
-+}
-+
-+static int
-+mtk_flow_set_ipv6_addr(struct mtk_foe_entry *foe, struct mtk_flow_data *data)
-+{
-+ return mtk_foe_entry_set_ipv6_tuple(foe,
-+ data->v6.src_addr.s6_addr32, data->src_port,
-+ data->v6.dst_addr.s6_addr32, data->dst_port);
-+}
-+
-+static void
-+mtk_flow_offload_mangle_eth(const struct flow_action_entry *act, void *eth)
-+{
-+ void *dest = eth + act->mangle.offset;
-+ const void *src = &act->mangle.val;
-+
-+ if (act->mangle.offset > 8)
-+ return;
-+
-+ if (act->mangle.mask == 0xffff) {
-+ src += 2;
-+ dest += 2;
-+ }
-+
-+ memcpy(dest, src, act->mangle.mask ? 2 : 4);
-+}
-+
-+
-+static int
-+mtk_flow_mangle_ports(const struct flow_action_entry *act,
-+ struct mtk_flow_data *data)
-+{
-+ u32 val = ntohl(act->mangle.val);
-+
-+ switch (act->mangle.offset) {
-+ case 0:
-+ if (act->mangle.mask == ~htonl(0xffff))
-+ data->dst_port = cpu_to_be16(val);
-+ else
-+ data->src_port = cpu_to_be16(val >> 16);
-+ break;
-+ case 2:
-+ data->dst_port = cpu_to_be16(val);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+mtk_flow_mangle_ipv4(const struct flow_action_entry *act,
-+ struct mtk_flow_data *data)
-+{
-+ __be32 *dest;
-+
-+ switch (act->mangle.offset) {
-+ case offsetof(struct iphdr, saddr):
-+ dest = &data->v4.src_addr;
-+ break;
-+ case offsetof(struct iphdr, daddr):
-+ dest = &data->v4.dst_addr;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ memcpy(dest, &act->mangle.val, sizeof(u32));
-+
-+ return 0;
-+}
-+
-+static int
-+mtk_flow_get_dsa_port(struct net_device **dev)
-+{
-+#if IS_ENABLED(CONFIG_NET_DSA)
-+ struct dsa_port *dp;
-+
-+ dp = dsa_port_from_netdev(*dev);
-+ if (IS_ERR(dp))
-+ return -ENODEV;
-+
-+ if (dp->cpu_dp->tag_ops->proto != DSA_TAG_PROTO_MTK)
-+ return -ENODEV;
-+
-+ *dev = dp->cpu_dp->master;
-+
-+ return dp->index;
-+#else
-+ return -ENODEV;
-+#endif
-+}
-+
-+static int
-+mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
-+ struct net_device *dev)
-+{
-+ int pse_port, dsa_port;
-+
-+ dsa_port = mtk_flow_get_dsa_port(&dev);
-+ if (dsa_port >= 0)
-+ mtk_foe_entry_set_dsa(foe, dsa_port);
-+
-+ if (dev == eth->netdev[0])
-+ pse_port = PSE_GDM1_PORT;
-+ else if (dev == eth->netdev[1])
-+ pse_port = PSE_GDM2_PORT;
-+ else
-+ return -EOPNOTSUPP;
-+
-+ mtk_foe_entry_set_pse_port(foe, pse_port);
-+
-+ return 0;
-+}
-+
-+static int
-+mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
-+{
-+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
-+ struct flow_action_entry *act;
-+ struct mtk_flow_data data = {};
-+ struct mtk_foe_entry foe;
-+ struct net_device *odev = NULL;
-+ struct mtk_flow_entry *entry;
-+ int offload_type = 0;
-+ u16 addr_type = 0;
-+ u32 timestamp;
-+ u8 l4proto = 0;
-+ int err = 0;
-+ int hash;
-+ int i;
-+
-+ if (rhashtable_lookup(ð->flow_table, &f->cookie, mtk_flow_ht_params))
-+ return -EEXIST;
-+
-+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_META)) {
-+ struct flow_match_meta match;
-+
-+ flow_rule_match_meta(rule, &match);
-+ } else {
-+ return -EOPNOTSUPP;
-+ }
-+
-+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
-+ struct flow_match_control match;
-+
-+ flow_rule_match_control(rule, &match);
-+ addr_type = match.key->addr_type;
-+ } else {
-+ return -EOPNOTSUPP;
-+ }
-+
-+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
-+ struct flow_match_basic match;
-+
-+ flow_rule_match_basic(rule, &match);
-+ l4proto = match.key->ip_proto;
-+ } else {
-+ return -EOPNOTSUPP;
-+ }
-+
-+ flow_action_for_each(i, act, &rule->action) {
-+ switch (act->id) {
-+ case FLOW_ACTION_MANGLE:
-+ if (act->mangle.htype == FLOW_ACT_MANGLE_HDR_TYPE_ETH)
-+ mtk_flow_offload_mangle_eth(act, &data.eth);
-+ break;
-+ case FLOW_ACTION_REDIRECT:
-+ odev = act->dev;
-+ break;
-+ case FLOW_ACTION_CSUM:
-+ break;
-+ case FLOW_ACTION_VLAN_PUSH:
-+ if (data.vlan.num == 1 ||
-+ act->vlan.proto != htons(ETH_P_8021Q))
-+ return -EOPNOTSUPP;
-+
-+ data.vlan.id = act->vlan.vid;
-+ data.vlan.proto = act->vlan.proto;
-+ data.vlan.num++;
-+ break;
-+ case FLOW_ACTION_VLAN_POP:
-+ break;
-+ case FLOW_ACTION_PPPOE_PUSH:
-+ if (data.pppoe.num == 1)
-+ return -EOPNOTSUPP;
-+
-+ data.pppoe.sid = act->pppoe.sid;
-+ data.pppoe.num++;
-+ break;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+ }
-+
-+ switch (addr_type) {
-+ case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
-+ offload_type = MTK_PPE_PKT_TYPE_IPV4_HNAPT;
-+ break;
-+ case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
-+ offload_type = MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T;
-+ break;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+
-+ if (!is_valid_ether_addr(data.eth.h_source) ||
-+ !is_valid_ether_addr(data.eth.h_dest))
-+ return -EINVAL;
-+
-+ err = mtk_foe_entry_prepare(&foe, offload_type, l4proto, 0,
-+ data.eth.h_source,
-+ data.eth.h_dest);
-+ if (err)
-+ return err;
-+
-+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
-+ struct flow_match_ports ports;
-+
-+ flow_rule_match_ports(rule, &ports);
-+ data.src_port = ports.key->src;
-+ data.dst_port = ports.key->dst;
-+ } else {
-+ return -EOPNOTSUPP;
-+ }
-+
-+ if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
-+ struct flow_match_ipv4_addrs addrs;
-+
-+ flow_rule_match_ipv4_addrs(rule, &addrs);
-+
-+ data.v4.src_addr = addrs.key->src;
-+ data.v4.dst_addr = addrs.key->dst;
-+
-+ mtk_flow_set_ipv4_addr(&foe, &data, false);
-+ }
-+
-+ if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
-+ struct flow_match_ipv6_addrs addrs;
-+
-+ flow_rule_match_ipv6_addrs(rule, &addrs);
-+
-+ data.v6.src_addr = addrs.key->src;
-+ data.v6.dst_addr = addrs.key->dst;
-+
-+ mtk_flow_set_ipv6_addr(&foe, &data);
-+ }
-+
-+ flow_action_for_each(i, act, &rule->action) {
-+ if (act->id != FLOW_ACTION_MANGLE)
-+ continue;
-+
-+ switch (act->mangle.htype) {
-+ case FLOW_ACT_MANGLE_HDR_TYPE_TCP:
-+ case FLOW_ACT_MANGLE_HDR_TYPE_UDP:
-+ err = mtk_flow_mangle_ports(act, &data);
-+ break;
-+ case FLOW_ACT_MANGLE_HDR_TYPE_IP4:
-+ err = mtk_flow_mangle_ipv4(act, &data);
-+ break;
-+ case FLOW_ACT_MANGLE_HDR_TYPE_ETH:
-+ /* handled earlier */
-+ break;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+
-+ if (err)
-+ return err;
-+ }
-+
-+ if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
-+ err = mtk_flow_set_ipv4_addr(&foe, &data, true);
-+ if (err)
-+ return err;
-+ }
-+
-+ if (data.vlan.num == 1) {
-+ if (data.vlan.proto != htons(ETH_P_8021Q))
-+ return -EOPNOTSUPP;
-+
-+ mtk_foe_entry_set_vlan(&foe, data.vlan.id);
-+ }
-+ if (data.pppoe.num == 1)
-+ mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid);
-+
-+ err = mtk_flow_set_output_device(eth, &foe, odev);
-+ if (err)
-+ return err;
-+
-+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
-+ if (!entry)
-+ return -ENOMEM;
-+
-+ entry->cookie = f->cookie;
-+ timestamp = mtk_eth_timestamp(eth);
-+ hash = mtk_foe_entry_commit(ð->ppe, &foe, timestamp);
-+ if (hash < 0) {
-+ err = hash;
-+ goto free;
-+ }
-+
-+ entry->hash = hash;
-+ err = rhashtable_insert_fast(ð->flow_table, &entry->node,
-+ mtk_flow_ht_params);
-+ if (err < 0)
-+ goto clear_flow;
-+
-+ return 0;
-+clear_flow:
-+ mtk_foe_entry_clear(ð->ppe, hash);
-+free:
-+ kfree(entry);
-+ return err;
-+}
-+
-+static int
-+mtk_flow_offload_destroy(struct mtk_eth *eth, struct flow_cls_offload *f)
-+{
-+ struct mtk_flow_entry *entry;
-+
-+ entry = rhashtable_lookup(ð->flow_table, &f->cookie,
-+ mtk_flow_ht_params);
-+ if (!entry)
-+ return -ENOENT;
-+
-+ mtk_foe_entry_clear(ð->ppe, entry->hash);
-+ rhashtable_remove_fast(ð->flow_table, &entry->node,
-+ mtk_flow_ht_params);
-+ kfree(entry);
-+
-+ return 0;
-+}
-+
-+static int
-+mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f)
-+{
-+ struct mtk_flow_entry *entry;
-+ int timestamp;
-+ u32 idle;
-+
-+ entry = rhashtable_lookup(ð->flow_table, &f->cookie,
-+ mtk_flow_ht_params);
-+ if (!entry)
-+ return -ENOENT;
-+
-+ timestamp = mtk_foe_entry_timestamp(ð->ppe, entry->hash);
-+ if (timestamp < 0)
-+ return -ETIMEDOUT;
-+
-+ idle = mtk_eth_timestamp(eth) - timestamp;
-+ f->stats.lastused = jiffies - idle * HZ;
-+
-+ return 0;
-+}
-+
-+static DEFINE_MUTEX(mtk_flow_offload_mutex);
-+
-+static int
-+mtk_eth_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv)
-+{
-+ struct flow_cls_offload *cls = type_data;
-+ struct net_device *dev = cb_priv;
-+ struct mtk_mac *mac = netdev_priv(dev);
-+ struct mtk_eth *eth = mac->hw;
-+ int err;
-+
-+ if (!tc_can_offload(dev))
-+ return -EOPNOTSUPP;
-+
-+ if (type != TC_SETUP_CLSFLOWER)
-+ return -EOPNOTSUPP;
-+
-+ mutex_lock(&mtk_flow_offload_mutex);
-+ switch (cls->command) {
-+ case FLOW_CLS_REPLACE:
-+ err = mtk_flow_offload_replace(eth, cls);
-+ break;
-+ case FLOW_CLS_DESTROY:
-+ err = mtk_flow_offload_destroy(eth, cls);
-+ break;
-+ case FLOW_CLS_STATS:
-+ err = mtk_flow_offload_stats(eth, cls);
-+ break;
-+ default:
-+ err = -EOPNOTSUPP;
-+ break;
-+ }
-+ mutex_unlock(&mtk_flow_offload_mutex);
-+
-+ return err;
-+}
-+
-+static int
-+mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f)
-+{
-+ struct mtk_mac *mac = netdev_priv(dev);
-+ struct mtk_eth *eth = mac->hw;
-+ static LIST_HEAD(block_cb_list);
-+ struct flow_block_cb *block_cb;
-+ flow_setup_cb_t *cb;
-+ int err = 0;
-+
-+ if (!eth->ppe.foe_table)
-+ return -EOPNOTSUPP;
-+
-+ if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
-+ return -EOPNOTSUPP;
-+
-+ cb = mtk_eth_setup_tc_block_cb;
-+ f->driver_block_list = &block_cb_list;
-+
-+ switch (f->command) {
-+ case FLOW_BLOCK_BIND:
-+ block_cb = flow_block_cb_lookup(f->block, cb, dev);
-+ if (block_cb) {
-+ flow_block_cb_incref(block_cb);
-+ goto unlock;
-+ }
-+ block_cb = flow_block_cb_alloc(cb, dev, dev, NULL);
-+ if (IS_ERR(block_cb)) {
-+ err = PTR_ERR(block_cb);
-+ goto unlock;
-+ }
-+
-+ flow_block_cb_add(block_cb, f);
-+ list_add_tail(&block_cb->driver_list, &block_cb_list);
-+ break;
-+ case FLOW_BLOCK_UNBIND:
-+ block_cb = flow_block_cb_lookup(f->block, cb, dev);
-+ if (!block_cb) {
-+ err = -ENOENT;
-+ goto unlock;
-+ }
-+
-+ if (flow_block_cb_decref(block_cb)) {
-+ flow_block_cb_remove(block_cb, f);
-+ list_del(&block_cb->driver_list);
-+ }
-+ break;
-+ default:
-+ err = -EOPNOTSUPP;
-+ break;
-+ }
-+
-+unlock:
-+ return err;
-+}
-+
-+int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
-+ void *type_data)
-+{
-+ if (type == TC_SETUP_FT)
-+ return mtk_eth_setup_tc_block(dev, type_data);
-+
-+ return -EOPNOTSUPP;
-+}
-+
-+int mtk_eth_offload_init(struct mtk_eth *eth)
-+{
-+ if (!eth->ppe.foe_table)
-+ return 0;
-+
-+ return rhashtable_init(ð->flow_table, &mtk_flow_ht_params);
-+}
-diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_regs.h b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
-new file mode 100644
-index 0000000..0c45ea0
---- /dev/null
-+++ b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
-@@ -0,0 +1,144 @@
-+// SPDX-License-Identifier: GPL-2.0-only
-+/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
-+
-+#ifndef __MTK_PPE_REGS_H
-+#define __MTK_PPE_REGS_H
-+
-+#define MTK_PPE_GLO_CFG 0x200
-+#define MTK_PPE_GLO_CFG_EN BIT(0)
-+#define MTK_PPE_GLO_CFG_TSID_EN BIT(1)
-+#define MTK_PPE_GLO_CFG_IP4_L4_CS_DROP BIT(2)
-+#define MTK_PPE_GLO_CFG_IP4_CS_DROP BIT(3)
-+#define MTK_PPE_GLO_CFG_TTL0_DROP BIT(4)
-+#define MTK_PPE_GLO_CFG_PPE_BSWAP BIT(5)
-+#define MTK_PPE_GLO_CFG_PSE_HASH_OFS BIT(6)
-+#define MTK_PPE_GLO_CFG_MCAST_TB_EN BIT(7)
-+#define MTK_PPE_GLO_CFG_FLOW_DROP_KA BIT(8)
-+#define MTK_PPE_GLO_CFG_FLOW_DROP_UPDATE BIT(9)
-+#define MTK_PPE_GLO_CFG_UDP_LITE_EN BIT(10)
-+#define MTK_PPE_GLO_CFG_UDP_LEN_DROP BIT(11)
-+#define MTK_PPE_GLO_CFG_MCAST_ENTRIES GNEMASK(13, 12)
-+#define MTK_PPE_GLO_CFG_BUSY BIT(31)
-+
-+#define MTK_PPE_FLOW_CFG 0x204
-+#define MTK_PPE_FLOW_CFG_IP4_TCP_FRAG BIT(6)
-+#define MTK_PPE_FLOW_CFG_IP4_UDP_FRAG BIT(7)
-+#define MTK_PPE_FLOW_CFG_IP6_3T_ROUTE BIT(8)
-+#define MTK_PPE_FLOW_CFG_IP6_5T_ROUTE BIT(9)
-+#define MTK_PPE_FLOW_CFG_IP6_6RD BIT(10)
-+#define MTK_PPE_FLOW_CFG_IP4_NAT BIT(12)
-+#define MTK_PPE_FLOW_CFG_IP4_NAPT BIT(13)
-+#define MTK_PPE_FLOW_CFG_IP4_DSLITE BIT(14)
-+#define MTK_PPE_FLOW_CFG_L2_BRIDGE BIT(15)
-+#define MTK_PPE_FLOW_CFG_IP_PROTO_BLACKLIST BIT(16)
-+#define MTK_PPE_FLOW_CFG_IP4_NAT_FRAG BIT(17)
-+#define MTK_PPE_FLOW_CFG_IP4_HASH_FLOW_LABEL BIT(18)
-+#define MTK_PPE_FLOW_CFG_IP4_HASH_GRE_KEY BIT(19)
-+#define MTK_PPE_FLOW_CFG_IP6_HASH_GRE_KEY BIT(20)
-+
-+#define MTK_PPE_IP_PROTO_CHK 0x208
-+#define MTK_PPE_IP_PROTO_CHK_IPV4 GENMASK(15, 0)
-+#define MTK_PPE_IP_PROTO_CHK_IPV6 GENMASK(31, 16)
-+
-+#define MTK_PPE_TB_CFG 0x21c
-+#define MTK_PPE_TB_CFG_ENTRY_NUM GENMASK(2, 0)
-+#define MTK_PPE_TB_CFG_ENTRY_80B BIT(3)
-+#define MTK_PPE_TB_CFG_SEARCH_MISS GENMASK(5, 4)
-+#define MTK_PPE_TB_CFG_AGE_PREBIND BIT(6)
-+#define MTK_PPE_TB_CFG_AGE_NON_L4 BIT(7)
-+#define MTK_PPE_TB_CFG_AGE_UNBIND BIT(8)
-+#define MTK_PPE_TB_CFG_AGE_TCP BIT(9)
-+#define MTK_PPE_TB_CFG_AGE_UDP BIT(10)
-+#define MTK_PPE_TB_CFG_AGE_TCP_FIN BIT(11)
-+#define MTK_PPE_TB_CFG_KEEPALIVE GENMASK(13, 12)
-+#define MTK_PPE_TB_CFG_HASH_MODE GENMASK(15, 14)
-+#define MTK_PPE_TB_CFG_SCAN_MODE GENMASK(17, 16)
-+#define MTK_PPE_TB_CFG_HASH_DEBUG GENMASK(19, 18)
-+
-+enum {
-+ MTK_PPE_SCAN_MODE_DISABLED,
-+ MTK_PPE_SCAN_MODE_CHECK_AGE,
-+ MTK_PPE_SCAN_MODE_KEEPALIVE_AGE,
-+};
-+
-+enum {
-+ MTK_PPE_KEEPALIVE_DISABLE,
-+ MTK_PPE_KEEPALIVE_UNICAST_CPU,
-+ MTK_PPE_KEEPALIVE_DUP_CPU = 3,
-+};
-+
-+enum {
-+ MTK_PPE_SEARCH_MISS_ACTION_DROP,
-+ MTK_PPE_SEARCH_MISS_ACTION_FORWARD = 2,
-+ MTK_PPE_SEARCH_MISS_ACTION_FORWARD_BUILD = 3,
-+};
-+
-+#define MTK_PPE_TB_BASE 0x220
-+
-+#define MTK_PPE_TB_USED 0x224
-+#define MTK_PPE_TB_USED_NUM GENMASK(13, 0)
-+
-+#define MTK_PPE_BIND_RATE 0x228
-+#define MTK_PPE_BIND_RATE_BIND GENMASK(15, 0)
-+#define MTK_PPE_BIND_RATE_PREBIND GENMASK(31, 16)
-+
-+#define MTK_PPE_BIND_LIMIT0 0x22c
-+#define MTK_PPE_BIND_LIMIT0_QUARTER GENMASK(13, 0)
-+#define MTK_PPE_BIND_LIMIT0_HALF GENMASK(29, 16)
-+
-+#define MTK_PPE_BIND_LIMIT1 0x230
-+#define MTK_PPE_BIND_LIMIT1_FULL GENMASK(13, 0)
-+#define MTK_PPE_BIND_LIMIT1_NON_L4 GENMASK(23, 16)
-+
-+#define MTK_PPE_KEEPALIVE 0x234
-+#define MTK_PPE_KEEPALIVE_TIME GENMASK(15, 0)
-+#define MTK_PPE_KEEPALIVE_TIME_TCP GENMASK(23, 16)
-+#define MTK_PPE_KEEPALIVE_TIME_UDP GENMASK(31, 24)
-+
-+#define MTK_PPE_UNBIND_AGE 0x238
-+#define MTK_PPE_UNBIND_AGE_MIN_PACKETS GENMASK(31, 16)
-+#define MTK_PPE_UNBIND_AGE_DELTA GENMASK(7, 0)
-+
-+#define MTK_PPE_BIND_AGE0 0x23c
-+#define MTK_PPE_BIND_AGE0_DELTA_NON_L4 GENMASK(30, 16)
-+#define MTK_PPE_BIND_AGE0_DELTA_UDP GENMASK(14, 0)
-+
-+#define MTK_PPE_BIND_AGE1 0x240
-+#define MTK_PPE_BIND_AGE1_DELTA_TCP_FIN GENMASK(30, 16)
-+#define MTK_PPE_BIND_AGE1_DELTA_TCP GENMASK(14, 0)
-+
-+#define MTK_PPE_HASH_SEED 0x244
-+
-+#define MTK_PPE_DEFAULT_CPU_PORT 0x248
-+#define MTK_PPE_DEFAULT_CPU_PORT_MASK(_n) (GENMASK(2, 0) << ((_n) * 4))
-+
-+#define MTK_PPE_MTU_DROP 0x308
-+
-+#define MTK_PPE_VLAN_MTU0 0x30c
-+#define MTK_PPE_VLAN_MTU0_NONE GENMASK(13, 0)
-+#define MTK_PPE_VLAN_MTU0_1TAG GENMASK(29, 16)
-+
-+#define MTK_PPE_VLAN_MTU1 0x310
-+#define MTK_PPE_VLAN_MTU1_2TAG GENMASK(13, 0)
-+#define MTK_PPE_VLAN_MTU1_3TAG GENMASK(29, 16)
-+
-+#define MTK_PPE_VPM_TPID 0x318
-+
-+#define MTK_PPE_CACHE_CTL 0x320
-+#define MTK_PPE_CACHE_CTL_EN BIT(0)
-+#define MTK_PPE_CACHE_CTL_LOCK_CLR BIT(4)
-+#define MTK_PPE_CACHE_CTL_REQ BIT(8)
-+#define MTK_PPE_CACHE_CTL_CLEAR BIT(9)
-+#define MTK_PPE_CACHE_CTL_CMD GENMASK(13, 12)
-+
-+#define MTK_PPE_MIB_CFG 0x334
-+#define MTK_PPE_MIB_CFG_EN BIT(0)
-+#define MTK_PPE_MIB_CFG_RD_CLR BIT(1)
-+
-+#define MTK_PPE_MIB_TB_BASE 0x338
-+
-+#define MTK_PPE_MIB_CACHE_CTL 0x350
-+#define MTK_PPE_MIB_CACHE_CTL_EN BIT(0)
-+#define MTK_PPE_MIB_CACHE_CTL_FLUSH BIT(2)
-+
-+#endif
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 76ed2d4..ec2fbd1 100644
--- a/drivers/net/ppp/ppp_generic.c
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2101-Add-trngv2-driver-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2101-Add-trngv2-driver-support.patch
index 2169d20..9b11cd0 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2101-Add-trngv2-driver-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2101-Add-trngv2-driver-support.patch
@@ -164,7 +164,7 @@
+};
+
+static const struct mtk_rng_of_data mt7986_rng_data = {
-+ .rng_version = 1,
++ .rng_version = 2,
+};
+
+static const struct mtk_rng_of_data mt7623_rng_data = {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2701-netfilter-nf_flow_table-support-hw-offload-through-v.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2701-netfilter-nf_flow_table-support-hw-offload-through-v.patch
new file mode 100644
index 0000000..eb4c823
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2701-netfilter-nf_flow_table-support-hw-offload-through-v.patch
@@ -0,0 +1,69 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 15 Mar 2018 20:46:31 +0100
+Subject: [PATCH] netfilter: nf_flow_table: support hw offload through
+ virtual interfaces
+
+There are hardware offload devices that support offloading VLANs and
+PPPoE devices. Additionally, it is useful to be able to offload packets
+routed through bridge interfaces as well.
+Add support for finding the path to the offload device through these
+virtual interfaces, while collecting useful parameters for the offload
+device, like VLAN ID/protocol, PPPoE session and Ethernet MAC address.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index 2d1aa35..b60b506 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -989,6 +989,7 @@ struct dev_ifalias {
+ struct devlink;
+ struct tlsdev_ops;
+
++struct flow_offload_hw_path;
+
+ /*
+ * This structure defines the management hooks for network devices.
+@@ -1222,6 +1223,11 @@ struct tlsdev_ops;
+ * int (*ndo_bridge_dellink)(struct net_device *dev, struct nlmsghdr *nlh,
+ * u16 flags);
+ *
++ * int (*ndo_flow_offload_check)(struct flow_offload_hw_path *path);
++ * For virtual devices like bridges, vlan, and pppoe, fill in the
++ * underlying network device that can be used for offloading connections.
++ * Return an error if offloading is not supported.
++ *
+ * int (*ndo_change_carrier)(struct net_device *dev, bool new_carrier);
+ * Called to change device carrier. Soft-devices (like dummy, team, etc)
+ * which do not represent real hardware may define this to allow their
+@@ -1471,6 +1477,7 @@ struct net_device_ops {
+ int (*ndo_bridge_dellink)(struct net_device *dev,
+ struct nlmsghdr *nlh,
+ u16 flags);
++ int (*ndo_flow_offload_check)(struct flow_offload_hw_path *path);
+ int (*ndo_change_carrier)(struct net_device *dev,
+ bool new_carrier);
+ int (*ndo_get_phys_port_id)(struct net_device *dev,
+diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
+index 7374cb2..e0c0a80 100644
+--- a/include/net/netfilter/nf_flow_table.h
++++ b/include/net/netfilter/nf_flow_table.h
+@@ -179,6 +179,17 @@ struct flow_offload {
+ struct rcu_head rcu_head;
+ };
+
++struct flow_offload_hw_path {
++ struct net_device *dev;
++ u32 flags;
++
++ u8 eth_src[ETH_ALEN];
++ u8 eth_dest[ETH_ALEN];
++ u16 vlan_proto;
++ u16 vlan_id;
++ u16 pppoe_sid;
++};
++
+ #define NF_FLOW_TIMEOUT (30 * HZ)
+ #define nf_flowtable_time_stamp (u32)jiffies
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/642-net-8021q-support-hardware-flow-table-offload.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2702-net-8021q-support-hardware-flow-table-offload.patch
similarity index 78%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/642-net-8021q-support-hardware-flow-table-offload.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2702-net-8021q-support-hardware-flow-table-offload.patch
index cfcc28a..6fa10d4 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/642-net-8021q-support-hardware-flow-table-offload.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2702-net-8021q-support-hardware-flow-table-offload.patch
@@ -7,6 +7,8 @@
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
+diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
+index c373f1d..f45abd5 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -27,6 +27,11 @@
@@ -21,8 +23,8 @@
#include "vlan.h"
#include "vlanproc.h"
#include <linux/if_vlan.h>
-@@ -747,6 +752,27 @@ static int vlan_dev_get_iflink(const str
- return real_dev->ifindex;
+@@ -791,6 +796,27 @@ static int vlan_dev_fill_forward_path(struct net_device_path_ctx *ctx,
+ return 0;
}
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
@@ -31,10 +33,10 @@
+ struct net_device *dev = path->dev;
+ struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
+
-+ if (path->flags & FLOW_OFFLOAD_PATH_VLAN)
++ if (path->flags & BIT(DEV_PATH_VLAN))
+ return -EEXIST;
+
-+ path->flags |= FLOW_OFFLOAD_PATH_VLAN;
++ path->flags |= BIT(DEV_PATH_VLAN);
+ path->vlan_proto = vlan->vlan_proto;
+ path->vlan_id = vlan->vlan_id;
+ path->dev = vlan->real_dev;
@@ -49,10 +51,10 @@
static const struct ethtool_ops vlan_ethtool_ops = {
.get_link_ksettings = vlan_ethtool_get_link_ksettings,
.get_drvinfo = vlan_ethtool_get_drvinfo,
-@@ -785,6 +811,9 @@ static const struct net_device_ops vlan_
- #endif
+@@ -830,6 +856,9 @@ static const struct net_device_ops vlan_netdev_ops = {
.ndo_fix_features = vlan_dev_fix_features,
.ndo_get_iflink = vlan_dev_get_iflink,
+ .ndo_fill_forward_path = vlan_dev_fill_forward_path,
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ .ndo_flow_offload_check = vlan_dev_flow_offload_check,
+#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/643-net-bridge-support-hardware-flow-table-offload.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2703-net-bridge-support-hardware-flow-table-offload.patch
similarity index 81%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/643-net-bridge-support-hardware-flow-table-offload.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2703-net-bridge-support-hardware-flow-table-offload.patch
index d47482d..6ec4d74 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/643-net-bridge-support-hardware-flow-table-offload.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2703-net-bridge-support-hardware-flow-table-offload.patch
@@ -7,6 +7,8 @@
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
+diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
+index 03934dd..094b2b1 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -14,6 +14,10 @@
@@ -20,7 +22,7 @@
#include <linux/uaccess.h>
#include "br_private.h"
-@@ -382,6 +386,28 @@ static const struct ethtool_ops br_ethto
+@@ -440,6 +444,28 @@ static const struct ethtool_ops br_ethtool_ops = {
.get_link = ethtool_op_get_link,
};
@@ -31,7 +33,7 @@
+ struct net_bridge *br = netdev_priv(dev);
+ struct net_bridge_fdb_entry *dst;
+
-+ if (!(path->flags & FLOW_OFFLOAD_PATH_ETHERNET))
++ if (!(path->flags & BIT(DEV_PATH_ETHERNET)))
+ return -EINVAL;
+
+ dst = br_fdb_find_rcu(br, path->eth_dest, path->vlan_id);
@@ -49,10 +51,10 @@
static const struct net_device_ops br_netdev_ops = {
.ndo_open = br_dev_open,
.ndo_stop = br_dev_stop,
-@@ -410,6 +436,9 @@ static const struct net_device_ops br_ne
- .ndo_bridge_setlink = br_setlink,
+@@ -469,6 +495,9 @@ static const struct net_device_ops br_netdev_ops = {
.ndo_bridge_dellink = br_dellink,
.ndo_features_check = passthru_features_check,
+ .ndo_fill_forward_path = br_fill_forward_path,
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ .ndo_flow_offload_check = br_flow_offload_check,
+#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/644-net-pppoe-support-hardware-flow-table-offload.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2704-net-pppoe-support-hardware-flow-table-offload.patch
similarity index 76%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/644-net-pppoe-support-hardware-flow-table-offload.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2704-net-pppoe-support-hardware-flow-table-offload.patch
index b09b3bc..d287e52 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/644-net-pppoe-support-hardware-flow-table-offload.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2704-net-pppoe-support-hardware-flow-table-offload.patch
@@ -7,6 +7,8 @@
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
+diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
+index ec2fbd1..f361b52 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -53,6 +53,11 @@
@@ -21,8 +23,8 @@
#define PPP_VERSION "2.4.2"
/*
-@@ -1378,12 +1383,37 @@ static void ppp_dev_priv_destructor(stru
- ppp_destroy_interface(ppp);
+@@ -1416,6 +1421,28 @@ static int ppp_fill_forward_path(struct net_device_path_ctx *ctx,
+ return chan->ops->fill_forward_path(ctx, path, chan);
}
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
@@ -50,15 +52,18 @@
static const struct net_device_ops ppp_netdev_ops = {
.ndo_init = ppp_dev_init,
.ndo_uninit = ppp_dev_uninit,
- .ndo_start_xmit = ppp_start_xmit,
+@@ -1423,6 +1450,9 @@ static const struct net_device_ops ppp_netdev_ops = {
.ndo_do_ioctl = ppp_net_ioctl,
.ndo_get_stats64 = ppp_get_stats64,
+ .ndo_fill_forward_path = ppp_fill_forward_path,
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ .ndo_flow_offload_check = ppp_flow_offload_check,
+#endif
};
static struct device_type ppp_type = {
+diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
+index 7a8c246..1018464 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -73,6 +73,11 @@
@@ -73,8 +78,8 @@
#include <linux/nsproxy.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
-@@ -974,8 +979,36 @@ static int pppoe_xmit(struct ppp_channel
- return __pppoe_xmit(sk, skb);
+@@ -997,9 +1002,37 @@ static int pppoe_fill_forward_path(struct net_device_path_ctx *ctx,
+ return 0;
}
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
@@ -90,7 +95,7 @@
+ return -ENODEV;
+
+ path->dev = po->pppoe_dev;
-+ path->flags |= FLOW_OFFLOAD_PATH_PPPOE;
++ path->flags |= BIT(DEV_PATH_PPPOE);
+ memcpy(path->eth_src, po->pppoe_dev->dev_addr, ETH_ALEN);
+ memcpy(path->eth_dest, po->pppoe_pa.remote, ETH_ALEN);
+ path->pppoe_sid = be16_to_cpu(po->num);
@@ -104,19 +109,21 @@
+
static const struct ppp_channel_ops pppoe_chan_ops = {
.start_xmit = pppoe_xmit,
+ .fill_forward_path = pppoe_fill_forward_path,
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ .flow_offload_check = pppoe_flow_offload_check,
+#endif
};
static int pppoe_recvmsg(struct socket *sock, struct msghdr *m,
+diff --git a/include/linux/ppp_channel.h b/include/linux/ppp_channel.h
+index 91f9a92..4a1729b 100644
--- a/include/linux/ppp_channel.h
+++ b/include/linux/ppp_channel.h
-@@ -28,6 +28,10 @@ struct ppp_channel_ops {
- int (*start_xmit)(struct ppp_channel *, struct sk_buff *);
- /* Handle an ioctl call that has come in via /dev/ppp. */
- int (*ioctl)(struct ppp_channel *, unsigned int, unsigned long);
-+
+@@ -31,6 +31,9 @@ struct ppp_channel_ops {
+ int (*fill_forward_path)(struct net_device_path_ctx *,
+ struct net_device_path *,
+ const struct ppp_channel *);
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ int (*flow_offload_check)(struct ppp_channel *, struct flow_offload_hw_path *);
+#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/647-net-dsa-support-hardware-flow-table-offload.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2705-net-dsa-support-hardware-flow-table-offload.patch
similarity index 71%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/647-net-dsa-support-hardware-flow-table-offload.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2705-net-dsa-support-hardware-flow-table-offload.patch
index ff41a17..54fd0a4 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/647-net-dsa-support-hardware-flow-table-offload.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2705-net-dsa-support-hardware-flow-table-offload.patch
@@ -7,17 +7,11 @@
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
+diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
+index e0c0a80..a1b4ab5 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
-@@ -93,6 +93,7 @@ struct flow_offload {
- #define FLOW_OFFLOAD_PATH_ETHERNET BIT(0)
- #define FLOW_OFFLOAD_PATH_VLAN BIT(1)
- #define FLOW_OFFLOAD_PATH_PPPOE BIT(2)
-+#define FLOW_OFFLOAD_PATH_DSA BIT(3)
-
- struct flow_offload_hw_path {
- struct net_device *dev;
-@@ -103,6 +104,7 @@ struct flow_offload_hw_path {
+@@ -188,6 +188,7 @@ struct flow_offload_hw_path {
u16 vlan_proto;
u16 vlan_id;
u16 pppoe_sid;
@@ -25,6 +19,8 @@
};
#define NF_FLOW_TIMEOUT (30 * HZ)
+diff --git a/net/dsa/slave.c b/net/dsa/slave.c
+index 2ea9ec1..eab4e4a 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -19,6 +19,10 @@
@@ -38,8 +34,8 @@
#include "dsa_priv.h"
-@@ -1224,6 +1228,27 @@ static struct devlink_port *dsa_slave_ge
- return dp->ds->devlink ? &dp->devlink_port : NULL;
+@@ -1257,6 +1261,27 @@ static int dsa_slave_fill_forward_path(struct net_device_path_ctx *ctx,
+ return 0;
}
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
@@ -48,13 +44,13 @@
+ struct net_device *dev = path->dev;
+ struct dsa_port *dp;
+
-+ if (!(path->flags & FLOW_OFFLOAD_PATH_ETHERNET))
++ if (!(path->flags & BIT(DEV_PATH_ETHERNET)))
+ return -EINVAL;
+
+ dp = dsa_slave_to_port(dev);
+ path->dsa_port = dp->index;
+ path->dev = dsa_slave_to_master(dev);
-+ path->flags |= FLOW_OFFLOAD_PATH_DSA;
++ path->flags |= BIT(DEV_PATH_DSA);
+
+ if (path->dev->netdev_ops->ndo_flow_offload_check)
+ return path->dev->netdev_ops->ndo_flow_offload_check(path);
@@ -66,10 +62,10 @@
static const struct net_device_ops dsa_slave_netdev_ops = {
.ndo_open = dsa_slave_open,
.ndo_stop = dsa_slave_close,
-@@ -1248,6 +1273,9 @@ static const struct net_device_ops dsa_s
- .ndo_vlan_rx_add_vid = dsa_slave_vlan_rx_add_vid,
+@@ -1282,6 +1307,9 @@ static const struct net_device_ops dsa_slave_netdev_ops = {
.ndo_vlan_rx_kill_vid = dsa_slave_vlan_rx_kill_vid,
.ndo_get_devlink_port = dsa_slave_get_devlink_port,
+ .ndo_fill_forward_path = dsa_slave_fill_forward_path,
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ .ndo_flow_offload_check = dsa_flow_offload_check,
+#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-2708-mtkhnat-add-support-for-virtual-interface-acceleration.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2708-mtkhnat-add-support-for-virtual-interface-acceleration.patch
similarity index 76%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-2708-mtkhnat-add-support-for-virtual-interface-acceleration.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2708-mtkhnat-add-support-for-virtual-interface-acceleration.patch
index 4d21ebd..8cc6f3d 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-2708-mtkhnat-add-support-for-virtual-interface-acceleration.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2708-mtkhnat-add-support-for-virtual-interface-acceleration.patch
@@ -5,22 +5,31 @@
[networking][999-2708-mtkhnat-add-support-for-virtual-interface-acceleration.patch]
---
- include/net/netfilter/nf_flow_table.h | 3 +++
+ include/linux/netdevice.h | 1 +
+ include/net/netfilter/nf_flow_table.h | 1 +
net/8021q/vlan_dev.c | 1 +
net/ipv6/ip6_tunnel.c | 24 ++++++++++++++++++++++++
net/ipv6/sit.c | 24 ++++++++++++++++++++++++
- 4 files changed, 52 insertions(+)
+ 5 files changed, 51 insertions(+)
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index b60b506..c30952f 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -849,6 +849,8 @@ enum net_device_path_type {
+ DEV_PATH_BRIDGE,
+ DEV_PATH_PPPOE,
+ DEV_PATH_DSA,
++ DEV_PATH_DSLITE,
++ DEV_PATH_6RD,
+ };
+
+ struct net_device_path {
diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
-index 16dbf5461..4cb73a7cb 100644
+index a1b4ab5..7a2945e 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
-@@ -94,9 +94,12 @@ struct flow_offload {
- #define FLOW_OFFLOAD_PATH_VLAN BIT(1)
- #define FLOW_OFFLOAD_PATH_PPPOE BIT(2)
- #define FLOW_OFFLOAD_PATH_DSA BIT(3)
-+#define FLOW_OFFLOAD_PATH_DSLITE BIT(4)
-+#define FLOW_OFFLOAD_PATH_6RD BIT(5)
+@@ -181,6 +181,7 @@ struct flow_offload {
struct flow_offload_hw_path {
struct net_device *dev;
@@ -29,11 +38,11 @@
u8 eth_src[ETH_ALEN];
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
-index f973bec77..dbb3cea5c 100644
+index f45abd5..db5867d 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
-@@ -764,6 +764,7 @@ static int vlan_dev_flow_offload_check(struct flow_offload_hw_path *path)
- path->flags |= FLOW_OFFLOAD_PATH_VLAN;
+@@ -808,6 +808,7 @@ static int vlan_dev_flow_offload_check(struct flow_offload_hw_path *path)
+ path->flags |= BIT(DEV_PATH_VLAN);
path->vlan_proto = vlan->vlan_proto;
path->vlan_id = vlan->vlan_id;
+ path->virt_dev = dev;
@@ -41,7 +50,7 @@
if (vlan->real_dev->netdev_ops->ndo_flow_offload_check)
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
-index 71ef26e60..f8302fdd5 100644
+index 2e8a528..0bf25b0 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -57,6 +57,11 @@
@@ -66,10 +75,10 @@
+ struct net_device *dev = path->dev;
+ struct ip6_tnl *tnl = netdev_priv(dev);
+
-+ if (path->flags & FLOW_OFFLOAD_PATH_DSLITE)
++ if (path->flags & BIT(DEV_PATH_DSLITE))
+ return -EEXIST;
+
-+ path->flags |= FLOW_OFFLOAD_PATH_DSLITE;
++ path->flags |= BIT(DEV_PATH_DSLITE);
+ path->dev = tnl->dev;
+
+ return 0;
@@ -90,7 +99,7 @@
#define IPXIPX_FEATURES (NETIF_F_SG | \
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
-index 117960895..0844a95e3 100644
+index 8d704ea..c50bbef 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -52,6 +52,11 @@
@@ -105,7 +114,7 @@
/*
This version of net/ipv6/sit.c is cloned of net/ipv4/ip_gre.c
-@@ -1342,6 +1347,22 @@ done:
+@@ -1344,6 +1349,22 @@ ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return err;
}
@@ -115,10 +124,10 @@
+ struct net_device *dev = path->dev;
+ struct ip_tunnel *tnl = netdev_priv(dev);
+
-+ if (path->flags & FLOW_OFFLOAD_PATH_6RD)
++ if (path->flags & BIT(DEV_PATH_6RD))
+ return -EEXIST;
+
-+ path->flags |= FLOW_OFFLOAD_PATH_6RD;
++ path->flags |= BIT(DEV_PATH_6RD);
+ path->dev = tnl->dev;
+
+ return 0;
@@ -128,7 +137,7 @@
static const struct net_device_ops ipip6_netdev_ops = {
.ndo_init = ipip6_tunnel_init,
.ndo_uninit = ipip6_tunnel_uninit,
-@@ -1349,6 +1370,9 @@ static const struct net_device_ops ipip6_netdev_ops = {
+@@ -1351,6 +1372,9 @@ static const struct net_device_ops ipip6_netdev_ops = {
.ndo_do_ioctl = ipip6_tunnel_ioctl,
.ndo_get_stats64 = ip_tunnel_get_stats64,
.ndo_get_iflink = ip_tunnel_get_iflink,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-2726-mtkhnat-tnl-interface-offload-check.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2726-mtkhnat-tnl-interface-offload-check.patch
similarity index 70%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-2726-mtkhnat-tnl-interface-offload-check.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2726-mtkhnat-tnl-interface-offload-check.patch
index e94185f..5f8bf62 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-2726-mtkhnat-tnl-interface-offload-check.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2726-mtkhnat-tnl-interface-offload-check.patch
@@ -1,13 +1,17 @@
---- a/include/net/netfilter/nf_flow_table.h
-+++ b/include/net/netfilter/nf_flow_table.h
-@@ -96,6 +96,7 @@ struct flow_offload {
- #define FLOW_OFFLOAD_PATH_DSA BIT(3)
- #define FLOW_OFFLOAD_PATH_DSLITE BIT(4)
- #define FLOW_OFFLOAD_PATH_6RD BIT(5)
-+#define FLOW_OFFLOAD_PATH_TNL BIT(6)
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index c30952f..6c0860b 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -851,6 +851,7 @@ enum net_device_path_type {
+ DEV_PATH_DSA,
+ DEV_PATH_DSLITE,
+ DEV_PATH_6RD,
++ DEV_PATH_TNL,
+ };
- struct flow_offload_hw_path {
- struct net_device *dev;
+ struct net_device_path {
+diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
+index 7d3c782..d7a5a9a 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -89,6 +89,7 @@
@@ -33,7 +37,7 @@
};
static const struct proto_ops pppol2tp_ops;
-@@ -335,6 +341,26 @@ error:
+@@ -335,6 +341,26 @@ static int pppol2tp_sendmsg(struct socket *sock, struct msghdr *m,
return error;
}
@@ -44,14 +48,14 @@
+ struct sock *sk = (struct sock *)chan->private;
+ struct l2tp_session *session;
+
-+ if (path->flags & FLOW_OFFLOAD_PATH_TNL)
++ if (path->flags & BIT(DEV_PATH_TNL))
+ return -EEXIST;
+
+ session = pppol2tp_sock_to_session(sk);
+ if (!session)
+ return -EINVAL;
+
-+ path->flags |= FLOW_OFFLOAD_PATH_TNL;
++ path->flags |= BIT(DEV_PATH_TNL);
+
+ return 0;
+}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
index 47dfb49..a4ede55 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
@@ -57,6 +57,7 @@
file://999-1715-v6.2-net-dsa-add-set-queue-mapping.patch \
file://999-1716-v6.6-net-phy-add-phylink-pcs_enable-and-pcs_disable.patch;apply=no \
file://999-1717-v5.12-net-phy-sfp-add-debugfs-support.patch \
+ file://999-1718-v5.15-net-netfilter-add-nf-hw-offload.patch \
file://999-1719-v6.2-net-ptp-introduce-adjust-by-scaled-ppm.patch \
file://999-1750-v5.18-net-macsec-get-ready-to-backport-from-5-18.patch \
file://999-1751-01-v5.18-net-macsec-move-some-definitions-in-a-dedicated-header.patch \
@@ -188,10 +189,16 @@
file://999-2621-xHCI-MT7986-USB-2.0-USBIF-compliance-toolkit.patch \
file://999-2622-usb-add-embedded-Host-feature-support.patch \
file://999-2700-netfilter_optional_tcp_window_check.patch \
+ file://999-2701-netfilter-nf_flow_table-support-hw-offload-through-v.patch \
+ file://999-2702-net-8021q-support-hardware-flow-table-offload.patch \
+ file://999-2703-net-bridge-support-hardware-flow-table-offload.patch \
file://999-2704-en8811h-2p5gphy-support.patch \
+ file://999-2704-net-pppoe-support-hardware-flow-table-offload.patch \
file://999-2705-hwnat_Kconfig_Makefile.patch \
+ file://999-2705-net-dsa-support-hardware-flow-table-offload.patch \
file://999-2706-crypto-add-eip197-inside-secure-support.patch \
file://999-2707-mtkhnat-ipv6-fix-pskb-expand-head-limitation.patch \
+ file://999-2708-mtkhnat-add-support-for-virtual-interface-acceleration.patch \
file://999-2709-fix-race-inside-napi-enable.patch \
file://999-2710-net-make-napi-disable-symmetric-with-enable.patch \
file://999-2711-net-fix-premature-exit-from-napi-state-polling-in-napi-disable-v2.patch \
@@ -207,6 +214,7 @@
file://999-2723-dt-bindings-phy-Add-PHY_TYPE_XPCS-definition.patch \
file://999-2724-dt-bindings-phy-Add-DT-bindings-for-Xilinx-ZynqMP-PS.patch \
file://999-2725-iwconfig-wireless-rate-fix.patch;apply=no \
+ file://999-2726-mtkhnat-tnl-interface-offload-check.patch \
file://999-2727-net-phy-sfp-add-debug-info.patch.patch \
file://999-2728-net-phy-aquantia-add-mib-read.patch \
file://999-2730-net-phy-sfp-change-shared-mod-def0.patch \
diff --git a/recipes-kernel/linux/linux-mediatek_5.4.bb b/recipes-kernel/linux/linux-mediatek_5.4.bb
index e558eb8..7a27349 100644
--- a/recipes-kernel/linux/linux-mediatek_5.4.bb
+++ b/recipes-kernel/linux/linux-mediatek_5.4.bb
@@ -125,8 +125,7 @@
for i in ${WORKDIR}/mediatek/flow_patch/*.patch; do patch -p1 < $i; done
fi
if [ $DISTRO_logan_ENABLED = 'true' ]; then
- for i in ${WORKDIR}/mediatek/nf_hnat/6*.patch; do patch -p1 < $i; done
- for i in ${WORKDIR}/mediatek/nf_hnat/9*.patch; do patch -p1 < $i; done
+ for i in ${WORKDIR}/mediatek/nf_hnat/*.patch; do patch -p1 < $i; done
patch -p1 < ${WORKDIR}/004-rdkb-hnat-bind-ifname.patch
fi
touch patch_applied