trap.c (7840B)
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 9static 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 35out: 36 rcu_read_unlock(); 37 return work_done; 38} 39 40static 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 60static 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 87err_destroy_cq: 88 mlx5e_close_cq(&rq->cq); 89 90 return err; 91} 92 93static void mlx5e_close_trap_rq(struct mlx5e_rq *rq) 94{ 95 mlx5e_close_rq(rq); 96 mlx5e_close_cq(&rq->cq); 97} 98 99static 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 117static 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 129static 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, 64); 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 162err_close_trap_rq: 163 mlx5e_close_trap_rq(&t->rq); 164err_napi_del: 165 netif_napi_del(&t->napi); 166 kvfree(t); 167 return ERR_PTR(err); 168} 169 170void 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 178static 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 185void 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 193static 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); 202out: 203 return trap; 204} 205 206static 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 213static int mlx5e_trap_get_tirn(struct mlx5e_trap *en_trap) 214{ 215 return en_trap->tir.tirn; 216} 217 218static 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, 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, 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 249err_out: 250 if (open_queue) 251 mlx5e_del_trap_queue(priv); 252 return err; 253} 254 255static 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); 260 break; 261 case DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER: 262 mlx5e_remove_mac_trap(priv); 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 274int 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 301static 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 315static const int mlx5e_traps_arr[] = { 316 DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER, 317 DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER, 318}; 319 320int 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}