Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
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                         &region[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                         &region[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(&region[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(&region[MLXSW_SP_L3_PROTO_IPV6]);
0331     mlxsw_sp1_mr_tcam_region_fini(&region[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 };