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