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_port *mlxsw_sp_port; 140 struct mlxsw_sp *mlxsw_sp = priv; 141 int err; 142 143 err = mlxsw_sp_span_agent_get(mlxsw_sp, out_dev, p_span_id); 144 if (err) 145 return err; 146 147 mlxsw_sp_port = mlxsw_sp->ports[local_in_port]; 148 err = mlxsw_sp_span_analyzed_port_get(mlxsw_sp_port, ingress); 149 if (err) 150 goto err_analyzed_port_get; 151 152 return 0; 153 154 err_analyzed_port_get: 155 mlxsw_sp_span_agent_put(mlxsw_sp, *p_span_id); 156 return err; 157 } 158 159 static void 160 mlxsw_sp_act_mirror_del(void *priv, u8 local_in_port, int span_id, bool ingress) 161 { 162 struct mlxsw_sp_port *mlxsw_sp_port; 163 struct mlxsw_sp *mlxsw_sp = priv; 164 165 mlxsw_sp_port = mlxsw_sp->ports[local_in_port]; 166 mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, ingress); 167 mlxsw_sp_span_agent_put(mlxsw_sp, span_id); 168 } 169 170 const struct mlxsw_afa_ops mlxsw_sp1_act_afa_ops = { 171 .kvdl_set_add = mlxsw_sp1_act_kvdl_set_add, 172 .kvdl_set_del = mlxsw_sp_act_kvdl_set_del, 173 .kvdl_set_activity_get = mlxsw_sp1_act_kvdl_set_activity_get, 174 .kvdl_fwd_entry_add = mlxsw_sp_act_kvdl_fwd_entry_add, 175 .kvdl_fwd_entry_del = mlxsw_sp_act_kvdl_fwd_entry_del, 176 .counter_index_get = mlxsw_sp_act_counter_index_get, 177 .counter_index_put = mlxsw_sp_act_counter_index_put, 178 .mirror_add = mlxsw_sp_act_mirror_add, 179 .mirror_del = mlxsw_sp_act_mirror_del, 180 }; 181 182 const struct mlxsw_afa_ops mlxsw_sp2_act_afa_ops = { 183 .kvdl_set_add = mlxsw_sp2_act_kvdl_set_add, 184 .kvdl_set_del = mlxsw_sp_act_kvdl_set_del, 185 .kvdl_set_activity_get = mlxsw_sp2_act_kvdl_set_activity_get, 186 .kvdl_fwd_entry_add = mlxsw_sp_act_kvdl_fwd_entry_add, 187 .kvdl_fwd_entry_del = mlxsw_sp_act_kvdl_fwd_entry_del, 188 .counter_index_get = mlxsw_sp_act_counter_index_get, 189 .counter_index_put = mlxsw_sp_act_counter_index_put, 190 .mirror_add = mlxsw_sp_act_mirror_add, 191 .mirror_del = mlxsw_sp_act_mirror_del, 192 .dummy_first_set = true, 193 }; 194 195 int mlxsw_sp_afa_init(struct mlxsw_sp *mlxsw_sp) 196 { 197 mlxsw_sp->afa = mlxsw_afa_create(MLXSW_CORE_RES_GET(mlxsw_sp->core, 198 ACL_ACTIONS_PER_SET), 199 mlxsw_sp->afa_ops, mlxsw_sp); 200 return PTR_ERR_OR_ZERO(mlxsw_sp->afa); 201 } 202 203 void mlxsw_sp_afa_fini(struct mlxsw_sp *mlxsw_sp) 204 { 205 mlxsw_afa_destroy(mlxsw_sp->afa); 206 } 207