xref: /linux/drivers/net/ethernet/mellanox/mlx5/core/en/trap.c (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
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 	u16 q_counter;
67 	int node;
68 	int err;
69 
70 	node = dev_to_node(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(priv->mdev, trap_moder, &rq_param->cqp, &ccp, &rq->cq);
80 	if (err)
81 		return err;
82 
83 	mlx5e_init_trap_rq(t, &t->params, rq);
84 	err = mlx5e_open_rq(&t->params, rq_param, NULL, node, q_counter, rq);
85 	if (err)
86 		goto err_destroy_cq;
87 
88 	return 0;
89 
90 err_destroy_cq:
91 	mlx5e_close_cq(&rq->cq);
92 
93 	return err;
94 }
95 
mlx5e_close_trap_rq(struct mlx5e_rq * rq)96 static void mlx5e_close_trap_rq(struct mlx5e_rq *rq)
97 {
98 	mlx5e_close_rq(rq);
99 	mlx5e_close_cq(&rq->cq);
100 }
101 
mlx5e_create_trap_direct_rq_tir(struct mlx5_core_dev * mdev,struct mlx5e_tir * tir,u32 rqn)102 static 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(false);
109 	if (!builder)
110 		return -ENOMEM;
111 
112 	mlx5e_tir_builder_build_inline(builder, mdev->mlx5e_res.hw_objs.td.tdn, rqn);
113 	err = mlx5e_tir_init(tir, builder, mdev, true);
114 
115 	mlx5e_tir_builder_free(builder);
116 
117 	return err;
118 }
119 
mlx5e_build_trap_params(struct mlx5_core_dev * mdev,int max_mtu,struct mlx5e_trap * t)120 static 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, &t->rq_param);
129 }
130 
mlx5e_open_trap(struct mlx5e_priv * priv)131 static struct mlx5e_trap *mlx5e_open_trap(struct mlx5e_priv *priv)
132 {
133 	int cpu = mlx5_comp_vector_get_cpu(priv->mdev, 0);
134 	struct net_device *netdev = priv->netdev;
135 	struct mlx5e_trap *t;
136 	int err;
137 
138 	t = kvzalloc_node(sizeof(*t), GFP_KERNEL, cpu_to_node(cpu));
139 	if (!t)
140 		return ERR_PTR(-ENOMEM);
141 
142 	mlx5e_build_trap_params(priv->mdev, 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(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(netdev, &t->napi, 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(t->mdev, &t->tir, t->rq.rqn);
159 	if (err)
160 		goto err_close_trap_rq;
161 
162 	return t;
163 
164 err_close_trap_rq:
165 	mlx5e_close_trap_rq(&t->rq);
166 err_napi_del:
167 	netif_napi_del(&t->napi);
168 	kvfree(t);
169 	return ERR_PTR(err);
170 }
171 
mlx5e_close_trap(struct mlx5e_trap * trap)172 void mlx5e_close_trap(struct mlx5e_trap *trap)
173 {
174 	mlx5e_tir_destroy(&trap->tir);
175 	mlx5e_close_trap_rq(&trap->rq);
176 	netif_napi_del(&trap->napi);
177 	kvfree(trap);
178 }
179 
mlx5e_activate_trap(struct mlx5e_trap * trap)180 static void mlx5e_activate_trap(struct mlx5e_trap *trap)
181 {
182 	napi_enable(&trap->napi);
183 	mlx5e_activate_rq(&trap->rq);
184 	mlx5e_trigger_napi_sched(&trap->napi);
185 }
186 
mlx5e_deactivate_trap(struct mlx5e_priv * priv)187 void mlx5e_deactivate_trap(struct mlx5e_priv *priv)
188 {
189 	struct mlx5e_trap *trap = priv->en_trap;
190 
191 	mlx5e_deactivate_rq(&trap->rq);
192 	napi_disable(&trap->napi);
193 }
194 
mlx5e_add_trap_queue(struct mlx5e_priv * priv)195 static 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(trap))
201 		goto out;
202 
203 	mlx5e_activate_trap(trap);
204 out:
205 	return trap;
206 }
207 
mlx5e_del_trap_queue(struct mlx5e_priv * priv)208 static void mlx5e_del_trap_queue(struct mlx5e_priv *priv)
209 {
210 	mlx5e_deactivate_trap(priv);
211 	mlx5e_close_trap(priv->en_trap);
212 	priv->en_trap = NULL;
213 }
214 
mlx5e_trap_get_tirn(struct mlx5e_trap * en_trap)215 static int mlx5e_trap_get_tirn(struct mlx5e_trap *en_trap)
216 {
217 	return en_trap->tir.tirn;
218 }
219 
mlx5e_handle_action_trap(struct mlx5e_priv * priv,int trap_id)220 static 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(trap))
229 			return PTR_ERR(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(priv->fs, trap_id, mlx5e_trap_get_tirn(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(priv->fs, trap_id, mlx5e_trap_get_tirn(priv->en_trap));
241 		if (err)
242 			goto err_out;
243 		break;
244 	default:
245 		netdev_warn(priv->netdev, "%s: Unknown trap id %d\n", __func__, trap_id);
246 		err = -EINVAL;
247 		goto err_out;
248 	}
249 	return 0;
250 
251 err_out:
252 	if (open_queue)
253 		mlx5e_del_trap_queue(priv);
254 	return err;
255 }
256 
mlx5e_handle_action_drop(struct mlx5e_priv * priv,int trap_id)257 static 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(priv->fs);
262 		break;
263 	case DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER:
264 		mlx5e_remove_mac_trap(priv->fs);
265 		break;
266 	default:
267 		netdev_warn(priv->netdev, "%s: Unknown trap id %d\n", __func__, trap_id);
268 		return -EINVAL;
269 	}
270 	if (priv->en_trap && !mlx5_devlink_trap_get_num_active(priv->mdev))
271 		mlx5e_del_trap_queue(priv);
272 
273 	return 0;
274 }
275 
mlx5e_handle_trap_event(struct mlx5e_priv * priv,struct mlx5_trap_ctx * trap_ctx)276 int 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_ctx->id);
291 		break;
292 	case DEVLINK_TRAP_ACTION_DROP:
293 		err = mlx5e_handle_action_drop(priv, trap_ctx->id);
294 		break;
295 	default:
296 		netdev_warn(priv->netdev, "%s: Unsupported action %d\n", __func__,
297 			    trap_ctx->action);
298 		err = -EINVAL;
299 	}
300 	return err;
301 }
302 
mlx5e_apply_trap(struct mlx5e_priv * priv,int trap_id,bool enable)303 static 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(priv->mdev, trap_id, &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 
317 static const int mlx5e_traps_arr[] = {
318 	DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER,
319 	DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER,
320 };
321 
mlx5e_apply_traps(struct mlx5e_priv * priv,bool enable)322 int 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, mlx5e_traps_arr[i], enable);
329 		if (err)
330 			return err;
331 	}
332 	return 0;
333 }
334