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

source code of linux/drivers/net/ethernet/mellanox/mlx5/core/en/trap.c