mediatek: add kernel code for supporting offloading wlan->eth and wlan->wlan flows
authorFelix Fietkau <nbd@nbd.name>
Mon, 20 Mar 2023 17:51:06 +0000 (18:51 +0100)
committerFelix Fietkau <nbd@nbd.name>
Thu, 23 Mar 2023 16:54:18 +0000 (17:54 +0100)
Will be enabled by an upcoming mt76 update

Signed-off-by: Felix Fietkau <nbd@nbd.name>
package/kernel/mac80211/patches/subsys/327-wifi-mac80211-add-support-for-letting-drivers-regist.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch
target/linux/generic/hack-5.10/100-update-mtk_wed_h.patch
target/linux/generic/pending-5.15/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch [new file with mode: 0644]
target/linux/generic/pending-5.15/736-02-net-ethernet-mediatek-mtk_ppe-prefer-newly-added-l2-.patch [new file with mode: 0644]
target/linux/mediatek/patches-5.15/944-net-ethernet-mtk_wed-move-dlm-a-dedicated-dts-node.patch

diff --git a/package/kernel/mac80211/patches/subsys/327-wifi-mac80211-add-support-for-letting-drivers-regist.patch b/package/kernel/mac80211/patches/subsys/327-wifi-mac80211-add-support-for-letting-drivers-regist.patch
new file mode 100644 (file)
index 0000000..f1807bd
--- /dev/null
@@ -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,
index 80ffb493b8930c5700d53a2af1f0ef75da6bbb21..d7ee33bebc0fa11edc82debbbe945fab0c399a8d 100644 (file)
@@ -18,7 +18,7 @@
  
 --- a/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
   *    value only that is set to the minimum of all interfaces
@@ -26,7 +26,7 @@
   *
   * @chandef: the channel definition to tune to
   * @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 {
        u32 flags;
        int power_level, dynamic_ps_timeout;
@@ -57,7 +57,7 @@
        __NL80211_ATTR_AFTER_LAST,
 --- a/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;
  }
  
@@ -77,7 +77,7 @@
  static void ieee80211_rfkill_poll(struct wiphy *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_tx_power = ieee80211_set_tx_power,
        .get_tx_power = ieee80211_get_tx_power,
index 151f2e8054d93ad7cdfdc920ce651855ee1d1c4e..5f05179a36a1834dd1e2a457e8e02965542f7fe4 100644 (file)
@@ -1,10 +1,11 @@
 --- a/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/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
@@ -77,7 +78,7 @@
  struct mtk_wed_device {
  #ifdef CONFIG_NET_MEDIATEK_SOC_WED
        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;
        int wdma_idx;
        int irq;
        } wlan;
  #endif
  };
-@@ -59,10 +160,16 @@ struct mtk_wed_device {
+@@ -59,10 +161,16 @@ struct mtk_wed_device {
  struct mtk_wed_ops {
        int (*attach)(struct mtk_wed_device *dev);
        int (*tx_ring_setup)(struct mtk_wed_device *dev, int ring,
  
        void (*stop)(struct mtk_wed_device *dev);
        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;
  }
  
  #define mtk_wed_device_txfree_ring_setup(_dev, _regs) \
        (_dev)->ops->txfree_ring_setup(_dev, _regs)
  #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)
  #define mtk_wed_device_irq_set_mask(_dev, _mask) \
        (_dev)->ops->irq_set_mask(_dev, _mask)
 +      (_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)
  {
-@@ -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_start(_dev, _mask) do {} while (0)
 +#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
diff --git a/target/linux/generic/pending-5.15/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch b/target/linux/generic/pending-5.15/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch
new file mode 100644 (file)
index 0000000..0496752
--- /dev/null
@@ -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
diff --git a/target/linux/generic/pending-5.15/736-02-net-ethernet-mediatek-mtk_ppe-prefer-newly-added-l2-.patch b/target/linux/generic/pending-5.15/736-02-net-ethernet-mediatek-mtk_ppe-prefer-newly-added-l2-.patch
new file mode 100644 (file)
index 0000000..6e17e4d
--- /dev/null
@@ -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)
index fb3940f5447f702c0962c90fdc1a8f95645166cd..a455005504cead5f41035a08bfd8253509c58a6d 100644 (file)
@@ -22,7 +22,7 @@ Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
 
 --- a/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;
        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",
                                         "wo-dlm");
        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;
  
        dev->rro.miod_phys = rmem->base;