164eccd00SJiri Pirko /* 264eccd00SJiri Pirko * drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_ctcam.c 364eccd00SJiri Pirko * Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved. 464eccd00SJiri Pirko * Copyright (c) 2017-2018 Jiri Pirko <jiri@mellanox.com> 564eccd00SJiri Pirko * 664eccd00SJiri Pirko * Redistribution and use in source and binary forms, with or without 764eccd00SJiri Pirko * modification, are permitted provided that the following conditions are met: 864eccd00SJiri Pirko * 964eccd00SJiri Pirko * 1. Redistributions of source code must retain the above copyright 1064eccd00SJiri Pirko * notice, this list of conditions and the following disclaimer. 1164eccd00SJiri Pirko * 2. Redistributions in binary form must reproduce the above copyright 1264eccd00SJiri Pirko * notice, this list of conditions and the following disclaimer in the 1364eccd00SJiri Pirko * documentation and/or other materials provided with the distribution. 1464eccd00SJiri Pirko * 3. Neither the names of the copyright holders nor the names of its 1564eccd00SJiri Pirko * contributors may be used to endorse or promote products derived from 1664eccd00SJiri Pirko * this software without specific prior written permission. 1764eccd00SJiri Pirko * 1864eccd00SJiri Pirko * Alternatively, this software may be distributed under the terms of the 1964eccd00SJiri Pirko * GNU General Public License ("GPL") version 2 as published by the Free 2064eccd00SJiri Pirko * Software Foundation. 2164eccd00SJiri Pirko * 2264eccd00SJiri Pirko * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2364eccd00SJiri Pirko * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2464eccd00SJiri Pirko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2564eccd00SJiri Pirko * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 2664eccd00SJiri Pirko * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2764eccd00SJiri Pirko * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2864eccd00SJiri Pirko * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2964eccd00SJiri Pirko * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3064eccd00SJiri Pirko * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3164eccd00SJiri Pirko * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3264eccd00SJiri Pirko * POSSIBILITY OF SUCH DAMAGE. 3364eccd00SJiri Pirko */ 3464eccd00SJiri Pirko 3564eccd00SJiri Pirko #include <linux/kernel.h> 3664eccd00SJiri Pirko #include <linux/errno.h> 3764eccd00SJiri Pirko #include <linux/parman.h> 3864eccd00SJiri Pirko 3964eccd00SJiri Pirko #include "reg.h" 4064eccd00SJiri Pirko #include "core.h" 4164eccd00SJiri Pirko #include "spectrum.h" 4264eccd00SJiri Pirko #include "spectrum_acl_tcam.h" 4364eccd00SJiri Pirko 4464eccd00SJiri Pirko static int 4564eccd00SJiri Pirko mlxsw_sp_acl_ctcam_region_resize(struct mlxsw_sp *mlxsw_sp, 4664eccd00SJiri Pirko struct mlxsw_sp_acl_tcam_region *region, 4764eccd00SJiri Pirko u16 new_size) 4864eccd00SJiri Pirko { 4964eccd00SJiri Pirko char ptar_pl[MLXSW_REG_PTAR_LEN]; 5064eccd00SJiri Pirko 5164eccd00SJiri Pirko mlxsw_reg_ptar_pack(ptar_pl, MLXSW_REG_PTAR_OP_RESIZE, 5264eccd00SJiri Pirko region->key_type, new_size, region->id, 5364eccd00SJiri Pirko region->tcam_region_info); 5464eccd00SJiri Pirko return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptar), ptar_pl); 5564eccd00SJiri Pirko } 5664eccd00SJiri Pirko 5764eccd00SJiri Pirko static void 5864eccd00SJiri Pirko mlxsw_sp_acl_ctcam_region_move(struct mlxsw_sp *mlxsw_sp, 5964eccd00SJiri Pirko struct mlxsw_sp_acl_tcam_region *region, 6064eccd00SJiri Pirko u16 src_offset, u16 dst_offset, u16 size) 6164eccd00SJiri Pirko { 6264eccd00SJiri Pirko char prcr_pl[MLXSW_REG_PRCR_LEN]; 6364eccd00SJiri Pirko 6464eccd00SJiri Pirko mlxsw_reg_prcr_pack(prcr_pl, MLXSW_REG_PRCR_OP_MOVE, 6564eccd00SJiri Pirko region->tcam_region_info, src_offset, 6664eccd00SJiri Pirko region->tcam_region_info, dst_offset, size); 6764eccd00SJiri Pirko mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(prcr), prcr_pl); 6864eccd00SJiri Pirko } 6964eccd00SJiri Pirko 7064eccd00SJiri Pirko static int 7164eccd00SJiri Pirko mlxsw_sp_acl_ctcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp, 72a20ff8ebSIdo Schimmel struct mlxsw_sp_acl_ctcam_region *cregion, 73a20ff8ebSIdo Schimmel struct mlxsw_sp_acl_ctcam_entry *centry, 74ea8b2e28SJiri Pirko struct mlxsw_sp_acl_rule_info *rulei, 75ea8b2e28SJiri Pirko bool fillup_priority) 7664eccd00SJiri Pirko { 77a20ff8ebSIdo Schimmel struct mlxsw_sp_acl_tcam_region *region = cregion->region; 78a5995cc8SJiri Pirko struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl); 7964eccd00SJiri Pirko char ptce2_pl[MLXSW_REG_PTCE2_LEN]; 80ca49544eSIdo Schimmel unsigned int blocks_count; 8164eccd00SJiri Pirko char *act_set; 82ea8b2e28SJiri Pirko u32 priority; 8364eccd00SJiri Pirko char *mask; 8464eccd00SJiri Pirko char *key; 85ea8b2e28SJiri Pirko int err; 86ea8b2e28SJiri Pirko 87ea8b2e28SJiri Pirko err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp, rulei, &priority, 88ea8b2e28SJiri Pirko fillup_priority); 89ea8b2e28SJiri Pirko if (err) 90ea8b2e28SJiri Pirko return err; 9164eccd00SJiri Pirko 9264eccd00SJiri Pirko mlxsw_reg_ptce2_pack(ptce2_pl, true, MLXSW_REG_PTCE2_OP_WRITE_WRITE, 93a20ff8ebSIdo Schimmel region->tcam_region_info, 94a20ff8ebSIdo Schimmel centry->parman_item.index, priority); 9564eccd00SJiri Pirko key = mlxsw_reg_ptce2_flex_key_blocks_data(ptce2_pl); 9664eccd00SJiri Pirko mask = mlxsw_reg_ptce2_mask_data(ptce2_pl); 97ca49544eSIdo Schimmel blocks_count = mlxsw_afk_key_info_blocks_count_get(region->key_info); 98ca49544eSIdo Schimmel mlxsw_afk_encode(afk, region->key_info, &rulei->values, key, mask, 0, 99ca49544eSIdo Schimmel blocks_count - 1); 10064eccd00SJiri Pirko 101*a0a777b9SIdo Schimmel err = cregion->ops->entry_insert(cregion, centry, mask); 102*a0a777b9SIdo Schimmel if (err) 103*a0a777b9SIdo Schimmel return err; 104*a0a777b9SIdo Schimmel 10564eccd00SJiri Pirko /* Only the first action set belongs here, the rest is in KVD */ 10664eccd00SJiri Pirko act_set = mlxsw_afa_block_first_set(rulei->act_block); 10764eccd00SJiri Pirko mlxsw_reg_ptce2_flex_action_set_memcpy_to(ptce2_pl, act_set); 10864eccd00SJiri Pirko 10964eccd00SJiri Pirko return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl); 11064eccd00SJiri Pirko } 11164eccd00SJiri Pirko 11264eccd00SJiri Pirko static void 11364eccd00SJiri Pirko mlxsw_sp_acl_ctcam_region_entry_remove(struct mlxsw_sp *mlxsw_sp, 114a20ff8ebSIdo Schimmel struct mlxsw_sp_acl_ctcam_region *cregion, 115a20ff8ebSIdo Schimmel struct mlxsw_sp_acl_ctcam_entry *centry) 11664eccd00SJiri Pirko { 11764eccd00SJiri Pirko char ptce2_pl[MLXSW_REG_PTCE2_LEN]; 11864eccd00SJiri Pirko 11964eccd00SJiri Pirko mlxsw_reg_ptce2_pack(ptce2_pl, false, MLXSW_REG_PTCE2_OP_WRITE_WRITE, 120a20ff8ebSIdo Schimmel cregion->region->tcam_region_info, 121a20ff8ebSIdo Schimmel centry->parman_item.index, 0); 12264eccd00SJiri Pirko mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl); 123*a0a777b9SIdo Schimmel cregion->ops->entry_remove(cregion, centry); 12464eccd00SJiri Pirko } 12564eccd00SJiri Pirko 12664eccd00SJiri Pirko static int mlxsw_sp_acl_ctcam_region_parman_resize(void *priv, 12764eccd00SJiri Pirko unsigned long new_count) 12864eccd00SJiri Pirko { 12964eccd00SJiri Pirko struct mlxsw_sp_acl_ctcam_region *cregion = priv; 13064eccd00SJiri Pirko struct mlxsw_sp_acl_tcam_region *region = cregion->region; 13164eccd00SJiri Pirko struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp; 13264eccd00SJiri Pirko u64 max_tcam_rules; 13364eccd00SJiri Pirko 13464eccd00SJiri Pirko max_tcam_rules = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_TCAM_RULES); 13564eccd00SJiri Pirko if (new_count > max_tcam_rules) 13664eccd00SJiri Pirko return -EINVAL; 13764eccd00SJiri Pirko return mlxsw_sp_acl_ctcam_region_resize(mlxsw_sp, region, new_count); 13864eccd00SJiri Pirko } 13964eccd00SJiri Pirko 14064eccd00SJiri Pirko static void mlxsw_sp_acl_ctcam_region_parman_move(void *priv, 14164eccd00SJiri Pirko unsigned long from_index, 14264eccd00SJiri Pirko unsigned long to_index, 14364eccd00SJiri Pirko unsigned long count) 14464eccd00SJiri Pirko { 14564eccd00SJiri Pirko struct mlxsw_sp_acl_ctcam_region *cregion = priv; 14664eccd00SJiri Pirko struct mlxsw_sp_acl_tcam_region *region = cregion->region; 14764eccd00SJiri Pirko struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp; 14864eccd00SJiri Pirko 14964eccd00SJiri Pirko mlxsw_sp_acl_ctcam_region_move(mlxsw_sp, region, 15064eccd00SJiri Pirko from_index, to_index, count); 15164eccd00SJiri Pirko } 15264eccd00SJiri Pirko 15364eccd00SJiri Pirko static const struct parman_ops mlxsw_sp_acl_ctcam_region_parman_ops = { 15464eccd00SJiri Pirko .base_count = MLXSW_SP_ACL_TCAM_REGION_BASE_COUNT, 15564eccd00SJiri Pirko .resize_step = MLXSW_SP_ACL_TCAM_REGION_RESIZE_STEP, 15664eccd00SJiri Pirko .resize = mlxsw_sp_acl_ctcam_region_parman_resize, 15764eccd00SJiri Pirko .move = mlxsw_sp_acl_ctcam_region_parman_move, 15864eccd00SJiri Pirko .algo = PARMAN_ALGO_TYPE_LSORT, 15964eccd00SJiri Pirko }; 16064eccd00SJiri Pirko 161*a0a777b9SIdo Schimmel int 162*a0a777b9SIdo Schimmel mlxsw_sp_acl_ctcam_region_init(struct mlxsw_sp *mlxsw_sp, 16364eccd00SJiri Pirko struct mlxsw_sp_acl_ctcam_region *cregion, 164*a0a777b9SIdo Schimmel struct mlxsw_sp_acl_tcam_region *region, 165*a0a777b9SIdo Schimmel const struct mlxsw_sp_acl_ctcam_region_ops *ops) 16664eccd00SJiri Pirko { 16764eccd00SJiri Pirko cregion->region = region; 168*a0a777b9SIdo Schimmel cregion->ops = ops; 16964eccd00SJiri Pirko cregion->parman = parman_create(&mlxsw_sp_acl_ctcam_region_parman_ops, 17064eccd00SJiri Pirko cregion); 17164eccd00SJiri Pirko if (!cregion->parman) 17264eccd00SJiri Pirko return -ENOMEM; 17364eccd00SJiri Pirko return 0; 17464eccd00SJiri Pirko } 17564eccd00SJiri Pirko 17664eccd00SJiri Pirko void mlxsw_sp_acl_ctcam_region_fini(struct mlxsw_sp_acl_ctcam_region *cregion) 17764eccd00SJiri Pirko { 17864eccd00SJiri Pirko parman_destroy(cregion->parman); 17964eccd00SJiri Pirko } 18064eccd00SJiri Pirko 18164eccd00SJiri Pirko void mlxsw_sp_acl_ctcam_chunk_init(struct mlxsw_sp_acl_ctcam_region *cregion, 18264eccd00SJiri Pirko struct mlxsw_sp_acl_ctcam_chunk *cchunk, 18364eccd00SJiri Pirko unsigned int priority) 18464eccd00SJiri Pirko { 18564eccd00SJiri Pirko parman_prio_init(cregion->parman, &cchunk->parman_prio, priority); 18664eccd00SJiri Pirko } 18764eccd00SJiri Pirko 18864eccd00SJiri Pirko void mlxsw_sp_acl_ctcam_chunk_fini(struct mlxsw_sp_acl_ctcam_chunk *cchunk) 18964eccd00SJiri Pirko { 19064eccd00SJiri Pirko parman_prio_fini(&cchunk->parman_prio); 19164eccd00SJiri Pirko } 19264eccd00SJiri Pirko 19364eccd00SJiri Pirko int mlxsw_sp_acl_ctcam_entry_add(struct mlxsw_sp *mlxsw_sp, 19464eccd00SJiri Pirko struct mlxsw_sp_acl_ctcam_region *cregion, 19564eccd00SJiri Pirko struct mlxsw_sp_acl_ctcam_chunk *cchunk, 19664eccd00SJiri Pirko struct mlxsw_sp_acl_ctcam_entry *centry, 197ea8b2e28SJiri Pirko struct mlxsw_sp_acl_rule_info *rulei, 198ea8b2e28SJiri Pirko bool fillup_priority) 19964eccd00SJiri Pirko { 20064eccd00SJiri Pirko int err; 20164eccd00SJiri Pirko 20264eccd00SJiri Pirko err = parman_item_add(cregion->parman, &cchunk->parman_prio, 20364eccd00SJiri Pirko ¢ry->parman_item); 20464eccd00SJiri Pirko if (err) 20564eccd00SJiri Pirko return err; 20664eccd00SJiri Pirko 207a20ff8ebSIdo Schimmel err = mlxsw_sp_acl_ctcam_region_entry_insert(mlxsw_sp, cregion, centry, 208ea8b2e28SJiri Pirko rulei, fillup_priority); 20964eccd00SJiri Pirko if (err) 21064eccd00SJiri Pirko goto err_rule_insert; 21164eccd00SJiri Pirko return 0; 21264eccd00SJiri Pirko 21364eccd00SJiri Pirko err_rule_insert: 21464eccd00SJiri Pirko parman_item_remove(cregion->parman, &cchunk->parman_prio, 21564eccd00SJiri Pirko ¢ry->parman_item); 21664eccd00SJiri Pirko return err; 21764eccd00SJiri Pirko } 21864eccd00SJiri Pirko 21964eccd00SJiri Pirko void mlxsw_sp_acl_ctcam_entry_del(struct mlxsw_sp *mlxsw_sp, 22064eccd00SJiri Pirko struct mlxsw_sp_acl_ctcam_region *cregion, 22164eccd00SJiri Pirko struct mlxsw_sp_acl_ctcam_chunk *cchunk, 22264eccd00SJiri Pirko struct mlxsw_sp_acl_ctcam_entry *centry) 22364eccd00SJiri Pirko { 224a20ff8ebSIdo Schimmel mlxsw_sp_acl_ctcam_region_entry_remove(mlxsw_sp, cregion, centry); 22564eccd00SJiri Pirko parman_item_remove(cregion->parman, &cchunk->parman_prio, 22664eccd00SJiri Pirko ¢ry->parman_item); 22764eccd00SJiri Pirko } 228