15543e989SAya Levin // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
25543e989SAya Levin /* Copyright (c) 2020 Mellanox Technologies */
35543e989SAya Levin 
45543e989SAya Levin #include <net/page_pool.h>
55543e989SAya Levin #include "en/txrx.h"
65543e989SAya Levin #include "en/params.h"
75543e989SAya Levin #include "en/trap.h"
85543e989SAya Levin 
95543e989SAya Levin static int mlx5e_trap_napi_poll(struct napi_struct *napi, int budget)
105543e989SAya Levin {
115543e989SAya Levin 	struct mlx5e_trap *trap_ctx = container_of(napi, struct mlx5e_trap, napi);
125543e989SAya Levin 	struct mlx5e_ch_stats *ch_stats = trap_ctx->stats;
135543e989SAya Levin 	struct mlx5e_rq *rq = &trap_ctx->rq;
145543e989SAya Levin 	bool busy = false;
155543e989SAya Levin 	int work_done = 0;
165543e989SAya Levin 
175543e989SAya Levin 	ch_stats->poll++;
185543e989SAya Levin 
195543e989SAya Levin 	work_done = mlx5e_poll_rx_cq(&rq->cq, budget);
205543e989SAya Levin 	busy |= work_done == budget;
215543e989SAya Levin 	busy |= rq->post_wqes(rq);
225543e989SAya Levin 
235543e989SAya Levin 	if (busy)
245543e989SAya Levin 		return budget;
255543e989SAya Levin 
265543e989SAya Levin 	if (unlikely(!napi_complete_done(napi, work_done)))
275543e989SAya Levin 		return work_done;
285543e989SAya Levin 
295543e989SAya Levin 	mlx5e_cq_arm(&rq->cq);
305543e989SAya Levin 	return work_done;
315543e989SAya Levin }
325543e989SAya Levin 
33869c5f92SAya Levin static void mlx5e_init_trap_rq(struct mlx5e_trap *t, struct mlx5e_params *params,
345543e989SAya Levin 			       struct mlx5e_rq *rq)
355543e989SAya Levin {
36869c5f92SAya Levin 	struct mlx5_core_dev *mdev = t->mdev;
37869c5f92SAya Levin 	struct mlx5e_priv *priv = t->priv;
38869c5f92SAya Levin 
39869c5f92SAya Levin 	rq->wq_type      = params->rq_wq_type;
40*497008e7SAya Levin 	rq->pdev         = t->pdev;
41869c5f92SAya Levin 	rq->netdev       = priv->netdev;
42869c5f92SAya Levin 	rq->priv         = priv;
43869c5f92SAya Levin 	rq->clock        = &mdev->clock;
44869c5f92SAya Levin 	rq->tstamp       = &priv->tstamp;
45869c5f92SAya Levin 	rq->mdev         = mdev;
46869c5f92SAya Levin 	rq->hw_mtu       = MLX5E_SW2HW_MTU(params, params->sw_mtu);
47869c5f92SAya Levin 	rq->stats        = &priv->trap_stats.rq;
48869c5f92SAya Levin 	rq->ptp_cyc2time = mlx5_rq_ts_translator(mdev);
49869c5f92SAya Levin 	xdp_rxq_info_unused(&rq->xdp_rxq);
50869c5f92SAya Levin 	mlx5e_rq_set_trap_handlers(rq, params);
51869c5f92SAya Levin }
52869c5f92SAya Levin 
53869c5f92SAya Levin static int mlx5e_open_trap_rq(struct mlx5e_priv *priv, struct mlx5e_trap *t)
54869c5f92SAya Levin {
55869c5f92SAya Levin 	struct mlx5e_rq_param *rq_param = &t->rq_param;
565543e989SAya Levin 	struct mlx5_core_dev *mdev = priv->mdev;
575543e989SAya Levin 	struct mlx5e_create_cq_param ccp = {};
585543e989SAya Levin 	struct dim_cq_moder trap_moder = {};
59869c5f92SAya Levin 	struct mlx5e_rq *rq = &t->rq;
60869c5f92SAya Levin 	int node;
615543e989SAya Levin 	int err;
625543e989SAya Levin 
63869c5f92SAya Levin 	node = dev_to_node(mdev->device);
64869c5f92SAya Levin 
65869c5f92SAya Levin 	ccp.node     = node;
66869c5f92SAya Levin 	ccp.ch_stats = t->stats;
67869c5f92SAya Levin 	ccp.napi     = &t->napi;
685543e989SAya Levin 	ccp.ix       = 0;
69869c5f92SAya Levin 	err = mlx5e_open_cq(priv, trap_moder, &rq_param->cqp, &ccp, &rq->cq);
705543e989SAya Levin 	if (err)
715543e989SAya Levin 		return err;
725543e989SAya Levin 
73869c5f92SAya Levin 	mlx5e_init_trap_rq(t, &t->params, rq);
74869c5f92SAya Levin 	err = mlx5e_open_rq(&t->params, rq_param, NULL, node, rq);
755543e989SAya Levin 	if (err)
765543e989SAya Levin 		goto err_destroy_cq;
775543e989SAya Levin 
785543e989SAya Levin 	return 0;
795543e989SAya Levin 
805543e989SAya Levin err_destroy_cq:
81869c5f92SAya Levin 	mlx5e_close_cq(&rq->cq);
825543e989SAya Levin 
835543e989SAya Levin 	return err;
845543e989SAya Levin }
855543e989SAya Levin 
865543e989SAya Levin static void mlx5e_close_trap_rq(struct mlx5e_rq *rq)
875543e989SAya Levin {
88e078e8dfSAya Levin 	mlx5e_close_rq(rq);
895543e989SAya Levin 	mlx5e_close_cq(&rq->cq);
905543e989SAya Levin }
915543e989SAya Levin 
925543e989SAya Levin static int mlx5e_create_trap_direct_rq_tir(struct mlx5_core_dev *mdev, struct mlx5e_tir *tir,
935543e989SAya Levin 					   u32 rqn)
945543e989SAya Levin {
955543e989SAya Levin 	void *tirc;
965543e989SAya Levin 	int inlen;
975543e989SAya Levin 	u32 *in;
985543e989SAya Levin 	int err;
995543e989SAya Levin 
1005543e989SAya Levin 	inlen = MLX5_ST_SZ_BYTES(create_tir_in);
1015543e989SAya Levin 	in = kvzalloc(inlen, GFP_KERNEL);
1025543e989SAya Levin 	if (!in)
1035543e989SAya Levin 		return -ENOMEM;
1045543e989SAya Levin 
1055543e989SAya Levin 	tirc = MLX5_ADDR_OF(create_tir_in, in, ctx);
106c276aae8SRoi Dayan 	MLX5_SET(tirc, tirc, transport_domain, mdev->mlx5e_res.hw_objs.td.tdn);
1075543e989SAya Levin 	MLX5_SET(tirc, tirc, rx_hash_fn, MLX5_RX_HASH_FN_NONE);
1085543e989SAya Levin 	MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_DIRECT);
1095543e989SAya Levin 	MLX5_SET(tirc, tirc, inline_rqn, rqn);
1105543e989SAya Levin 	err = mlx5e_create_tir(mdev, tir, in);
1115543e989SAya Levin 	kvfree(in);
1125543e989SAya Levin 
1135543e989SAya Levin 	return err;
1145543e989SAya Levin }
1155543e989SAya Levin 
1165543e989SAya Levin static void mlx5e_destroy_trap_direct_rq_tir(struct mlx5_core_dev *mdev, struct mlx5e_tir *tir)
1175543e989SAya Levin {
1185543e989SAya Levin 	mlx5e_destroy_tir(mdev, tir);
1195543e989SAya Levin }
1205543e989SAya Levin 
12189564920STariq Toukan static void mlx5e_build_trap_params(struct mlx5_core_dev *mdev,
12289564920STariq Toukan 				    int max_mtu, u16 q_counter,
12389564920STariq Toukan 				    struct mlx5e_trap *t)
1245543e989SAya Levin {
1255543e989SAya Levin 	struct mlx5e_params *params = &t->params;
1265543e989SAya Levin 
1275543e989SAya Levin 	params->rq_wq_type = MLX5_WQ_TYPE_CYCLIC;
12889564920STariq Toukan 	mlx5e_init_rq_type_params(mdev, params);
12989564920STariq Toukan 	params->sw_mtu = max_mtu;
13089564920STariq Toukan 	mlx5e_build_rq_param(mdev, params, NULL, q_counter, &t->rq_param);
1315543e989SAya Levin }
1325543e989SAya Levin 
1335543e989SAya Levin static struct mlx5e_trap *mlx5e_open_trap(struct mlx5e_priv *priv)
1345543e989SAya Levin {
1355543e989SAya Levin 	int cpu = cpumask_first(mlx5_comp_irq_get_affinity_mask(priv->mdev, 0));
1365543e989SAya Levin 	struct net_device *netdev = priv->netdev;
1375543e989SAya Levin 	struct mlx5e_trap *t;
1385543e989SAya Levin 	int err;
1395543e989SAya Levin 
1405543e989SAya Levin 	t = kvzalloc_node(sizeof(*t), GFP_KERNEL, cpu_to_node(cpu));
1415543e989SAya Levin 	if (!t)
1425543e989SAya Levin 		return ERR_PTR(-ENOMEM);
1435543e989SAya Levin 
14489564920STariq Toukan 	mlx5e_build_trap_params(priv->mdev, netdev->max_mtu, priv->q_counter, t);
1455543e989SAya Levin 
1465543e989SAya Levin 	t->priv     = priv;
1475543e989SAya Levin 	t->mdev     = priv->mdev;
1485543e989SAya Levin 	t->tstamp   = &priv->tstamp;
1495543e989SAya Levin 	t->pdev     = mlx5_core_dma_dev(priv->mdev);
1505543e989SAya Levin 	t->netdev   = priv->netdev;
151c276aae8SRoi Dayan 	t->mkey_be  = cpu_to_be32(priv->mdev->mlx5e_res.hw_objs.mkey.key);
1525543e989SAya Levin 	t->stats    = &priv->trap_stats.ch;
1535543e989SAya Levin 
1545543e989SAya Levin 	netif_napi_add(netdev, &t->napi, mlx5e_trap_napi_poll, 64);
1555543e989SAya Levin 
156869c5f92SAya Levin 	err = mlx5e_open_trap_rq(priv, t);
1575543e989SAya Levin 	if (unlikely(err))
1585543e989SAya Levin 		goto err_napi_del;
1595543e989SAya Levin 
1605543e989SAya Levin 	err = mlx5e_create_trap_direct_rq_tir(t->mdev, &t->tir, t->rq.rqn);
1615543e989SAya Levin 	if (err)
1625543e989SAya Levin 		goto err_close_trap_rq;
1635543e989SAya Levin 
1645543e989SAya Levin 	return t;
1655543e989SAya Levin 
1665543e989SAya Levin err_close_trap_rq:
1675543e989SAya Levin 	mlx5e_close_trap_rq(&t->rq);
1685543e989SAya Levin err_napi_del:
1695543e989SAya Levin 	netif_napi_del(&t->napi);
1705543e989SAya Levin 	kvfree(t);
1715543e989SAya Levin 	return ERR_PTR(err);
1725543e989SAya Levin }
1735543e989SAya Levin 
1745543e989SAya Levin void mlx5e_close_trap(struct mlx5e_trap *trap)
1755543e989SAya Levin {
1765543e989SAya Levin 	mlx5e_destroy_trap_direct_rq_tir(trap->mdev, &trap->tir);
1775543e989SAya Levin 	mlx5e_close_trap_rq(&trap->rq);
1785543e989SAya Levin 	netif_napi_del(&trap->napi);
1795543e989SAya Levin 	kvfree(trap);
1805543e989SAya Levin }
1815543e989SAya Levin 
1825543e989SAya Levin static void mlx5e_activate_trap(struct mlx5e_trap *trap)
1835543e989SAya Levin {
1845543e989SAya Levin 	napi_enable(&trap->napi);
185a8dd7ac1SAya Levin 	mlx5e_activate_rq(&trap->rq);
1865543e989SAya Levin }
1875543e989SAya Levin 
1885543e989SAya Levin void mlx5e_deactivate_trap(struct mlx5e_priv *priv)
1895543e989SAya Levin {
1905543e989SAya Levin 	struct mlx5e_trap *trap = priv->en_trap;
1915543e989SAya Levin 
192a8dd7ac1SAya Levin 	mlx5e_deactivate_rq(&trap->rq);
1935543e989SAya Levin 	napi_disable(&trap->napi);
1945543e989SAya Levin }
1955543e989SAya Levin 
1965543e989SAya Levin static struct mlx5e_trap *mlx5e_add_trap_queue(struct mlx5e_priv *priv)
1975543e989SAya Levin {
1985543e989SAya Levin 	struct mlx5e_trap *trap;
1995543e989SAya Levin 
2005543e989SAya Levin 	trap = mlx5e_open_trap(priv);
2015543e989SAya Levin 	if (IS_ERR(trap))
2025543e989SAya Levin 		goto out;
2035543e989SAya Levin 
2045543e989SAya Levin 	mlx5e_activate_trap(trap);
2055543e989SAya Levin out:
2065543e989SAya Levin 	return trap;
2075543e989SAya Levin }
2085543e989SAya Levin 
2095543e989SAya Levin static void mlx5e_del_trap_queue(struct mlx5e_priv *priv)
2105543e989SAya Levin {
2115543e989SAya Levin 	mlx5e_deactivate_trap(priv);
2125543e989SAya Levin 	mlx5e_close_trap(priv->en_trap);
2135543e989SAya Levin 	priv->en_trap = NULL;
2145543e989SAya Levin }
2155543e989SAya Levin 
2165543e989SAya Levin static int mlx5e_trap_get_tirn(struct mlx5e_trap *en_trap)
2175543e989SAya Levin {
2185543e989SAya Levin 	return en_trap->tir.tirn;
2195543e989SAya Levin }
2205543e989SAya Levin 
2215543e989SAya Levin static int mlx5e_handle_action_trap(struct mlx5e_priv *priv, int trap_id)
2225543e989SAya Levin {
2235543e989SAya Levin 	bool open_queue = !priv->en_trap;
2245543e989SAya Levin 	struct mlx5e_trap *trap;
2255543e989SAya Levin 	int err;
2265543e989SAya Levin 
2275543e989SAya Levin 	if (open_queue) {
2285543e989SAya Levin 		trap = mlx5e_add_trap_queue(priv);
2295543e989SAya Levin 		if (IS_ERR(trap))
2305543e989SAya Levin 			return PTR_ERR(trap);
2315543e989SAya Levin 		priv->en_trap = trap;
2325543e989SAya Levin 	}
2335543e989SAya Levin 
2345543e989SAya Levin 	switch (trap_id) {
2355543e989SAya Levin 	case DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER:
2365543e989SAya Levin 		err = mlx5e_add_vlan_trap(priv, trap_id, mlx5e_trap_get_tirn(priv->en_trap));
2375543e989SAya Levin 		if (err)
2385543e989SAya Levin 			goto err_out;
2395543e989SAya Levin 		break;
24049fdbd23SAya Levin 	case DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER:
24149fdbd23SAya Levin 		err = mlx5e_add_mac_trap(priv, trap_id, mlx5e_trap_get_tirn(priv->en_trap));
24249fdbd23SAya Levin 		if (err)
24349fdbd23SAya Levin 			goto err_out;
24449fdbd23SAya Levin 		break;
2455543e989SAya Levin 	default:
2465543e989SAya Levin 		netdev_warn(priv->netdev, "%s: Unknown trap id %d\n", __func__, trap_id);
2475543e989SAya Levin 		err = -EINVAL;
2485543e989SAya Levin 		goto err_out;
2495543e989SAya Levin 	}
2505543e989SAya Levin 	return 0;
2515543e989SAya Levin 
2525543e989SAya Levin err_out:
2535543e989SAya Levin 	if (open_queue)
2545543e989SAya Levin 		mlx5e_del_trap_queue(priv);
2555543e989SAya Levin 	return err;
2565543e989SAya Levin }
2575543e989SAya Levin 
2585543e989SAya Levin static int mlx5e_handle_action_drop(struct mlx5e_priv *priv, int trap_id)
2595543e989SAya Levin {
2605543e989SAya Levin 	switch (trap_id) {
2615543e989SAya Levin 	case DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER:
2625543e989SAya Levin 		mlx5e_remove_vlan_trap(priv);
2635543e989SAya Levin 		break;
26449fdbd23SAya Levin 	case DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER:
26549fdbd23SAya Levin 		mlx5e_remove_mac_trap(priv);
26649fdbd23SAya Levin 		break;
2675543e989SAya Levin 	default:
2685543e989SAya Levin 		netdev_warn(priv->netdev, "%s: Unknown trap id %d\n", __func__, trap_id);
2695543e989SAya Levin 		return -EINVAL;
2705543e989SAya Levin 	}
2715543e989SAya Levin 	if (priv->en_trap && !mlx5_devlink_trap_get_num_active(priv->mdev))
2725543e989SAya Levin 		mlx5e_del_trap_queue(priv);
2735543e989SAya Levin 
2745543e989SAya Levin 	return 0;
2755543e989SAya Levin }
2765543e989SAya Levin 
2775543e989SAya Levin int mlx5e_handle_trap_event(struct mlx5e_priv *priv, struct mlx5_trap_ctx *trap_ctx)
2785543e989SAya Levin {
2795543e989SAya Levin 	int err = 0;
2805543e989SAya Levin 
281eb3862a0SAya Levin 	/* Traps are unarmed when interface is down, no need to update
282eb3862a0SAya Levin 	 * them. The configuration is saved in the core driver,
283eb3862a0SAya Levin 	 * queried and applied upon interface up operation in
284eb3862a0SAya Levin 	 * mlx5e_open_locked().
285eb3862a0SAya Levin 	 */
286eb3862a0SAya Levin 	if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
287eb3862a0SAya Levin 		return 0;
288eb3862a0SAya Levin 
2895543e989SAya Levin 	switch (trap_ctx->action) {
2905543e989SAya Levin 	case DEVLINK_TRAP_ACTION_TRAP:
2915543e989SAya Levin 		err = mlx5e_handle_action_trap(priv, trap_ctx->id);
2925543e989SAya Levin 		break;
2935543e989SAya Levin 	case DEVLINK_TRAP_ACTION_DROP:
2945543e989SAya Levin 		err = mlx5e_handle_action_drop(priv, trap_ctx->id);
2955543e989SAya Levin 		break;
2965543e989SAya Levin 	default:
2975543e989SAya Levin 		netdev_warn(priv->netdev, "%s: Unsupported action %d\n", __func__,
2985543e989SAya Levin 			    trap_ctx->action);
2995543e989SAya Levin 		err = -EINVAL;
3005543e989SAya Levin 	}
3015543e989SAya Levin 	return err;
3025543e989SAya Levin }
303eb3862a0SAya Levin 
304eb3862a0SAya Levin static int mlx5e_apply_trap(struct mlx5e_priv *priv, int trap_id, bool enable)
305eb3862a0SAya Levin {
306eb3862a0SAya Levin 	enum devlink_trap_action action;
307eb3862a0SAya Levin 	int err;
308eb3862a0SAya Levin 
309eb3862a0SAya Levin 	err = mlx5_devlink_traps_get_action(priv->mdev, trap_id, &action);
310eb3862a0SAya Levin 	if (err)
311eb3862a0SAya Levin 		return err;
312eb3862a0SAya Levin 	if (action == DEVLINK_TRAP_ACTION_TRAP)
313eb3862a0SAya Levin 		err = enable ? mlx5e_handle_action_trap(priv, trap_id) :
314eb3862a0SAya Levin 			       mlx5e_handle_action_drop(priv, trap_id);
315eb3862a0SAya Levin 	return err;
316eb3862a0SAya Levin }
317eb3862a0SAya Levin 
318eb3862a0SAya Levin static const int mlx5e_traps_arr[] = {
319eb3862a0SAya Levin 	DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER,
320eb3862a0SAya Levin 	DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER,
321eb3862a0SAya Levin };
322eb3862a0SAya Levin 
323eb3862a0SAya Levin int mlx5e_apply_traps(struct mlx5e_priv *priv, bool enable)
324eb3862a0SAya Levin {
325eb3862a0SAya Levin 	int err;
326eb3862a0SAya Levin 	int i;
327eb3862a0SAya Levin 
328eb3862a0SAya Levin 	for (i = 0; i < ARRAY_SIZE(mlx5e_traps_arr); i++) {
329eb3862a0SAya Levin 		err = mlx5e_apply_trap(priv, mlx5e_traps_arr[i], enable);
330eb3862a0SAya Levin 		if (err)
331eb3862a0SAya Levin 			return err;
332eb3862a0SAya Levin 	}
333eb3862a0SAya Levin 	return 0;
334eb3862a0SAya Levin }
335