1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ 3 4 #include <linux/kernel.h> 5 #include <linux/slab.h> 6 7 #include "reg.h" 8 #include "core.h" 9 #include "spectrum.h" 10 #include "spectrum_acl_tcam.h" 11 12 struct mlxsw_sp1_acl_tcam_region { 13 struct mlxsw_sp_acl_ctcam_region cregion; 14 struct mlxsw_sp_acl_tcam_region *region; 15 struct { 16 struct mlxsw_sp_acl_ctcam_chunk cchunk; 17 struct mlxsw_sp_acl_ctcam_entry centry; 18 struct mlxsw_sp_acl_rule_info *rulei; 19 } catchall; 20 }; 21 22 struct mlxsw_sp1_acl_tcam_chunk { 23 struct mlxsw_sp_acl_ctcam_chunk cchunk; 24 }; 25 26 struct mlxsw_sp1_acl_tcam_entry { 27 struct mlxsw_sp_acl_ctcam_entry centry; 28 }; 29 30 static int 31 mlxsw_sp1_acl_ctcam_region_entry_insert(struct mlxsw_sp_acl_ctcam_region *cregion, 32 struct mlxsw_sp_acl_ctcam_entry *centry, 33 const char *mask) 34 { 35 return 0; 36 } 37 38 static void 39 mlxsw_sp1_acl_ctcam_region_entry_remove(struct mlxsw_sp_acl_ctcam_region *cregion, 40 struct mlxsw_sp_acl_ctcam_entry *centry) 41 { 42 } 43 44 static const struct mlxsw_sp_acl_ctcam_region_ops 45 mlxsw_sp1_acl_ctcam_region_ops = { 46 .entry_insert = mlxsw_sp1_acl_ctcam_region_entry_insert, 47 .entry_remove = mlxsw_sp1_acl_ctcam_region_entry_remove, 48 }; 49 50 static int mlxsw_sp1_acl_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv, 51 struct mlxsw_sp_acl_tcam *tcam) 52 { 53 return 0; 54 } 55 56 static void mlxsw_sp1_acl_tcam_fini(struct mlxsw_sp *mlxsw_sp, void *priv) 57 { 58 } 59 60 static int 61 mlxsw_sp1_acl_ctcam_region_catchall_add(struct mlxsw_sp *mlxsw_sp, 62 struct mlxsw_sp1_acl_tcam_region *region) 63 { 64 struct mlxsw_sp_acl_rule_info *rulei; 65 int err; 66 67 mlxsw_sp_acl_ctcam_chunk_init(®ion->cregion, 68 ®ion->catchall.cchunk, 69 MLXSW_SP_ACL_TCAM_CATCHALL_PRIO); 70 rulei = mlxsw_sp_acl_rulei_create(mlxsw_sp->acl, NULL); 71 if (IS_ERR(rulei)) { 72 err = PTR_ERR(rulei); 73 goto err_rulei_create; 74 } 75 err = mlxsw_sp_acl_rulei_act_continue(rulei); 76 if (WARN_ON(err)) 77 goto err_rulei_act_continue; 78 err = mlxsw_sp_acl_rulei_commit(rulei); 79 if (err) 80 goto err_rulei_commit; 81 err = mlxsw_sp_acl_ctcam_entry_add(mlxsw_sp, ®ion->cregion, 82 ®ion->catchall.cchunk, 83 ®ion->catchall.centry, 84 rulei, false); 85 if (err) 86 goto err_entry_add; 87 region->catchall.rulei = rulei; 88 return 0; 89 90 err_entry_add: 91 err_rulei_commit: 92 err_rulei_act_continue: 93 mlxsw_sp_acl_rulei_destroy(rulei); 94 err_rulei_create: 95 mlxsw_sp_acl_ctcam_chunk_fini(®ion->catchall.cchunk); 96 return err; 97 } 98 99 static void 100 mlxsw_sp1_acl_ctcam_region_catchall_del(struct mlxsw_sp *mlxsw_sp, 101 struct mlxsw_sp1_acl_tcam_region *region) 102 { 103 struct mlxsw_sp_acl_rule_info *rulei = region->catchall.rulei; 104 105 mlxsw_sp_acl_ctcam_entry_del(mlxsw_sp, ®ion->cregion, 106 ®ion->catchall.cchunk, 107 ®ion->catchall.centry); 108 mlxsw_sp_acl_rulei_destroy(rulei); 109 mlxsw_sp_acl_ctcam_chunk_fini(®ion->catchall.cchunk); 110 } 111 112 static int 113 mlxsw_sp1_acl_tcam_region_init(struct mlxsw_sp *mlxsw_sp, void *region_priv, 114 void *tcam_priv, 115 struct mlxsw_sp_acl_tcam_region *_region) 116 { 117 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 118 int err; 119 120 err = mlxsw_sp_acl_ctcam_region_init(mlxsw_sp, ®ion->cregion, 121 _region, 122 &mlxsw_sp1_acl_ctcam_region_ops); 123 if (err) 124 return err; 125 err = mlxsw_sp1_acl_ctcam_region_catchall_add(mlxsw_sp, region); 126 if (err) 127 goto err_catchall_add; 128 region->region = _region; 129 return 0; 130 131 err_catchall_add: 132 mlxsw_sp_acl_ctcam_region_fini(®ion->cregion); 133 return err; 134 } 135 136 static void 137 mlxsw_sp1_acl_tcam_region_fini(struct mlxsw_sp *mlxsw_sp, void *region_priv) 138 { 139 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 140 141 mlxsw_sp1_acl_ctcam_region_catchall_del(mlxsw_sp, region); 142 mlxsw_sp_acl_ctcam_region_fini(®ion->cregion); 143 } 144 145 static int 146 mlxsw_sp1_acl_tcam_region_associate(struct mlxsw_sp *mlxsw_sp, 147 struct mlxsw_sp_acl_tcam_region *region) 148 { 149 return 0; 150 } 151 152 static void mlxsw_sp1_acl_tcam_chunk_init(void *region_priv, void *chunk_priv, 153 unsigned int priority) 154 { 155 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 156 struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; 157 158 mlxsw_sp_acl_ctcam_chunk_init(®ion->cregion, &chunk->cchunk, 159 priority); 160 } 161 162 static void mlxsw_sp1_acl_tcam_chunk_fini(void *chunk_priv) 163 { 164 struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; 165 166 mlxsw_sp_acl_ctcam_chunk_fini(&chunk->cchunk); 167 } 168 169 static int mlxsw_sp1_acl_tcam_entry_add(struct mlxsw_sp *mlxsw_sp, 170 void *region_priv, void *chunk_priv, 171 void *entry_priv, 172 struct mlxsw_sp_acl_rule_info *rulei) 173 { 174 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 175 struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; 176 struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv; 177 178 return mlxsw_sp_acl_ctcam_entry_add(mlxsw_sp, ®ion->cregion, 179 &chunk->cchunk, &entry->centry, 180 rulei, false); 181 } 182 183 static void mlxsw_sp1_acl_tcam_entry_del(struct mlxsw_sp *mlxsw_sp, 184 void *region_priv, void *chunk_priv, 185 void *entry_priv) 186 { 187 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 188 struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; 189 struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv; 190 191 mlxsw_sp_acl_ctcam_entry_del(mlxsw_sp, ®ion->cregion, 192 &chunk->cchunk, &entry->centry); 193 } 194 195 static int 196 mlxsw_sp1_acl_tcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp, 197 void *region_priv, void *chunk_priv, 198 void *entry_priv, 199 struct mlxsw_sp_acl_rule_info *rulei) 200 { 201 return -EOPNOTSUPP; 202 } 203 204 static int 205 mlxsw_sp1_acl_tcam_region_entry_activity_get(struct mlxsw_sp *mlxsw_sp, 206 struct mlxsw_sp_acl_tcam_region *_region, 207 unsigned int offset, 208 bool *activity) 209 { 210 char ptce2_pl[MLXSW_REG_PTCE2_LEN]; 211 int err; 212 213 mlxsw_reg_ptce2_pack(ptce2_pl, true, MLXSW_REG_PTCE2_OP_QUERY_CLEAR_ON_READ, 214 _region->tcam_region_info, offset, 0); 215 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl); 216 if (err) 217 return err; 218 *activity = mlxsw_reg_ptce2_a_get(ptce2_pl); 219 return 0; 220 } 221 222 static int 223 mlxsw_sp1_acl_tcam_entry_activity_get(struct mlxsw_sp *mlxsw_sp, 224 void *region_priv, void *entry_priv, 225 bool *activity) 226 { 227 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 228 struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv; 229 unsigned int offset; 230 231 offset = mlxsw_sp_acl_ctcam_entry_offset(&entry->centry); 232 return mlxsw_sp1_acl_tcam_region_entry_activity_get(mlxsw_sp, 233 region->region, 234 offset, activity); 235 } 236 237 const struct mlxsw_sp_acl_tcam_ops mlxsw_sp1_acl_tcam_ops = { 238 .key_type = MLXSW_REG_PTAR_KEY_TYPE_FLEX, 239 .priv_size = 0, 240 .init = mlxsw_sp1_acl_tcam_init, 241 .fini = mlxsw_sp1_acl_tcam_fini, 242 .region_priv_size = sizeof(struct mlxsw_sp1_acl_tcam_region), 243 .region_init = mlxsw_sp1_acl_tcam_region_init, 244 .region_fini = mlxsw_sp1_acl_tcam_region_fini, 245 .region_associate = mlxsw_sp1_acl_tcam_region_associate, 246 .chunk_priv_size = sizeof(struct mlxsw_sp1_acl_tcam_chunk), 247 .chunk_init = mlxsw_sp1_acl_tcam_chunk_init, 248 .chunk_fini = mlxsw_sp1_acl_tcam_chunk_fini, 249 .entry_priv_size = sizeof(struct mlxsw_sp1_acl_tcam_entry), 250 .entry_add = mlxsw_sp1_acl_tcam_entry_add, 251 .entry_del = mlxsw_sp1_acl_tcam_entry_del, 252 .entry_action_replace = mlxsw_sp1_acl_tcam_entry_action_replace, 253 .entry_activity_get = mlxsw_sp1_acl_tcam_entry_activity_get, 254 }; 255