0001
0002
0003
0004 #include <linux/kernel.h>
0005 #include <linux/parman.h>
0006
0007 #include "reg.h"
0008 #include "spectrum.h"
0009 #include "core_acl_flex_actions.h"
0010 #include "spectrum_mr.h"
0011
0012 struct mlxsw_sp1_mr_tcam_region {
0013 struct mlxsw_sp *mlxsw_sp;
0014 enum mlxsw_reg_rtar_key_type rtar_key_type;
0015 struct parman *parman;
0016 struct parman_prio *parman_prios;
0017 };
0018
0019 struct mlxsw_sp1_mr_tcam {
0020 struct mlxsw_sp1_mr_tcam_region tcam_regions[MLXSW_SP_L3_PROTO_MAX];
0021 };
0022
0023 struct mlxsw_sp1_mr_tcam_route {
0024 struct parman_item parman_item;
0025 struct parman_prio *parman_prio;
0026 };
0027
0028 static int mlxsw_sp1_mr_tcam_route_replace(struct mlxsw_sp *mlxsw_sp,
0029 struct parman_item *parman_item,
0030 struct mlxsw_sp_mr_route_key *key,
0031 struct mlxsw_afa_block *afa_block)
0032 {
0033 char rmft2_pl[MLXSW_REG_RMFT2_LEN];
0034
0035 switch (key->proto) {
0036 case MLXSW_SP_L3_PROTO_IPV4:
0037 mlxsw_reg_rmft2_ipv4_pack(rmft2_pl, true, parman_item->index,
0038 key->vrid,
0039 MLXSW_REG_RMFT2_IRIF_MASK_IGNORE, 0,
0040 ntohl(key->group.addr4),
0041 ntohl(key->group_mask.addr4),
0042 ntohl(key->source.addr4),
0043 ntohl(key->source_mask.addr4),
0044 mlxsw_afa_block_first_set(afa_block));
0045 break;
0046 case MLXSW_SP_L3_PROTO_IPV6:
0047 mlxsw_reg_rmft2_ipv6_pack(rmft2_pl, true, parman_item->index,
0048 key->vrid,
0049 MLXSW_REG_RMFT2_IRIF_MASK_IGNORE, 0,
0050 key->group.addr6,
0051 key->group_mask.addr6,
0052 key->source.addr6,
0053 key->source_mask.addr6,
0054 mlxsw_afa_block_first_set(afa_block));
0055 }
0056
0057 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rmft2), rmft2_pl);
0058 }
0059
0060 static int mlxsw_sp1_mr_tcam_route_remove(struct mlxsw_sp *mlxsw_sp,
0061 struct parman_item *parman_item,
0062 struct mlxsw_sp_mr_route_key *key)
0063 {
0064 struct in6_addr zero_addr = IN6ADDR_ANY_INIT;
0065 char rmft2_pl[MLXSW_REG_RMFT2_LEN];
0066
0067 switch (key->proto) {
0068 case MLXSW_SP_L3_PROTO_IPV4:
0069 mlxsw_reg_rmft2_ipv4_pack(rmft2_pl, false, parman_item->index,
0070 key->vrid, 0, 0, 0, 0, 0, 0, NULL);
0071 break;
0072 case MLXSW_SP_L3_PROTO_IPV6:
0073 mlxsw_reg_rmft2_ipv6_pack(rmft2_pl, false, parman_item->index,
0074 key->vrid, 0, 0, zero_addr, zero_addr,
0075 zero_addr, zero_addr, NULL);
0076 break;
0077 }
0078
0079 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rmft2), rmft2_pl);
0080 }
0081
0082 static struct mlxsw_sp1_mr_tcam_region *
0083 mlxsw_sp1_mr_tcam_protocol_region(struct mlxsw_sp1_mr_tcam *mr_tcam,
0084 enum mlxsw_sp_l3proto proto)
0085 {
0086 return &mr_tcam->tcam_regions[proto];
0087 }
0088
0089 static int
0090 mlxsw_sp1_mr_tcam_route_parman_item_add(struct mlxsw_sp1_mr_tcam *mr_tcam,
0091 struct mlxsw_sp1_mr_tcam_route *route,
0092 struct mlxsw_sp_mr_route_key *key,
0093 enum mlxsw_sp_mr_route_prio prio)
0094 {
0095 struct mlxsw_sp1_mr_tcam_region *tcam_region;
0096 int err;
0097
0098 tcam_region = mlxsw_sp1_mr_tcam_protocol_region(mr_tcam, key->proto);
0099 err = parman_item_add(tcam_region->parman,
0100 &tcam_region->parman_prios[prio],
0101 &route->parman_item);
0102 if (err)
0103 return err;
0104
0105 route->parman_prio = &tcam_region->parman_prios[prio];
0106 return 0;
0107 }
0108
0109 static void
0110 mlxsw_sp1_mr_tcam_route_parman_item_remove(struct mlxsw_sp1_mr_tcam *mr_tcam,
0111 struct mlxsw_sp1_mr_tcam_route *route,
0112 struct mlxsw_sp_mr_route_key *key)
0113 {
0114 struct mlxsw_sp1_mr_tcam_region *tcam_region;
0115
0116 tcam_region = mlxsw_sp1_mr_tcam_protocol_region(mr_tcam, key->proto);
0117 parman_item_remove(tcam_region->parman,
0118 route->parman_prio, &route->parman_item);
0119 }
0120
0121 static int
0122 mlxsw_sp1_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
0123 void *route_priv,
0124 struct mlxsw_sp_mr_route_key *key,
0125 struct mlxsw_afa_block *afa_block,
0126 enum mlxsw_sp_mr_route_prio prio)
0127 {
0128 struct mlxsw_sp1_mr_tcam_route *route = route_priv;
0129 struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
0130 int err;
0131
0132 err = mlxsw_sp1_mr_tcam_route_parman_item_add(mr_tcam, route,
0133 key, prio);
0134 if (err)
0135 return err;
0136
0137 err = mlxsw_sp1_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
0138 key, afa_block);
0139 if (err)
0140 goto err_route_replace;
0141 return 0;
0142
0143 err_route_replace:
0144 mlxsw_sp1_mr_tcam_route_parman_item_remove(mr_tcam, route, key);
0145 return err;
0146 }
0147
0148 static void
0149 mlxsw_sp1_mr_tcam_route_destroy(struct mlxsw_sp *mlxsw_sp, void *priv,
0150 void *route_priv,
0151 struct mlxsw_sp_mr_route_key *key)
0152 {
0153 struct mlxsw_sp1_mr_tcam_route *route = route_priv;
0154 struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
0155
0156 mlxsw_sp1_mr_tcam_route_remove(mlxsw_sp, &route->parman_item, key);
0157 mlxsw_sp1_mr_tcam_route_parman_item_remove(mr_tcam, route, key);
0158 }
0159
0160 static int
0161 mlxsw_sp1_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp,
0162 void *route_priv,
0163 struct mlxsw_sp_mr_route_key *key,
0164 struct mlxsw_afa_block *afa_block)
0165 {
0166 struct mlxsw_sp1_mr_tcam_route *route = route_priv;
0167
0168 return mlxsw_sp1_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
0169 key, afa_block);
0170 }
0171
0172 #define MLXSW_SP1_MR_TCAM_REGION_BASE_COUNT 16
0173 #define MLXSW_SP1_MR_TCAM_REGION_RESIZE_STEP 16
0174
0175 static int
0176 mlxsw_sp1_mr_tcam_region_alloc(struct mlxsw_sp1_mr_tcam_region *mr_tcam_region)
0177 {
0178 struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
0179 char rtar_pl[MLXSW_REG_RTAR_LEN];
0180
0181 mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_ALLOCATE,
0182 mr_tcam_region->rtar_key_type,
0183 MLXSW_SP1_MR_TCAM_REGION_BASE_COUNT);
0184 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
0185 }
0186
0187 static void
0188 mlxsw_sp1_mr_tcam_region_free(struct mlxsw_sp1_mr_tcam_region *mr_tcam_region)
0189 {
0190 struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
0191 char rtar_pl[MLXSW_REG_RTAR_LEN];
0192
0193 mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_DEALLOCATE,
0194 mr_tcam_region->rtar_key_type, 0);
0195 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
0196 }
0197
0198 static int mlxsw_sp1_mr_tcam_region_parman_resize(void *priv,
0199 unsigned long new_count)
0200 {
0201 struct mlxsw_sp1_mr_tcam_region *mr_tcam_region = priv;
0202 struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
0203 char rtar_pl[MLXSW_REG_RTAR_LEN];
0204 u64 max_tcam_rules;
0205
0206 max_tcam_rules = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_TCAM_RULES);
0207 if (new_count > max_tcam_rules)
0208 return -EINVAL;
0209 mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_RESIZE,
0210 mr_tcam_region->rtar_key_type, new_count);
0211 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
0212 }
0213
0214 static void mlxsw_sp1_mr_tcam_region_parman_move(void *priv,
0215 unsigned long from_index,
0216 unsigned long to_index,
0217 unsigned long count)
0218 {
0219 struct mlxsw_sp1_mr_tcam_region *mr_tcam_region = priv;
0220 struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
0221 char rrcr_pl[MLXSW_REG_RRCR_LEN];
0222
0223 mlxsw_reg_rrcr_pack(rrcr_pl, MLXSW_REG_RRCR_OP_MOVE,
0224 from_index, count,
0225 mr_tcam_region->rtar_key_type, to_index);
0226 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rrcr), rrcr_pl);
0227 }
0228
0229 static const struct parman_ops mlxsw_sp1_mr_tcam_region_parman_ops = {
0230 .base_count = MLXSW_SP1_MR_TCAM_REGION_BASE_COUNT,
0231 .resize_step = MLXSW_SP1_MR_TCAM_REGION_RESIZE_STEP,
0232 .resize = mlxsw_sp1_mr_tcam_region_parman_resize,
0233 .move = mlxsw_sp1_mr_tcam_region_parman_move,
0234 .algo = PARMAN_ALGO_TYPE_LSORT,
0235 };
0236
0237 static int
0238 mlxsw_sp1_mr_tcam_region_init(struct mlxsw_sp *mlxsw_sp,
0239 struct mlxsw_sp1_mr_tcam_region *mr_tcam_region,
0240 enum mlxsw_reg_rtar_key_type rtar_key_type)
0241 {
0242 struct parman_prio *parman_prios;
0243 struct parman *parman;
0244 int err;
0245 int i;
0246
0247 mr_tcam_region->rtar_key_type = rtar_key_type;
0248 mr_tcam_region->mlxsw_sp = mlxsw_sp;
0249
0250 err = mlxsw_sp1_mr_tcam_region_alloc(mr_tcam_region);
0251 if (err)
0252 return err;
0253
0254 parman = parman_create(&mlxsw_sp1_mr_tcam_region_parman_ops,
0255 mr_tcam_region);
0256 if (!parman) {
0257 err = -ENOMEM;
0258 goto err_parman_create;
0259 }
0260 mr_tcam_region->parman = parman;
0261
0262 parman_prios = kmalloc_array(MLXSW_SP_MR_ROUTE_PRIO_MAX + 1,
0263 sizeof(*parman_prios), GFP_KERNEL);
0264 if (!parman_prios) {
0265 err = -ENOMEM;
0266 goto err_parman_prios_alloc;
0267 }
0268 mr_tcam_region->parman_prios = parman_prios;
0269
0270 for (i = 0; i < MLXSW_SP_MR_ROUTE_PRIO_MAX + 1; i++)
0271 parman_prio_init(mr_tcam_region->parman,
0272 &mr_tcam_region->parman_prios[i], i);
0273 return 0;
0274
0275 err_parman_prios_alloc:
0276 parman_destroy(parman);
0277 err_parman_create:
0278 mlxsw_sp1_mr_tcam_region_free(mr_tcam_region);
0279 return err;
0280 }
0281
0282 static void
0283 mlxsw_sp1_mr_tcam_region_fini(struct mlxsw_sp1_mr_tcam_region *mr_tcam_region)
0284 {
0285 int i;
0286
0287 for (i = 0; i < MLXSW_SP_MR_ROUTE_PRIO_MAX + 1; i++)
0288 parman_prio_fini(&mr_tcam_region->parman_prios[i]);
0289 kfree(mr_tcam_region->parman_prios);
0290 parman_destroy(mr_tcam_region->parman);
0291 mlxsw_sp1_mr_tcam_region_free(mr_tcam_region);
0292 }
0293
0294 static int mlxsw_sp1_mr_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv)
0295 {
0296 struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
0297 struct mlxsw_sp1_mr_tcam_region *region = &mr_tcam->tcam_regions[0];
0298 u32 rtar_key;
0299 int err;
0300
0301 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_TCAM_RULES))
0302 return -EIO;
0303
0304 rtar_key = MLXSW_REG_RTAR_KEY_TYPE_IPV4_MULTICAST;
0305 err = mlxsw_sp1_mr_tcam_region_init(mlxsw_sp,
0306 ®ion[MLXSW_SP_L3_PROTO_IPV4],
0307 rtar_key);
0308 if (err)
0309 return err;
0310
0311 rtar_key = MLXSW_REG_RTAR_KEY_TYPE_IPV6_MULTICAST;
0312 err = mlxsw_sp1_mr_tcam_region_init(mlxsw_sp,
0313 ®ion[MLXSW_SP_L3_PROTO_IPV6],
0314 rtar_key);
0315 if (err)
0316 goto err_ipv6_region_init;
0317
0318 return 0;
0319
0320 err_ipv6_region_init:
0321 mlxsw_sp1_mr_tcam_region_fini(®ion[MLXSW_SP_L3_PROTO_IPV4]);
0322 return err;
0323 }
0324
0325 static void mlxsw_sp1_mr_tcam_fini(void *priv)
0326 {
0327 struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
0328 struct mlxsw_sp1_mr_tcam_region *region = &mr_tcam->tcam_regions[0];
0329
0330 mlxsw_sp1_mr_tcam_region_fini(®ion[MLXSW_SP_L3_PROTO_IPV6]);
0331 mlxsw_sp1_mr_tcam_region_fini(®ion[MLXSW_SP_L3_PROTO_IPV4]);
0332 }
0333
0334 const struct mlxsw_sp_mr_tcam_ops mlxsw_sp1_mr_tcam_ops = {
0335 .priv_size = sizeof(struct mlxsw_sp1_mr_tcam),
0336 .init = mlxsw_sp1_mr_tcam_init,
0337 .fini = mlxsw_sp1_mr_tcam_fini,
0338 .route_priv_size = sizeof(struct mlxsw_sp1_mr_tcam_route),
0339 .route_create = mlxsw_sp1_mr_tcam_route_create,
0340 .route_destroy = mlxsw_sp1_mr_tcam_route_destroy,
0341 .route_update = mlxsw_sp1_mr_tcam_route_update,
0342 };