Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /* Copyright (c) 2020 Mellanox Technologies. All rights reserved */
0003 
0004 #include <linux/idr.h>
0005 #include <linux/log2.h>
0006 #include <linux/mutex.h>
0007 #include <linux/netlink.h>
0008 #include <net/devlink.h>
0009 
0010 #include "spectrum.h"
0011 
0012 struct mlxsw_sp_policer_family {
0013     enum mlxsw_sp_policer_type type;
0014     enum mlxsw_reg_qpcr_g qpcr_type;
0015     struct mlxsw_sp *mlxsw_sp;
0016     u16 start_index; /* Inclusive */
0017     u16 end_index; /* Exclusive */
0018     struct idr policer_idr;
0019     struct mutex lock; /* Protects policer_idr */
0020     atomic_t policers_count;
0021     const struct mlxsw_sp_policer_family_ops *ops;
0022 };
0023 
0024 struct mlxsw_sp_policer {
0025     struct mlxsw_sp_policer_params params;
0026     u16 index;
0027 };
0028 
0029 struct mlxsw_sp_policer_family_ops {
0030     int (*init)(struct mlxsw_sp_policer_family *family);
0031     void (*fini)(struct mlxsw_sp_policer_family *family);
0032     int (*policer_index_alloc)(struct mlxsw_sp_policer_family *family,
0033                    struct mlxsw_sp_policer *policer);
0034     struct mlxsw_sp_policer * (*policer_index_free)(struct mlxsw_sp_policer_family *family,
0035                             u16 policer_index);
0036     int (*policer_init)(struct mlxsw_sp_policer_family *family,
0037                 const struct mlxsw_sp_policer *policer);
0038     int (*policer_params_check)(const struct mlxsw_sp_policer_family *family,
0039                     const struct mlxsw_sp_policer_params *params,
0040                     struct netlink_ext_ack *extack);
0041 };
0042 
0043 struct mlxsw_sp_policer_core {
0044     struct mlxsw_sp_policer_family *family_arr[MLXSW_SP_POLICER_TYPE_MAX + 1];
0045     const struct mlxsw_sp_policer_core_ops *ops;
0046     u8 lowest_bs_bits;
0047     u8 highest_bs_bits;
0048 };
0049 
0050 struct mlxsw_sp_policer_core_ops {
0051     int (*init)(struct mlxsw_sp_policer_core *policer_core);
0052 };
0053 
0054 static u64 mlxsw_sp_policer_rate_bytes_ps_kbps(u64 rate_bytes_ps)
0055 {
0056     return div_u64(rate_bytes_ps, 1000) * BITS_PER_BYTE;
0057 }
0058 
0059 static u8 mlxsw_sp_policer_burst_bytes_hw_units(u64 burst_bytes)
0060 {
0061     /* Provided burst size is in bytes. The ASIC burst size value is
0062      * (2 ^ bs) * 512 bits. Convert the provided size to 512-bit units.
0063      */
0064     u64 bs512 = div_u64(burst_bytes, 64);
0065 
0066     if (!bs512)
0067         return 0;
0068 
0069     return fls64(bs512) - 1;
0070 }
0071 
0072 static u64 mlxsw_sp_policer_single_rate_occ_get(void *priv)
0073 {
0074     struct mlxsw_sp_policer_family *family = priv;
0075 
0076     return atomic_read(&family->policers_count);
0077 }
0078 
0079 static int
0080 mlxsw_sp_policer_single_rate_family_init(struct mlxsw_sp_policer_family *family)
0081 {
0082     struct mlxsw_core *core = family->mlxsw_sp->core;
0083     struct devlink *devlink;
0084 
0085     /* CPU policers are allocated from the first N policers in the global
0086      * range, so skip them.
0087      */
0088     if (!MLXSW_CORE_RES_VALID(core, MAX_GLOBAL_POLICERS) ||
0089         !MLXSW_CORE_RES_VALID(core, MAX_CPU_POLICERS))
0090         return -EIO;
0091 
0092     family->start_index = MLXSW_CORE_RES_GET(core, MAX_CPU_POLICERS);
0093     family->end_index = MLXSW_CORE_RES_GET(core, MAX_GLOBAL_POLICERS);
0094 
0095     atomic_set(&family->policers_count, 0);
0096     devlink = priv_to_devlink(core);
0097     devl_resource_occ_get_register(devlink,
0098                        MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS,
0099                        mlxsw_sp_policer_single_rate_occ_get,
0100                        family);
0101 
0102     return 0;
0103 }
0104 
0105 static void
0106 mlxsw_sp_policer_single_rate_family_fini(struct mlxsw_sp_policer_family *family)
0107 {
0108     struct devlink *devlink = priv_to_devlink(family->mlxsw_sp->core);
0109 
0110     devl_resource_occ_get_unregister(devlink,
0111                      MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS);
0112     WARN_ON(atomic_read(&family->policers_count) != 0);
0113 }
0114 
0115 static int
0116 mlxsw_sp_policer_single_rate_index_alloc(struct mlxsw_sp_policer_family *family,
0117                      struct mlxsw_sp_policer *policer)
0118 {
0119     int id;
0120 
0121     mutex_lock(&family->lock);
0122     id = idr_alloc(&family->policer_idr, policer, family->start_index,
0123                family->end_index, GFP_KERNEL);
0124     mutex_unlock(&family->lock);
0125 
0126     if (id < 0)
0127         return id;
0128 
0129     atomic_inc(&family->policers_count);
0130     policer->index = id;
0131 
0132     return 0;
0133 }
0134 
0135 static struct mlxsw_sp_policer *
0136 mlxsw_sp_policer_single_rate_index_free(struct mlxsw_sp_policer_family *family,
0137                     u16 policer_index)
0138 {
0139     struct mlxsw_sp_policer *policer;
0140 
0141     atomic_dec(&family->policers_count);
0142 
0143     mutex_lock(&family->lock);
0144     policer = idr_remove(&family->policer_idr, policer_index);
0145     mutex_unlock(&family->lock);
0146 
0147     WARN_ON(!policer);
0148 
0149     return policer;
0150 }
0151 
0152 static int
0153 mlxsw_sp_policer_single_rate_init(struct mlxsw_sp_policer_family *family,
0154                   const struct mlxsw_sp_policer *policer)
0155 {
0156     u64 rate_kbps = mlxsw_sp_policer_rate_bytes_ps_kbps(policer->params.rate);
0157     u8 bs = mlxsw_sp_policer_burst_bytes_hw_units(policer->params.burst);
0158     struct mlxsw_sp *mlxsw_sp = family->mlxsw_sp;
0159     char qpcr_pl[MLXSW_REG_QPCR_LEN];
0160 
0161     mlxsw_reg_qpcr_pack(qpcr_pl, policer->index, MLXSW_REG_QPCR_IR_UNITS_K,
0162                 true, rate_kbps, bs);
0163     mlxsw_reg_qpcr_clear_counter_set(qpcr_pl, true);
0164 
0165     return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
0166 }
0167 
0168 static int
0169 mlxsw_sp_policer_single_rate_params_check(const struct mlxsw_sp_policer_family *family,
0170                       const struct mlxsw_sp_policer_params *params,
0171                       struct netlink_ext_ack *extack)
0172 {
0173     struct mlxsw_sp_policer_core *policer_core = family->mlxsw_sp->policer_core;
0174     u64 rate_bps = params->rate * BITS_PER_BYTE;
0175     u8 bs;
0176 
0177     if (!params->bytes) {
0178         NL_SET_ERR_MSG_MOD(extack, "Only bandwidth policing is currently supported by single rate policers");
0179         return -EINVAL;
0180     }
0181 
0182     if (!is_power_of_2(params->burst)) {
0183         NL_SET_ERR_MSG_MOD(extack, "Policer burst size is not power of two");
0184         return -EINVAL;
0185     }
0186 
0187     bs = mlxsw_sp_policer_burst_bytes_hw_units(params->burst);
0188 
0189     if (bs < policer_core->lowest_bs_bits) {
0190         NL_SET_ERR_MSG_MOD(extack, "Policer burst size lower than limit");
0191         return -EINVAL;
0192     }
0193 
0194     if (bs > policer_core->highest_bs_bits) {
0195         NL_SET_ERR_MSG_MOD(extack, "Policer burst size higher than limit");
0196         return -EINVAL;
0197     }
0198 
0199     if (rate_bps < MLXSW_REG_QPCR_LOWEST_CIR_BITS) {
0200         NL_SET_ERR_MSG_MOD(extack, "Policer rate lower than limit");
0201         return -EINVAL;
0202     }
0203 
0204     if (rate_bps > MLXSW_REG_QPCR_HIGHEST_CIR_BITS) {
0205         NL_SET_ERR_MSG_MOD(extack, "Policer rate higher than limit");
0206         return -EINVAL;
0207     }
0208 
0209     return 0;
0210 }
0211 
0212 static const struct mlxsw_sp_policer_family_ops mlxsw_sp_policer_single_rate_ops = {
0213     .init           = mlxsw_sp_policer_single_rate_family_init,
0214     .fini           = mlxsw_sp_policer_single_rate_family_fini,
0215     .policer_index_alloc    = mlxsw_sp_policer_single_rate_index_alloc,
0216     .policer_index_free = mlxsw_sp_policer_single_rate_index_free,
0217     .policer_init       = mlxsw_sp_policer_single_rate_init,
0218     .policer_params_check   = mlxsw_sp_policer_single_rate_params_check,
0219 };
0220 
0221 static const struct mlxsw_sp_policer_family mlxsw_sp_policer_single_rate_family = {
0222     .type       = MLXSW_SP_POLICER_TYPE_SINGLE_RATE,
0223     .qpcr_type  = MLXSW_REG_QPCR_G_GLOBAL,
0224     .ops        = &mlxsw_sp_policer_single_rate_ops,
0225 };
0226 
0227 static const struct mlxsw_sp_policer_family *mlxsw_sp_policer_family_arr[] = {
0228     [MLXSW_SP_POLICER_TYPE_SINGLE_RATE] = &mlxsw_sp_policer_single_rate_family,
0229 };
0230 
0231 int mlxsw_sp_policer_add(struct mlxsw_sp *mlxsw_sp,
0232              enum mlxsw_sp_policer_type type,
0233              const struct mlxsw_sp_policer_params *params,
0234              struct netlink_ext_ack *extack, u16 *p_policer_index)
0235 {
0236     struct mlxsw_sp_policer_family *family;
0237     struct mlxsw_sp_policer *policer;
0238     int err;
0239 
0240     family = mlxsw_sp->policer_core->family_arr[type];
0241 
0242     err = family->ops->policer_params_check(family, params, extack);
0243     if (err)
0244         return err;
0245 
0246     policer = kmalloc(sizeof(*policer), GFP_KERNEL);
0247     if (!policer)
0248         return -ENOMEM;
0249     policer->params = *params;
0250 
0251     err = family->ops->policer_index_alloc(family, policer);
0252     if (err) {
0253         NL_SET_ERR_MSG_MOD(extack, "Failed to allocate policer index");
0254         goto err_policer_index_alloc;
0255     }
0256 
0257     err = family->ops->policer_init(family, policer);
0258     if (err) {
0259         NL_SET_ERR_MSG_MOD(extack, "Failed to initialize policer");
0260         goto err_policer_init;
0261     }
0262 
0263     *p_policer_index = policer->index;
0264 
0265     return 0;
0266 
0267 err_policer_init:
0268     family->ops->policer_index_free(family, policer->index);
0269 err_policer_index_alloc:
0270     kfree(policer);
0271     return err;
0272 }
0273 
0274 void mlxsw_sp_policer_del(struct mlxsw_sp *mlxsw_sp,
0275               enum mlxsw_sp_policer_type type, u16 policer_index)
0276 {
0277     struct mlxsw_sp_policer_family *family;
0278     struct mlxsw_sp_policer *policer;
0279 
0280     family = mlxsw_sp->policer_core->family_arr[type];
0281     policer = family->ops->policer_index_free(family, policer_index);
0282     kfree(policer);
0283 }
0284 
0285 int mlxsw_sp_policer_drops_counter_get(struct mlxsw_sp *mlxsw_sp,
0286                        enum mlxsw_sp_policer_type type,
0287                        u16 policer_index, u64 *p_drops)
0288 {
0289     struct mlxsw_sp_policer_family *family;
0290     char qpcr_pl[MLXSW_REG_QPCR_LEN];
0291     int err;
0292 
0293     family = mlxsw_sp->policer_core->family_arr[type];
0294 
0295     MLXSW_REG_ZERO(qpcr, qpcr_pl);
0296     mlxsw_reg_qpcr_pid_set(qpcr_pl, policer_index);
0297     mlxsw_reg_qpcr_g_set(qpcr_pl, family->qpcr_type);
0298     err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
0299     if (err)
0300         return err;
0301 
0302     *p_drops = mlxsw_reg_qpcr_violate_count_get(qpcr_pl);
0303 
0304     return 0;
0305 }
0306 
0307 static int
0308 mlxsw_sp_policer_family_register(struct mlxsw_sp *mlxsw_sp,
0309                  const struct mlxsw_sp_policer_family *tmpl)
0310 {
0311     struct mlxsw_sp_policer_family *family;
0312     int err;
0313 
0314     family = kmemdup(tmpl, sizeof(*family), GFP_KERNEL);
0315     if (!family)
0316         return -ENOMEM;
0317 
0318     family->mlxsw_sp = mlxsw_sp;
0319     idr_init(&family->policer_idr);
0320     mutex_init(&family->lock);
0321 
0322     err = family->ops->init(family);
0323     if (err)
0324         goto err_family_init;
0325 
0326     if (WARN_ON(family->start_index >= family->end_index)) {
0327         err = -EINVAL;
0328         goto err_index_check;
0329     }
0330 
0331     mlxsw_sp->policer_core->family_arr[tmpl->type] = family;
0332 
0333     return 0;
0334 
0335 err_index_check:
0336     family->ops->fini(family);
0337 err_family_init:
0338     mutex_destroy(&family->lock);
0339     idr_destroy(&family->policer_idr);
0340     kfree(family);
0341     return err;
0342 }
0343 
0344 static void
0345 mlxsw_sp_policer_family_unregister(struct mlxsw_sp *mlxsw_sp,
0346                    struct mlxsw_sp_policer_family *family)
0347 {
0348     family->ops->fini(family);
0349     mutex_destroy(&family->lock);
0350     WARN_ON(!idr_is_empty(&family->policer_idr));
0351     idr_destroy(&family->policer_idr);
0352     kfree(family);
0353 }
0354 
0355 int mlxsw_sp_policers_init(struct mlxsw_sp *mlxsw_sp)
0356 {
0357     struct mlxsw_sp_policer_core *policer_core;
0358     int i, err;
0359 
0360     policer_core = kzalloc(sizeof(*policer_core), GFP_KERNEL);
0361     if (!policer_core)
0362         return -ENOMEM;
0363     mlxsw_sp->policer_core = policer_core;
0364     policer_core->ops = mlxsw_sp->policer_core_ops;
0365 
0366     err = policer_core->ops->init(policer_core);
0367     if (err)
0368         goto err_init;
0369 
0370     for (i = 0; i < MLXSW_SP_POLICER_TYPE_MAX + 1; i++) {
0371         err = mlxsw_sp_policer_family_register(mlxsw_sp, mlxsw_sp_policer_family_arr[i]);
0372         if (err)
0373             goto err_family_register;
0374     }
0375 
0376     return 0;
0377 
0378 err_family_register:
0379     for (i--; i >= 0; i--) {
0380         struct mlxsw_sp_policer_family *family;
0381 
0382         family = mlxsw_sp->policer_core->family_arr[i];
0383         mlxsw_sp_policer_family_unregister(mlxsw_sp, family);
0384     }
0385 err_init:
0386     kfree(mlxsw_sp->policer_core);
0387     return err;
0388 }
0389 
0390 void mlxsw_sp_policers_fini(struct mlxsw_sp *mlxsw_sp)
0391 {
0392     int i;
0393 
0394     for (i = MLXSW_SP_POLICER_TYPE_MAX; i >= 0; i--) {
0395         struct mlxsw_sp_policer_family *family;
0396 
0397         family = mlxsw_sp->policer_core->family_arr[i];
0398         mlxsw_sp_policer_family_unregister(mlxsw_sp, family);
0399     }
0400 
0401     kfree(mlxsw_sp->policer_core);
0402 }
0403 
0404 int mlxsw_sp_policer_resources_register(struct mlxsw_core *mlxsw_core)
0405 {
0406     u64 global_policers, cpu_policers, single_rate_policers;
0407     struct devlink *devlink = priv_to_devlink(mlxsw_core);
0408     struct devlink_resource_size_params size_params;
0409     int err;
0410 
0411     if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_GLOBAL_POLICERS) ||
0412         !MLXSW_CORE_RES_VALID(mlxsw_core, MAX_CPU_POLICERS))
0413         return -EIO;
0414 
0415     global_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_GLOBAL_POLICERS);
0416     cpu_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_CPU_POLICERS);
0417     single_rate_policers = global_policers - cpu_policers;
0418 
0419     devlink_resource_size_params_init(&size_params, global_policers,
0420                       global_policers, 1,
0421                       DEVLINK_RESOURCE_UNIT_ENTRY);
0422     err = devl_resource_register(devlink, "global_policers",
0423                      global_policers,
0424                      MLXSW_SP_RESOURCE_GLOBAL_POLICERS,
0425                      DEVLINK_RESOURCE_ID_PARENT_TOP,
0426                      &size_params);
0427     if (err)
0428         return err;
0429 
0430     devlink_resource_size_params_init(&size_params, single_rate_policers,
0431                       single_rate_policers, 1,
0432                       DEVLINK_RESOURCE_UNIT_ENTRY);
0433     err = devl_resource_register(devlink, "single_rate_policers",
0434                      single_rate_policers,
0435                      MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS,
0436                      MLXSW_SP_RESOURCE_GLOBAL_POLICERS,
0437                      &size_params);
0438     if (err)
0439         return err;
0440 
0441     return 0;
0442 }
0443 
0444 static int
0445 mlxsw_sp1_policer_core_init(struct mlxsw_sp_policer_core *policer_core)
0446 {
0447     policer_core->lowest_bs_bits = MLXSW_REG_QPCR_LOWEST_CBS_BITS_SP1;
0448     policer_core->highest_bs_bits = MLXSW_REG_QPCR_HIGHEST_CBS_BITS_SP1;
0449 
0450     return 0;
0451 }
0452 
0453 const struct mlxsw_sp_policer_core_ops mlxsw_sp1_policer_core_ops = {
0454     .init = mlxsw_sp1_policer_core_init,
0455 };
0456 
0457 static int
0458 mlxsw_sp2_policer_core_init(struct mlxsw_sp_policer_core *policer_core)
0459 {
0460     policer_core->lowest_bs_bits = MLXSW_REG_QPCR_LOWEST_CBS_BITS_SP2;
0461     policer_core->highest_bs_bits = MLXSW_REG_QPCR_HIGHEST_CBS_BITS_SP2;
0462 
0463     return 0;
0464 }
0465 
0466 const struct mlxsw_sp_policer_core_ops mlxsw_sp2_policer_core_ops = {
0467     .init = mlxsw_sp2_policer_core_init,
0468 };