1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* Copyright (c) 2020 Mellanox Technologies */ 3 4 #include "en/txrx.h" 5 #include "en/params.h" 6 #include "en/trap.h" 7 8 static int mlx5e_trap_napi_poll(struct napi_struct *napi, int budget) 9 { 10 struct mlx5e_trap *trap_ctx = container_of(napi, struct mlx5e_trap, napi); 11 struct mlx5e_ch_stats *ch_stats = trap_ctx->stats; 12 struct mlx5e_rq *rq = &trap_ctx->rq; 13 bool busy = false; 14 int work_done = 0; 15 16 rcu_read_lock(); 17 18 ch_stats->poll++; 19 20 work_done = mlx5e_poll_rx_cq(&rq->cq, budget); 21 busy |= work_done == budget; 22 busy |= rq->post_wqes(rq); 23 24 if (busy) { 25 work_done = budget; 26 goto out; 27 } 28 29 if (unlikely(!napi_complete_done(napi, work_done))) 30 goto out; 31 32 mlx5e_cq_arm(&rq->cq); 33 34 out: 35 rcu_read_unlock(); 36 return work_done; 37 } 38 39 static void mlx5e_init_trap_rq(struct mlx5e_trap *t, struct mlx5e_params *params, 40 struct mlx5e_rq *rq) 41 { 42 struct mlx5_core_dev *mdev = t->mdev; 43 struct mlx5e_priv *priv = t->priv; 44 45 rq->wq_type = params->rq_wq_type; 46 rq->pdev = t->pdev; 47 rq->netdev = priv->netdev; 48 rq->priv = priv; 49 rq->clock = &mdev->clock; 50 rq->tstamp = &priv->tstamp; 51 rq->mdev = mdev; 52 rq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu); 53 rq->stats = &priv->trap_stats.rq; 54 rq->ptp_cyc2time = mlx5_rq_ts_translator(mdev); 55 xdp_rxq_info_unused(&rq->xdp_rxq); 56 mlx5e_rq_set_trap_handlers(rq, params); 57 } 58 59 static int mlx5e_open_trap_rq(struct mlx5e_priv *priv, struct mlx5e_trap *t) 60 { 61 struct mlx5e_rq_param *rq_param = &t->rq_param; 62 struct mlx5_core_dev *mdev = priv->mdev; 63 struct mlx5e_create_cq_param ccp = {}; 64 struct dim_cq_moder trap_moder = {}; 65 struct mlx5e_rq *rq = &t->rq; 66 int node; 67 int err; 68 69 node = dev_to_node(mdev->device); 70 71 ccp.node = node; 72 ccp.ch_stats = t->stats; 73 ccp.napi = &t->napi; 74 ccp.ix = 0; 75 err = mlx5e_open_cq(priv, trap_moder, &rq_param->cqp, &ccp, &rq->cq); 76 if (err) 77 return err; 78 79 mlx5e_init_trap_rq(t, &t->params, rq); 80 err = mlx5e_open_rq(&t->params, rq_param, NULL, node, rq); 81 if (err) 82 goto err_destroy_cq; 83 84 return 0; 85 86 err_destroy_cq: 87 mlx5e_close_cq(&rq->cq); 88 89 return err; 90 } 91 92 static void mlx5e_close_trap_rq(struct mlx5e_rq *rq) 93 { 94 mlx5e_close_rq(rq); 95 mlx5e_close_cq(&rq->cq); 96 } 97 98 static int mlx5e_create_trap_direct_rq_tir(struct mlx5_core_dev *mdev, struct mlx5e_tir *tir, 99 u32 rqn) 100 { 101 struct mlx5e_tir_builder *builder; 102 int err; 103 104 builder = mlx5e_tir_builder_alloc(false); 105 if (!builder) 106 return -ENOMEM; 107 108 mlx5e_tir_builder_build_inline(builder, mdev->mlx5e_res.hw_objs.td.tdn, rqn); 109 err = mlx5e_tir_init(tir, builder, mdev, true); 110 111 mlx5e_tir_builder_free(builder); 112 113 return err; 114 } 115 116 static void mlx5e_build_trap_params(struct mlx5_core_dev *mdev, 117 int max_mtu, u16 q_counter, 118 struct mlx5e_trap *t) 119 { 120 struct mlx5e_params *params = &t->params; 121 122 params->rq_wq_type = MLX5_WQ_TYPE_CYCLIC; 123 mlx5e_init_rq_type_params(mdev, params); 124 params->sw_mtu = max_mtu; 125 mlx5e_build_rq_param(mdev, params, NULL, q_counter, &t->rq_param); 126 } 127 128 static struct mlx5e_trap *mlx5e_open_trap(struct mlx5e_priv *priv) 129 { 130 int cpu = mlx5_comp_vector_get_cpu(priv->mdev, 0); 131 struct net_device *netdev = priv->netdev; 132 struct mlx5e_trap *t; 133 int err; 134 135 t = kvzalloc_node(sizeof(*t), GFP_KERNEL, cpu_to_node(cpu)); 136 if (!t) 137 return ERR_PTR(-ENOMEM); 138 139 mlx5e_build_trap_params(priv->mdev, netdev->max_mtu, priv->q_counter, t); 140 141 t->priv = priv; 142 t->mdev = priv->mdev; 143 t->tstamp = &priv->tstamp; 144 t->pdev = mlx5_core_dma_dev(priv->mdev); 145 t->netdev = priv->netdev; 146 t->mkey_be = cpu_to_be32(priv->mdev->mlx5e_res.hw_objs.mkey); 147 t->stats = &priv->trap_stats.ch; 148 149 netif_napi_add(netdev, &t->napi, mlx5e_trap_napi_poll); 150 151 err = mlx5e_open_trap_rq(priv, t); 152 if (unlikely(err)) 153 goto err_napi_del; 154 155 err = mlx5e_create_trap_direct_rq_tir(t->mdev, &t->tir, t->rq.rqn); 156 if (err) 157 goto err_close_trap_rq; 158 159 return t; 160 161 err_close_trap_rq: 162 mlx5e_close_trap_rq(&t->rq); 163 err_napi_del: 164 netif_napi_del(&t->napi); 165 kvfree(t); 166 return ERR_PTR(err); 167 } 168 169 void mlx5e_close_trap(struct mlx5e_trap *trap) 170 { 171 mlx5e_tir_destroy(&trap->tir); 172 mlx5e_close_trap_rq(&trap->rq); 173 netif_napi_del(&trap->napi); 174 kvfree(trap); 175 } 176 177 static void mlx5e_activate_trap(struct mlx5e_trap *trap) 178 { 179 napi_enable(&trap->napi); 180 mlx5e_activate_rq(&trap->rq); 181 mlx5e_trigger_napi_sched(&trap->napi); 182 } 183 184 void mlx5e_deactivate_trap(struct mlx5e_priv *priv) 185 { 186 struct mlx5e_trap *trap = priv->en_trap; 187 188 mlx5e_deactivate_rq(&trap->rq); 189 napi_disable(&trap->napi); 190 } 191 192 static struct mlx5e_trap *mlx5e_add_trap_queue(struct mlx5e_priv *priv) 193 { 194 struct mlx5e_trap *trap; 195 196 trap = mlx5e_open_trap(priv); 197 if (IS_ERR(trap)) 198 goto out; 199 200 mlx5e_activate_trap(trap); 201 out: 202 return trap; 203 } 204 205 static void mlx5e_del_trap_queue(struct mlx5e_priv *priv) 206 { 207 mlx5e_deactivate_trap(priv); 208 mlx5e_close_trap(priv->en_trap); 209 priv->en_trap = NULL; 210 } 211 212 static int mlx5e_trap_get_tirn(struct mlx5e_trap *en_trap) 213 { 214 return en_trap->tir.tirn; 215 } 216 217 static int mlx5e_handle_action_trap(struct mlx5e_priv *priv, int trap_id) 218 { 219 bool open_queue = !priv->en_trap; 220 struct mlx5e_trap *trap; 221 int err; 222 223 if (open_queue) { 224 trap = mlx5e_add_trap_queue(priv); 225 if (IS_ERR(trap)) 226 return PTR_ERR(trap); 227 priv->en_trap = trap; 228 } 229 230 switch (trap_id) { 231 case DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER: 232 err = mlx5e_add_vlan_trap(priv->fs, trap_id, mlx5e_trap_get_tirn(priv->en_trap)); 233 if (err) 234 goto err_out; 235 break; 236 case DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER: 237 err = mlx5e_add_mac_trap(priv->fs, trap_id, mlx5e_trap_get_tirn(priv->en_trap)); 238 if (err) 239 goto err_out; 240 break; 241 default: 242 netdev_warn(priv->netdev, "%s: Unknown trap id %d\n", __func__, trap_id); 243 err = -EINVAL; 244 goto err_out; 245 } 246 return 0; 247 248 err_out: 249 if (open_queue) 250 mlx5e_del_trap_queue(priv); 251 return err; 252 } 253 254 static int mlx5e_handle_action_drop(struct mlx5e_priv *priv, int trap_id) 255 { 256 switch (trap_id) { 257 case DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER: 258 mlx5e_remove_vlan_trap(priv->fs); 259 break; 260 case DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER: 261 mlx5e_remove_mac_trap(priv->fs); 262 break; 263 default: 264 netdev_warn(priv->netdev, "%s: Unknown trap id %d\n", __func__, trap_id); 265 return -EINVAL; 266 } 267 if (priv->en_trap && !mlx5_devlink_trap_get_num_active(priv->mdev)) 268 mlx5e_del_trap_queue(priv); 269 270 return 0; 271 } 272 273 int mlx5e_handle_trap_event(struct mlx5e_priv *priv, struct mlx5_trap_ctx *trap_ctx) 274 { 275 int err = 0; 276 277 /* Traps are unarmed when interface is down, no need to update 278 * them. The configuration is saved in the core driver, 279 * queried and applied upon interface up operation in 280 * mlx5e_open_locked(). 281 */ 282 if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) 283 return 0; 284 285 switch (trap_ctx->action) { 286 case DEVLINK_TRAP_ACTION_TRAP: 287 err = mlx5e_handle_action_trap(priv, trap_ctx->id); 288 break; 289 case DEVLINK_TRAP_ACTION_DROP: 290 err = mlx5e_handle_action_drop(priv, trap_ctx->id); 291 break; 292 default: 293 netdev_warn(priv->netdev, "%s: Unsupported action %d\n", __func__, 294 trap_ctx->action); 295 err = -EINVAL; 296 } 297 return err; 298 } 299 300 static int mlx5e_apply_trap(struct mlx5e_priv *priv, int trap_id, bool enable) 301 { 302 enum devlink_trap_action action; 303 int err; 304 305 err = mlx5_devlink_traps_get_action(priv->mdev, trap_id, &action); 306 if (err) 307 return err; 308 if (action == DEVLINK_TRAP_ACTION_TRAP) 309 err = enable ? mlx5e_handle_action_trap(priv, trap_id) : 310 mlx5e_handle_action_drop(priv, trap_id); 311 return err; 312 } 313 314 static const int mlx5e_traps_arr[] = { 315 DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER, 316 DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER, 317 }; 318 319 int mlx5e_apply_traps(struct mlx5e_priv *priv, bool enable) 320 { 321 int err; 322 int i; 323 324 for (i = 0; i < ARRAY_SIZE(mlx5e_traps_arr); i++) { 325 err = mlx5e_apply_trap(priv, mlx5e_traps_arr[i], enable); 326 if (err) 327 return err; 328 } 329 return 0; 330 } 331