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