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:
		| @@ -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; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Felix Fietkau
					Felix Fietkau