1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Mon, 20 Mar 2023 11:44:30 +0100
3 Subject: [PATCH] net: ethernet: mtk_eth_soc: add code for offloading flows
6 WED version 2 (on MT7986 and later) can offload flows originating from wireless
7 devices. In order to make that work, ndo_setup_tc needs to be implemented on
8 the netdevs. This adds the required code to offload flows coming in from WED,
9 while keeping track of the incoming wed index used for selecting the correct
12 Signed-off-by: Felix Fietkau <nbd@nbd.name>
15 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
16 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
17 @@ -1277,6 +1277,9 @@ int mtk_gmac_rgmii_path_setup(struct mtk
18 int mtk_eth_offload_init(struct mtk_eth *eth);
19 int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
21 +int mtk_flow_offload_cmd(struct mtk_eth *eth, struct flow_cls_offload *cls,
23 +void mtk_flow_offload_cleanup(struct mtk_eth *eth, struct list_head *list);
24 void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
27 --- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
28 +++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
29 @@ -235,7 +235,8 @@ out:
33 -mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
34 +mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f,
37 struct flow_rule *rule = flow_cls_offload_flow_rule(f);
38 struct flow_action_entry *act;
39 @@ -452,6 +453,7 @@ mtk_flow_offload_replace(struct mtk_eth
40 entry->cookie = f->cookie;
41 memcpy(&entry->data, &foe, sizeof(entry->data));
42 entry->wed_index = wed_index;
43 + entry->ppe_index = ppe_index;
45 err = mtk_foe_entry_commit(eth->ppe[entry->ppe_index], entry);
47 @@ -520,25 +522,15 @@ mtk_flow_offload_stats(struct mtk_eth *e
49 static DEFINE_MUTEX(mtk_flow_offload_mutex);
52 -mtk_eth_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv)
53 +int mtk_flow_offload_cmd(struct mtk_eth *eth, struct flow_cls_offload *cls,
56 - struct flow_cls_offload *cls = type_data;
57 - struct net_device *dev = cb_priv;
58 - struct mtk_mac *mac = netdev_priv(dev);
59 - struct mtk_eth *eth = mac->hw;
62 - if (!tc_can_offload(dev))
65 - if (type != TC_SETUP_CLSFLOWER)
68 mutex_lock(&mtk_flow_offload_mutex);
69 switch (cls->command) {
70 case FLOW_CLS_REPLACE:
71 - err = mtk_flow_offload_replace(eth, cls);
72 + err = mtk_flow_offload_replace(eth, cls, ppe_index);
74 case FLOW_CLS_DESTROY:
75 err = mtk_flow_offload_destroy(eth, cls);
76 @@ -556,6 +548,23 @@ mtk_eth_setup_tc_block_cb(enum tc_setup_
80 +mtk_eth_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv)
82 + struct flow_cls_offload *cls = type_data;
83 + struct net_device *dev = cb_priv;
84 + struct mtk_mac *mac = netdev_priv(dev);
85 + struct mtk_eth *eth = mac->hw;
87 + if (!tc_can_offload(dev))
90 + if (type != TC_SETUP_CLSFLOWER)
93 + return mtk_flow_offload_cmd(eth, cls, 0);
97 mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f)
99 struct mtk_mac *mac = netdev_priv(dev);
100 --- a/drivers/net/ethernet/mediatek/mtk_wed.c
101 +++ b/drivers/net/ethernet/mediatek/mtk_wed.c
103 #include <linux/mfd/syscon.h>
104 #include <linux/debugfs.h>
105 #include <linux/soc/mediatek/mtk_wed.h>
106 +#include <net/flow_offload.h>
107 +#include <net/pkt_cls.h>
108 #include "mtk_eth_soc.h"
109 #include "mtk_wed_regs.h"
112 static struct mtk_wed_hw *hw_list[2];
113 static DEFINE_MUTEX(hw_lock);
115 +struct mtk_wed_flow_block_priv {
116 + struct mtk_wed_hw *hw;
117 + struct net_device *dev;
121 wed_m32(struct mtk_wed_device *dev, u32 reg, u32 mask, u32 val)
123 @@ -1752,6 +1759,99 @@ out:
124 mutex_unlock(&hw_lock);
128 +mtk_wed_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv)
130 + struct mtk_wed_flow_block_priv *priv = cb_priv;
131 + struct flow_cls_offload *cls = type_data;
132 + struct mtk_wed_hw *hw = priv->hw;
134 + if (!tc_can_offload(priv->dev))
135 + return -EOPNOTSUPP;
137 + if (type != TC_SETUP_CLSFLOWER)
138 + return -EOPNOTSUPP;
140 + return mtk_flow_offload_cmd(hw->eth, cls, hw->index);
144 +mtk_wed_setup_tc_block(struct mtk_wed_hw *hw, struct net_device *dev,
145 + struct flow_block_offload *f)
147 + struct mtk_wed_flow_block_priv *priv;
148 + static LIST_HEAD(block_cb_list);
149 + struct flow_block_cb *block_cb;
150 + struct mtk_eth *eth = hw->eth;
151 + flow_setup_cb_t *cb;
153 + if (!eth->soc->offload_version)
154 + return -EOPNOTSUPP;
156 + if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
157 + return -EOPNOTSUPP;
159 + cb = mtk_wed_setup_tc_block_cb;
160 + f->driver_block_list = &block_cb_list;
162 + switch (f->command) {
163 + case FLOW_BLOCK_BIND:
164 + block_cb = flow_block_cb_lookup(f->block, cb, dev);
166 + flow_block_cb_incref(block_cb);
170 + priv = kzalloc(sizeof(*priv), GFP_KERNEL);
176 + block_cb = flow_block_cb_alloc(cb, dev, priv, NULL);
177 + if (IS_ERR(block_cb)) {
179 + return PTR_ERR(block_cb);
182 + flow_block_cb_incref(block_cb);
183 + flow_block_cb_add(block_cb, f);
184 + list_add_tail(&block_cb->driver_list, &block_cb_list);
186 + case FLOW_BLOCK_UNBIND:
187 + block_cb = flow_block_cb_lookup(f->block, cb, dev);
191 + if (!flow_block_cb_decref(block_cb)) {
192 + flow_block_cb_remove(block_cb, f);
193 + list_del(&block_cb->driver_list);
194 + kfree(block_cb->cb_priv);
198 + return -EOPNOTSUPP;
203 +mtk_wed_setup_tc(struct mtk_wed_device *wed, struct net_device *dev,
204 + enum tc_setup_type type, void *type_data)
206 + struct mtk_wed_hw *hw = wed->hw;
208 + if (hw->version < 2)
209 + return -EOPNOTSUPP;
212 + case TC_SETUP_BLOCK:
214 + return mtk_wed_setup_tc_block(hw, dev, type_data);
216 + return -EOPNOTSUPP;
220 void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
221 void __iomem *wdma, phys_addr_t wdma_phy,
223 @@ -1771,6 +1871,7 @@ void mtk_wed_add_hw(struct device_node *
224 .irq_set_mask = mtk_wed_irq_set_mask,
225 .detach = mtk_wed_detach,
226 .ppe_check = mtk_wed_ppe_check,
227 + .setup_tc = mtk_wed_setup_tc,
229 struct device_node *eth_np = eth->dev->of_node;
230 struct platform_device *pdev;
231 --- a/include/linux/soc/mediatek/mtk_wed.h
232 +++ b/include/linux/soc/mediatek/mtk_wed.h
234 #include <linux/regmap.h>
235 #include <linux/pci.h>
236 #include <linux/skbuff.h>
237 +#include <linux/netdevice.h>
239 #define MTK_WED_TX_QUEUES 2
240 #define MTK_WED_RX_QUEUES 2
241 @@ -180,6 +181,8 @@ struct mtk_wed_ops {
243 u32 (*irq_get)(struct mtk_wed_device *dev, u32 mask);
244 void (*irq_set_mask)(struct mtk_wed_device *dev, u32 mask);
245 + int (*setup_tc)(struct mtk_wed_device *wed, struct net_device *dev,
246 + enum tc_setup_type type, void *type_data);
249 extern const struct mtk_wed_ops __rcu *mtk_soc_wed_ops;
250 @@ -238,6 +241,8 @@ mtk_wed_get_rx_capa(struct mtk_wed_devic
251 (_dev)->ops->msg_update(_dev, _id, _msg, _len)
252 #define mtk_wed_device_stop(_dev) (_dev)->ops->stop(_dev)
253 #define mtk_wed_device_dma_reset(_dev) (_dev)->ops->reset_dma(_dev)
254 +#define mtk_wed_device_setup_tc(_dev, _netdev, _type, _type_data) \
255 + (_dev)->ops->setup_tc(_dev, _netdev, _type, _type_data)
257 static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
259 @@ -256,6 +261,7 @@ static inline bool mtk_wed_device_active
260 #define mtk_wed_device_update_msg(_dev, _id, _msg, _len) -ENODEV
261 #define mtk_wed_device_stop(_dev) do {} while (0)
262 #define mtk_wed_device_dma_reset(_dev) do {} while (0)
263 +#define mtk_wed_device_setup_tc(_dev, _netdev, _type, _type_data) -EOPNOTSUPP