mediatek: add kernel code for supporting offloading wlan->eth and wlan->wlan flows
Will be enabled by an upcoming mt76 update Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
parent
fbcfb7f7af
commit
d0a06965e8
6 changed files with 477 additions and 12 deletions
|
@ -0,0 +1,149 @@
|
||||||
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
|
Date: Mon, 20 Mar 2023 14:28:08 +0100
|
||||||
|
Subject: [PATCH] wifi: mac80211: add support for letting drivers register tc
|
||||||
|
offload support
|
||||||
|
|
||||||
|
On newer MediaTek SoCs (e.g. MT7986), WLAN->WLAN or WLAN->Ethernet flows can
|
||||||
|
be offloaded by the SoC. In order to support that, the .ndo_setup_tc op is
|
||||||
|
needed.
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/include/net/mac80211.h
|
||||||
|
+++ b/include/net/mac80211.h
|
||||||
|
@@ -4196,6 +4196,10 @@ struct ieee80211_prep_tx_info {
|
||||||
|
* Note that a sta can also be inserted or removed with valid links,
|
||||||
|
* i.e. passed to @sta_add/@sta_state with sta->valid_links not zero.
|
||||||
|
* In fact, cannot change from having valid_links and not having them.
|
||||||
|
+ * @net_setup_tc: Called from .ndo_setup_tc in order to prepare hardware
|
||||||
|
+ * flow offloading for flows originating from the vif.
|
||||||
|
+ * Note that the driver must not assume that the vif driver_data is valid
|
||||||
|
+ * at this point, since the callback can be called during netdev teardown.
|
||||||
|
*/
|
||||||
|
struct ieee80211_ops {
|
||||||
|
void (*tx)(struct ieee80211_hw *hw,
|
||||||
|
@@ -4551,6 +4555,11 @@ struct ieee80211_ops {
|
||||||
|
struct ieee80211_vif *vif,
|
||||||
|
struct ieee80211_sta *sta,
|
||||||
|
u16 old_links, u16 new_links);
|
||||||
|
+ int (*net_setup_tc)(struct ieee80211_hw *hw,
|
||||||
|
+ struct ieee80211_vif *vif,
|
||||||
|
+ struct net_device *dev,
|
||||||
|
+ enum tc_setup_type type,
|
||||||
|
+ void *type_data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
--- a/net/mac80211/driver-ops.h
|
||||||
|
+++ b/net/mac80211/driver-ops.h
|
||||||
|
@@ -1470,6 +1470,23 @@ static inline int drv_net_fill_forward_p
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static inline int drv_net_setup_tc(struct ieee80211_local *local,
|
||||||
|
+ struct ieee80211_sub_if_data *sdata,
|
||||||
|
+ struct net_device *dev,
|
||||||
|
+ enum tc_setup_type type, void *type_data)
|
||||||
|
+{
|
||||||
|
+ int ret = -EOPNOTSUPP;
|
||||||
|
+
|
||||||
|
+ sdata = get_bss_sdata(sdata);
|
||||||
|
+ trace_drv_net_setup_tc(local, sdata, type);
|
||||||
|
+ if (local->ops->net_setup_tc)
|
||||||
|
+ ret = local->ops->net_setup_tc(&local->hw, &sdata->vif, dev,
|
||||||
|
+ type, type_data);
|
||||||
|
+ trace_drv_return_int(local, ret);
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
int drv_change_vif_links(struct ieee80211_local *local,
|
||||||
|
struct ieee80211_sub_if_data *sdata,
|
||||||
|
u16 old_links, u16 new_links,
|
||||||
|
--- a/net/mac80211/ieee80211_i.h
|
||||||
|
+++ b/net/mac80211/ieee80211_i.h
|
||||||
|
@@ -1935,7 +1935,8 @@ void ieee80211_color_change_finalize_wor
|
||||||
|
/* interface handling */
|
||||||
|
#define MAC80211_SUPPORTED_FEATURES_TX (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | \
|
||||||
|
NETIF_F_HW_CSUM | NETIF_F_SG | \
|
||||||
|
- NETIF_F_HIGHDMA | NETIF_F_GSO_SOFTWARE)
|
||||||
|
+ NETIF_F_HIGHDMA | NETIF_F_GSO_SOFTWARE | \
|
||||||
|
+ NETIF_F_HW_TC)
|
||||||
|
#define MAC80211_SUPPORTED_FEATURES_RX (NETIF_F_RXCSUM)
|
||||||
|
#define MAC80211_SUPPORTED_FEATURES (MAC80211_SUPPORTED_FEATURES_TX | \
|
||||||
|
MAC80211_SUPPORTED_FEATURES_RX)
|
||||||
|
--- a/net/mac80211/iface.c
|
||||||
|
+++ b/net/mac80211/iface.c
|
||||||
|
@@ -813,6 +813,21 @@ ieee80211_get_stats64(struct net_device
|
||||||
|
dev_fetch_sw_netstats(stats, dev->tstats);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int ieee80211_netdev_setup_tc(struct net_device *dev,
|
||||||
|
+ enum tc_setup_type type, void *type_data)
|
||||||
|
+{
|
||||||
|
+ struct ieee80211_sub_if_data *sdata;
|
||||||
|
+ struct ieee80211_local *local;
|
||||||
|
+
|
||||||
|
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||||
|
+ local = sdata->local;
|
||||||
|
+
|
||||||
|
+ if (!local->ops->net_setup_tc)
|
||||||
|
+ return -EOPNOTSUPP;
|
||||||
|
+
|
||||||
|
+ return drv_net_setup_tc(local, sdata, dev, type, type_data);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static const struct net_device_ops ieee80211_dataif_ops = {
|
||||||
|
.ndo_open = ieee80211_open,
|
||||||
|
.ndo_stop = ieee80211_stop,
|
||||||
|
@@ -821,6 +836,7 @@ static const struct net_device_ops ieee8
|
||||||
|
.ndo_set_rx_mode = ieee80211_set_multicast_list,
|
||||||
|
.ndo_set_mac_address = ieee80211_change_mac,
|
||||||
|
.ndo_get_stats64 = ieee80211_get_stats64,
|
||||||
|
+ .ndo_setup_tc = ieee80211_netdev_setup_tc,
|
||||||
|
};
|
||||||
|
|
||||||
|
static u16 ieee80211_monitor_select_queue(struct net_device *dev,
|
||||||
|
@@ -929,6 +945,7 @@ static const struct net_device_ops ieee8
|
||||||
|
.ndo_set_mac_address = ieee80211_change_mac,
|
||||||
|
.ndo_get_stats64 = ieee80211_get_stats64,
|
||||||
|
.ndo_fill_forward_path = ieee80211_netdev_fill_forward_path,
|
||||||
|
+ .ndo_setup_tc = ieee80211_netdev_setup_tc,
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool ieee80211_iftype_supports_hdr_offload(enum nl80211_iftype iftype)
|
||||||
|
--- a/net/mac80211/trace.h
|
||||||
|
+++ b/net/mac80211/trace.h
|
||||||
|
@@ -2478,6 +2478,31 @@ DEFINE_EVENT(sta_event, drv_net_fill_for
|
||||||
|
TP_ARGS(local, sdata, sta)
|
||||||
|
);
|
||||||
|
|
||||||
|
+TRACE_EVENT(drv_net_setup_tc,
|
||||||
|
+ TP_PROTO(struct ieee80211_local *local,
|
||||||
|
+ struct ieee80211_sub_if_data *sdata,
|
||||||
|
+ u8 type),
|
||||||
|
+
|
||||||
|
+ TP_ARGS(local, sdata, type),
|
||||||
|
+
|
||||||
|
+ TP_STRUCT__entry(
|
||||||
|
+ LOCAL_ENTRY
|
||||||
|
+ VIF_ENTRY
|
||||||
|
+ __field(u8, type)
|
||||||
|
+ ),
|
||||||
|
+
|
||||||
|
+ TP_fast_assign(
|
||||||
|
+ LOCAL_ASSIGN;
|
||||||
|
+ VIF_ASSIGN;
|
||||||
|
+ __entry->type = type;
|
||||||
|
+ ),
|
||||||
|
+
|
||||||
|
+ TP_printk(
|
||||||
|
+ LOCAL_PR_FMT VIF_PR_FMT " type:%d\n",
|
||||||
|
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->type
|
||||||
|
+ )
|
||||||
|
+);
|
||||||
|
+
|
||||||
|
TRACE_EVENT(drv_change_vif_links,
|
||||||
|
TP_PROTO(struct ieee80211_local *local,
|
||||||
|
struct ieee80211_sub_if_data *sdata,
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
--- a/include/net/mac80211.h
|
--- a/include/net/mac80211.h
|
||||||
+++ b/include/net/mac80211.h
|
+++ b/include/net/mac80211.h
|
||||||
@@ -1645,6 +1645,7 @@ enum ieee80211_smps_mode {
|
@@ -1671,6 +1671,7 @@ enum ieee80211_smps_mode {
|
||||||
*
|
*
|
||||||
* @power_level: requested transmit power (in dBm), backward compatibility
|
* @power_level: requested transmit power (in dBm), backward compatibility
|
||||||
* value only that is set to the minimum of all interfaces
|
* value only that is set to the minimum of all interfaces
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
*
|
*
|
||||||
* @chandef: the channel definition to tune to
|
* @chandef: the channel definition to tune to
|
||||||
* @radar_enabled: whether radar detection is enabled
|
* @radar_enabled: whether radar detection is enabled
|
||||||
@@ -1665,6 +1666,7 @@ enum ieee80211_smps_mode {
|
@@ -1691,6 +1692,7 @@ enum ieee80211_smps_mode {
|
||||||
struct ieee80211_conf {
|
struct ieee80211_conf {
|
||||||
u32 flags;
|
u32 flags;
|
||||||
int power_level, dynamic_ps_timeout;
|
int power_level, dynamic_ps_timeout;
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
__NL80211_ATTR_AFTER_LAST,
|
__NL80211_ATTR_AFTER_LAST,
|
||||||
--- a/net/mac80211/cfg.c
|
--- a/net/mac80211/cfg.c
|
||||||
+++ b/net/mac80211/cfg.c
|
+++ b/net/mac80211/cfg.c
|
||||||
@@ -2998,6 +2998,19 @@ static int ieee80211_get_tx_power(struct
|
@@ -3028,6 +3028,19 @@ static int ieee80211_get_tx_power(struct
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@
|
||||||
static void ieee80211_rfkill_poll(struct wiphy *wiphy)
|
static void ieee80211_rfkill_poll(struct wiphy *wiphy)
|
||||||
{
|
{
|
||||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||||
@@ -4881,6 +4894,7 @@ const struct cfg80211_ops mac80211_confi
|
@@ -4911,6 +4924,7 @@ const struct cfg80211_ops mac80211_confi
|
||||||
.set_wiphy_params = ieee80211_set_wiphy_params,
|
.set_wiphy_params = ieee80211_set_wiphy_params,
|
||||||
.set_tx_power = ieee80211_set_tx_power,
|
.set_tx_power = ieee80211_set_tx_power,
|
||||||
.get_tx_power = ieee80211_get_tx_power,
|
.get_tx_power = ieee80211_get_tx_power,
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
--- a/include/linux/soc/mediatek/mtk_wed.h
|
--- a/include/linux/soc/mediatek/mtk_wed.h
|
||||||
+++ b/include/linux/soc/mediatek/mtk_wed.h
|
+++ b/include/linux/soc/mediatek/mtk_wed.h
|
||||||
@@ -5,21 +5,76 @@
|
@@ -5,21 +5,77 @@
|
||||||
#include <linux/rcupdate.h>
|
#include <linux/rcupdate.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
+#include <linux/skbuff.h>
|
+#include <linux/skbuff.h>
|
||||||
|
+#include <linux/netdevice.h>
|
||||||
|
|
||||||
#define MTK_WED_TX_QUEUES 2
|
#define MTK_WED_TX_QUEUES 2
|
||||||
+#define MTK_WED_RX_QUEUES 2
|
+#define MTK_WED_RX_QUEUES 2
|
||||||
|
@ -77,7 +78,7 @@
|
||||||
struct mtk_wed_device {
|
struct mtk_wed_device {
|
||||||
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
|
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
|
||||||
const struct mtk_wed_ops *ops;
|
const struct mtk_wed_ops *ops;
|
||||||
@@ -28,30 +83,76 @@ struct mtk_wed_device {
|
@@ -28,30 +84,76 @@ struct mtk_wed_device {
|
||||||
bool init_done, running;
|
bool init_done, running;
|
||||||
int wdma_idx;
|
int wdma_idx;
|
||||||
int irq;
|
int irq;
|
||||||
|
@ -156,7 +157,7 @@
|
||||||
} wlan;
|
} wlan;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
@@ -59,10 +160,16 @@ struct mtk_wed_device {
|
@@ -59,10 +161,16 @@ struct mtk_wed_device {
|
||||||
struct mtk_wed_ops {
|
struct mtk_wed_ops {
|
||||||
int (*attach)(struct mtk_wed_device *dev);
|
int (*attach)(struct mtk_wed_device *dev);
|
||||||
int (*tx_ring_setup)(struct mtk_wed_device *dev, int ring,
|
int (*tx_ring_setup)(struct mtk_wed_device *dev, int ring,
|
||||||
|
@ -174,7 +175,16 @@
|
||||||
|
|
||||||
void (*stop)(struct mtk_wed_device *dev);
|
void (*stop)(struct mtk_wed_device *dev);
|
||||||
void (*start)(struct mtk_wed_device *dev, u32 irq_mask);
|
void (*start)(struct mtk_wed_device *dev, u32 irq_mask);
|
||||||
@@ -97,12 +204,22 @@ mtk_wed_device_attach(struct mtk_wed_dev
|
@@ -73,6 +181,8 @@ struct mtk_wed_ops {
|
||||||
|
|
||||||
|
u32 (*irq_get)(struct mtk_wed_device *dev, u32 mask);
|
||||||
|
void (*irq_set_mask)(struct mtk_wed_device *dev, u32 mask);
|
||||||
|
+ int (*setup_tc)(struct mtk_wed_device *wed, struct net_device *dev,
|
||||||
|
+ enum tc_setup_type type, void *type_data);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct mtk_wed_ops __rcu *mtk_soc_wed_ops;
|
||||||
|
@@ -97,12 +207,22 @@ mtk_wed_device_attach(struct mtk_wed_dev
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +209,7 @@
|
||||||
#define mtk_wed_device_txfree_ring_setup(_dev, _regs) \
|
#define mtk_wed_device_txfree_ring_setup(_dev, _regs) \
|
||||||
(_dev)->ops->txfree_ring_setup(_dev, _regs)
|
(_dev)->ops->txfree_ring_setup(_dev, _regs)
|
||||||
#define mtk_wed_device_reg_read(_dev, _reg) \
|
#define mtk_wed_device_reg_read(_dev, _reg) \
|
||||||
@@ -113,6 +230,14 @@ mtk_wed_device_attach(struct mtk_wed_dev
|
@@ -113,6 +233,16 @@ mtk_wed_device_attach(struct mtk_wed_dev
|
||||||
(_dev)->ops->irq_get(_dev, _mask)
|
(_dev)->ops->irq_get(_dev, _mask)
|
||||||
#define mtk_wed_device_irq_set_mask(_dev, _mask) \
|
#define mtk_wed_device_irq_set_mask(_dev, _mask) \
|
||||||
(_dev)->ops->irq_set_mask(_dev, _mask)
|
(_dev)->ops->irq_set_mask(_dev, _mask)
|
||||||
|
@ -211,10 +221,12 @@
|
||||||
+ (_dev)->ops->msg_update(_dev, _id, _msg, _len)
|
+ (_dev)->ops->msg_update(_dev, _id, _msg, _len)
|
||||||
+#define mtk_wed_device_stop(_dev) (_dev)->ops->stop(_dev)
|
+#define mtk_wed_device_stop(_dev) (_dev)->ops->stop(_dev)
|
||||||
+#define mtk_wed_device_dma_reset(_dev) (_dev)->ops->reset_dma(_dev)
|
+#define mtk_wed_device_dma_reset(_dev) (_dev)->ops->reset_dma(_dev)
|
||||||
|
+#define mtk_wed_device_setup_tc(_dev, _netdev, _type, _type_data) \
|
||||||
|
+ (_dev)->ops->setup_tc(_dev, _netdev, _type, _type_data)
|
||||||
#else
|
#else
|
||||||
static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
|
static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
|
||||||
{
|
{
|
||||||
@@ -120,12 +245,17 @@ static inline bool mtk_wed_device_active
|
@@ -120,12 +250,18 @@ static inline bool mtk_wed_device_active
|
||||||
}
|
}
|
||||||
#define mtk_wed_device_detach(_dev) do {} while (0)
|
#define mtk_wed_device_detach(_dev) do {} while (0)
|
||||||
#define mtk_wed_device_start(_dev, _mask) do {} while (0)
|
#define mtk_wed_device_start(_dev, _mask) do {} while (0)
|
||||||
|
@ -230,6 +242,7 @@
|
||||||
+#define mtk_wed_device_update_msg(_dev, _id, _msg, _len) -ENODEV
|
+#define mtk_wed_device_update_msg(_dev, _id, _msg, _len) -ENODEV
|
||||||
+#define mtk_wed_device_stop(_dev) do {} while (0)
|
+#define mtk_wed_device_stop(_dev) do {} while (0)
|
||||||
+#define mtk_wed_device_dma_reset(_dev) do {} while (0)
|
+#define mtk_wed_device_dma_reset(_dev) do {} while (0)
|
||||||
|
+#define mtk_wed_device_setup_tc(_dev, _netdev, _type, _type_data) -EOPNOTSUPP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,266 @@
|
||||||
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
|
Date: Mon, 20 Mar 2023 11:44:30 +0100
|
||||||
|
Subject: [PATCH] net: ethernet: mtk_eth_soc: add code for offloading flows
|
||||||
|
from wlan devices
|
||||||
|
|
||||||
|
WED version 2 (on MT7986 and later) can offload flows originating from wireless
|
||||||
|
devices. In order to make that work, ndo_setup_tc needs to be implemented on
|
||||||
|
the netdevs. This adds the required code to offload flows coming in from WED,
|
||||||
|
while keeping track of the incoming wed index used for selecting the correct
|
||||||
|
PPE device.
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||||
|
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||||
|
@@ -1319,6 +1319,9 @@ int mtk_gmac_rgmii_path_setup(struct mtk
|
||||||
|
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);
|
||||||
|
+int mtk_flow_offload_cmd(struct mtk_eth *eth, struct flow_cls_offload *cls,
|
||||||
|
+ int ppe_index);
|
||||||
|
+void mtk_flow_offload_cleanup(struct mtk_eth *eth, struct list_head *list);
|
||||||
|
void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
|
||||||
|
|
||||||
|
|
||||||
|
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||||
|
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||||
|
@@ -235,7 +235,8 @@ out:
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
-mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
|
||||||
|
+mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f,
|
||||||
|
+ int ppe_index)
|
||||||
|
{
|
||||||
|
struct flow_rule *rule = flow_cls_offload_flow_rule(f);
|
||||||
|
struct flow_action_entry *act;
|
||||||
|
@@ -452,6 +453,7 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||||
|
entry->cookie = f->cookie;
|
||||||
|
memcpy(&entry->data, &foe, sizeof(entry->data));
|
||||||
|
entry->wed_index = wed_index;
|
||||||
|
+ entry->ppe_index = ppe_index;
|
||||||
|
|
||||||
|
err = mtk_foe_entry_commit(eth->ppe[entry->ppe_index], entry);
|
||||||
|
if (err < 0)
|
||||||
|
@@ -520,25 +522,15 @@ mtk_flow_offload_stats(struct mtk_eth *e
|
||||||
|
|
||||||
|
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)
|
||||||
|
+int mtk_flow_offload_cmd(struct mtk_eth *eth, struct flow_cls_offload *cls,
|
||||||
|
+ int ppe_index)
|
||||||
|
{
|
||||||
|
- 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);
|
||||||
|
+ err = mtk_flow_offload_replace(eth, cls, ppe_index);
|
||||||
|
break;
|
||||||
|
case FLOW_CLS_DESTROY:
|
||||||
|
err = mtk_flow_offload_destroy(eth, cls);
|
||||||
|
@@ -556,6 +548,23 @@ mtk_eth_setup_tc_block_cb(enum tc_setup_
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
+
|
||||||
|
+ if (!tc_can_offload(dev))
|
||||||
|
+ return -EOPNOTSUPP;
|
||||||
|
+
|
||||||
|
+ if (type != TC_SETUP_CLSFLOWER)
|
||||||
|
+ return -EOPNOTSUPP;
|
||||||
|
+
|
||||||
|
+ return mtk_flow_offload_cmd(eth, cls, 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f)
|
||||||
|
{
|
||||||
|
struct mtk_mac *mac = netdev_priv(dev);
|
||||||
|
--- a/drivers/net/ethernet/mediatek/mtk_wed.c
|
||||||
|
+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
|
||||||
|
@@ -13,6 +13,8 @@
|
||||||
|
#include <linux/mfd/syscon.h>
|
||||||
|
#include <linux/debugfs.h>
|
||||||
|
#include <linux/soc/mediatek/mtk_wed.h>
|
||||||
|
+#include <net/flow_offload.h>
|
||||||
|
+#include <net/pkt_cls.h>
|
||||||
|
#include "mtk_eth_soc.h"
|
||||||
|
#include "mtk_wed_regs.h"
|
||||||
|
#include "mtk_wed.h"
|
||||||
|
@@ -41,6 +43,11 @@
|
||||||
|
static struct mtk_wed_hw *hw_list[2];
|
||||||
|
static DEFINE_MUTEX(hw_lock);
|
||||||
|
|
||||||
|
+struct mtk_wed_flow_block_priv {
|
||||||
|
+ struct mtk_wed_hw *hw;
|
||||||
|
+ struct net_device *dev;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
static void
|
||||||
|
wed_m32(struct mtk_wed_device *dev, u32 reg, u32 mask, u32 val)
|
||||||
|
{
|
||||||
|
@@ -1752,6 +1759,99 @@ out:
|
||||||
|
mutex_unlock(&hw_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int
|
||||||
|
+mtk_wed_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv)
|
||||||
|
+{
|
||||||
|
+ struct mtk_wed_flow_block_priv *priv = cb_priv;
|
||||||
|
+ struct flow_cls_offload *cls = type_data;
|
||||||
|
+ struct mtk_wed_hw *hw = priv->hw;
|
||||||
|
+
|
||||||
|
+ if (!tc_can_offload(priv->dev))
|
||||||
|
+ return -EOPNOTSUPP;
|
||||||
|
+
|
||||||
|
+ if (type != TC_SETUP_CLSFLOWER)
|
||||||
|
+ return -EOPNOTSUPP;
|
||||||
|
+
|
||||||
|
+ return mtk_flow_offload_cmd(hw->eth, cls, hw->index);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+mtk_wed_setup_tc_block(struct mtk_wed_hw *hw, struct net_device *dev,
|
||||||
|
+ struct flow_block_offload *f)
|
||||||
|
+{
|
||||||
|
+ struct mtk_wed_flow_block_priv *priv;
|
||||||
|
+ static LIST_HEAD(block_cb_list);
|
||||||
|
+ struct flow_block_cb *block_cb;
|
||||||
|
+ struct mtk_eth *eth = hw->eth;
|
||||||
|
+ flow_setup_cb_t *cb;
|
||||||
|
+
|
||||||
|
+ if (!eth->soc->offload_version)
|
||||||
|
+ return -EOPNOTSUPP;
|
||||||
|
+
|
||||||
|
+ if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
|
||||||
|
+ return -EOPNOTSUPP;
|
||||||
|
+
|
||||||
|
+ cb = mtk_wed_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);
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||||
|
+ if (!priv)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+
|
||||||
|
+ priv->hw = hw;
|
||||||
|
+ priv->dev = dev;
|
||||||
|
+ block_cb = flow_block_cb_alloc(cb, dev, priv, NULL);
|
||||||
|
+ if (IS_ERR(block_cb)) {
|
||||||
|
+ kfree(priv);
|
||||||
|
+ return PTR_ERR(block_cb);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ flow_block_cb_incref(block_cb);
|
||||||
|
+ flow_block_cb_add(block_cb, f);
|
||||||
|
+ list_add_tail(&block_cb->driver_list, &block_cb_list);
|
||||||
|
+ return 0;
|
||||||
|
+ case FLOW_BLOCK_UNBIND:
|
||||||
|
+ block_cb = flow_block_cb_lookup(f->block, cb, dev);
|
||||||
|
+ if (!block_cb)
|
||||||
|
+ return -ENOENT;
|
||||||
|
+
|
||||||
|
+ if (!flow_block_cb_decref(block_cb)) {
|
||||||
|
+ flow_block_cb_remove(block_cb, f);
|
||||||
|
+ list_del(&block_cb->driver_list);
|
||||||
|
+ kfree(block_cb->cb_priv);
|
||||||
|
+ }
|
||||||
|
+ return 0;
|
||||||
|
+ default:
|
||||||
|
+ return -EOPNOTSUPP;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+mtk_wed_setup_tc(struct mtk_wed_device *wed, struct net_device *dev,
|
||||||
|
+ enum tc_setup_type type, void *type_data)
|
||||||
|
+{
|
||||||
|
+ struct mtk_wed_hw *hw = wed->hw;
|
||||||
|
+
|
||||||
|
+ if (hw->version < 2)
|
||||||
|
+ return -EOPNOTSUPP;
|
||||||
|
+
|
||||||
|
+ switch (type) {
|
||||||
|
+ case TC_SETUP_BLOCK:
|
||||||
|
+ case TC_SETUP_FT:
|
||||||
|
+ return mtk_wed_setup_tc_block(hw, dev, type_data);
|
||||||
|
+ default:
|
||||||
|
+ return -EOPNOTSUPP;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
|
||||||
|
void __iomem *wdma, phys_addr_t wdma_phy,
|
||||||
|
int index)
|
||||||
|
@@ -1771,6 +1871,7 @@ void mtk_wed_add_hw(struct device_node *
|
||||||
|
.irq_set_mask = mtk_wed_irq_set_mask,
|
||||||
|
.detach = mtk_wed_detach,
|
||||||
|
.ppe_check = mtk_wed_ppe_check,
|
||||||
|
+ .setup_tc = mtk_wed_setup_tc,
|
||||||
|
};
|
||||||
|
struct device_node *eth_np = eth->dev->of_node;
|
||||||
|
struct platform_device *pdev;
|
||||||
|
--- a/include/linux/soc/mediatek/mtk_wed.h
|
||||||
|
+++ b/include/linux/soc/mediatek/mtk_wed.h
|
||||||
|
@@ -6,6 +6,7 @@
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
+#include <linux/netdevice.h>
|
||||||
|
|
||||||
|
#define MTK_WED_TX_QUEUES 2
|
||||||
|
#define MTK_WED_RX_QUEUES 2
|
||||||
|
@@ -180,6 +181,8 @@ struct mtk_wed_ops {
|
||||||
|
|
||||||
|
u32 (*irq_get)(struct mtk_wed_device *dev, u32 mask);
|
||||||
|
void (*irq_set_mask)(struct mtk_wed_device *dev, u32 mask);
|
||||||
|
+ int (*setup_tc)(struct mtk_wed_device *wed, struct net_device *dev,
|
||||||
|
+ enum tc_setup_type type, void *type_data);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct mtk_wed_ops __rcu *mtk_soc_wed_ops;
|
||||||
|
@@ -238,6 +241,8 @@ mtk_wed_get_rx_capa(struct mtk_wed_devic
|
||||||
|
(_dev)->ops->msg_update(_dev, _id, _msg, _len)
|
||||||
|
#define mtk_wed_device_stop(_dev) (_dev)->ops->stop(_dev)
|
||||||
|
#define mtk_wed_device_dma_reset(_dev) (_dev)->ops->reset_dma(_dev)
|
||||||
|
+#define mtk_wed_device_setup_tc(_dev, _netdev, _type, _type_data) \
|
||||||
|
+ (_dev)->ops->setup_tc(_dev, _netdev, _type, _type_data)
|
||||||
|
#else
|
||||||
|
static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
|
||||||
|
{
|
||||||
|
@@ -256,6 +261,7 @@ static inline bool mtk_wed_device_active
|
||||||
|
#define mtk_wed_device_update_msg(_dev, _id, _msg, _len) -ENODEV
|
||||||
|
#define mtk_wed_device_stop(_dev) do {} while (0)
|
||||||
|
#define mtk_wed_device_dma_reset(_dev) do {} while (0)
|
||||||
|
+#define mtk_wed_device_setup_tc(_dev, _netdev, _type, _type_data) -EOPNOTSUPP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,37 @@
|
||||||
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
|
Date: Mon, 20 Mar 2023 15:37:55 +0100
|
||||||
|
Subject: [PATCH] net: ethernet: mediatek: mtk_ppe: prefer newly added l2
|
||||||
|
flows over existing ones
|
||||||
|
|
||||||
|
When a device is roaming between interfaces and a new flow entry is created,
|
||||||
|
we should assume that its output device is more up to date than whatever
|
||||||
|
entry existed already.
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||||
|
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||||
|
@@ -639,10 +639,20 @@ void mtk_foe_entry_clear(struct mtk_ppe
|
||||||
|
static int
|
||||||
|
mtk_foe_entry_commit_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||||
|
{
|
||||||
|
+ struct mtk_flow_entry *prev;
|
||||||
|
+
|
||||||
|
entry->type = MTK_FLOW_TYPE_L2;
|
||||||
|
|
||||||
|
- return rhashtable_insert_fast(&ppe->l2_flows, &entry->l2_node,
|
||||||
|
- mtk_flow_l2_ht_params);
|
||||||
|
+ prev = rhashtable_lookup_get_insert_fast(&ppe->l2_flows, &entry->l2_node,
|
||||||
|
+ mtk_flow_l2_ht_params);
|
||||||
|
+ if (likely(!prev))
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ if (IS_ERR(prev))
|
||||||
|
+ return PTR_ERR(prev);
|
||||||
|
+
|
||||||
|
+ return rhashtable_replace_fast(&ppe->l2_flows, &prev->l2_node,
|
||||||
|
+ &entry->l2_node, mtk_flow_l2_ht_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
|
@ -22,7 +22,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/mediatek/mtk_wed.c
|
--- a/drivers/net/ethernet/mediatek/mtk_wed.c
|
||||||
+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
|
+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
|
||||||
@@ -806,6 +806,24 @@ mtk_wed_rro_alloc(struct mtk_wed_device
|
@@ -813,6 +813,24 @@ mtk_wed_rro_alloc(struct mtk_wed_device
|
||||||
struct device_node *np;
|
struct device_node *np;
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||||
index = of_property_match_string(dev->hw->node, "memory-region-names",
|
index = of_property_match_string(dev->hw->node, "memory-region-names",
|
||||||
"wo-dlm");
|
"wo-dlm");
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
@@ -822,6 +840,7 @@ mtk_wed_rro_alloc(struct mtk_wed_device
|
@@ -829,6 +847,7 @@ mtk_wed_rro_alloc(struct mtk_wed_device
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
dev->rro.miod_phys = rmem->base;
|
dev->rro.miod_phys = rmem->base;
|
||||||
|
|
Loading…
Reference in a new issue