1 /* 2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_actions.c 3 * Copyright (c) 2017 Mellanox Technologies. All rights reserved. 4 * Copyright (c) 2017 Jiri Pirko <jiri@mellanox.com> 5 * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the names of the copyright holders nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * Alternatively, this software may be distributed under the terms of the 20 * GNU General Public License ("GPL") version 2 as published by the Free 21 * Software Foundation. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 #include "spectrum_acl_flex_actions.h" 37 #include "core_acl_flex_actions.h" 38 #include "spectrum_span.h" 39 40 #define MLXSW_SP_KVDL_ACT_EXT_SIZE 1 41 42 static int mlxsw_sp_act_kvdl_set_add(void *priv, u32 *p_kvdl_index, 43 char *enc_actions, bool is_first) 44 { 45 struct mlxsw_sp *mlxsw_sp = priv; 46 char pefa_pl[MLXSW_REG_PEFA_LEN]; 47 u32 kvdl_index; 48 int err; 49 50 /* The first action set of a TCAM entry is stored directly in TCAM, 51 * not KVD linear area. 52 */ 53 if (is_first) 54 return 0; 55 56 err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ACT_EXT_SIZE, 57 &kvdl_index); 58 if (err) 59 return err; 60 mlxsw_reg_pefa_pack(pefa_pl, kvdl_index, enc_actions); 61 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pefa), pefa_pl); 62 if (err) 63 goto err_pefa_write; 64 *p_kvdl_index = kvdl_index; 65 return 0; 66 67 err_pefa_write: 68 mlxsw_sp_kvdl_free(mlxsw_sp, kvdl_index); 69 return err; 70 } 71 72 static void mlxsw_sp_act_kvdl_set_del(void *priv, u32 kvdl_index, 73 bool is_first) 74 { 75 struct mlxsw_sp *mlxsw_sp = priv; 76 77 if (is_first) 78 return; 79 mlxsw_sp_kvdl_free(mlxsw_sp, kvdl_index); 80 } 81 82 static int mlxsw_sp_act_kvdl_fwd_entry_add(void *priv, u32 *p_kvdl_index, 83 u8 local_port) 84 { 85 struct mlxsw_sp *mlxsw_sp = priv; 86 char ppbs_pl[MLXSW_REG_PPBS_LEN]; 87 u32 kvdl_index; 88 int err; 89 90 err = mlxsw_sp_kvdl_alloc(mlxsw_sp, 1, &kvdl_index); 91 if (err) 92 return err; 93 mlxsw_reg_ppbs_pack(ppbs_pl, kvdl_index, local_port); 94 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ppbs), ppbs_pl); 95 if (err) 96 goto err_ppbs_write; 97 *p_kvdl_index = kvdl_index; 98 return 0; 99 100 err_ppbs_write: 101 mlxsw_sp_kvdl_free(mlxsw_sp, kvdl_index); 102 return err; 103 } 104 105 static void mlxsw_sp_act_kvdl_fwd_entry_del(void *priv, u32 kvdl_index) 106 { 107 struct mlxsw_sp *mlxsw_sp = priv; 108 109 mlxsw_sp_kvdl_free(mlxsw_sp, kvdl_index); 110 } 111 112 static int 113 mlxsw_sp_act_counter_index_get(void *priv, unsigned int *p_counter_index) 114 { 115 struct mlxsw_sp *mlxsw_sp = priv; 116 117 return mlxsw_sp_flow_counter_alloc(mlxsw_sp, p_counter_index); 118 } 119 120 static void 121 mlxsw_sp_act_counter_index_put(void *priv, unsigned int counter_index) 122 { 123 struct mlxsw_sp *mlxsw_sp = priv; 124 125 mlxsw_sp_flow_counter_free(mlxsw_sp, counter_index); 126 } 127 128 static int 129 mlxsw_sp_act_mirror_add(void *priv, u8 local_in_port, u8 local_out_port, 130 bool ingress, int *p_span_id) 131 { 132 struct mlxsw_sp_port *in_port, *out_port; 133 struct mlxsw_sp_span_entry *span_entry; 134 struct mlxsw_sp *mlxsw_sp = priv; 135 enum mlxsw_sp_span_type type; 136 int err; 137 138 type = ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS; 139 out_port = mlxsw_sp->ports[local_out_port]; 140 in_port = mlxsw_sp->ports[local_in_port]; 141 142 err = mlxsw_sp_span_mirror_add(in_port, out_port, type, false); 143 if (err) 144 return err; 145 146 span_entry = mlxsw_sp_span_entry_find(mlxsw_sp, local_out_port); 147 if (!span_entry) { 148 err = -ENOENT; 149 goto err_span_entry_find; 150 } 151 152 *p_span_id = span_entry->id; 153 return 0; 154 155 err_span_entry_find: 156 mlxsw_sp_span_mirror_del(in_port, local_out_port, type, false); 157 return err; 158 } 159 160 static void 161 mlxsw_sp_act_mirror_del(void *priv, u8 local_in_port, u8 local_out_port, 162 bool ingress) 163 { 164 struct mlxsw_sp *mlxsw_sp = priv; 165 struct mlxsw_sp_port *in_port; 166 enum mlxsw_sp_span_type type; 167 168 type = ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS; 169 in_port = mlxsw_sp->ports[local_in_port]; 170 171 mlxsw_sp_span_mirror_del(in_port, local_out_port, type, false); 172 } 173 174 static const struct mlxsw_afa_ops mlxsw_sp_act_afa_ops = { 175 .kvdl_set_add = mlxsw_sp_act_kvdl_set_add, 176 .kvdl_set_del = mlxsw_sp_act_kvdl_set_del, 177 .kvdl_fwd_entry_add = mlxsw_sp_act_kvdl_fwd_entry_add, 178 .kvdl_fwd_entry_del = mlxsw_sp_act_kvdl_fwd_entry_del, 179 .counter_index_get = mlxsw_sp_act_counter_index_get, 180 .counter_index_put = mlxsw_sp_act_counter_index_put, 181 .mirror_add = mlxsw_sp_act_mirror_add, 182 .mirror_del = mlxsw_sp_act_mirror_del, 183 }; 184 185 int mlxsw_sp_afa_init(struct mlxsw_sp *mlxsw_sp) 186 { 187 mlxsw_sp->afa = mlxsw_afa_create(MLXSW_CORE_RES_GET(mlxsw_sp->core, 188 ACL_ACTIONS_PER_SET), 189 &mlxsw_sp_act_afa_ops, mlxsw_sp); 190 return PTR_ERR_OR_ZERO(mlxsw_sp->afa); 191 } 192 193 void mlxsw_sp_afa_fini(struct mlxsw_sp *mlxsw_sp) 194 { 195 mlxsw_afa_destroy(mlxsw_sp->afa); 196 } 197