1 /* 2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_ctcam.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/errno.h> 37 #include <linux/parman.h> 38 39 #include "reg.h" 40 #include "core.h" 41 #include "spectrum.h" 42 #include "spectrum_acl_tcam.h" 43 44 static int 45 mlxsw_sp_acl_ctcam_region_resize(struct mlxsw_sp *mlxsw_sp, 46 struct mlxsw_sp_acl_tcam_region *region, 47 u16 new_size) 48 { 49 char ptar_pl[MLXSW_REG_PTAR_LEN]; 50 51 mlxsw_reg_ptar_pack(ptar_pl, MLXSW_REG_PTAR_OP_RESIZE, 52 region->key_type, new_size, region->id, 53 region->tcam_region_info); 54 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptar), ptar_pl); 55 } 56 57 static void 58 mlxsw_sp_acl_ctcam_region_move(struct mlxsw_sp *mlxsw_sp, 59 struct mlxsw_sp_acl_tcam_region *region, 60 u16 src_offset, u16 dst_offset, u16 size) 61 { 62 char prcr_pl[MLXSW_REG_PRCR_LEN]; 63 64 mlxsw_reg_prcr_pack(prcr_pl, MLXSW_REG_PRCR_OP_MOVE, 65 region->tcam_region_info, src_offset, 66 region->tcam_region_info, dst_offset, size); 67 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(prcr), prcr_pl); 68 } 69 70 static int 71 mlxsw_sp_acl_ctcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp, 72 struct mlxsw_sp_acl_tcam_region *region, 73 unsigned int offset, 74 struct mlxsw_sp_acl_rule_info *rulei, 75 bool fillup_priority) 76 { 77 struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl); 78 char ptce2_pl[MLXSW_REG_PTCE2_LEN]; 79 char *act_set; 80 u32 priority; 81 char *mask; 82 char *key; 83 int err; 84 85 err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp, rulei, &priority, 86 fillup_priority); 87 if (err) 88 return err; 89 90 mlxsw_reg_ptce2_pack(ptce2_pl, true, MLXSW_REG_PTCE2_OP_WRITE_WRITE, 91 region->tcam_region_info, offset, priority); 92 key = mlxsw_reg_ptce2_flex_key_blocks_data(ptce2_pl); 93 mask = mlxsw_reg_ptce2_mask_data(ptce2_pl); 94 mlxsw_afk_encode(afk, region->key_info, &rulei->values, key, mask); 95 96 /* Only the first action set belongs here, the rest is in KVD */ 97 act_set = mlxsw_afa_block_first_set(rulei->act_block); 98 mlxsw_reg_ptce2_flex_action_set_memcpy_to(ptce2_pl, act_set); 99 100 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl); 101 } 102 103 static void 104 mlxsw_sp_acl_ctcam_region_entry_remove(struct mlxsw_sp *mlxsw_sp, 105 struct mlxsw_sp_acl_tcam_region *region, 106 unsigned int offset) 107 { 108 char ptce2_pl[MLXSW_REG_PTCE2_LEN]; 109 110 mlxsw_reg_ptce2_pack(ptce2_pl, false, MLXSW_REG_PTCE2_OP_WRITE_WRITE, 111 region->tcam_region_info, offset, 0); 112 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl); 113 } 114 115 static int mlxsw_sp_acl_ctcam_region_parman_resize(void *priv, 116 unsigned long new_count) 117 { 118 struct mlxsw_sp_acl_ctcam_region *cregion = priv; 119 struct mlxsw_sp_acl_tcam_region *region = cregion->region; 120 struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp; 121 u64 max_tcam_rules; 122 123 max_tcam_rules = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_TCAM_RULES); 124 if (new_count > max_tcam_rules) 125 return -EINVAL; 126 return mlxsw_sp_acl_ctcam_region_resize(mlxsw_sp, region, new_count); 127 } 128 129 static void mlxsw_sp_acl_ctcam_region_parman_move(void *priv, 130 unsigned long from_index, 131 unsigned long to_index, 132 unsigned long count) 133 { 134 struct mlxsw_sp_acl_ctcam_region *cregion = priv; 135 struct mlxsw_sp_acl_tcam_region *region = cregion->region; 136 struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp; 137 138 mlxsw_sp_acl_ctcam_region_move(mlxsw_sp, region, 139 from_index, to_index, count); 140 } 141 142 static const struct parman_ops mlxsw_sp_acl_ctcam_region_parman_ops = { 143 .base_count = MLXSW_SP_ACL_TCAM_REGION_BASE_COUNT, 144 .resize_step = MLXSW_SP_ACL_TCAM_REGION_RESIZE_STEP, 145 .resize = mlxsw_sp_acl_ctcam_region_parman_resize, 146 .move = mlxsw_sp_acl_ctcam_region_parman_move, 147 .algo = PARMAN_ALGO_TYPE_LSORT, 148 }; 149 150 int mlxsw_sp_acl_ctcam_region_init(struct mlxsw_sp *mlxsw_sp, 151 struct mlxsw_sp_acl_ctcam_region *cregion, 152 struct mlxsw_sp_acl_tcam_region *region) 153 { 154 cregion->region = region; 155 cregion->parman = parman_create(&mlxsw_sp_acl_ctcam_region_parman_ops, 156 cregion); 157 if (!cregion->parman) 158 return -ENOMEM; 159 return 0; 160 } 161 162 void mlxsw_sp_acl_ctcam_region_fini(struct mlxsw_sp_acl_ctcam_region *cregion) 163 { 164 parman_destroy(cregion->parman); 165 } 166 167 void mlxsw_sp_acl_ctcam_chunk_init(struct mlxsw_sp_acl_ctcam_region *cregion, 168 struct mlxsw_sp_acl_ctcam_chunk *cchunk, 169 unsigned int priority) 170 { 171 parman_prio_init(cregion->parman, &cchunk->parman_prio, priority); 172 } 173 174 void mlxsw_sp_acl_ctcam_chunk_fini(struct mlxsw_sp_acl_ctcam_chunk *cchunk) 175 { 176 parman_prio_fini(&cchunk->parman_prio); 177 } 178 179 int mlxsw_sp_acl_ctcam_entry_add(struct mlxsw_sp *mlxsw_sp, 180 struct mlxsw_sp_acl_ctcam_region *cregion, 181 struct mlxsw_sp_acl_ctcam_chunk *cchunk, 182 struct mlxsw_sp_acl_ctcam_entry *centry, 183 struct mlxsw_sp_acl_rule_info *rulei, 184 bool fillup_priority) 185 { 186 int err; 187 188 err = parman_item_add(cregion->parman, &cchunk->parman_prio, 189 ¢ry->parman_item); 190 if (err) 191 return err; 192 193 err = mlxsw_sp_acl_ctcam_region_entry_insert(mlxsw_sp, cregion->region, 194 centry->parman_item.index, 195 rulei, fillup_priority); 196 if (err) 197 goto err_rule_insert; 198 return 0; 199 200 err_rule_insert: 201 parman_item_remove(cregion->parman, &cchunk->parman_prio, 202 ¢ry->parman_item); 203 return err; 204 } 205 206 void mlxsw_sp_acl_ctcam_entry_del(struct mlxsw_sp *mlxsw_sp, 207 struct mlxsw_sp_acl_ctcam_region *cregion, 208 struct mlxsw_sp_acl_ctcam_chunk *cchunk, 209 struct mlxsw_sp_acl_ctcam_entry *centry) 210 { 211 mlxsw_sp_acl_ctcam_region_entry_remove(mlxsw_sp, cregion->region, 212 centry->parman_item.index); 213 parman_item_remove(cregion->parman, &cchunk->parman_prio, 214 ¢ry->parman_item); 215 } 216