123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- From: Felix Fietkau <[email protected]>
- Date: Sat, 5 Feb 2022 18:29:22 +0100
- Subject: [PATCH] net: ethernet: mtk_eth_soc: implement flow offloading
- to WED devices
- This allows hardware flow offloading from Ethernet to WLAN on MT7622 SoC
- Co-developed-by: Lorenzo Bianconi <[email protected]>
- Signed-off-by: Lorenzo Bianconi <[email protected]>
- Signed-off-by: Felix Fietkau <[email protected]>
- ---
- --- a/drivers/net/ethernet/mediatek/mtk_ppe.c
- +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
- @@ -329,6 +329,24 @@ int mtk_foe_entry_set_pppoe(struct mtk_f
- return 0;
- }
-
- +int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
- + int bss, int wcid)
- +{
- + struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
- + u32 *ib2 = mtk_foe_entry_ib2(entry);
- +
- + *ib2 &= ~MTK_FOE_IB2_PORT_MG;
- + *ib2 |= MTK_FOE_IB2_WDMA_WINFO;
- + if (wdma_idx)
- + *ib2 |= MTK_FOE_IB2_WDMA_DEVIDX;
- +
- + l2->vlan2 = FIELD_PREP(MTK_FOE_VLAN2_WINFO_BSS, bss) |
- + FIELD_PREP(MTK_FOE_VLAN2_WINFO_WCID, wcid) |
- + FIELD_PREP(MTK_FOE_VLAN2_WINFO_RING, txq);
- +
- + return 0;
- +}
- +
- static inline bool mtk_foe_entry_usable(struct mtk_foe_entry *entry)
- {
- return !(entry->ib1 & MTK_FOE_IB1_STATIC) &&
- --- a/drivers/net/ethernet/mediatek/mtk_ppe.h
- +++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
- @@ -48,9 +48,9 @@ enum {
- #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_WDMA_QID2 GENMASK(13, 12)
- +#define MTK_FOE_IB2_WDMA_DEVIDX BIT(16)
- +#define MTK_FOE_IB2_WDMA_WINFO BIT(17)
-
- #define MTK_FOE_IB2_PORT_MG GENMASK(17, 12)
-
- @@ -58,9 +58,9 @@ enum {
-
- #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)
- +#define MTK_FOE_VLAN2_WINFO_BSS GENMASK(5, 0)
- +#define MTK_FOE_VLAN2_WINFO_WCID GENMASK(13, 6)
- +#define MTK_FOE_VLAN2_WINFO_RING GENMASK(15, 14)
-
- enum {
- MTK_FOE_STATE_INVALID,
- @@ -281,6 +281,8 @@ int mtk_foe_entry_set_ipv6_tuple(struct
- 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_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
- + int bss, int wcid);
- 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);
- --- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
- +++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
- @@ -10,6 +10,7 @@
- #include <net/pkt_cls.h>
- #include <net/dsa.h>
- #include "mtk_eth_soc.h"
- +#include "mtk_wed.h"
-
- struct mtk_flow_data {
- struct ethhdr eth;
- @@ -39,6 +40,7 @@ struct mtk_flow_entry {
- struct rhash_head node;
- unsigned long cookie;
- u16 hash;
- + s8 wed_index;
- };
-
- static const struct rhashtable_params mtk_flow_ht_params = {
- @@ -80,6 +82,35 @@ mtk_flow_offload_mangle_eth(const struct
- memcpy(dest, src, act->mangle.mask ? 2 : 4);
- }
-
- +static int
- +mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_info *info)
- +{
- + struct net_device_path_ctx ctx = {
- + .dev = dev,
- + .daddr = addr,
- + };
- + struct net_device_path path = {};
- +
- + if (!IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED))
- + return -1;
- +
- + if (!dev->netdev_ops->ndo_fill_forward_path)
- + return -1;
- +
- + if (dev->netdev_ops->ndo_fill_forward_path(&ctx, &path))
- + return -1;
- +
- + if (path.type != DEV_PATH_MTK_WDMA)
- + return -1;
- +
- + info->wdma_idx = path.mtk_wdma.wdma_idx;
- + info->queue = path.mtk_wdma.queue;
- + info->bss = path.mtk_wdma.bss;
- + info->wcid = path.mtk_wdma.wcid;
- +
- + return 0;
- +}
- +
-
- static int
- mtk_flow_mangle_ports(const struct flow_action_entry *act,
- @@ -149,10 +180,20 @@ mtk_flow_get_dsa_port(struct net_device
-
- static int
- mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
- - struct net_device *dev)
- + struct net_device *dev, const u8 *dest_mac,
- + int *wed_index)
- {
- + struct mtk_wdma_info info = {};
- int pse_port, dsa_port;
-
- + if (mtk_flow_get_wdma_info(dev, dest_mac, &info) == 0) {
- + mtk_foe_entry_set_wdma(foe, info.wdma_idx, info.queue, info.bss,
- + info.wcid);
- + pse_port = 3;
- + *wed_index = info.wdma_idx;
- + goto out;
- + }
- +
- dsa_port = mtk_flow_get_dsa_port(&dev);
- if (dsa_port >= 0)
- mtk_foe_entry_set_dsa(foe, dsa_port);
- @@ -164,6 +205,7 @@ mtk_flow_set_output_device(struct mtk_et
- else
- return -EOPNOTSUPP;
-
- +out:
- mtk_foe_entry_set_pse_port(foe, pse_port);
-
- return 0;
- @@ -179,6 +221,7 @@ mtk_flow_offload_replace(struct mtk_eth
- struct net_device *odev = NULL;
- struct mtk_flow_entry *entry;
- int offload_type = 0;
- + int wed_index = -1;
- u16 addr_type = 0;
- u32 timestamp;
- u8 l4proto = 0;
- @@ -326,10 +369,14 @@ mtk_flow_offload_replace(struct mtk_eth
- if (data.pppoe.num == 1)
- mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid);
-
- - err = mtk_flow_set_output_device(eth, &foe, odev);
- + err = mtk_flow_set_output_device(eth, &foe, odev, data.eth.h_dest,
- + &wed_index);
- if (err)
- return err;
-
- + if (wed_index >= 0 && (err = mtk_wed_flow_add(wed_index)) < 0)
- + return err;
- +
- entry = kzalloc(sizeof(*entry), GFP_KERNEL);
- if (!entry)
- return -ENOMEM;
- @@ -343,6 +390,7 @@ mtk_flow_offload_replace(struct mtk_eth
- }
-
- entry->hash = hash;
- + entry->wed_index = wed_index;
- err = rhashtable_insert_fast(ð->flow_table, &entry->node,
- mtk_flow_ht_params);
- if (err < 0)
- @@ -353,6 +401,8 @@ clear_flow:
- mtk_foe_entry_clear(ð->ppe, hash);
- free:
- kfree(entry);
- + if (wed_index >= 0)
- + mtk_wed_flow_remove(wed_index);
- return err;
- }
-
- @@ -369,6 +419,8 @@ mtk_flow_offload_destroy(struct mtk_eth
- mtk_foe_entry_clear(ð->ppe, entry->hash);
- rhashtable_remove_fast(ð->flow_table, &entry->node,
- mtk_flow_ht_params);
- + if (entry->wed_index >= 0)
- + mtk_wed_flow_remove(entry->wed_index);
- kfree(entry);
-
- return 0;
- --- a/drivers/net/ethernet/mediatek/mtk_wed.h
- +++ b/drivers/net/ethernet/mediatek/mtk_wed.h
- @@ -7,6 +7,7 @@
- #include <linux/soc/mediatek/mtk_wed.h>
- #include <linux/debugfs.h>
- #include <linux/regmap.h>
- +#include <linux/netdevice.h>
-
- struct mtk_eth;
-
- @@ -27,6 +28,12 @@ struct mtk_wed_hw {
- int index;
- };
-
- +struct mtk_wdma_info {
- + u8 wdma_idx;
- + u8 queue;
- + u16 wcid;
- + u8 bss;
- +};
-
- #ifdef CONFIG_NET_MEDIATEK_SOC_WED
- static inline void
- --- a/include/linux/netdevice.h
- +++ b/include/linux/netdevice.h
- @@ -863,6 +863,7 @@ enum net_device_path_type {
- DEV_PATH_BRIDGE,
- DEV_PATH_PPPOE,
- DEV_PATH_DSA,
- + DEV_PATH_MTK_WDMA,
- };
-
- struct net_device_path {
- @@ -888,6 +889,12 @@ struct net_device_path {
- int port;
- u16 proto;
- } dsa;
- + struct {
- + u8 wdma_idx;
- + u8 queue;
- + u16 wcid;
- + u8 bss;
- + } mtk_wdma;
- };
- };
-
- --- a/net/core/dev.c
- +++ b/net/core/dev.c
- @@ -763,6 +763,10 @@ int dev_fill_forward_path(const struct n
- if (WARN_ON_ONCE(last_dev == ctx.dev))
- return -1;
- }
- +
- + if (!ctx.dev)
- + return ret;
- +
- path = dev_fwd_path(stack);
- if (!path)
- return -1;
|