234 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */3 4#include <linux/kernel.h>5#include <linux/errno.h>6#include <linux/parman.h>7 8#include "reg.h"9#include "core.h"10#include "spectrum.h"11#include "spectrum_acl_tcam.h"12 13static int14mlxsw_sp_acl_ctcam_region_resize(struct mlxsw_sp *mlxsw_sp,15 struct mlxsw_sp_acl_tcam_region *region,16 u16 new_size)17{18 char ptar_pl[MLXSW_REG_PTAR_LEN];19 20 mlxsw_reg_ptar_pack(ptar_pl, MLXSW_REG_PTAR_OP_RESIZE,21 region->key_type, new_size, region->id,22 region->tcam_region_info);23 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptar), ptar_pl);24}25 26static void27mlxsw_sp_acl_ctcam_region_move(struct mlxsw_sp *mlxsw_sp,28 struct mlxsw_sp_acl_tcam_region *region,29 u16 src_offset, u16 dst_offset, u16 size)30{31 char prcr_pl[MLXSW_REG_PRCR_LEN];32 33 mlxsw_reg_prcr_pack(prcr_pl, MLXSW_REG_PRCR_OP_MOVE,34 region->tcam_region_info, src_offset,35 region->tcam_region_info, dst_offset, size);36 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(prcr), prcr_pl);37}38 39static int40mlxsw_sp_acl_ctcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp,41 struct mlxsw_sp_acl_ctcam_region *cregion,42 struct mlxsw_sp_acl_ctcam_entry *centry,43 struct mlxsw_sp_acl_rule_info *rulei,44 bool fillup_priority)45{46 struct mlxsw_sp_acl_tcam_region *region = cregion->region;47 struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl);48 char ptce2_pl[MLXSW_REG_PTCE2_LEN];49 char *act_set;50 u32 priority;51 char *mask;52 char *key;53 int err;54 55 err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp, rulei, &priority,56 fillup_priority);57 if (err)58 return err;59 60 mlxsw_reg_ptce2_pack(ptce2_pl, true, MLXSW_REG_PTCE2_OP_WRITE_WRITE,61 region->tcam_region_info,62 centry->parman_item.index, priority);63 key = mlxsw_reg_ptce2_flex_key_blocks_data(ptce2_pl);64 mask = mlxsw_reg_ptce2_mask_data(ptce2_pl);65 mlxsw_afk_encode(afk, region->key_info, &rulei->values, key, mask);66 67 err = cregion->ops->entry_insert(cregion, centry, mask);68 if (err)69 return err;70 71 /* Only the first action set belongs here, the rest is in KVD */72 act_set = mlxsw_afa_block_first_set(rulei->act_block);73 mlxsw_reg_ptce2_flex_action_set_memcpy_to(ptce2_pl, act_set);74 75 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl);76 if (err)77 goto err_ptce2_write;78 79 return 0;80 81err_ptce2_write:82 cregion->ops->entry_remove(cregion, centry);83 return err;84}85 86static void87mlxsw_sp_acl_ctcam_region_entry_remove(struct mlxsw_sp *mlxsw_sp,88 struct mlxsw_sp_acl_ctcam_region *cregion,89 struct mlxsw_sp_acl_ctcam_entry *centry)90{91 char ptce2_pl[MLXSW_REG_PTCE2_LEN];92 93 mlxsw_reg_ptce2_pack(ptce2_pl, false, MLXSW_REG_PTCE2_OP_WRITE_WRITE,94 cregion->region->tcam_region_info,95 centry->parman_item.index, 0);96 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl);97 cregion->ops->entry_remove(cregion, centry);98}99 100static int101mlxsw_sp_acl_ctcam_region_entry_action_replace(struct mlxsw_sp *mlxsw_sp,102 struct mlxsw_sp_acl_ctcam_region *cregion,103 struct mlxsw_sp_acl_ctcam_entry *centry,104 struct mlxsw_afa_block *afa_block,105 unsigned int priority)106{107 char ptce2_pl[MLXSW_REG_PTCE2_LEN];108 char *act_set;109 110 mlxsw_reg_ptce2_pack(ptce2_pl, true, MLXSW_REG_PTCE2_OP_WRITE_UPDATE,111 cregion->region->tcam_region_info,112 centry->parman_item.index, priority);113 114 act_set = mlxsw_afa_block_first_set(afa_block);115 mlxsw_reg_ptce2_flex_action_set_memcpy_to(ptce2_pl, act_set);116 117 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl);118}119 120 121static int mlxsw_sp_acl_ctcam_region_parman_resize(void *priv,122 unsigned long new_count)123{124 struct mlxsw_sp_acl_ctcam_region *cregion = priv;125 struct mlxsw_sp_acl_tcam_region *region = cregion->region;126 struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp;127 u64 max_tcam_rules;128 129 max_tcam_rules = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_TCAM_RULES);130 if (new_count > max_tcam_rules)131 return -EINVAL;132 return mlxsw_sp_acl_ctcam_region_resize(mlxsw_sp, region, new_count);133}134 135static void mlxsw_sp_acl_ctcam_region_parman_move(void *priv,136 unsigned long from_index,137 unsigned long to_index,138 unsigned long count)139{140 struct mlxsw_sp_acl_ctcam_region *cregion = priv;141 struct mlxsw_sp_acl_tcam_region *region = cregion->region;142 struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp;143 144 mlxsw_sp_acl_ctcam_region_move(mlxsw_sp, region,145 from_index, to_index, count);146}147 148static const struct parman_ops mlxsw_sp_acl_ctcam_region_parman_ops = {149 .base_count = MLXSW_SP_ACL_TCAM_REGION_BASE_COUNT,150 .resize_step = MLXSW_SP_ACL_TCAM_REGION_RESIZE_STEP,151 .resize = mlxsw_sp_acl_ctcam_region_parman_resize,152 .move = mlxsw_sp_acl_ctcam_region_parman_move,153 .algo = PARMAN_ALGO_TYPE_LSORT,154};155 156int157mlxsw_sp_acl_ctcam_region_init(struct mlxsw_sp *mlxsw_sp,158 struct mlxsw_sp_acl_ctcam_region *cregion,159 struct mlxsw_sp_acl_tcam_region *region,160 const struct mlxsw_sp_acl_ctcam_region_ops *ops)161{162 cregion->region = region;163 cregion->ops = ops;164 cregion->parman = parman_create(&mlxsw_sp_acl_ctcam_region_parman_ops,165 cregion);166 if (!cregion->parman)167 return -ENOMEM;168 return 0;169}170 171void mlxsw_sp_acl_ctcam_region_fini(struct mlxsw_sp_acl_ctcam_region *cregion)172{173 parman_destroy(cregion->parman);174}175 176void mlxsw_sp_acl_ctcam_chunk_init(struct mlxsw_sp_acl_ctcam_region *cregion,177 struct mlxsw_sp_acl_ctcam_chunk *cchunk,178 unsigned int priority)179{180 parman_prio_init(cregion->parman, &cchunk->parman_prio, priority);181}182 183void mlxsw_sp_acl_ctcam_chunk_fini(struct mlxsw_sp_acl_ctcam_chunk *cchunk)184{185 parman_prio_fini(&cchunk->parman_prio);186}187 188int mlxsw_sp_acl_ctcam_entry_add(struct mlxsw_sp *mlxsw_sp,189 struct mlxsw_sp_acl_ctcam_region *cregion,190 struct mlxsw_sp_acl_ctcam_chunk *cchunk,191 struct mlxsw_sp_acl_ctcam_entry *centry,192 struct mlxsw_sp_acl_rule_info *rulei,193 bool fillup_priority)194{195 int err;196 197 err = parman_item_add(cregion->parman, &cchunk->parman_prio,198 ¢ry->parman_item);199 if (err)200 return err;201 202 err = mlxsw_sp_acl_ctcam_region_entry_insert(mlxsw_sp, cregion, centry,203 rulei, fillup_priority);204 if (err)205 goto err_rule_insert;206 return 0;207 208err_rule_insert:209 parman_item_remove(cregion->parman, &cchunk->parman_prio,210 ¢ry->parman_item);211 return err;212}213 214void mlxsw_sp_acl_ctcam_entry_del(struct mlxsw_sp *mlxsw_sp,215 struct mlxsw_sp_acl_ctcam_region *cregion,216 struct mlxsw_sp_acl_ctcam_chunk *cchunk,217 struct mlxsw_sp_acl_ctcam_entry *centry)218{219 mlxsw_sp_acl_ctcam_region_entry_remove(mlxsw_sp, cregion, centry);220 parman_item_remove(cregion->parman, &cchunk->parman_prio,221 ¢ry->parman_item);222}223 224int mlxsw_sp_acl_ctcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp,225 struct mlxsw_sp_acl_ctcam_region *cregion,226 struct mlxsw_sp_acl_ctcam_entry *centry,227 struct mlxsw_sp_acl_rule_info *rulei)228{229 return mlxsw_sp_acl_ctcam_region_entry_action_replace(mlxsw_sp, cregion,230 centry,231 rulei->act_block,232 rulei->priority);233}234