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         = mdev->device;
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 	void *tirc;
96 	int inlen;
97 	u32 *in;
98 	int err;
99 
100 	inlen = MLX5_ST_SZ_BYTES(create_tir_in);
101 	in = kvzalloc(inlen, GFP_KERNEL);
102 	if (!in)
103 		return -ENOMEM;
104 
105 	tirc = MLX5_ADDR_OF(create_tir_in, in, ctx);
106 	MLX5_SET(tirc, tirc, transport_domain, mdev->mlx5e_res.hw_objs.td.tdn);
107 	MLX5_SET(tirc, tirc, rx_hash_fn, MLX5_RX_HASH_FN_NONE);
108 	MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_DIRECT);
109 	MLX5_SET(tirc, tirc, inline_rqn, rqn);
110 	err = mlx5e_create_tir(mdev, tir, in);
111 	kvfree(in);
112 
113 	return err;
114 }
115 
mlx5e_destroy_trap_direct_rq_tir(struct mlx5_core_dev * mdev,struct mlx5e_tir * tir)116 static void mlx5e_destroy_trap_direct_rq_tir(struct mlx5_core_dev *mdev, struct mlx5e_tir *tir)
117 {
118 	mlx5e_destroy_tir(mdev, tir);
119 }
120 
mlx5e_build_trap_params(struct mlx5_core_dev * mdev,int max_mtu,u16 q_counter,struct mlx5e_trap * t)121 static void mlx5e_build_trap_params(struct mlx5_core_dev *mdev,
122 				    int max_mtu, u16 q_counter,
123 				    struct mlx5e_trap *t)
124 {
125 	struct mlx5e_params *params = &t->params;
126 
127 	params->rq_wq_type = MLX5_WQ_TYPE_CYCLIC;
128 	mlx5e_init_rq_type_params(mdev, params);
129 	params->sw_mtu = max_mtu;
130 	mlx5e_build_rq_param(mdev, params, NULL, q_counter, &t->rq_param);
131 }
132 
mlx5e_open_trap(struct mlx5e_priv * priv)133 static struct mlx5e_trap *mlx5e_open_trap(struct mlx5e_priv *priv)
134 {
135 	int cpu = cpumask_first(mlx5_comp_irq_get_affinity_mask(priv->mdev, 0));
136 	struct net_device *netdev = priv->netdev;
137 	struct mlx5e_trap *t;
138 	int err;
139 
140 	t = kvzalloc_node(sizeof(*t), GFP_KERNEL, cpu_to_node(cpu));
141 	if (!t)
142 		return ERR_PTR(-ENOMEM);
143 
144 	mlx5e_build_trap_params(priv->mdev, netdev->max_mtu, priv->q_counter, t);
145 
146 	t->priv     = priv;
147 	t->mdev     = priv->mdev;
148 	t->tstamp   = &priv->tstamp;
149 	t->pdev     = mlx5_core_dma_dev(priv->mdev);
150 	t->netdev   = priv->netdev;
151 	t->mkey_be  = cpu_to_be32(priv->mdev->mlx5e_res.hw_objs.mkey.key);
152 	t->stats    = &priv->trap_stats.ch;
153 
154 	netif_napi_add(netdev, &t->napi, mlx5e_trap_napi_poll, 64);
155 
156 	err = mlx5e_open_trap_rq(priv, t);
157 	if (unlikely(err))
158 		goto err_napi_del;
159 
160 	err = mlx5e_create_trap_direct_rq_tir(t->mdev, &t->tir, t->rq.rqn);
161 	if (err)
162 		goto err_close_trap_rq;
163 
164 	return t;
165 
166 err_close_trap_rq:
167 	mlx5e_close_trap_rq(&t->rq);
168 err_napi_del:
169 	netif_napi_del(&t->napi);
170 	kvfree(t);
171 	return ERR_PTR(err);
172 }
173 
mlx5e_close_trap(struct mlx5e_trap * trap)174 void mlx5e_close_trap(struct mlx5e_trap *trap)
175 {
176 	mlx5e_destroy_trap_direct_rq_tir(trap->mdev, &trap->tir);
177 	mlx5e_close_trap_rq(&trap->rq);
178 	netif_napi_del(&trap->napi);
179 	kvfree(trap);
180 }
181 
mlx5e_activate_trap(struct mlx5e_trap * trap)182 static void mlx5e_activate_trap(struct mlx5e_trap *trap)
183 {
184 	napi_enable(&trap->napi);
185 	mlx5e_activate_rq(&trap->rq);
186 }
187 
mlx5e_deactivate_trap(struct mlx5e_priv * priv)188 void mlx5e_deactivate_trap(struct mlx5e_priv *priv)
189 {
190 	struct mlx5e_trap *trap = priv->en_trap;
191 
192 	mlx5e_deactivate_rq(&trap->rq);
193 	napi_disable(&trap->napi);
194 }
195 
mlx5e_add_trap_queue(struct mlx5e_priv * priv)196 static struct mlx5e_trap *mlx5e_add_trap_queue(struct mlx5e_priv *priv)
197 {
198 	struct mlx5e_trap *trap;
199 
200 	trap = mlx5e_open_trap(priv);
201 	if (IS_ERR(trap))
202 		goto out;
203 
204 	mlx5e_activate_trap(trap);
205 out:
206 	return trap;
207 }
208 
mlx5e_del_trap_queue(struct mlx5e_priv * priv)209 static void mlx5e_del_trap_queue(struct mlx5e_priv *priv)
210 {
211 	mlx5e_deactivate_trap(priv);
212 	mlx5e_close_trap(priv->en_trap);
213 	priv->en_trap = NULL;
214 }
215 
mlx5e_trap_get_tirn(struct mlx5e_trap * en_trap)216 static int mlx5e_trap_get_tirn(struct mlx5e_trap *en_trap)
217 {
218 	return en_trap->tir.tirn;
219 }
220 
mlx5e_handle_action_trap(struct mlx5e_priv * priv,int trap_id)221 static int mlx5e_handle_action_trap(struct mlx5e_priv *priv, int trap_id)
222 {
223 	bool open_queue = !priv->en_trap;
224 	struct mlx5e_trap *trap;
225 	int err;
226 
227 	if (open_queue) {
228 		trap = mlx5e_add_trap_queue(priv);
229 		if (IS_ERR(trap))
230 			return PTR_ERR(trap);
231 		priv->en_trap = trap;
232 	}
233 
234 	switch (trap_id) {
235 	case DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER:
236 		err = mlx5e_add_vlan_trap(priv, trap_id, mlx5e_trap_get_tirn(priv->en_trap));
237 		if (err)
238 			goto err_out;
239 		break;
240 	case DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER:
241 		err = mlx5e_add_mac_trap(priv, trap_id, mlx5e_trap_get_tirn(priv->en_trap));
242 		if (err)
243 			goto err_out;
244 		break;
245 	default:
246 		netdev_warn(priv->netdev, "%s: Unknown trap id %d\n", __func__, trap_id);
247 		err = -EINVAL;
248 		goto err_out;
249 	}
250 	return 0;
251 
252 err_out:
253 	if (open_queue)
254 		mlx5e_del_trap_queue(priv);
255 	return err;
256 }
257 
mlx5e_handle_action_drop(struct mlx5e_priv * priv,int trap_id)258 static int mlx5e_handle_action_drop(struct mlx5e_priv *priv, int trap_id)
259 {
260 	switch (trap_id) {
261 	case DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER:
262 		mlx5e_remove_vlan_trap(priv);
263 		break;
264 	case DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER:
265 		mlx5e_remove_mac_trap(priv);
266 		break;
267 	default:
268 		netdev_warn(priv->netdev, "%s: Unknown trap id %d\n", __func__, trap_id);
269 		return -EINVAL;
270 	}
271 	if (priv->en_trap && !mlx5_devlink_trap_get_num_active(priv->mdev))
272 		mlx5e_del_trap_queue(priv);
273 
274 	return 0;
275 }
276 
mlx5e_handle_trap_event(struct mlx5e_priv * priv,struct mlx5_trap_ctx * trap_ctx)277 int mlx5e_handle_trap_event(struct mlx5e_priv *priv, struct mlx5_trap_ctx *trap_ctx)
278 {
279 	int err = 0;
280 
281 	/* Traps are unarmed when interface is down, no need to update
282 	 * them. The configuration is saved in the core driver,
283 	 * queried and applied upon interface up operation in
284 	 * mlx5e_open_locked().
285 	 */
286 	if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
287 		return 0;
288 
289 	switch (trap_ctx->action) {
290 	case DEVLINK_TRAP_ACTION_TRAP:
291 		err = mlx5e_handle_action_trap(priv, trap_ctx->id);
292 		break;
293 	case DEVLINK_TRAP_ACTION_DROP:
294 		err = mlx5e_handle_action_drop(priv, trap_ctx->id);
295 		break;
296 	default:
297 		netdev_warn(priv->netdev, "%s: Unsupported action %d\n", __func__,
298 			    trap_ctx->action);
299 		err = -EINVAL;
300 	}
301 	return err;
302 }
303 
mlx5e_apply_trap(struct mlx5e_priv * priv,int trap_id,bool enable)304 static int mlx5e_apply_trap(struct mlx5e_priv *priv, int trap_id, bool enable)
305 {
306 	enum devlink_trap_action action;
307 	int err;
308 
309 	err = mlx5_devlink_traps_get_action(priv->mdev, trap_id, &action);
310 	if (err)
311 		return err;
312 	if (action == DEVLINK_TRAP_ACTION_TRAP)
313 		err = enable ? mlx5e_handle_action_trap(priv, trap_id) :
314 			       mlx5e_handle_action_drop(priv, trap_id);
315 	return err;
316 }
317 
318 static const int mlx5e_traps_arr[] = {
319 	DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER,
320 	DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER,
321 };
322 
mlx5e_apply_traps(struct mlx5e_priv * priv,bool enable)323 int mlx5e_apply_traps(struct mlx5e_priv *priv, bool enable)
324 {
325 	int err;
326 	int i;
327 
328 	for (i = 0; i < ARRAY_SIZE(mlx5e_traps_arr); i++) {
329 		err = mlx5e_apply_trap(priv, mlx5e_traps_arr[i], enable);
330 		if (err)
331 			return err;
332 	}
333 	return 0;
334 }
335