1 /* 2 * drivers/net/ethernet/mellanox/mlxsw/spectrum1_acl_tcam.c 3 * Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved. 4 * Copyright (c) 2017-2018 Jiri Pirko <jiri@mellanox.com> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the names of the copyright holders nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * Alternatively, this software may be distributed under the terms of the 19 * GNU General Public License ("GPL") version 2 as published by the Free 20 * Software Foundation. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <linux/kernel.h> 36 #include <linux/slab.h> 37 38 #include "reg.h" 39 #include "core.h" 40 #include "spectrum.h" 41 #include "spectrum_acl_tcam.h" 42 43 struct mlxsw_sp1_acl_tcam_region { 44 struct mlxsw_sp_acl_ctcam_region cregion; 45 struct mlxsw_sp_acl_tcam_region *region; 46 struct { 47 struct mlxsw_sp_acl_ctcam_chunk cchunk; 48 struct mlxsw_sp_acl_ctcam_entry centry; 49 struct mlxsw_sp_acl_rule_info *rulei; 50 } catchall; 51 }; 52 53 struct mlxsw_sp1_acl_tcam_chunk { 54 struct mlxsw_sp_acl_ctcam_chunk cchunk; 55 }; 56 57 struct mlxsw_sp1_acl_tcam_entry { 58 struct mlxsw_sp_acl_ctcam_entry centry; 59 }; 60 61 static int mlxsw_sp1_acl_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv, 62 struct mlxsw_sp_acl_tcam *tcam) 63 { 64 return 0; 65 } 66 67 static void mlxsw_sp1_acl_tcam_fini(struct mlxsw_sp *mlxsw_sp, void *priv) 68 { 69 } 70 71 static int 72 mlxsw_sp1_acl_ctcam_region_catchall_add(struct mlxsw_sp *mlxsw_sp, 73 struct mlxsw_sp1_acl_tcam_region *region) 74 { 75 struct mlxsw_sp_acl_rule_info *rulei; 76 int err; 77 78 mlxsw_sp_acl_ctcam_chunk_init(®ion->cregion, 79 ®ion->catchall.cchunk, 80 MLXSW_SP_ACL_TCAM_CATCHALL_PRIO); 81 rulei = mlxsw_sp_acl_rulei_create(mlxsw_sp->acl); 82 if (IS_ERR(rulei)) { 83 err = PTR_ERR(rulei); 84 goto err_rulei_create; 85 } 86 err = mlxsw_sp_acl_rulei_act_continue(rulei); 87 if (WARN_ON(err)) 88 goto err_rulei_act_continue; 89 err = mlxsw_sp_acl_rulei_commit(rulei); 90 if (err) 91 goto err_rulei_commit; 92 err = mlxsw_sp_acl_ctcam_entry_add(mlxsw_sp, ®ion->cregion, 93 ®ion->catchall.cchunk, 94 ®ion->catchall.centry, 95 rulei, false); 96 if (err) 97 goto err_entry_add; 98 region->catchall.rulei = rulei; 99 return 0; 100 101 err_entry_add: 102 err_rulei_commit: 103 err_rulei_act_continue: 104 mlxsw_sp_acl_rulei_destroy(rulei); 105 err_rulei_create: 106 mlxsw_sp_acl_ctcam_chunk_fini(®ion->catchall.cchunk); 107 return err; 108 } 109 110 static void 111 mlxsw_sp1_acl_ctcam_region_catchall_del(struct mlxsw_sp *mlxsw_sp, 112 struct mlxsw_sp1_acl_tcam_region *region) 113 { 114 struct mlxsw_sp_acl_rule_info *rulei = region->catchall.rulei; 115 116 mlxsw_sp_acl_ctcam_entry_del(mlxsw_sp, ®ion->cregion, 117 ®ion->catchall.cchunk, 118 ®ion->catchall.centry); 119 mlxsw_sp_acl_rulei_destroy(rulei); 120 mlxsw_sp_acl_ctcam_chunk_fini(®ion->catchall.cchunk); 121 } 122 123 static int 124 mlxsw_sp1_acl_tcam_region_init(struct mlxsw_sp *mlxsw_sp, void *region_priv, 125 struct mlxsw_sp_acl_tcam_region *_region) 126 { 127 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 128 int err; 129 130 err = mlxsw_sp_acl_ctcam_region_init(mlxsw_sp, ®ion->cregion, 131 _region); 132 if (err) 133 return err; 134 err = mlxsw_sp1_acl_ctcam_region_catchall_add(mlxsw_sp, region); 135 if (err) 136 goto err_catchall_add; 137 region->region = _region; 138 return 0; 139 140 err_catchall_add: 141 mlxsw_sp_acl_ctcam_region_fini(®ion->cregion); 142 return err; 143 } 144 145 static void 146 mlxsw_sp1_acl_tcam_region_fini(struct mlxsw_sp *mlxsw_sp, void *region_priv) 147 { 148 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 149 150 mlxsw_sp1_acl_ctcam_region_catchall_del(mlxsw_sp, region); 151 mlxsw_sp_acl_ctcam_region_fini(®ion->cregion); 152 } 153 154 static int 155 mlxsw_sp1_acl_tcam_region_associate(struct mlxsw_sp *mlxsw_sp, 156 struct mlxsw_sp_acl_tcam_region *region) 157 { 158 return 0; 159 } 160 161 static void mlxsw_sp1_acl_tcam_chunk_init(void *region_priv, void *chunk_priv, 162 unsigned int priority) 163 { 164 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 165 struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; 166 167 mlxsw_sp_acl_ctcam_chunk_init(®ion->cregion, &chunk->cchunk, 168 priority); 169 } 170 171 static void mlxsw_sp1_acl_tcam_chunk_fini(void *chunk_priv) 172 { 173 struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; 174 175 mlxsw_sp_acl_ctcam_chunk_fini(&chunk->cchunk); 176 } 177 178 static int mlxsw_sp1_acl_tcam_entry_add(struct mlxsw_sp *mlxsw_sp, 179 void *region_priv, void *chunk_priv, 180 void *entry_priv, 181 struct mlxsw_sp_acl_rule_info *rulei) 182 { 183 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 184 struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; 185 struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv; 186 187 return mlxsw_sp_acl_ctcam_entry_add(mlxsw_sp, ®ion->cregion, 188 &chunk->cchunk, &entry->centry, 189 rulei, false); 190 } 191 192 static void mlxsw_sp1_acl_tcam_entry_del(struct mlxsw_sp *mlxsw_sp, 193 void *region_priv, void *chunk_priv, 194 void *entry_priv) 195 { 196 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 197 struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; 198 struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv; 199 200 mlxsw_sp_acl_ctcam_entry_del(mlxsw_sp, ®ion->cregion, 201 &chunk->cchunk, &entry->centry); 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_activity_get = mlxsw_sp1_acl_tcam_entry_activity_get, 253 }; 254