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