linux/drivers/net/ethernet/mellanox/mlx5/core/en/trap.c
<<
>>
Prefs
   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        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
  33static 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         = t->pdev;
  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
  53static 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
  80err_destroy_cq:
  81        mlx5e_close_cq(&rq->cq);
  82
  83        return err;
  84}
  85
  86static void mlx5e_close_trap_rq(struct mlx5e_rq *rq)
  87{
  88        mlx5e_close_rq(rq);
  89        mlx5e_close_cq(&rq->cq);
  90}
  91
  92static int mlx5e_create_trap_direct_rq_tir(struct mlx5_core_dev *mdev, struct mlx5e_tir *tir,
  93                                           u32 rqn)
  94{
  95        struct mlx5e_tir_builder *builder;
  96        int err;
  97
  98        builder = mlx5e_tir_builder_alloc(false);
  99        if (!builder)
 100                return -ENOMEM;
 101
 102        mlx5e_tir_builder_build_inline(builder, mdev->mlx5e_res.hw_objs.td.tdn, rqn);
 103        err = mlx5e_tir_init(tir, builder, mdev, true);
 104
 105        mlx5e_tir_builder_free(builder);
 106
 107        return err;
 108}
 109
 110static void mlx5e_build_trap_params(struct mlx5_core_dev *mdev,
 111                                    int max_mtu, u16 q_counter,
 112                                    struct mlx5e_trap *t)
 113{
 114        struct mlx5e_params *params = &t->params;
 115
 116        params->rq_wq_type = MLX5_WQ_TYPE_CYCLIC;
 117        mlx5e_init_rq_type_params(mdev, params);
 118        params->sw_mtu = max_mtu;
 119        mlx5e_build_rq_param(mdev, params, NULL, q_counter, &t->rq_param);
 120}
 121
 122static struct mlx5e_trap *mlx5e_open_trap(struct mlx5e_priv *priv)
 123{
 124        int cpu = cpumask_first(mlx5_comp_irq_get_affinity_mask(priv->mdev, 0));
 125        struct net_device *netdev = priv->netdev;
 126        struct mlx5e_trap *t;
 127        int err;
 128
 129        t = kvzalloc_node(sizeof(*t), GFP_KERNEL, cpu_to_node(cpu));
 130        if (!t)
 131                return ERR_PTR(-ENOMEM);
 132
 133        mlx5e_build_trap_params(priv->mdev, netdev->max_mtu, priv->q_counter, t);
 134
 135        t->priv     = priv;
 136        t->mdev     = priv->mdev;
 137        t->tstamp   = &priv->tstamp;
 138        t->pdev     = mlx5_core_dma_dev(priv->mdev);
 139        t->netdev   = priv->netdev;
 140        t->mkey_be  = cpu_to_be32(priv->mdev->mlx5e_res.hw_objs.mkey.key);
 141        t->stats    = &priv->trap_stats.ch;
 142
 143        netif_napi_add(netdev, &t->napi, mlx5e_trap_napi_poll, 64);
 144
 145        err = mlx5e_open_trap_rq(priv, t);
 146        if (unlikely(err))
 147                goto err_napi_del;
 148
 149        err = mlx5e_create_trap_direct_rq_tir(t->mdev, &t->tir, t->rq.rqn);
 150        if (err)
 151                goto err_close_trap_rq;
 152
 153        return t;
 154
 155err_close_trap_rq:
 156        mlx5e_close_trap_rq(&t->rq);
 157err_napi_del:
 158        netif_napi_del(&t->napi);
 159        kvfree(t);
 160        return ERR_PTR(err);
 161}
 162
 163void mlx5e_close_trap(struct mlx5e_trap *trap)
 164{
 165        mlx5e_tir_destroy(&trap->tir);
 166        mlx5e_close_trap_rq(&trap->rq);
 167        netif_napi_del(&trap->napi);
 168        kvfree(trap);
 169}
 170
 171static void mlx5e_activate_trap(struct mlx5e_trap *trap)
 172{
 173        napi_enable(&trap->napi);
 174        mlx5e_activate_rq(&trap->rq);
 175}
 176
 177void mlx5e_deactivate_trap(struct mlx5e_priv *priv)
 178{
 179        struct mlx5e_trap *trap = priv->en_trap;
 180
 181        mlx5e_deactivate_rq(&trap->rq);
 182        napi_disable(&trap->napi);
 183}
 184
 185static struct mlx5e_trap *mlx5e_add_trap_queue(struct mlx5e_priv *priv)
 186{
 187        struct mlx5e_trap *trap;
 188
 189        trap = mlx5e_open_trap(priv);
 190        if (IS_ERR(trap))
 191                goto out;
 192
 193        mlx5e_activate_trap(trap);
 194out:
 195        return trap;
 196}
 197
 198static void mlx5e_del_trap_queue(struct mlx5e_priv *priv)
 199{
 200        mlx5e_deactivate_trap(priv);
 201        mlx5e_close_trap(priv->en_trap);
 202        priv->en_trap = NULL;
 203}
 204
 205static int mlx5e_trap_get_tirn(struct mlx5e_trap *en_trap)
 206{
 207        return en_trap->tir.tirn;
 208}
 209
 210static int mlx5e_handle_action_trap(struct mlx5e_priv *priv, int trap_id)
 211{
 212        bool open_queue = !priv->en_trap;
 213        struct mlx5e_trap *trap;
 214        int err;
 215
 216        if (open_queue) {
 217                trap = mlx5e_add_trap_queue(priv);
 218                if (IS_ERR(trap))
 219                        return PTR_ERR(trap);
 220                priv->en_trap = trap;
 221        }
 222
 223        switch (trap_id) {
 224        case DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER:
 225                err = mlx5e_add_vlan_trap(priv, trap_id, mlx5e_trap_get_tirn(priv->en_trap));
 226                if (err)
 227                        goto err_out;
 228                break;
 229        case DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER:
 230                err = mlx5e_add_mac_trap(priv, trap_id, mlx5e_trap_get_tirn(priv->en_trap));
 231                if (err)
 232                        goto err_out;
 233                break;
 234        default:
 235                netdev_warn(priv->netdev, "%s: Unknown trap id %d\n", __func__, trap_id);
 236                err = -EINVAL;
 237                goto err_out;
 238        }
 239        return 0;
 240
 241err_out:
 242        if (open_queue)
 243                mlx5e_del_trap_queue(priv);
 244        return err;
 245}
 246
 247static int mlx5e_handle_action_drop(struct mlx5e_priv *priv, int trap_id)
 248{
 249        switch (trap_id) {
 250        case DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER:
 251                mlx5e_remove_vlan_trap(priv);
 252                break;
 253        case DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER:
 254                mlx5e_remove_mac_trap(priv);
 255                break;
 256        default:
 257                netdev_warn(priv->netdev, "%s: Unknown trap id %d\n", __func__, trap_id);
 258                return -EINVAL;
 259        }
 260        if (priv->en_trap && !mlx5_devlink_trap_get_num_active(priv->mdev))
 261                mlx5e_del_trap_queue(priv);
 262
 263        return 0;
 264}
 265
 266int mlx5e_handle_trap_event(struct mlx5e_priv *priv, struct mlx5_trap_ctx *trap_ctx)
 267{
 268        int err = 0;
 269
 270        /* Traps are unarmed when interface is down, no need to update
 271         * them. The configuration is saved in the core driver,
 272         * queried and applied upon interface up operation in
 273         * mlx5e_open_locked().
 274         */
 275        if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
 276                return 0;
 277
 278        switch (trap_ctx->action) {
 279        case DEVLINK_TRAP_ACTION_TRAP:
 280                err = mlx5e_handle_action_trap(priv, trap_ctx->id);
 281                break;
 282        case DEVLINK_TRAP_ACTION_DROP:
 283                err = mlx5e_handle_action_drop(priv, trap_ctx->id);
 284                break;
 285        default:
 286                netdev_warn(priv->netdev, "%s: Unsupported action %d\n", __func__,
 287                            trap_ctx->action);
 288                err = -EINVAL;
 289        }
 290        return err;
 291}
 292
 293static int mlx5e_apply_trap(struct mlx5e_priv *priv, int trap_id, bool enable)
 294{
 295        enum devlink_trap_action action;
 296        int err;
 297
 298        err = mlx5_devlink_traps_get_action(priv->mdev, trap_id, &action);
 299        if (err)
 300                return err;
 301        if (action == DEVLINK_TRAP_ACTION_TRAP)
 302                err = enable ? mlx5e_handle_action_trap(priv, trap_id) :
 303                               mlx5e_handle_action_drop(priv, trap_id);
 304        return err;
 305}
 306
 307static const int mlx5e_traps_arr[] = {
 308        DEVLINK_TRAP_GENERIC_ID_INGRESS_VLAN_FILTER,
 309        DEVLINK_TRAP_GENERIC_ID_DMAC_FILTER,
 310};
 311
 312int mlx5e_apply_traps(struct mlx5e_priv *priv, bool enable)
 313{
 314        int err;
 315        int i;
 316
 317        for (i = 0; i < ARRAY_SIZE(mlx5e_traps_arr); i++) {
 318                err = mlx5e_apply_trap(priv, mlx5e_traps_arr[i], enable);
 319                if (err)
 320                        return err;
 321        }
 322        return 0;
 323}
 324