linux/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_actions.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
   3
   4#include "spectrum_acl_flex_actions.h"
   5#include "core_acl_flex_actions.h"
   6#include "spectrum_span.h"
   7
   8static int mlxsw_sp_act_kvdl_set_add(void *priv, u32 *p_kvdl_index,
   9                                     char *enc_actions, bool is_first, bool ca)
  10{
  11        struct mlxsw_sp *mlxsw_sp = priv;
  12        char pefa_pl[MLXSW_REG_PEFA_LEN];
  13        u32 kvdl_index;
  14        int err;
  15
  16        /* The first action set of a TCAM entry is stored directly in TCAM,
  17         * not KVD linear area.
  18         */
  19        if (is_first)
  20                return 0;
  21
  22        err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET,
  23                                  1, &kvdl_index);
  24        if (err)
  25                return err;
  26        mlxsw_reg_pefa_pack(pefa_pl, kvdl_index, ca, enc_actions);
  27        err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pefa), pefa_pl);
  28        if (err)
  29                goto err_pefa_write;
  30        *p_kvdl_index = kvdl_index;
  31        return 0;
  32
  33err_pefa_write:
  34        mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET,
  35                           1, kvdl_index);
  36        return err;
  37}
  38
  39static int mlxsw_sp1_act_kvdl_set_add(void *priv, u32 *p_kvdl_index,
  40                                      char *enc_actions, bool is_first)
  41{
  42        return mlxsw_sp_act_kvdl_set_add(priv, p_kvdl_index, enc_actions,
  43                                         is_first, false);
  44}
  45
  46static int mlxsw_sp2_act_kvdl_set_add(void *priv, u32 *p_kvdl_index,
  47                                      char *enc_actions, bool is_first)
  48{
  49        return mlxsw_sp_act_kvdl_set_add(priv, p_kvdl_index, enc_actions,
  50                                         is_first, true);
  51}
  52
  53static void mlxsw_sp_act_kvdl_set_del(void *priv, u32 kvdl_index,
  54                                      bool is_first)
  55{
  56        struct mlxsw_sp *mlxsw_sp = priv;
  57
  58        if (is_first)
  59                return;
  60        mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET,
  61                           1, kvdl_index);
  62}
  63
  64static int mlxsw_sp1_act_kvdl_set_activity_get(void *priv, u32 kvdl_index,
  65                                               bool *activity)
  66{
  67        return -EOPNOTSUPP;
  68}
  69
  70static int mlxsw_sp2_act_kvdl_set_activity_get(void *priv, u32 kvdl_index,
  71                                               bool *activity)
  72{
  73        struct mlxsw_sp *mlxsw_sp = priv;
  74        char pefa_pl[MLXSW_REG_PEFA_LEN];
  75        int err;
  76
  77        mlxsw_reg_pefa_pack(pefa_pl, kvdl_index, true, NULL);
  78        err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pefa), pefa_pl);
  79        if (err)
  80                return err;
  81        mlxsw_reg_pefa_unpack(pefa_pl, activity);
  82        return 0;
  83}
  84
  85static int mlxsw_sp_act_kvdl_fwd_entry_add(void *priv, u32 *p_kvdl_index,
  86                                           u8 local_port)
  87{
  88        struct mlxsw_sp *mlxsw_sp = priv;
  89        char ppbs_pl[MLXSW_REG_PPBS_LEN];
  90        u32 kvdl_index;
  91        int err;
  92
  93        err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_PBS,
  94                                  1, &kvdl_index);
  95        if (err)
  96                return err;
  97        mlxsw_reg_ppbs_pack(ppbs_pl, kvdl_index, local_port);
  98        err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ppbs), ppbs_pl);
  99        if (err)
 100                goto err_ppbs_write;
 101        *p_kvdl_index = kvdl_index;
 102        return 0;
 103
 104err_ppbs_write:
 105        mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_PBS,
 106                           1, kvdl_index);
 107        return err;
 108}
 109
 110static void mlxsw_sp_act_kvdl_fwd_entry_del(void *priv, u32 kvdl_index)
 111{
 112        struct mlxsw_sp *mlxsw_sp = priv;
 113
 114        mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_PBS,
 115                           1, kvdl_index);
 116}
 117
 118static int
 119mlxsw_sp_act_counter_index_get(void *priv, unsigned int *p_counter_index)
 120{
 121        struct mlxsw_sp *mlxsw_sp = priv;
 122
 123        return mlxsw_sp_flow_counter_alloc(mlxsw_sp, p_counter_index);
 124}
 125
 126static void
 127mlxsw_sp_act_counter_index_put(void *priv, unsigned int counter_index)
 128{
 129        struct mlxsw_sp *mlxsw_sp = priv;
 130
 131        mlxsw_sp_flow_counter_free(mlxsw_sp, counter_index);
 132}
 133
 134static int
 135mlxsw_sp_act_mirror_add(void *priv, u8 local_in_port,
 136                        const struct net_device *out_dev,
 137                        bool ingress, int *p_span_id)
 138{
 139        struct mlxsw_sp_port *in_port;
 140        struct mlxsw_sp *mlxsw_sp = priv;
 141        enum mlxsw_sp_span_type type;
 142
 143        type = ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS;
 144        in_port = mlxsw_sp->ports[local_in_port];
 145
 146        return mlxsw_sp_span_mirror_add(in_port, out_dev, type,
 147                                        false, p_span_id);
 148}
 149
 150static void
 151mlxsw_sp_act_mirror_del(void *priv, u8 local_in_port, int span_id, bool ingress)
 152{
 153        struct mlxsw_sp *mlxsw_sp = priv;
 154        struct mlxsw_sp_port *in_port;
 155        enum mlxsw_sp_span_type type;
 156
 157        type = ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS;
 158        in_port = mlxsw_sp->ports[local_in_port];
 159
 160        mlxsw_sp_span_mirror_del(in_port, span_id, type, false);
 161}
 162
 163const struct mlxsw_afa_ops mlxsw_sp1_act_afa_ops = {
 164        .kvdl_set_add           = mlxsw_sp1_act_kvdl_set_add,
 165        .kvdl_set_del           = mlxsw_sp_act_kvdl_set_del,
 166        .kvdl_set_activity_get  = mlxsw_sp1_act_kvdl_set_activity_get,
 167        .kvdl_fwd_entry_add     = mlxsw_sp_act_kvdl_fwd_entry_add,
 168        .kvdl_fwd_entry_del     = mlxsw_sp_act_kvdl_fwd_entry_del,
 169        .counter_index_get      = mlxsw_sp_act_counter_index_get,
 170        .counter_index_put      = mlxsw_sp_act_counter_index_put,
 171        .mirror_add             = mlxsw_sp_act_mirror_add,
 172        .mirror_del             = mlxsw_sp_act_mirror_del,
 173};
 174
 175const struct mlxsw_afa_ops mlxsw_sp2_act_afa_ops = {
 176        .kvdl_set_add           = mlxsw_sp2_act_kvdl_set_add,
 177        .kvdl_set_del           = mlxsw_sp_act_kvdl_set_del,
 178        .kvdl_set_activity_get  = mlxsw_sp2_act_kvdl_set_activity_get,
 179        .kvdl_fwd_entry_add     = mlxsw_sp_act_kvdl_fwd_entry_add,
 180        .kvdl_fwd_entry_del     = mlxsw_sp_act_kvdl_fwd_entry_del,
 181        .counter_index_get      = mlxsw_sp_act_counter_index_get,
 182        .counter_index_put      = mlxsw_sp_act_counter_index_put,
 183        .mirror_add             = mlxsw_sp_act_mirror_add,
 184        .mirror_del             = mlxsw_sp_act_mirror_del,
 185        .dummy_first_set        = true,
 186};
 187
 188int mlxsw_sp_afa_init(struct mlxsw_sp *mlxsw_sp)
 189{
 190        mlxsw_sp->afa = mlxsw_afa_create(MLXSW_CORE_RES_GET(mlxsw_sp->core,
 191                                                            ACL_ACTIONS_PER_SET),
 192                                         mlxsw_sp->afa_ops, mlxsw_sp);
 193        return PTR_ERR_OR_ZERO(mlxsw_sp->afa);
 194}
 195
 196void mlxsw_sp_afa_fini(struct mlxsw_sp *mlxsw_sp)
 197{
 198        mlxsw_afa_destroy(mlxsw_sp->afa);
 199}
 200