[][MAC80211][WED][Add wed driver to support tx/rx offload]

[Description]
Add wed driver to support tx/rx offload

[Release-log]
N/A

Change-Id: Ic77fdde01ce06ef5638d077d880864dffa8ba821
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/6197267
diff --git a/autobuild_mac80211_release/target/linux/mediatek/patches-5.4/9995-flow-offload-add-mkhnat-dual-ppe-new-v2.patch b/autobuild_mac80211_release/target/linux/mediatek/patches-5.4/9995-flow-offload-add-mkhnat-dual-ppe-new-v2.patch
new file mode 100755
index 0000000..0eb1117
--- /dev/null
+++ b/autobuild_mac80211_release/target/linux/mediatek/patches-5.4/9995-flow-offload-add-mkhnat-dual-ppe-new-v2.patch
@@ -0,0 +1,474 @@
+From a59cb5c770a694cb34ab179ec59e91ba5c39908b Mon Sep 17 00:00:00 2001
+From: Bo Jiao <Bo.Jiao@mediatek.com>
+Date: Mon, 27 Jun 2022 14:48:35 +0800
+Subject: [PATCH 6/8] 9995-flow-offload-add-mkhnat-dual-ppe-new-v2
+
+---
+ arch/arm64/boot/dts/mediatek/mt7986a.dtsi     |  1 +
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c   | 67 ++++++++++++++-----
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h   | 10 ++-
+ drivers/net/ethernet/mediatek/mtk_ppe.c       |  5 +-
+ drivers/net/ethernet/mediatek/mtk_ppe.h       |  7 +-
+ .../net/ethernet/mediatek/mtk_ppe_debugfs.c   | 27 ++++++--
+ .../net/ethernet/mediatek/mtk_ppe_offload.c   | 45 ++++++++++---
+ include/linux/netdevice.h                     |  4 ++
+ 8 files changed, 125 insertions(+), 41 deletions(-)
+ mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+
+diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+index 7f78de6b9..381136c21 100644
+--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+@@ -479,6 +479,7 @@
+                 mediatek,ethsys = <&ethsys>;
+ 		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
+ 		mediatek,wed = <&wed0>, <&wed1>;
++                mtketh-ppe-num = <2>;
+                 #reset-cells = <1>;
+                 #address-cells = <1>;
+                 #size-cells = <0>;
+diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+index 01fc1e5c0..3f67bebfe 100644
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1379,6 +1379,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+ 	u8 *data, *new_data;
+ 	struct mtk_rx_dma *rxd, trxd;
+ 	int done = 0;
++	int i;
+ 
+ 	if (unlikely(!ring))
+ 		goto rx_done;
+@@ -1479,14 +1480,20 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+ 
+ #if defined(CONFIG_MEDIATEK_NETSYS_V2)
+ 		reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON_V2, trxd.rxd5);
+-		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
+-			mtk_ppe_check_skb(eth->ppe, skb,
+-					  trxd.rxd5 & MTK_RXD5_FOE_ENTRY_V2);
++		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) {
++			for (i = 0; i < eth->ppe_num; i++) {
++				mtk_ppe_check_skb(eth->ppe[i], skb,
++						  trxd.rxd5 & MTK_RXD5_FOE_ENTRY_V2);
++			}
++		}
+ #else
+ 		reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4);
+-		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
+-			mtk_ppe_check_skb(eth->ppe, skb,
+-					  trxd.rxd4 & MTK_RXD4_FOE_ENTRY);
++		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) {
++			for (i = 0; i < eth->ppe_num; i++) {
++				mtk_ppe_check_skb(eth->ppe[i], skb,
++						  trxd.rxd4 & MTK_RXD4_FOE_ENTRY);
++			}
++		}
+ #endif
+ 
+ 		if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
+@@ -2687,8 +2694,12 @@ static int mtk_open(struct net_device *dev)
+ 		if (err)
+ 			return err;
+ 
+-		if (eth->soc->offload_version && mtk_ppe_start(eth->ppe) == 0)
+-			gdm_config = MTK_GDMA_TO_PPE;
++		if (eth->soc->offload_version) {
++			gdm_config = MTK_GDMA_TO_PPE0;
++
++			for (i = 0; i < eth->ppe_num; i++)
++				mtk_ppe_start(eth->ppe[i]);
++		}
+ 
+ 		mtk_gdm_config(eth, gdm_config);
+ 
+@@ -2803,8 +2814,10 @@ static int mtk_stop(struct net_device *dev)
+ 
+ 	mtk_dma_free(eth);
+ 
+-	if (eth->soc->offload_version)
+-		mtk_ppe_stop(eth->ppe);
++	if (eth->soc->offload_version) {
++		for (i = 0; i < eth->ppe_num; i++)
++			mtk_ppe_stop(eth->ppe[i]);
++	}
+ 
+ 	return 0;
+ }
+@@ -3780,15 +3793,35 @@ static int mtk_probe(struct platform_device *pdev)
+ 	}
+ 
+ 	if (eth->soc->offload_version) {
+-		eth->ppe = mtk_ppe_init(eth, eth->base + MTK_ETH_PPE_BASE, 2);
+-		if (!eth->ppe) {
+-			err = -ENOMEM;
+-			goto err_free_dev;
++		unsigned int val;
++ 
++		err = of_property_read_u32_index(pdev->dev.of_node, "mtketh-ppe-num", 0, &val);
++		if (err < 0)
++			eth->ppe_num = 1;
++		else
++			eth->ppe_num = val;
++ 
++		if (eth->ppe_num > MTK_MAX_PPE_NUM) {
++			dev_warn(&pdev->dev, "%d is not a valid ppe num, please check mtketh-ppe-num in dts !", eth->ppe_num);
++			eth->ppe_num = MTK_MAX_PPE_NUM;
+ 		}
+ 
+-		err = mtk_eth_offload_init(eth);
+-		if (err)
+-			goto err_free_dev;
++		dev_info(&pdev->dev, "ppe num = %d\n", eth->ppe_num);
++
++		for (i = 0; i < eth->ppe_num; i++) {
++			eth->ppe[i] = mtk_ppe_init(eth,
++					   eth->base + MTK_ETH_PPE_BASE + i * 0x400, 2, i);
++			if (!eth->ppe[i]) {
++				err = -ENOMEM;
++				goto err_free_dev;
++			}
++
++			err = mtk_eth_offload_init(eth, i);
++			if (err)
++				goto err_free_dev;
++		}
++
++		mtk_ppe_debugfs_init(eth);
+ 	}
+ 
+ 	for (i = 0; i < MTK_MAX_DEVS; i++) {
+diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+index fce1a7172..b4de7c0c6 100644
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -110,7 +110,8 @@
+ #define MTK_GDMA_TCS_EN		BIT(21)
+ #define MTK_GDMA_UCS_EN		BIT(20)
+ #define MTK_GDMA_TO_PDMA	0x0
+-#define MTK_GDMA_TO_PPE		0x3333
++#define MTK_GDMA_TO_PPE0	0x3333
++#define MTK_GDMA_TO_PPE1	0x4444
+ #define MTK_GDMA_DROP_ALL	0x7777
+ 
+ /* Unicast Filter MAC Address Register - Low */
+@@ -1299,7 +1300,8 @@ struct mtk_eth {
+ 	spinlock_t			syscfg0_lock;
+ 	struct timer_list		mtk_dma_monitor_timer;
+ 
+-	struct mtk_ppe			*ppe;
++	u8				ppe_num;
++	struct mtk_ppe			*ppe[MTK_MAX_PPE_NUM];
+ 	struct rhashtable		flow_table;
+ };
+ 
+@@ -1349,9 +1351,11 @@ int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id);
+ void mtk_gdm_config(struct mtk_eth *eth, u32 config);
+ void ethsys_reset(struct mtk_eth *eth, u32 reset_bits);
+ 
+-int mtk_eth_offload_init(struct mtk_eth *eth);
++int mtk_eth_offload_init(struct mtk_eth *eth, int id);
+ 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);
+ 
++int mtk_ppe_debugfs_init(struct mtk_eth *eth);
++
+ #endif /* MTK_ETH_H */
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
+index d46e91178..3d6ff30ba 100755
+--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
+@@ -677,7 +677,7 @@ int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
+ }
+ 
+ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
+-		 int version)
++		 int version, int id)
+ {
+ 	struct device *dev = eth->dev;
+ 	struct mtk_foe_entry *foe;
+@@ -696,6 +696,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
+ 	ppe->eth = eth;
+ 	ppe->dev = dev;
+ 	ppe->version = version;
++	ppe->id = id;
+ 
+ 	foe = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*foe),
+ 				  &ppe->foe_phys, GFP_KERNEL);
+@@ -704,8 +705,6 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
+ 
+ 	ppe->foe_table = foe;
+ 
+-	mtk_ppe_debugfs_init(ppe);
+-
+ 	return ppe;
+ }
+ 
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
+index a76f4b0ac..21cc55145 100644
+--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
+@@ -8,6 +8,8 @@
+ #include <linux/bitfield.h>
+ #include <linux/rhashtable.h>
+ 
++#define MTK_MAX_PPE_NUM			2
++
+ #define MTK_ETH_PPE_BASE		0x2000
+ 
+ #define MTK_PPE_ENTRIES_SHIFT		3
+@@ -253,6 +255,7 @@ struct mtk_flow_entry {
+ 		};
+ 	};
+ 	u8 type;
++	s8 ppe_index;
+ 	s8 wed_index;
+ 	u16 hash;
+ 	union {
+@@ -272,6 +275,7 @@ struct mtk_ppe {
+ 	struct device *dev;
+ 	void __iomem *base;
+ 	int version;
++	int id;
+ 
+ 	struct mtk_foe_entry *foe_table;
+ 	dma_addr_t foe_phys;
+@@ -284,7 +288,7 @@ struct mtk_ppe {
+ 	void *acct_table;
+ };
+ 
+-struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int version);
++struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int version, int id);
+ int mtk_ppe_start(struct mtk_ppe *ppe);
+ int mtk_ppe_stop(struct mtk_ppe *ppe);
+ 
+@@ -335,6 +339,5 @@ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
+ int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
+ void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
+ int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
+-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
+index a591ab1fd..f4ebe5944 100644
+--- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
+@@ -73,9 +73,8 @@ mtk_print_addr_info(struct seq_file *m, struct mtk_flow_addr_info *ai)
+ }
+ 
+ static int
+-mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind)
++mtk_ppe_debugfs_foe_show(struct seq_file *m, struct mtk_ppe *ppe, bool bind)
+ {
+-	struct mtk_ppe *ppe = m->private;
+ 	int i;
+ 
+ 	for (i = 0; i < MTK_PPE_ENTRIES; i++) {
+@@ -122,6 +121,8 @@ mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind)
+ 			break;
+ 		}
+ 
++		seq_printf(m, " ppe=%d", ppe->id);
++
+ 		seq_printf(m, " orig=");
+ 		mtk_print_addr_info(m, &ai);
+ 
+@@ -164,13 +165,25 @@ mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind)
+ static int
+ mtk_ppe_debugfs_foe_show_all(struct seq_file *m, void *private)
+ {
+-	return mtk_ppe_debugfs_foe_show(m, private, false);
++	struct mtk_eth *eth = m->private;
++	int i;
++
++	for (i = 0; i < eth->ppe_num; i++)
++		mtk_ppe_debugfs_foe_show(m, eth->ppe[i], false);
++
++	return 0;
+ }
+ 
+ static int
+ mtk_ppe_debugfs_foe_show_bind(struct seq_file *m, void *private)
+ {
+-	return mtk_ppe_debugfs_foe_show(m, private, true);
++	struct mtk_eth *eth = m->private;
++	int i;
++
++	for (i = 0; i < eth->ppe_num; i++)
++		mtk_ppe_debugfs_foe_show(m, eth->ppe[i], true);
++
++	return 0;
+ }
+ 
+ static int
+@@ -187,7 +200,7 @@ mtk_ppe_debugfs_foe_open_bind(struct inode *inode, struct file *file)
+ 			   inode->i_private);
+ }
+ 
+-int mtk_ppe_debugfs_init(struct mtk_ppe *ppe)
++int mtk_ppe_debugfs_init(struct mtk_eth *eth)
+ {
+ 	static const struct file_operations fops_all = {
+ 		.open = mtk_ppe_debugfs_foe_open_all,
+@@ -209,8 +222,8 @@ int mtk_ppe_debugfs_init(struct mtk_ppe *ppe)
+ 	if (!root)
+ 		return -ENOMEM;
+ 
+-	debugfs_create_file("entries", S_IRUGO, root, ppe, &fops_all);
+-	debugfs_create_file("bind", S_IRUGO, root, ppe, &fops_bind);
++	debugfs_create_file("entries", S_IRUGO, root, eth, &fops_all);
++	debugfs_create_file("bind", S_IRUGO, root, eth, &fops_bind);
+ 
+ 	return 0;
+ }
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+old mode 100644
+new mode 100755
+index 5a4201447..2f7d76d3b
+--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+@@ -226,8 +226,10 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+ 	struct flow_action_entry *act;
+ 	struct mtk_flow_data data = {};
+ 	struct mtk_foe_entry foe;
+-	struct net_device *odev = NULL;
++	struct net_device *idev = NULL, *odev = NULL;
+ 	struct mtk_flow_entry *entry;
++	struct net_device_path_ctx ctx = {};
++	struct net_device_path path = {};
+ 	int offload_type = 0;
+ 	int wed_index = -1;
+ 	u16 addr_type = 0;
+@@ -242,6 +244,10 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+ 		struct flow_match_meta match;
+ 
+ 		flow_rule_match_meta(rule, &match);
++		idev = __dev_get_by_index(&init_net, match.key->ingress_ifindex);
++
++		if (!idev)
++			pr_info("[%s] idev doesn't exist !\n", __func__);
+ 	} else {
+ 		return -EOPNOTSUPP;
+ 	}
+@@ -435,11 +441,25 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+ 	if (!entry)
+ 		return -ENOMEM;
+ 
++	i = 0;
++	if (idev && idev->netdev_ops->ndo_fill_receive_path) {
++		ctx.dev = idev;
++		idev->netdev_ops->ndo_fill_receive_path(&ctx, &path);
++		i = path.mtk_wdma.wdma_idx;
++		if (i >= eth->ppe_num) {
++			if (printk_ratelimit())
++				pr_info("[%s] PPE%d doesn't exist, please check mtketh-ppe-num in dts !\n", __func__, i);
++
++			return -EINVAL;
++		}
++	}
++
+ 	entry->cookie = f->cookie;
+ 	memcpy(&entry->data, &foe, sizeof(entry->data));
++	entry->ppe_index = i;
+ 	entry->wed_index = wed_index;
+ 
+-	if (mtk_foe_entry_commit(eth->ppe, entry) < 0)
++	if (mtk_foe_entry_commit(eth->ppe[i], entry) < 0)
+ 		goto free;
+ 
+ 	err = rhashtable_insert_fast(&eth->flow_table, &entry->node,
+@@ -450,7 +470,7 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+ 	return 0;
+ 
+ clear:
+-	mtk_foe_entry_clear(eth->ppe, entry);
++	mtk_foe_entry_clear(eth->ppe[i], entry);
+ free:
+ 	kfree(entry);
+ 	if (wed_index >= 0)
+@@ -462,13 +482,15 @@ static int
+ mtk_flow_offload_destroy(struct mtk_eth *eth, struct flow_cls_offload *f)
+ {
+ 	struct mtk_flow_entry *entry;
++	int i;
+ 
+ 	entry = rhashtable_lookup(&eth->flow_table, &f->cookie,
+ 				  mtk_flow_ht_params);
+ 	if (!entry)
+ 		return -ENOENT;
+ 
+-	mtk_foe_entry_clear(eth->ppe, entry);
++	i = entry->ppe_index;
++	mtk_foe_entry_clear(eth->ppe[i], entry);
+ 	rhashtable_remove_fast(&eth->flow_table, &entry->node,
+ 			       mtk_flow_ht_params);
+ 	if (entry->wed_index >= 0)
+@@ -483,13 +505,15 @@ mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f)
+ {
+ 	struct mtk_flow_entry *entry;
+ 	u32 idle;
++	int i;
+ 
+ 	entry = rhashtable_lookup(&eth->flow_table, &f->cookie,
+ 				  mtk_flow_ht_params);
+ 	if (!entry)
+ 		return -ENOENT;
+ 
+-	idle = mtk_foe_entry_idle_time(eth->ppe, entry);
++	i = entry->ppe_index;
++	idle = mtk_foe_entry_idle_time(eth->ppe[i], entry);
+ 	f->stats.lastused = jiffies - idle * HZ;
+ 
+ 	return 0;
+@@ -540,9 +564,12 @@ mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f)
+ 	static LIST_HEAD(block_cb_list);
+ 	struct flow_block_cb *block_cb;
+ 	flow_setup_cb_t *cb;
++	int i;
+ 
+-	if (!eth->ppe || !eth->ppe->foe_table)
+-		return -EOPNOTSUPP;
++	for (i = 0; i < eth->ppe_num; i++) {
++		if (!eth->ppe[i] || !eth->ppe[i]->foe_table)
++			return -EOPNOTSUPP;
++	}
+ 
+ 	if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
+ 		return -EOPNOTSUPP;
+@@ -591,9 +618,9 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
+ 	}
+ }
+ 
+-int mtk_eth_offload_init(struct mtk_eth *eth)
++int mtk_eth_offload_init(struct mtk_eth *eth, int id)
+ {
+-	if (!eth->ppe || !eth->ppe->foe_table)
++	if (!eth->ppe[id] || !eth->ppe[id]->foe_table)
+ 		return 0;
+ 
+ 	return rhashtable_init(&eth->flow_table, &mtk_flow_ht_params);
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index 35998b1a7..0ada2461b 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1302,6 +1302,8 @@ struct tlsdev_ops;
+  *	rtnl_lock is not held.
+  * int (*ndo_fill_forward_path)(struct net_device_path_ctx *ctx, struct net_device_path *path);
+  *     Get the forwarding path to reach the real device from the HW destination address
++ * int (*ndo_fill_receive_path)(struct net_device_path_ctx *ctx, struct net_device_path *path);
++ *     Get the receiving path to reach the real device from the HW source address
+  */
+ struct net_device_ops {
+ 	int			(*ndo_init)(struct net_device *dev);
+@@ -1501,6 +1503,8 @@ struct net_device_ops {
+ 	struct devlink_port *	(*ndo_get_devlink_port)(struct net_device *dev);
+ 	int                     (*ndo_fill_forward_path)(struct net_device_path_ctx *ctx,
+                                                          struct net_device_path *path);
++	int                     (*ndo_fill_receive_path)(struct net_device_path_ctx *ctx,
++							 struct net_device_path *path);
+ };
+ 
+ /**
+-- 
+2.18.0
+