75aeb7ed62
Changelog: https://cdn.kernel.org/pub/linux/kernel/v5.x/ChangeLog-5.15.137 All patches automatically rebased. Build system: x86_64 Build-tested: ramips/tplink_archer-a6-v3 Run-tested: ramips/tplink_archer-a6-v3 Signed-off-by: John Audia <therealgraysky@proton.me>
270 lines
7.0 KiB
Diff
270 lines
7.0 KiB
Diff
From: Felix Fietkau <nbd@nbd.name>
|
|
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 <lorenzo@kernel.org>
|
|
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
---
|
|
|
|
--- 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
|
|
@@ -875,6 +875,7 @@ enum net_device_path_type {
|
|
DEV_PATH_BRIDGE,
|
|
DEV_PATH_PPPOE,
|
|
DEV_PATH_DSA,
|
|
+ DEV_PATH_MTK_WDMA,
|
|
};
|
|
|
|
struct net_device_path {
|
|
@@ -900,6 +901,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
|
|
@@ -769,6 +769,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;
|