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