Commit a333215e authored by Felix Fietkau's avatar Felix Fietkau Committed by David S. Miller
Browse files

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: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 804775df
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -329,6 +329,24 @@ int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid)
	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) &&
+8 −6
Original line number Diff line number Diff line
@@ -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 mtk_foe_entry *entry,
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);
+54 −2
Original line number Diff line number Diff line
@@ -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 flow_action_entry *act, void *eth)
	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 **dev)

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_eth *eth, struct mtk_foe_entry *foe,
	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 *eth, struct flow_cls_offload *f)
	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 *eth, struct flow_cls_offload *f)
	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 *eth, struct flow_cls_offload *f)
	}

	entry->hash = hash;
	entry->wed_index = wed_index;
	err = rhashtable_insert_fast(&eth->flow_table, &entry->node,
				     mtk_flow_ht_params);
	if (err < 0)
@@ -353,6 +401,8 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
	mtk_foe_entry_clear(&eth->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 *eth, struct flow_cls_offload *f)
	mtk_foe_entry_clear(&eth->ppe, entry->hash);
	rhashtable_remove_fast(&eth->flow_table, &entry->node,
			       mtk_flow_ht_params);
	if (entry->wed_index >= 0)
		mtk_wed_flow_remove(entry->wed_index);
	kfree(entry);

	return 0;
+7 −0
Original line number Diff line number Diff line
@@ -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
+7 −0
Original line number Diff line number Diff line
@@ -862,6 +862,7 @@ enum net_device_path_type {
	DEV_PATH_BRIDGE,
	DEV_PATH_PPPOE,
	DEV_PATH_DSA,
	DEV_PATH_MTK_WDMA,
};

struct net_device_path {
@@ -887,6 +888,12 @@ struct net_device_path {
			int port;
			u16 proto;
		} dsa;
		struct {
			u8 wdma_idx;
			u8 queue;
			u16 wcid;
			u8 bss;
		} mtk_wdma;
	};
};

Loading