15543e989SAya Levin // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
25543e989SAya Levin /* Copyright (c) 2020 Mellanox Technologies */
35543e989SAya Levin
45543e989SAya Levin #include "en/txrx.h"
55543e989SAya Levin #include "en/params.h"
65543e989SAya Levin #include "en/trap.h"
75543e989SAya Levin
mlx5e_trap_napi_poll(struct napi_struct * napi,int budget)85543e989SAya Levin static int mlx5e_trap_napi_poll(struct napi_struct *napi, int budget)
95543e989SAya Levin {
105543e989SAya Levin struct mlx5e_trap *trap_ctx = container_of(napi, struct mlx5e_trap, napi);
115543e989SAya Levin struct mlx5e_ch_stats *ch_stats = trap_ctx->stats;
125543e989SAya Levin struct mlx5e_rq *rq = &trap_ctx->rq;
135543e989SAya Levin bool busy = false;
145543e989SAya Levin int work_done = 0;
155543e989SAya Levin
1637916974SMaxim Mikityanskiy rcu_read_lock();
1737916974SMaxim Mikityanskiy
185543e989SAya Levin ch_stats->poll++;
195543e989SAya Levin
205543e989SAya Levin work_done = mlx5e_poll_rx_cq(&rq->cq, budget);
215543e989SAya Levin busy |= work_done == budget;
225543e989SAya Levin busy |= rq->post_wqes(rq);
235543e989SAya Levin
2437916974SMaxim Mikityanskiy if (busy) {
2537916974SMaxim Mikityanskiy work_done = budget;
2637916974SMaxim Mikityanskiy goto out;
2737916974SMaxim Mikityanskiy }
285543e989SAya Levin
295543e989SAya Levin if (unlikely(!napi_complete_done(napi, work_done)))
3037916974SMaxim Mikityanskiy goto out;
315543e989SAya Levin
325543e989SAya Levin mlx5e_cq_arm(&rq->cq);
3337916974SMaxim Mikityanskiy
3437916974SMaxim Mikityanskiy out:
3537916974SMaxim Mikityanskiy rcu_read_unlock();
365543e989SAya Levin return work_done;
375543e989SAya Levin }
385543e989SAya Levin
mlx5e_init_trap_rq(struct mlx5e_trap * t,struct mlx5e_params * params,struct mlx5e_rq * rq)39869c5f92SAya Levin static void mlx5e_init_trap_rq(struct mlx5e_trap *t, struct mlx5e_params *params,
405543e989SAya Levin struct mlx5e_rq *rq)
415543e989SAya Levin {
42869c5f92SAya Levin struct mlx5_core_dev *mdev = t->mdev;
43869c5f92SAya Levin struct mlx5e_priv *priv = t->priv;
44869c5f92SAya Levin
45869c5f92SAya Levin rq->wq_type = params->rq_wq_type;
46497008e7SAya Levin rq->pdev = t->pdev;
47869c5f92SAya Levin rq->netdev = priv->netdev;
48869c5f92SAya Levin rq->priv = priv;
49869c5f92SAya Levin rq->clock = &mdev->clock;
50869c5f92SAya Levin rq->tstamp = &priv->tstamp;
51869c5f92SAya Levin rq->mdev = mdev;
52869c5f92SAya Levin rq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu);
53869c5f92SAya Levin rq->stats = &priv->trap_stats.rq;
54869c5f92SAya Levin rq->ptp_cyc2time = mlx5_rq_ts_translator(mdev);
55869c5f92SAya Levin xdp_rxq_info_unused(&rq->xdp_rxq);
56869c5f92SAya Levin mlx5e_rq_set_trap_handlers(rq, params);
57869c5f92SAya Levin }
58869c5f92SAya Levin
mlx5e_open_trap_rq(struct mlx5e_priv * priv,struct mlx5e_trap * t)59869c5f92SAya Levin static int mlx5e_open_trap_rq(struct mlx5e_priv *priv, struct mlx5e_trap *t)
60869c5f92SAya Levin {
61869c5f92SAya Levin struct mlx5e_rq_param *rq_param = &t->rq_param;
625543e989SAya Levin struct mlx5_core_dev *mdev = priv->mdev;
635543e989SAya Levin struct mlx5e_create_cq_param ccp = {};
645543e989SAya Levin struct dim_cq_moder trap_moder = {};
65869c5f92SAya Levin struct mlx5e_rq *rq = &t->rq;
66869c5f92SAya Levin int node;
675543e989SAya Levin int err;
685543e989SAya Levin
69869c5f92SAya Levin node = dev_to_node(mdev->device);
70869c5f92SAya Levin
71869c5f92SAya Levin ccp.node = node;
72869c5f92SAya Levin ccp.ch_stats = t->stats;
73869c5f92SAya Levin ccp.napi = &t->napi;
745543e989SAya Levin ccp.ix = 0;
75869c5f92SAya Levin err = mlx5e_open_cq(priv, trap_moder, &rq_param->cqp, &ccp, &rq->cq);
765543e989SAya Levin if (err)
775543e989SAya Levin return err;
785543e989SAya Levin
79869c5f92SAya Levin mlx5e_init_trap_rq(t, &t->params, rq);
80869c5f92SAya Levin err = mlx5e_open_rq(&t->params, rq_param, NULL, node, rq);
815543e989SAya Levin if (err)
825543e989SAya Levin goto err_destroy_cq;
835543e989SAya Levin
845543e989SAya Levin return 0;
855543e989SAya Levin
865543e989SAya Levin err_destroy_cq:
87869c5f92SAya Levin mlx5e_close_cq(&rq->cq);
885543e989SAya Levin
895543e989SAya Levin return err;
905543e989SAya Levin }
915543e989SAya Levin
mlx5e_close_trap_rq(struct mlx5e_rq * rq)925543e989SAya Levin static void mlx5e_close_trap_rq(struct mlx5e_rq *rq)
935543e989SAya Levin {
94e078e8dfSAya Levin mlx5e_close_rq(rq);
955543e989SAya Levin mlx5e_close_cq(&rq->cq);
965543e989SAya Levin }
975543e989SAya Levin
mlx5e_create_trap_direct_rq_tir(struct mlx5_core_dev * mdev,struct mlx5e_tir * tir,u32 rqn)985543e989SAya Levin static int mlx5e_create_trap_direct_rq_tir(struct mlx5_core_dev *mdev, struct mlx5e_tir *tir,
995543e989SAya Levin u32 rqn)
1005543e989SAya Levin {
101a6696735SMaxim Mikityanskiy struct mlx5e_tir_builder *builder;
1025543e989SAya Levin int err;
1035543e989SAya Levin
104a6696735SMaxim Mikityanskiy builder = mlx5e_tir_builder_alloc(false);
105a6696735SMaxim Mikityanskiy if (!builder)
1065543e989SAya Levin return -ENOMEM;
1075543e989SAya Levin
108a6696735SMaxim Mikityanskiy mlx5e_tir_builder_build_inline(builder, mdev->mlx5e_res.hw_objs.td.tdn, rqn);
109a6696735SMaxim Mikityanskiy err = mlx5e_tir_init(tir, builder, mdev, true);
110a6696735SMaxim Mikityanskiy
111a6696735SMaxim Mikityanskiy mlx5e_tir_builder_free(builder);
1125543e989SAya Levin
1135543e989SAya Levin return err;
1145543e989SAya Levin }
1155543e989SAya Levin
mlx5e_build_trap_params(struct mlx5_core_dev * mdev,int max_mtu,u16 q_counter,struct mlx5e_trap * t)11689564920STariq Toukan static void mlx5e_build_trap_params(struct mlx5_core_dev *mdev,
11789564920STariq Toukan int max_mtu, u16 q_counter,
11889564920STariq Toukan struct mlx5e_trap *t)
1195543e989SAya Levin {
1205543e989SAya Levin struct mlx5e_params *params = &t->params;
1215543e989SAya Levin
1225543e989SAya Levin params->rq_wq_type = MLX5_WQ_TYPE_CYCLIC;
12389564920STariq Toukan mlx5e_init_rq_type_params(mdev, params);
12489564920STariq Toukan params->sw_mtu = max_mtu;
12589564920STariq Toukan mlx5e_build_rq_param(mdev, params, NULL, q_counter, &t->rq_param);
1265543e989SAya Levin }
1275543e989SAya Levin
mlx5e_open_trap(struct mlx5e_priv * priv)1285543e989SAya Levin static struct mlx5e_trap *mlx5e_open_trap(struct mlx5e_priv *priv)
1295543e989SAya Levin {
1305543e989SAya Levin int cpu = mlx5_comp_vector_get_cpu(priv->mdev, 0);
1315543e989SAya Levin struct net_device *netdev = priv->netdev;
1325543e989SAya Levin struct mlx5e_trap *t;
1335543e989SAya Levin int err;
1345543e989SAya Levin
1355543e989SAya Levin t = kvzalloc_node(sizeof(*t), GFP_KERNEL, cpu_to_node(cpu));
1365543e989SAya Levin if (!t)
1375543e989SAya Levin return ERR_PTR(-ENOMEM);
1385543e989SAya Levin
13989564920STariq Toukan mlx5e_build_trap_params(priv->mdev, netdev->max_mtu, priv->q_counter, t);
1405543e989SAya Levin
1415543e989SAya Levin t->priv = priv;
1425543e989SAya Levin t->mdev = priv->mdev;
1435543e989SAya Levin t->tstamp = &priv->tstamp;
1445543e989SAya Levin t->pdev = mlx5_core_dma_dev(priv->mdev);
1455543e989SAya Levin t->netdev = priv->netdev;
14683fec3f1SAharon Landau t->mkey_be = cpu_to_be32(priv->mdev->mlx5e_res.hw_objs.mkey);
1475543e989SAya Levin t->stats = &priv->trap_stats.ch;
1485543e989SAya Levin
149*b48b89f9SJakub Kicinski netif_napi_add(netdev, &t->napi, mlx5e_trap_napi_poll);
1505543e989SAya Levin
151869c5f92SAya Levin err = mlx5e_open_trap_rq(priv, t);
1525543e989SAya Levin if (unlikely(err))
1535543e989SAya Levin goto err_napi_del;
1545543e989SAya Levin
1555543e989SAya Levin err = mlx5e_create_trap_direct_rq_tir(t->mdev, &t->tir, t->rq.rqn);
1565543e989SAya Levin if (err)
1575543e989SAya Levin goto err_close_trap_rq;
1585543e989SAya Levin
1595543e989SAya Levin return t;
1605543e989SAya Levin
1615543e989SAya Levin err_close_trap_rq:
1625543e989SAya Levin mlx5e_close_trap_rq(&t->rq);
1635543e989SAya Levin err_napi_del:
1645543e989SAya Levin netif_napi_del(&t->napi);
1655543e989SAya Levin kvfree(t);
1665543e989SAya Levin return ERR_PTR(err);
1675543e989SAya Levin }
1685543e989SAya Levin
mlx5e_close_trap(struct mlx5e_trap * trap)1695543e989SAya Levin void mlx5e_close_trap(struct mlx5e_trap *trap)
1705543e989SAya Levin {
171a6696735SMaxim Mikityanskiy mlx5e_tir_destroy(&trap->tir);
1725543e989SAya Levin mlx5e_close_trap_rq(&trap->rq);
1735543e989SAya Levin netif_napi_del(&trap->napi);
1745543e989SAya Levin kvfree(trap);
1755543e989SAya Levin }
1765543e989SAya Levin
mlx5e_activate_trap(struct mlx5e_trap * trap)1775543e989SAya Levin static void mlx5e_activate_trap(struct mlx5e_trap *trap)
1785543e989SAya Levin {
1795543e989SAya Levin napi_enable(&trap->napi);
180a8dd7ac1SAya Levin mlx5e_activate_rq(&trap->rq);
1812e642afbSMaxim Mikityanskiy mlx5e_trigger_napi_sched(&trap->napi);
1825543e989SAya Levin }
1835543e989SAya Levin
mlx5e_deactivate_trap(struct mlx5e_priv * priv)1845543e989SAya Levin void mlx5e_deactivate_trap(struct mlx5e_priv *priv)
1855543e989SAya Levin {
1865543e989SAya Levin struct mlx5e_trap *trap = priv->en_trap;
1875543e989SAya Levin
188a8dd7ac1SAya Levin mlx5e_deactivate_rq(&trap->rq);
1895543e989SAya Levin napi_disable(&trap->napi);
1905543e989SAya Levin }
1915543e989SAya Levin
mlx5e_add_trap_queue(struct mlx5e_priv * priv)1925543e989SAya Levin static struct mlx5e_trap *mlx5e_add_trap_queue(struct mlx5e_priv *priv)
1935543e989SAya Levin {
1945543e989SAya Levin struct mlx5e_trap *trap;
1955543e989SAya Levin
1965543e989SAya Levin trap = mlx5e_open_trap(priv);
1975543e989SAya Levin if (IS_ERR(trap))
1985543e989SAya Levin goto out;
1995543e989SAya Levin
2005543e989SAya Levin mlx5e_activate_trap(trap);
2015543e989SAya Levin out:
2025543e989SAya Levin return trap;
2035543e989SAya Levin }
2045543e989SAya Levin
mlx5e_del_trap_queue(struct mlx5e_priv * priv)2055543e989SAya Levin static void mlx5e_del_trap_queue(struct mlx5e_priv *priv)
2065543e989SAya Levin {
2075543e989SAya Levin mlx5e_deactivate_trap(priv);
2085543e989SAya Levin mlx5e_close_trap(priv->en_trap);
2095543e989SAya Levin priv->en_trap = NULL;
2105543e989SAya Levin }
2115543e989SAya Levin
mlx5e_trap_get_tirn(struct mlx5e_trap * en_trap)2125543e989SAya Levin static int mlx5e_trap_get_tirn(struct mlx5e_trap *en_trap)
2135543e989SAya Levin {
2145543e989SAya Levin return en_trap->tir.tirn;
2155543e989SAya Levin }
2165543e989SAya Levin
mlx5e_handle_action_trap(struct mlx5e_priv * priv,int trap_id)2175543e989SAya Levin static int mlx5e_handle_action_trap(struct mlx5e_priv *priv, int trap_id)
2185543e989SAya Levin {
2195543e989SAya Levin bool open_queue = !priv->en_trap;
2205543e989SAya Levin struct mlx5e_trap *trap;
2215543e989SAya Levin int err;
2225543e989SAya Levin
2235543e989SAya Levin if (open_queue) {
2245543e989SAya Levin trap = mlx5e_add_trap_queue(priv);
2255543e989SAya Levin if (IS_ERR(trap))
2265543e989SAya Levin return PTR_ERR(trap);
2275543e989SAya Levin priv->en_trap = trap;
2285543e989SAya Levin }
2295543e989SAya Levin
2305543e989SAya Levin switch (trap_id) {
2315543e989SAya Levin case DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER:
232d494dd2bSLama Kayal err = mlx5e_add_vlan_trap(priv->fs, trap_id, mlx5e_trap_get_tirn(priv->en_trap));
2335543e989SAya Levin if (err)
2345543e989SAya Levin goto err_out;
2355543e989SAya Levin break;
23649fdbd23SAya Levin case DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER:
237d494dd2bSLama Kayal err = mlx5e_add_mac_trap(priv->fs, trap_id, mlx5e_trap_get_tirn(priv->en_trap));
23849fdbd23SAya Levin if (err)
23949fdbd23SAya Levin goto err_out;
24049fdbd23SAya Levin break;
2415543e989SAya Levin default:
2425543e989SAya Levin netdev_warn(priv->netdev, "%s: Unknown trap id %d\n", __func__, trap_id);
2435543e989SAya Levin err = -EINVAL;
2445543e989SAya Levin goto err_out;
2455543e989SAya Levin }
2465543e989SAya Levin return 0;
2475543e989SAya Levin
2485543e989SAya Levin err_out:
2495543e989SAya Levin if (open_queue)
2505543e989SAya Levin mlx5e_del_trap_queue(priv);
2515543e989SAya Levin return err;
2525543e989SAya Levin }
2535543e989SAya Levin
mlx5e_handle_action_drop(struct mlx5e_priv * priv,int trap_id)2545543e989SAya Levin static int mlx5e_handle_action_drop(struct mlx5e_priv *priv, int trap_id)
2555543e989SAya Levin {
2565543e989SAya Levin switch (trap_id) {
2575543e989SAya Levin case DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER:
258d494dd2bSLama Kayal mlx5e_remove_vlan_trap(priv->fs);
2595543e989SAya Levin break;
26049fdbd23SAya Levin case DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER:
261d494dd2bSLama Kayal mlx5e_remove_mac_trap(priv->fs);
26249fdbd23SAya Levin break;
2635543e989SAya Levin default:
2645543e989SAya Levin netdev_warn(priv->netdev, "%s: Unknown trap id %d\n", __func__, trap_id);
2655543e989SAya Levin return -EINVAL;
2665543e989SAya Levin }
2675543e989SAya Levin if (priv->en_trap && !mlx5_devlink_trap_get_num_active(priv->mdev))
2685543e989SAya Levin mlx5e_del_trap_queue(priv);
2695543e989SAya Levin
2705543e989SAya Levin return 0;
2715543e989SAya Levin }
2725543e989SAya Levin
mlx5e_handle_trap_event(struct mlx5e_priv * priv,struct mlx5_trap_ctx * trap_ctx)2735543e989SAya Levin int mlx5e_handle_trap_event(struct mlx5e_priv *priv, struct mlx5_trap_ctx *trap_ctx)
2745543e989SAya Levin {
2755543e989SAya Levin int err = 0;
2765543e989SAya Levin
277eb3862a0SAya Levin /* Traps are unarmed when interface is down, no need to update
278eb3862a0SAya Levin * them. The configuration is saved in the core driver,
279eb3862a0SAya Levin * queried and applied upon interface up operation in
280eb3862a0SAya Levin * mlx5e_open_locked().
281eb3862a0SAya Levin */
282eb3862a0SAya Levin if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
283eb3862a0SAya Levin return 0;
284eb3862a0SAya Levin
2855543e989SAya Levin switch (trap_ctx->action) {
2865543e989SAya Levin case DEVLINK_TRAP_ACTION_TRAP:
2875543e989SAya Levin err = mlx5e_handle_action_trap(priv, trap_ctx->id);
2885543e989SAya Levin break;
2895543e989SAya Levin case DEVLINK_TRAP_ACTION_DROP:
2905543e989SAya Levin err = mlx5e_handle_action_drop(priv, trap_ctx->id);
2915543e989SAya Levin break;
2925543e989SAya Levin default:
2935543e989SAya Levin netdev_warn(priv->netdev, "%s: Unsupported action %d\n", __func__,
2945543e989SAya Levin trap_ctx->action);
2955543e989SAya Levin err = -EINVAL;
2965543e989SAya Levin }
2975543e989SAya Levin return err;
2985543e989SAya Levin }
299eb3862a0SAya Levin
mlx5e_apply_trap(struct mlx5e_priv * priv,int trap_id,bool enable)300eb3862a0SAya Levin static int mlx5e_apply_trap(struct mlx5e_priv *priv, int trap_id, bool enable)
301eb3862a0SAya Levin {
302eb3862a0SAya Levin enum devlink_trap_action action;
303eb3862a0SAya Levin int err;
304eb3862a0SAya Levin
305eb3862a0SAya Levin err = mlx5_devlink_traps_get_action(priv->mdev, trap_id, &action);
306eb3862a0SAya Levin if (err)
307eb3862a0SAya Levin return err;
308eb3862a0SAya Levin if (action == DEVLINK_TRAP_ACTION_TRAP)
309eb3862a0SAya Levin err = enable ? mlx5e_handle_action_trap(priv, trap_id) :
310eb3862a0SAya Levin mlx5e_handle_action_drop(priv, trap_id);
311eb3862a0SAya Levin return err;
312eb3862a0SAya Levin }
313eb3862a0SAya Levin
314eb3862a0SAya Levin static const int mlx5e_traps_arr[] = {
315eb3862a0SAya Levin DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER,
316eb3862a0SAya Levin DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER,
317eb3862a0SAya Levin };
318eb3862a0SAya Levin
mlx5e_apply_traps(struct mlx5e_priv * priv,bool enable)319eb3862a0SAya Levin int mlx5e_apply_traps(struct mlx5e_priv *priv, bool enable)
320eb3862a0SAya Levin {
321eb3862a0SAya Levin int err;
322eb3862a0SAya Levin int i;
323eb3862a0SAya Levin
324eb3862a0SAya Levin for (i = 0; i < ARRAY_SIZE(mlx5e_traps_arr); i++) {
325eb3862a0SAya Levin err = mlx5e_apply_trap(priv, mlx5e_traps_arr[i], enable);
326eb3862a0SAya Levin if (err)
327eb3862a0SAya Levin return err;
328eb3862a0SAya Levin }
329eb3862a0SAya Levin return 0;
330eb3862a0SAya Levin }
331