0001
0002
0003
0004 #include <net/page_pool.h>
0005 #include "en/txrx.h"
0006 #include "en/params.h"
0007 #include "en/trap.h"
0008
0009 static int mlx5e_trap_napi_poll(struct napi_struct *napi, int budget)
0010 {
0011 struct mlx5e_trap *trap_ctx = container_of(napi, struct mlx5e_trap, napi);
0012 struct mlx5e_ch_stats *ch_stats = trap_ctx->stats;
0013 struct mlx5e_rq *rq = &trap_ctx->rq;
0014 bool busy = false;
0015 int work_done = 0;
0016
0017 rcu_read_lock();
0018
0019 ch_stats->poll++;
0020
0021 work_done = mlx5e_poll_rx_cq(&rq->cq, budget);
0022 busy |= work_done == budget;
0023 busy |= rq->post_wqes(rq);
0024
0025 if (busy) {
0026 work_done = budget;
0027 goto out;
0028 }
0029
0030 if (unlikely(!napi_complete_done(napi, work_done)))
0031 goto out;
0032
0033 mlx5e_cq_arm(&rq->cq);
0034
0035 out:
0036 rcu_read_unlock();
0037 return work_done;
0038 }
0039
0040 static void mlx5e_init_trap_rq(struct mlx5e_trap *t, struct mlx5e_params *params,
0041 struct mlx5e_rq *rq)
0042 {
0043 struct mlx5_core_dev *mdev = t->mdev;
0044 struct mlx5e_priv *priv = t->priv;
0045
0046 rq->wq_type = params->rq_wq_type;
0047 rq->pdev = t->pdev;
0048 rq->netdev = priv->netdev;
0049 rq->priv = priv;
0050 rq->clock = &mdev->clock;
0051 rq->tstamp = &priv->tstamp;
0052 rq->mdev = mdev;
0053 rq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu);
0054 rq->stats = &priv->trap_stats.rq;
0055 rq->ptp_cyc2time = mlx5_rq_ts_translator(mdev);
0056 xdp_rxq_info_unused(&rq->xdp_rxq);
0057 mlx5e_rq_set_trap_handlers(rq, params);
0058 }
0059
0060 static int mlx5e_open_trap_rq(struct mlx5e_priv *priv, struct mlx5e_trap *t)
0061 {
0062 struct mlx5e_rq_param *rq_param = &t->rq_param;
0063 struct mlx5_core_dev *mdev = priv->mdev;
0064 struct mlx5e_create_cq_param ccp = {};
0065 struct dim_cq_moder trap_moder = {};
0066 struct mlx5e_rq *rq = &t->rq;
0067 int node;
0068 int err;
0069
0070 node = dev_to_node(mdev->device);
0071
0072 ccp.node = node;
0073 ccp.ch_stats = t->stats;
0074 ccp.napi = &t->napi;
0075 ccp.ix = 0;
0076 err = mlx5e_open_cq(priv, trap_moder, &rq_param->cqp, &ccp, &rq->cq);
0077 if (err)
0078 return err;
0079
0080 mlx5e_init_trap_rq(t, &t->params, rq);
0081 err = mlx5e_open_rq(&t->params, rq_param, NULL, node, rq);
0082 if (err)
0083 goto err_destroy_cq;
0084
0085 return 0;
0086
0087 err_destroy_cq:
0088 mlx5e_close_cq(&rq->cq);
0089
0090 return err;
0091 }
0092
0093 static void mlx5e_close_trap_rq(struct mlx5e_rq *rq)
0094 {
0095 mlx5e_close_rq(rq);
0096 mlx5e_close_cq(&rq->cq);
0097 }
0098
0099 static int mlx5e_create_trap_direct_rq_tir(struct mlx5_core_dev *mdev, struct mlx5e_tir *tir,
0100 u32 rqn)
0101 {
0102 struct mlx5e_tir_builder *builder;
0103 int err;
0104
0105 builder = mlx5e_tir_builder_alloc(false);
0106 if (!builder)
0107 return -ENOMEM;
0108
0109 mlx5e_tir_builder_build_inline(builder, mdev->mlx5e_res.hw_objs.td.tdn, rqn);
0110 err = mlx5e_tir_init(tir, builder, mdev, true);
0111
0112 mlx5e_tir_builder_free(builder);
0113
0114 return err;
0115 }
0116
0117 static void mlx5e_build_trap_params(struct mlx5_core_dev *mdev,
0118 int max_mtu, u16 q_counter,
0119 struct mlx5e_trap *t)
0120 {
0121 struct mlx5e_params *params = &t->params;
0122
0123 params->rq_wq_type = MLX5_WQ_TYPE_CYCLIC;
0124 mlx5e_init_rq_type_params(mdev, params);
0125 params->sw_mtu = max_mtu;
0126 mlx5e_build_rq_param(mdev, params, NULL, q_counter, &t->rq_param);
0127 }
0128
0129 static struct mlx5e_trap *mlx5e_open_trap(struct mlx5e_priv *priv)
0130 {
0131 int cpu = cpumask_first(mlx5_comp_irq_get_affinity_mask(priv->mdev, 0));
0132 struct net_device *netdev = priv->netdev;
0133 struct mlx5e_trap *t;
0134 int err;
0135
0136 t = kvzalloc_node(sizeof(*t), GFP_KERNEL, cpu_to_node(cpu));
0137 if (!t)
0138 return ERR_PTR(-ENOMEM);
0139
0140 mlx5e_build_trap_params(priv->mdev, netdev->max_mtu, priv->q_counter, t);
0141
0142 t->priv = priv;
0143 t->mdev = priv->mdev;
0144 t->tstamp = &priv->tstamp;
0145 t->pdev = mlx5_core_dma_dev(priv->mdev);
0146 t->netdev = priv->netdev;
0147 t->mkey_be = cpu_to_be32(priv->mdev->mlx5e_res.hw_objs.mkey);
0148 t->stats = &priv->trap_stats.ch;
0149
0150 netif_napi_add(netdev, &t->napi, mlx5e_trap_napi_poll, 64);
0151
0152 err = mlx5e_open_trap_rq(priv, t);
0153 if (unlikely(err))
0154 goto err_napi_del;
0155
0156 err = mlx5e_create_trap_direct_rq_tir(t->mdev, &t->tir, t->rq.rqn);
0157 if (err)
0158 goto err_close_trap_rq;
0159
0160 return t;
0161
0162 err_close_trap_rq:
0163 mlx5e_close_trap_rq(&t->rq);
0164 err_napi_del:
0165 netif_napi_del(&t->napi);
0166 kvfree(t);
0167 return ERR_PTR(err);
0168 }
0169
0170 void mlx5e_close_trap(struct mlx5e_trap *trap)
0171 {
0172 mlx5e_tir_destroy(&trap->tir);
0173 mlx5e_close_trap_rq(&trap->rq);
0174 netif_napi_del(&trap->napi);
0175 kvfree(trap);
0176 }
0177
0178 static void mlx5e_activate_trap(struct mlx5e_trap *trap)
0179 {
0180 napi_enable(&trap->napi);
0181 mlx5e_activate_rq(&trap->rq);
0182 mlx5e_trigger_napi_sched(&trap->napi);
0183 }
0184
0185 void mlx5e_deactivate_trap(struct mlx5e_priv *priv)
0186 {
0187 struct mlx5e_trap *trap = priv->en_trap;
0188
0189 mlx5e_deactivate_rq(&trap->rq);
0190 napi_disable(&trap->napi);
0191 }
0192
0193 static struct mlx5e_trap *mlx5e_add_trap_queue(struct mlx5e_priv *priv)
0194 {
0195 struct mlx5e_trap *trap;
0196
0197 trap = mlx5e_open_trap(priv);
0198 if (IS_ERR(trap))
0199 goto out;
0200
0201 mlx5e_activate_trap(trap);
0202 out:
0203 return trap;
0204 }
0205
0206 static void mlx5e_del_trap_queue(struct mlx5e_priv *priv)
0207 {
0208 mlx5e_deactivate_trap(priv);
0209 mlx5e_close_trap(priv->en_trap);
0210 priv->en_trap = NULL;
0211 }
0212
0213 static int mlx5e_trap_get_tirn(struct mlx5e_trap *en_trap)
0214 {
0215 return en_trap->tir.tirn;
0216 }
0217
0218 static int mlx5e_handle_action_trap(struct mlx5e_priv *priv, int trap_id)
0219 {
0220 bool open_queue = !priv->en_trap;
0221 struct mlx5e_trap *trap;
0222 int err;
0223
0224 if (open_queue) {
0225 trap = mlx5e_add_trap_queue(priv);
0226 if (IS_ERR(trap))
0227 return PTR_ERR(trap);
0228 priv->en_trap = trap;
0229 }
0230
0231 switch (trap_id) {
0232 case DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER:
0233 err = mlx5e_add_vlan_trap(priv, trap_id, mlx5e_trap_get_tirn(priv->en_trap));
0234 if (err)
0235 goto err_out;
0236 break;
0237 case DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER:
0238 err = mlx5e_add_mac_trap(priv, trap_id, mlx5e_trap_get_tirn(priv->en_trap));
0239 if (err)
0240 goto err_out;
0241 break;
0242 default:
0243 netdev_warn(priv->netdev, "%s: Unknown trap id %d\n", __func__, trap_id);
0244 err = -EINVAL;
0245 goto err_out;
0246 }
0247 return 0;
0248
0249 err_out:
0250 if (open_queue)
0251 mlx5e_del_trap_queue(priv);
0252 return err;
0253 }
0254
0255 static int mlx5e_handle_action_drop(struct mlx5e_priv *priv, int trap_id)
0256 {
0257 switch (trap_id) {
0258 case DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER:
0259 mlx5e_remove_vlan_trap(priv);
0260 break;
0261 case DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER:
0262 mlx5e_remove_mac_trap(priv);
0263 break;
0264 default:
0265 netdev_warn(priv->netdev, "%s: Unknown trap id %d\n", __func__, trap_id);
0266 return -EINVAL;
0267 }
0268 if (priv->en_trap && !mlx5_devlink_trap_get_num_active(priv->mdev))
0269 mlx5e_del_trap_queue(priv);
0270
0271 return 0;
0272 }
0273
0274 int mlx5e_handle_trap_event(struct mlx5e_priv *priv, struct mlx5_trap_ctx *trap_ctx)
0275 {
0276 int err = 0;
0277
0278
0279
0280
0281
0282
0283 if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
0284 return 0;
0285
0286 switch (trap_ctx->action) {
0287 case DEVLINK_TRAP_ACTION_TRAP:
0288 err = mlx5e_handle_action_trap(priv, trap_ctx->id);
0289 break;
0290 case DEVLINK_TRAP_ACTION_DROP:
0291 err = mlx5e_handle_action_drop(priv, trap_ctx->id);
0292 break;
0293 default:
0294 netdev_warn(priv->netdev, "%s: Unsupported action %d\n", __func__,
0295 trap_ctx->action);
0296 err = -EINVAL;
0297 }
0298 return err;
0299 }
0300
0301 static int mlx5e_apply_trap(struct mlx5e_priv *priv, int trap_id, bool enable)
0302 {
0303 enum devlink_trap_action action;
0304 int err;
0305
0306 err = mlx5_devlink_traps_get_action(priv->mdev, trap_id, &action);
0307 if (err)
0308 return err;
0309 if (action == DEVLINK_TRAP_ACTION_TRAP)
0310 err = enable ? mlx5e_handle_action_trap(priv, trap_id) :
0311 mlx5e_handle_action_drop(priv, trap_id);
0312 return err;
0313 }
0314
0315 static const int mlx5e_traps_arr[] = {
0316 DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER,
0317 DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER,
0318 };
0319
0320 int mlx5e_apply_traps(struct mlx5e_priv *priv, bool enable)
0321 {
0322 int err;
0323 int i;
0324
0325 for (i = 0; i < ARRAY_SIZE(mlx5e_traps_arr); i++) {
0326 err = mlx5e_apply_trap(priv, mlx5e_traps_arr[i], enable);
0327 if (err)
0328 return err;
0329 }
0330 return 0;
0331 }