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 void mlxsw_sp1_acl_tcam_chunk_init(void *region_priv, void *chunk_priv, 155 unsigned int priority) 156 { 157 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 158 struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; 159 160 mlxsw_sp_acl_ctcam_chunk_init(®ion->cregion, &chunk->cchunk, 161 priority); 162 } 163 164 static void mlxsw_sp1_acl_tcam_chunk_fini(void *chunk_priv) 165 { 166 struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; 167 168 mlxsw_sp_acl_ctcam_chunk_fini(&chunk->cchunk); 169 } 170 171 static int mlxsw_sp1_acl_tcam_entry_add(struct mlxsw_sp *mlxsw_sp, 172 void *region_priv, void *chunk_priv, 173 void *entry_priv, 174 struct mlxsw_sp_acl_rule_info *rulei) 175 { 176 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 177 struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; 178 struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv; 179 180 return mlxsw_sp_acl_ctcam_entry_add(mlxsw_sp, ®ion->cregion, 181 &chunk->cchunk, &entry->centry, 182 rulei, false); 183 } 184 185 static void mlxsw_sp1_acl_tcam_entry_del(struct mlxsw_sp *mlxsw_sp, 186 void *region_priv, void *chunk_priv, 187 void *entry_priv) 188 { 189 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 190 struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; 191 struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv; 192 193 mlxsw_sp_acl_ctcam_entry_del(mlxsw_sp, ®ion->cregion, 194 &chunk->cchunk, &entry->centry); 195 } 196 197 static int 198 mlxsw_sp1_acl_tcam_region_entry_activity_get(struct mlxsw_sp *mlxsw_sp, 199 struct mlxsw_sp_acl_tcam_region *_region, 200 unsigned int offset, 201 bool *activity) 202 { 203 char ptce2_pl[MLXSW_REG_PTCE2_LEN]; 204 int err; 205 206 mlxsw_reg_ptce2_pack(ptce2_pl, true, MLXSW_REG_PTCE2_OP_QUERY_CLEAR_ON_READ, 207 _region->tcam_region_info, offset, 0); 208 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl); 209 if (err) 210 return err; 211 *activity = mlxsw_reg_ptce2_a_get(ptce2_pl); 212 return 0; 213 } 214 215 static int 216 mlxsw_sp1_acl_tcam_entry_activity_get(struct mlxsw_sp *mlxsw_sp, 217 void *region_priv, void *entry_priv, 218 bool *activity) 219 { 220 struct mlxsw_sp1_acl_tcam_region *region = region_priv; 221 struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv; 222 unsigned int offset; 223 224 offset = mlxsw_sp_acl_ctcam_entry_offset(&entry->centry); 225 return mlxsw_sp1_acl_tcam_region_entry_activity_get(mlxsw_sp, 226 region->region, 227 offset, activity); 228 } 229 230 const struct mlxsw_sp_acl_tcam_ops mlxsw_sp1_acl_tcam_ops = { 231 .key_type = MLXSW_REG_PTAR_KEY_TYPE_FLEX, 232 .priv_size = 0, 233 .init = mlxsw_sp1_acl_tcam_init, 234 .fini = mlxsw_sp1_acl_tcam_fini, 235 .region_priv_size = sizeof(struct mlxsw_sp1_acl_tcam_region), 236 .region_init = mlxsw_sp1_acl_tcam_region_init, 237 .region_fini = mlxsw_sp1_acl_tcam_region_fini, 238 .chunk_priv_size = sizeof(struct mlxsw_sp1_acl_tcam_chunk), 239 .chunk_init = mlxsw_sp1_acl_tcam_chunk_init, 240 .chunk_fini = mlxsw_sp1_acl_tcam_chunk_fini, 241 .entry_priv_size = sizeof(struct mlxsw_sp1_acl_tcam_entry), 242 .entry_add = mlxsw_sp1_acl_tcam_entry_add, 243 .entry_del = mlxsw_sp1_acl_tcam_entry_del, 244 .entry_activity_get = mlxsw_sp1_acl_tcam_entry_activity_get, 245 }; 246