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 const struct mlxsw_afa_ops mlxsw_sp1_act_afa_ops = { 196 .kvdl_set_add = mlxsw_sp1_act_kvdl_set_add, 197 .kvdl_set_del = mlxsw_sp_act_kvdl_set_del, 198 .kvdl_set_activity_get = mlxsw_sp1_act_kvdl_set_activity_get, 199 .kvdl_fwd_entry_add = mlxsw_sp_act_kvdl_fwd_entry_add, 200 .kvdl_fwd_entry_del = mlxsw_sp_act_kvdl_fwd_entry_del, 201 .counter_index_get = mlxsw_sp_act_counter_index_get, 202 .counter_index_put = mlxsw_sp_act_counter_index_put, 203 .mirror_add = mlxsw_sp_act_mirror_add, 204 .mirror_del = mlxsw_sp_act_mirror_del, 205 .policer_add = mlxsw_sp_act_policer_add, 206 .policer_del = mlxsw_sp_act_policer_del, 207 }; 208 209 const struct mlxsw_afa_ops mlxsw_sp2_act_afa_ops = { 210 .kvdl_set_add = mlxsw_sp2_act_kvdl_set_add, 211 .kvdl_set_del = mlxsw_sp_act_kvdl_set_del, 212 .kvdl_set_activity_get = mlxsw_sp2_act_kvdl_set_activity_get, 213 .kvdl_fwd_entry_add = mlxsw_sp_act_kvdl_fwd_entry_add, 214 .kvdl_fwd_entry_del = mlxsw_sp_act_kvdl_fwd_entry_del, 215 .counter_index_get = mlxsw_sp_act_counter_index_get, 216 .counter_index_put = mlxsw_sp_act_counter_index_put, 217 .mirror_add = mlxsw_sp_act_mirror_add, 218 .mirror_del = mlxsw_sp_act_mirror_del, 219 .policer_add = mlxsw_sp_act_policer_add, 220 .policer_del = mlxsw_sp_act_policer_del, 221 .dummy_first_set = true, 222 }; 223 224 int mlxsw_sp_afa_init(struct mlxsw_sp *mlxsw_sp) 225 { 226 mlxsw_sp->afa = mlxsw_afa_create(MLXSW_CORE_RES_GET(mlxsw_sp->core, 227 ACL_ACTIONS_PER_SET), 228 mlxsw_sp->afa_ops, mlxsw_sp); 229 return PTR_ERR_OR_ZERO(mlxsw_sp->afa); 230 } 231 232 void mlxsw_sp_afa_fini(struct mlxsw_sp *mlxsw_sp) 233 { 234 mlxsw_afa_destroy(mlxsw_sp->afa); 235 } 236