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 void *hints_priv) 117 { 118 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 119 int err; 120 121 err = mlxsw_sp_acl_ctcam_region_init(mlxsw_sp, ®ion->cregion, 122 _region, 123 &mlxsw_sp1_acl_ctcam_region_ops); 124 if (err) 125 return err; 126 err = mlxsw_sp1_acl_ctcam_region_catchall_add(mlxsw_sp, region); 127 if (err) 128 goto err_catchall_add; 129 region->region = _region; 130 return 0; 131 132 err_catchall_add: 133 mlxsw_sp_acl_ctcam_region_fini(®ion->cregion); 134 return err; 135 } 136 137 static void 138 mlxsw_sp1_acl_tcam_region_fini(struct mlxsw_sp *mlxsw_sp, void *region_priv) 139 { 140 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 141 142 mlxsw_sp1_acl_ctcam_region_catchall_del(mlxsw_sp, region); 143 mlxsw_sp_acl_ctcam_region_fini(®ion->cregion); 144 } 145 146 static int 147 mlxsw_sp1_acl_tcam_region_associate(struct mlxsw_sp *mlxsw_sp, 148 struct mlxsw_sp_acl_tcam_region *region) 149 { 150 return 0; 151 } 152 153 static void mlxsw_sp1_acl_tcam_chunk_init(void *region_priv, void *chunk_priv, 154 unsigned int priority) 155 { 156 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 157 struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; 158 159 mlxsw_sp_acl_ctcam_chunk_init(®ion->cregion, &chunk->cchunk, 160 priority); 161 } 162 163 static void mlxsw_sp1_acl_tcam_chunk_fini(void *chunk_priv) 164 { 165 struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; 166 167 mlxsw_sp_acl_ctcam_chunk_fini(&chunk->cchunk); 168 } 169 170 static int mlxsw_sp1_acl_tcam_entry_add(struct mlxsw_sp *mlxsw_sp, 171 void *region_priv, void *chunk_priv, 172 void *entry_priv, 173 struct mlxsw_sp_acl_rule_info *rulei) 174 { 175 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 176 struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; 177 struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv; 178 179 return mlxsw_sp_acl_ctcam_entry_add(mlxsw_sp, ®ion->cregion, 180 &chunk->cchunk, &entry->centry, 181 rulei, false); 182 } 183 184 static void mlxsw_sp1_acl_tcam_entry_del(struct mlxsw_sp *mlxsw_sp, 185 void *region_priv, void *chunk_priv, 186 void *entry_priv) 187 { 188 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 189 struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; 190 struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv; 191 192 mlxsw_sp_acl_ctcam_entry_del(mlxsw_sp, ®ion->cregion, 193 &chunk->cchunk, &entry->centry); 194 } 195 196 static int 197 mlxsw_sp1_acl_tcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp, 198 void *region_priv, 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