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 *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 150 static void 151 mlxsw_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 163 const 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 175 const 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 188 int 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 196 void mlxsw_sp_afa_fini(struct mlxsw_sp *mlxsw_sp) 197 { 198 mlxsw_afa_destroy(mlxsw_sp->afa); 199 } 200