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 8 static 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 33 err_pefa_write: 34 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET, 35 1, kvdl_index); 36 return err; 37 } 38 39 static 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 46 static 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 53 static 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 64 static int mlxsw_sp1_act_kvdl_set_activity_get(void *priv, u32 kvdl_index, 65 bool *activity) 66 { 67 return -EOPNOTSUPP; 68 } 69 70 static 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 85 static 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 104 err_ppbs_write: 105 mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_PBS, 106 1, kvdl_index); 107 return err; 108 } 109 110 static 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 118 static int 119 mlxsw_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 126 static void 127 mlxsw_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 134 static int 135 mlxsw_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_span_agent_parms agent_parms = {}; 140 struct mlxsw_sp_port *mlxsw_sp_port; 141 struct mlxsw_sp *mlxsw_sp = priv; 142 int err; 143 144 agent_parms.to_dev = out_dev; 145 err = mlxsw_sp_span_agent_get(mlxsw_sp, p_span_id, &agent_parms); 146 if (err) 147 return err; 148 149 mlxsw_sp_port = mlxsw_sp->ports[local_in_port]; 150 err = mlxsw_sp_span_analyzed_port_get(mlxsw_sp_port, ingress); 151 if (err) 152 goto err_analyzed_port_get; 153 154 return 0; 155 156 err_analyzed_port_get: 157 mlxsw_sp_span_agent_put(mlxsw_sp, *p_span_id); 158 return err; 159 } 160 161 static void 162 mlxsw_sp_act_mirror_del(void *priv, u8 local_in_port, int span_id, bool ingress) 163 { 164 struct mlxsw_sp_port *mlxsw_sp_port; 165 struct mlxsw_sp *mlxsw_sp = priv; 166 167 mlxsw_sp_port = mlxsw_sp->ports[local_in_port]; 168 mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, ingress); 169 mlxsw_sp_span_agent_put(mlxsw_sp, span_id); 170 } 171 172 static int mlxsw_sp_act_policer_add(void *priv, u64 rate_bytes_ps, u32 burst, 173 u16 *p_policer_index, 174 struct netlink_ext_ack *extack) 175 { 176 struct mlxsw_sp_policer_params params; 177 struct mlxsw_sp *mlxsw_sp = priv; 178 179 params.rate = rate_bytes_ps; 180 params.burst = burst; 181 params.bytes = true; 182 return mlxsw_sp_policer_add(mlxsw_sp, 183 MLXSW_SP_POLICER_TYPE_SINGLE_RATE, 184 ¶ms, extack, p_policer_index); 185 } 186 187 static void mlxsw_sp_act_policer_del(void *priv, u16 policer_index) 188 { 189 struct mlxsw_sp *mlxsw_sp = priv; 190 191 mlxsw_sp_policer_del(mlxsw_sp, MLXSW_SP_POLICER_TYPE_SINGLE_RATE, 192 policer_index); 193 } 194 195 static int mlxsw_sp1_act_sampler_add(void *priv, u8 local_port, 196 struct psample_group *psample_group, 197 u32 rate, u32 trunc_size, bool truncate, 198 bool ingress, int *p_span_id, 199 struct netlink_ext_ack *extack) 200 { 201 NL_SET_ERR_MSG_MOD(extack, "Sampling action is not supported on Spectrum-1"); 202 return -EOPNOTSUPP; 203 } 204 205 static void mlxsw_sp1_act_sampler_del(void *priv, u8 local_port, int span_id, 206 bool ingress) 207 { 208 WARN_ON_ONCE(1); 209 } 210 211 const struct mlxsw_afa_ops mlxsw_sp1_act_afa_ops = { 212 .kvdl_set_add = mlxsw_sp1_act_kvdl_set_add, 213 .kvdl_set_del = mlxsw_sp_act_kvdl_set_del, 214 .kvdl_set_activity_get = mlxsw_sp1_act_kvdl_set_activity_get, 215 .kvdl_fwd_entry_add = mlxsw_sp_act_kvdl_fwd_entry_add, 216 .kvdl_fwd_entry_del = mlxsw_sp_act_kvdl_fwd_entry_del, 217 .counter_index_get = mlxsw_sp_act_counter_index_get, 218 .counter_index_put = mlxsw_sp_act_counter_index_put, 219 .mirror_add = mlxsw_sp_act_mirror_add, 220 .mirror_del = mlxsw_sp_act_mirror_del, 221 .policer_add = mlxsw_sp_act_policer_add, 222 .policer_del = mlxsw_sp_act_policer_del, 223 .sampler_add = mlxsw_sp1_act_sampler_add, 224 .sampler_del = mlxsw_sp1_act_sampler_del, 225 }; 226 227 static int mlxsw_sp2_act_sampler_add(void *priv, u8 local_port, 228 struct psample_group *psample_group, 229 u32 rate, u32 trunc_size, bool truncate, 230 bool ingress, int *p_span_id, 231 struct netlink_ext_ack *extack) 232 { 233 struct mlxsw_sp_span_agent_parms agent_parms = { 234 .session_id = MLXSW_SP_SPAN_SESSION_ID_SAMPLING, 235 }; 236 struct mlxsw_sp_sample_trigger trigger = { 237 .type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_POLICY_ENGINE, 238 }; 239 struct mlxsw_sp_sample_params params; 240 struct mlxsw_sp_port *mlxsw_sp_port; 241 struct mlxsw_sp *mlxsw_sp = priv; 242 int err; 243 244 params.psample_group = psample_group; 245 params.trunc_size = trunc_size; 246 params.rate = rate; 247 params.truncate = truncate; 248 err = mlxsw_sp_sample_trigger_params_set(mlxsw_sp, &trigger, ¶ms, 249 extack); 250 if (err) 251 return err; 252 253 err = mlxsw_sp_span_agent_get(mlxsw_sp, p_span_id, &agent_parms); 254 if (err) { 255 NL_SET_ERR_MSG_MOD(extack, "Failed to get SPAN agent"); 256 goto err_span_agent_get; 257 } 258 259 mlxsw_sp_port = mlxsw_sp->ports[local_port]; 260 err = mlxsw_sp_span_analyzed_port_get(mlxsw_sp_port, ingress); 261 if (err) { 262 NL_SET_ERR_MSG_MOD(extack, "Failed to get analyzed port"); 263 goto err_analyzed_port_get; 264 } 265 266 return 0; 267 268 err_analyzed_port_get: 269 mlxsw_sp_span_agent_put(mlxsw_sp, *p_span_id); 270 err_span_agent_get: 271 mlxsw_sp_sample_trigger_params_unset(mlxsw_sp, &trigger); 272 return err; 273 } 274 275 static void mlxsw_sp2_act_sampler_del(void *priv, u8 local_port, int span_id, 276 bool ingress) 277 { 278 struct mlxsw_sp_sample_trigger trigger = { 279 .type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_POLICY_ENGINE, 280 }; 281 struct mlxsw_sp_port *mlxsw_sp_port; 282 struct mlxsw_sp *mlxsw_sp = priv; 283 284 mlxsw_sp_port = mlxsw_sp->ports[local_port]; 285 mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, ingress); 286 mlxsw_sp_span_agent_put(mlxsw_sp, span_id); 287 mlxsw_sp_sample_trigger_params_unset(mlxsw_sp, &trigger); 288 } 289 290 const struct mlxsw_afa_ops mlxsw_sp2_act_afa_ops = { 291 .kvdl_set_add = mlxsw_sp2_act_kvdl_set_add, 292 .kvdl_set_del = mlxsw_sp_act_kvdl_set_del, 293 .kvdl_set_activity_get = mlxsw_sp2_act_kvdl_set_activity_get, 294 .kvdl_fwd_entry_add = mlxsw_sp_act_kvdl_fwd_entry_add, 295 .kvdl_fwd_entry_del = mlxsw_sp_act_kvdl_fwd_entry_del, 296 .counter_index_get = mlxsw_sp_act_counter_index_get, 297 .counter_index_put = mlxsw_sp_act_counter_index_put, 298 .mirror_add = mlxsw_sp_act_mirror_add, 299 .mirror_del = mlxsw_sp_act_mirror_del, 300 .policer_add = mlxsw_sp_act_policer_add, 301 .policer_del = mlxsw_sp_act_policer_del, 302 .sampler_add = mlxsw_sp2_act_sampler_add, 303 .sampler_del = mlxsw_sp2_act_sampler_del, 304 .dummy_first_set = true, 305 }; 306 307 int mlxsw_sp_afa_init(struct mlxsw_sp *mlxsw_sp) 308 { 309 mlxsw_sp->afa = mlxsw_afa_create(MLXSW_CORE_RES_GET(mlxsw_sp->core, 310 ACL_ACTIONS_PER_SET), 311 mlxsw_sp->afa_ops, mlxsw_sp); 312 return PTR_ERR_OR_ZERO(mlxsw_sp->afa); 313 } 314 315 void mlxsw_sp_afa_fini(struct mlxsw_sp *mlxsw_sp) 316 { 317 mlxsw_afa_destroy(mlxsw_sp->afa); 318 } 319