0001
0002
0003
0004 #include <linux/kernel.h>
0005 #include <linux/errno.h>
0006 #include <linux/parman.h>
0007
0008 #include "reg.h"
0009 #include "core.h"
0010 #include "spectrum.h"
0011 #include "spectrum_acl_tcam.h"
0012
0013 static int
0014 mlxsw_sp_acl_ctcam_region_resize(struct mlxsw_sp *mlxsw_sp,
0015 struct mlxsw_sp_acl_tcam_region *region,
0016 u16 new_size)
0017 {
0018 char ptar_pl[MLXSW_REG_PTAR_LEN];
0019
0020 mlxsw_reg_ptar_pack(ptar_pl, MLXSW_REG_PTAR_OP_RESIZE,
0021 region->key_type, new_size, region->id,
0022 region->tcam_region_info);
0023 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptar), ptar_pl);
0024 }
0025
0026 static void
0027 mlxsw_sp_acl_ctcam_region_move(struct mlxsw_sp *mlxsw_sp,
0028 struct mlxsw_sp_acl_tcam_region *region,
0029 u16 src_offset, u16 dst_offset, u16 size)
0030 {
0031 char prcr_pl[MLXSW_REG_PRCR_LEN];
0032
0033 mlxsw_reg_prcr_pack(prcr_pl, MLXSW_REG_PRCR_OP_MOVE,
0034 region->tcam_region_info, src_offset,
0035 region->tcam_region_info, dst_offset, size);
0036 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(prcr), prcr_pl);
0037 }
0038
0039 static int
0040 mlxsw_sp_acl_ctcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp,
0041 struct mlxsw_sp_acl_ctcam_region *cregion,
0042 struct mlxsw_sp_acl_ctcam_entry *centry,
0043 struct mlxsw_sp_acl_rule_info *rulei,
0044 bool fillup_priority)
0045 {
0046 struct mlxsw_sp_acl_tcam_region *region = cregion->region;
0047 struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl);
0048 char ptce2_pl[MLXSW_REG_PTCE2_LEN];
0049 char *act_set;
0050 u32 priority;
0051 char *mask;
0052 char *key;
0053 int err;
0054
0055 err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp, rulei, &priority,
0056 fillup_priority);
0057 if (err)
0058 return err;
0059
0060 mlxsw_reg_ptce2_pack(ptce2_pl, true, MLXSW_REG_PTCE2_OP_WRITE_WRITE,
0061 region->tcam_region_info,
0062 centry->parman_item.index, priority);
0063 key = mlxsw_reg_ptce2_flex_key_blocks_data(ptce2_pl);
0064 mask = mlxsw_reg_ptce2_mask_data(ptce2_pl);
0065 mlxsw_afk_encode(afk, region->key_info, &rulei->values, key, mask);
0066
0067 err = cregion->ops->entry_insert(cregion, centry, mask);
0068 if (err)
0069 return err;
0070
0071
0072 act_set = mlxsw_afa_block_first_set(rulei->act_block);
0073 mlxsw_reg_ptce2_flex_action_set_memcpy_to(ptce2_pl, act_set);
0074
0075 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl);
0076 if (err)
0077 goto err_ptce2_write;
0078
0079 return 0;
0080
0081 err_ptce2_write:
0082 cregion->ops->entry_remove(cregion, centry);
0083 return err;
0084 }
0085
0086 static void
0087 mlxsw_sp_acl_ctcam_region_entry_remove(struct mlxsw_sp *mlxsw_sp,
0088 struct mlxsw_sp_acl_ctcam_region *cregion,
0089 struct mlxsw_sp_acl_ctcam_entry *centry)
0090 {
0091 char ptce2_pl[MLXSW_REG_PTCE2_LEN];
0092
0093 mlxsw_reg_ptce2_pack(ptce2_pl, false, MLXSW_REG_PTCE2_OP_WRITE_WRITE,
0094 cregion->region->tcam_region_info,
0095 centry->parman_item.index, 0);
0096 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl);
0097 cregion->ops->entry_remove(cregion, centry);
0098 }
0099
0100 static int
0101 mlxsw_sp_acl_ctcam_region_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
0102 struct mlxsw_sp_acl_ctcam_region *cregion,
0103 struct mlxsw_sp_acl_ctcam_entry *centry,
0104 struct mlxsw_afa_block *afa_block,
0105 unsigned int priority)
0106 {
0107 char ptce2_pl[MLXSW_REG_PTCE2_LEN];
0108 char *act_set;
0109
0110 mlxsw_reg_ptce2_pack(ptce2_pl, true, MLXSW_REG_PTCE2_OP_WRITE_UPDATE,
0111 cregion->region->tcam_region_info,
0112 centry->parman_item.index, priority);
0113
0114 act_set = mlxsw_afa_block_first_set(afa_block);
0115 mlxsw_reg_ptce2_flex_action_set_memcpy_to(ptce2_pl, act_set);
0116
0117 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl);
0118 }
0119
0120
0121 static int mlxsw_sp_acl_ctcam_region_parman_resize(void *priv,
0122 unsigned long new_count)
0123 {
0124 struct mlxsw_sp_acl_ctcam_region *cregion = priv;
0125 struct mlxsw_sp_acl_tcam_region *region = cregion->region;
0126 struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp;
0127 u64 max_tcam_rules;
0128
0129 max_tcam_rules = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_TCAM_RULES);
0130 if (new_count > max_tcam_rules)
0131 return -EINVAL;
0132 return mlxsw_sp_acl_ctcam_region_resize(mlxsw_sp, region, new_count);
0133 }
0134
0135 static void mlxsw_sp_acl_ctcam_region_parman_move(void *priv,
0136 unsigned long from_index,
0137 unsigned long to_index,
0138 unsigned long count)
0139 {
0140 struct mlxsw_sp_acl_ctcam_region *cregion = priv;
0141 struct mlxsw_sp_acl_tcam_region *region = cregion->region;
0142 struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp;
0143
0144 mlxsw_sp_acl_ctcam_region_move(mlxsw_sp, region,
0145 from_index, to_index, count);
0146 }
0147
0148 static const struct parman_ops mlxsw_sp_acl_ctcam_region_parman_ops = {
0149 .base_count = MLXSW_SP_ACL_TCAM_REGION_BASE_COUNT,
0150 .resize_step = MLXSW_SP_ACL_TCAM_REGION_RESIZE_STEP,
0151 .resize = mlxsw_sp_acl_ctcam_region_parman_resize,
0152 .move = mlxsw_sp_acl_ctcam_region_parman_move,
0153 .algo = PARMAN_ALGO_TYPE_LSORT,
0154 };
0155
0156 int
0157 mlxsw_sp_acl_ctcam_region_init(struct mlxsw_sp *mlxsw_sp,
0158 struct mlxsw_sp_acl_ctcam_region *cregion,
0159 struct mlxsw_sp_acl_tcam_region *region,
0160 const struct mlxsw_sp_acl_ctcam_region_ops *ops)
0161 {
0162 cregion->region = region;
0163 cregion->ops = ops;
0164 cregion->parman = parman_create(&mlxsw_sp_acl_ctcam_region_parman_ops,
0165 cregion);
0166 if (!cregion->parman)
0167 return -ENOMEM;
0168 return 0;
0169 }
0170
0171 void mlxsw_sp_acl_ctcam_region_fini(struct mlxsw_sp_acl_ctcam_region *cregion)
0172 {
0173 parman_destroy(cregion->parman);
0174 }
0175
0176 void mlxsw_sp_acl_ctcam_chunk_init(struct mlxsw_sp_acl_ctcam_region *cregion,
0177 struct mlxsw_sp_acl_ctcam_chunk *cchunk,
0178 unsigned int priority)
0179 {
0180 parman_prio_init(cregion->parman, &cchunk->parman_prio, priority);
0181 }
0182
0183 void mlxsw_sp_acl_ctcam_chunk_fini(struct mlxsw_sp_acl_ctcam_chunk *cchunk)
0184 {
0185 parman_prio_fini(&cchunk->parman_prio);
0186 }
0187
0188 int mlxsw_sp_acl_ctcam_entry_add(struct mlxsw_sp *mlxsw_sp,
0189 struct mlxsw_sp_acl_ctcam_region *cregion,
0190 struct mlxsw_sp_acl_ctcam_chunk *cchunk,
0191 struct mlxsw_sp_acl_ctcam_entry *centry,
0192 struct mlxsw_sp_acl_rule_info *rulei,
0193 bool fillup_priority)
0194 {
0195 int err;
0196
0197 err = parman_item_add(cregion->parman, &cchunk->parman_prio,
0198 ¢ry->parman_item);
0199 if (err)
0200 return err;
0201
0202 err = mlxsw_sp_acl_ctcam_region_entry_insert(mlxsw_sp, cregion, centry,
0203 rulei, fillup_priority);
0204 if (err)
0205 goto err_rule_insert;
0206 return 0;
0207
0208 err_rule_insert:
0209 parman_item_remove(cregion->parman, &cchunk->parman_prio,
0210 ¢ry->parman_item);
0211 return err;
0212 }
0213
0214 void mlxsw_sp_acl_ctcam_entry_del(struct mlxsw_sp *mlxsw_sp,
0215 struct mlxsw_sp_acl_ctcam_region *cregion,
0216 struct mlxsw_sp_acl_ctcam_chunk *cchunk,
0217 struct mlxsw_sp_acl_ctcam_entry *centry)
0218 {
0219 mlxsw_sp_acl_ctcam_region_entry_remove(mlxsw_sp, cregion, centry);
0220 parman_item_remove(cregion->parman, &cchunk->parman_prio,
0221 ¢ry->parman_item);
0222 }
0223
0224 int mlxsw_sp_acl_ctcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
0225 struct mlxsw_sp_acl_ctcam_region *cregion,
0226 struct mlxsw_sp_acl_ctcam_entry *centry,
0227 struct mlxsw_sp_acl_rule_info *rulei)
0228 {
0229 return mlxsw_sp_acl_ctcam_region_entry_action_replace(mlxsw_sp, cregion,
0230 centry,
0231 rulei->act_block,
0232 rulei->priority);
0233 }