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); 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_region_entry_activity_get(struct mlxsw_sp *mlxsw_sp, 197 struct mlxsw_sp_acl_tcam_region *_region, 198 unsigned int offset, 199 bool *activity) 200 { 201 char ptce2_pl[MLXSW_REG_PTCE2_LEN]; 202 int err; 203 204 mlxsw_reg_ptce2_pack(ptce2_pl, true, MLXSW_REG_PTCE2_OP_QUERY_CLEAR_ON_READ, 205 _region->tcam_region_info, offset, 0); 206 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl); 207 if (err) 208 return err; 209 *activity = mlxsw_reg_ptce2_a_get(ptce2_pl); 210 return 0; 211 } 212 213 static int 214 mlxsw_sp1_acl_tcam_entry_activity_get(struct mlxsw_sp *mlxsw_sp, 215 void *region_priv, void *entry_priv, 216 bool *activity) 217 { 218 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 219 struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv; 220 unsigned int offset; 221 222 offset = mlxsw_sp_acl_ctcam_entry_offset(&entry->centry); 223 return mlxsw_sp1_acl_tcam_region_entry_activity_get(mlxsw_sp, 224 region->region, 225 offset, activity); 226 } 227 228 const struct mlxsw_sp_acl_tcam_ops mlxsw_sp1_acl_tcam_ops = { 229 .key_type = MLXSW_REG_PTAR_KEY_TYPE_FLEX, 230 .priv_size = 0, 231 .init = mlxsw_sp1_acl_tcam_init, 232 .fini = mlxsw_sp1_acl_tcam_fini, 233 .region_priv_size = sizeof(struct mlxsw_sp1_acl_tcam_region), 234 .region_init = mlxsw_sp1_acl_tcam_region_init, 235 .region_fini = mlxsw_sp1_acl_tcam_region_fini, 236 .region_associate = mlxsw_sp1_acl_tcam_region_associate, 237 .chunk_priv_size = sizeof(struct mlxsw_sp1_acl_tcam_chunk), 238 .chunk_init = mlxsw_sp1_acl_tcam_chunk_init, 239 .chunk_fini = mlxsw_sp1_acl_tcam_chunk_fini, 240 .entry_priv_size = sizeof(struct mlxsw_sp1_acl_tcam_entry), 241 .entry_add = mlxsw_sp1_acl_tcam_entry_add, 242 .entry_del = mlxsw_sp1_acl_tcam_entry_del, 243 .entry_activity_get = mlxsw_sp1_acl_tcam_entry_activity_get, 244 }; 245