1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2020 Mellanox Technologies */
3
4 #include <net/page_pool.h>
5 #include "en/txrx.h"
6 #include "en/params.h"
7 #include "en/trap.h"
8
mlx5e_trap_napi_poll(struct napi_struct * napi,int budget)9 static int mlx5e_trap_napi_poll(struct napi_struct *napi, int budget)
10 {
11 struct mlx5e_trap *trap_ctx = container_of(napi, struct mlx5e_trap, napi);
12 struct mlx5e_ch_stats *ch_stats = trap_ctx->stats;
13 struct mlx5e_rq *rq = &trap_ctx->rq;
14 bool busy = false;
15 int work_done = 0;
16
17 ch_stats->poll++;
18
19 work_done = mlx5e_poll_rx_cq(&rq->cq, budget);
20 busy |= work_done == budget;
21 busy |= rq->post_wqes(rq);
22
23 if (busy)
24 return budget;
25
26 if (unlikely(!napi_complete_done(napi, work_done)))
27 return work_done;
28
29 mlx5e_cq_arm(&rq->cq);
30 return work_done;
31 }
32
mlx5e_init_trap_rq(struct mlx5e_trap * t,struct mlx5e_params * params,struct mlx5e_rq * rq)33 static void mlx5e_init_trap_rq(struct mlx5e_trap *t, struct mlx5e_params *params,
34 struct mlx5e_rq *rq)
35 {
36 struct mlx5_core_dev *mdev = t->mdev;
37 struct mlx5e_priv *priv = t->priv;
38
39 rq->wq_type = params->rq_wq_type;
40 rq->pdev = t->pdev;
41 rq->netdev = priv->netdev;
42 rq->priv = priv;
43 rq->clock = &mdev->clock;
44 rq->tstamp = &priv->tstamp;
45 rq->mdev = mdev;
46 rq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu);
47 rq->stats = &priv->trap_stats.rq;
48 rq->ptp_cyc2time = mlx5_rq_ts_translator(mdev);
49 xdp_rxq_info_unused(&rq->xdp_rxq);
50 mlx5e_rq_set_trap_handlers(rq, params);
51 }
52
mlx5e_open_trap_rq(struct mlx5e_priv * priv,struct mlx5e_trap * t)53 static int mlx5e_open_trap_rq(struct mlx5e_priv *priv, struct mlx5e_trap *t)
54 {
55 struct mlx5e_rq_param *rq_param = &t->rq_param;
56 struct mlx5_core_dev *mdev = priv->mdev;
57 struct mlx5e_create_cq_param ccp = {};
58 struct dim_cq_moder trap_moder = {};
59 struct mlx5e_rq *rq = &t->rq;
60 int node;
61 int err;
62
63 node = dev_to_node(mdev->device);
64
65 ccp.node = node;
66 ccp.ch_stats = t->stats;
67 ccp.napi = &t->napi;
68 ccp.ix = 0;
69 err = mlx5e_open_cq(priv, trap_moder, &rq_param->cqp, &ccp, &rq->cq);
70 if (err)
71 return err;
72
73 mlx5e_init_trap_rq(t, &t->params, rq);
74 err = mlx5e_open_rq(&t->params, rq_param, NULL, node, rq);
75 if (err)
76 goto err_destroy_cq;
77
78 return 0;
79
80 err_destroy_cq:
81 mlx5e_close_cq(&rq->cq);
82
83 return err;
84 }
85
mlx5e_close_trap_rq(struct mlx5e_rq * rq)86 static void mlx5e_close_trap_rq(struct mlx5e_rq *rq)
87 {
88 mlx5e_close_rq(rq);
89 mlx5e_close_cq(&rq->cq);
90 }
91
mlx5e_create_trap_direct_rq_tir(struct mlx5_core_dev * mdev,struct mlx5e_tir * tir,u32 rqn)92 static int mlx5e_create_trap_direct_rq_tir(struct mlx5_core_dev *mdev, struct mlx5e_tir *tir,
93 u32 rqn)
94 {
95 struct mlx5e_tir_builder *builder;
96 int err;
97
98 builder = mlx5e_tir_builder_alloc(false);
99 if (!builder)
100 return -ENOMEM;
101
102 mlx5e_tir_builder_build_inline(builder, mdev->mlx5e_res.hw_objs.td.tdn, rqn);
103 err = mlx5e_tir_init(tir, builder, mdev, true);
104
105 mlx5e_tir_builder_free(builder);
106
107 return err;
108 }
109
mlx5e_build_trap_params(struct mlx5_core_dev * mdev,int max_mtu,u16 q_counter,struct mlx5e_trap * t)110 static void mlx5e_build_trap_params(struct mlx5_core_dev *mdev,
111 int max_mtu, u16 q_counter,
112 struct mlx5e_trap *t)
113 {
114 struct mlx5e_params *params = &t->params;
115
116 params->rq_wq_type = MLX5_WQ_TYPE_CYCLIC;
117 mlx5e_init_rq_type_params(mdev, params);
118 params->sw_mtu = max_mtu;
119 mlx5e_build_rq_param(mdev, params, NULL, q_counter, &t->rq_param);
120 }
121
mlx5e_open_trap(struct mlx5e_priv * priv)122 static struct mlx5e_trap *mlx5e_open_trap(struct mlx5e_priv *priv)
123 {
124 int cpu = cpumask_first(mlx5_comp_irq_get_affinity_mask(priv->mdev, 0));
125 struct net_device *netdev = priv->netdev;
126 struct mlx5e_trap *t;
127 int err;
128
129 t = kvzalloc_node(sizeof(*t), GFP_KERNEL, cpu_to_node(cpu));
130 if (!t)
131 return ERR_PTR(-ENOMEM);
132
133 mlx5e_build_trap_params(priv->mdev, netdev->max_mtu, priv->q_counter, t);
134
135 t->priv = priv;
136 t->mdev = priv->mdev;
137 t->tstamp = &priv->tstamp;
138 t->pdev = mlx5_core_dma_dev(priv->mdev);
139 t->netdev = priv->netdev;
140 t->mkey_be = cpu_to_be32(priv->mdev->mlx5e_res.hw_objs.mkey);
141 t->stats = &priv->trap_stats.ch;
142
143 netif_napi_add(netdev, &t->napi, mlx5e_trap_napi_poll, 64);
144
145 err = mlx5e_open_trap_rq(priv, t);
146 if (unlikely(err))
147 goto err_napi_del;
148
149 err = mlx5e_create_trap_direct_rq_tir(t->mdev, &t->tir, t->rq.rqn);
150 if (err)
151 goto err_close_trap_rq;
152
153 return t;
154
155 err_close_trap_rq:
156 mlx5e_close_trap_rq(&t->rq);
157 err_napi_del:
158 netif_napi_del(&t->napi);
159 kvfree(t);
160 return ERR_PTR(err);
161 }
162
mlx5e_close_trap(struct mlx5e_trap * trap)163 void mlx5e_close_trap(struct mlx5e_trap *trap)
164 {
165 mlx5e_tir_destroy(&trap->tir);
166 mlx5e_close_trap_rq(&trap->rq);
167 netif_napi_del(&trap->napi);
168 kvfree(trap);
169 }
170
mlx5e_activate_trap(struct mlx5e_trap * trap)171 static void mlx5e_activate_trap(struct mlx5e_trap *trap)
172 {
173 napi_enable(&trap->napi);
174 mlx5e_activate_rq(&trap->rq);
175 }
176
mlx5e_deactivate_trap(struct mlx5e_priv * priv)177 void mlx5e_deactivate_trap(struct mlx5e_priv *priv)
178 {
179 struct mlx5e_trap *trap = priv->en_trap;
180
181 mlx5e_deactivate_rq(&trap->rq);
182 napi_disable(&trap->napi);
183 }
184
mlx5e_add_trap_queue(struct mlx5e_priv * priv)185 static struct mlx5e_trap *mlx5e_add_trap_queue(struct mlx5e_priv *priv)
186 {
187 struct mlx5e_trap *trap;
188
189 trap = mlx5e_open_trap(priv);
190 if (IS_ERR(trap))
191 goto out;
192
193 mlx5e_activate_trap(trap);
194 out:
195 return trap;
196 }
197
mlx5e_del_trap_queue(struct mlx5e_priv * priv)198 static void mlx5e_del_trap_queue(struct mlx5e_priv *priv)
199 {
200 mlx5e_deactivate_trap(priv);
201 mlx5e_close_trap(priv->en_trap);
202 priv->en_trap = NULL;
203 }
204
mlx5e_trap_get_tirn(struct mlx5e_trap * en_trap)205 static int mlx5e_trap_get_tirn(struct mlx5e_trap *en_trap)
206 {
207 return en_trap->tir.tirn;
208 }
209
mlx5e_handle_action_trap(struct mlx5e_priv * priv,int trap_id)210 static int mlx5e_handle_action_trap(struct mlx5e_priv *priv, int trap_id)
211 {
212 bool open_queue = !priv->en_trap;
213 struct mlx5e_trap *trap;
214 int err;
215
216 if (open_queue) {
217 trap = mlx5e_add_trap_queue(priv);
218 if (IS_ERR(trap))
219 return PTR_ERR(trap);
220 priv->en_trap = trap;
221 }
222
223 switch (trap_id) {
224 case DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER:
225 err = mlx5e_add_vlan_trap(priv, trap_id, mlx5e_trap_get_tirn(priv->en_trap));
226 if (err)
227 goto err_out;
228 break;
229 case DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER:
230 err = mlx5e_add_mac_trap(priv, trap_id, mlx5e_trap_get_tirn(priv->en_trap));
231 if (err)
232 goto err_out;
233 break;
234 default:
235 netdev_warn(priv->netdev, "%s: Unknown trap id %d\n", __func__, trap_id);
236 err = -EINVAL;
237 goto err_out;
238 }
239 return 0;
240
241 err_out:
242 if (open_queue)
243 mlx5e_del_trap_queue(priv);
244 return err;
245 }
246
mlx5e_handle_action_drop(struct mlx5e_priv * priv,int trap_id)247 static int mlx5e_handle_action_drop(struct mlx5e_priv *priv, int trap_id)
248 {
249 switch (trap_id) {
250 case DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER:
251 mlx5e_remove_vlan_trap(priv);
252 break;
253 case DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER:
254 mlx5e_remove_mac_trap(priv);
255 break;
256 default:
257 netdev_warn(priv->netdev, "%s: Unknown trap id %d\n", __func__, trap_id);
258 return -EINVAL;
259 }
260 if (priv->en_trap && !mlx5_devlink_trap_get_num_active(priv->mdev))
261 mlx5e_del_trap_queue(priv);
262
263 return 0;
264 }
265
mlx5e_handle_trap_event(struct mlx5e_priv * priv,struct mlx5_trap_ctx * trap_ctx)266 int mlx5e_handle_trap_event(struct mlx5e_priv *priv, struct mlx5_trap_ctx *trap_ctx)
267 {
268 int err = 0;
269
270 /* Traps are unarmed when interface is down, no need to update
271 * them. The configuration is saved in the core driver,
272 * queried and applied upon interface up operation in
273 * mlx5e_open_locked().
274 */
275 if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
276 return 0;
277
278 switch (trap_ctx->action) {
279 case DEVLINK_TRAP_ACTION_TRAP:
280 err = mlx5e_handle_action_trap(priv, trap_ctx->id);
281 break;
282 case DEVLINK_TRAP_ACTION_DROP:
283 err = mlx5e_handle_action_drop(priv, trap_ctx->id);
284 break;
285 default:
286 netdev_warn(priv->netdev, "%s: Unsupported action %d\n", __func__,
287 trap_ctx->action);
288 err = -EINVAL;
289 }
290 return err;
291 }
292
mlx5e_apply_trap(struct mlx5e_priv * priv,int trap_id,bool enable)293 static int mlx5e_apply_trap(struct mlx5e_priv *priv, int trap_id, bool enable)
294 {
295 enum devlink_trap_action action;
296 int err;
297
298 err = mlx5_devlink_traps_get_action(priv->mdev, trap_id, &action);
299 if (err)
300 return err;
301 if (action == DEVLINK_TRAP_ACTION_TRAP)
302 err = enable ? mlx5e_handle_action_trap(priv, trap_id) :
303 mlx5e_handle_action_drop(priv, trap_id);
304 return err;
305 }
306
307 static const int mlx5e_traps_arr[] = {
308 DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER,
309 DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER,
310 };
311
mlx5e_apply_traps(struct mlx5e_priv * priv,bool enable)312 int mlx5e_apply_traps(struct mlx5e_priv *priv, bool enable)
313 {
314 int err;
315 int i;
316
317 for (i = 0; i < ARRAY_SIZE(mlx5e_traps_arr); i++) {
318 err = mlx5e_apply_trap(priv, mlx5e_traps_arr[i], enable);
319 if (err)
320 return err;
321 }
322 return 0;
323 }
324