linux/drivers/net/ethernet/mellanox/mlxsw/spectrum_policer.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/* Copyright (c) 2020 Mellanox Technologies. All rights reserved */
   3
   4#include <linux/idr.h>
   5#include <linux/log2.h>
   6#include <linux/mutex.h>
   7#include <linux/netlink.h>
   8#include <net/devlink.h>
   9
  10#include "spectrum.h"
  11
  12struct mlxsw_sp_policer_family {
  13        enum mlxsw_sp_policer_type type;
  14        enum mlxsw_reg_qpcr_g qpcr_type;
  15        struct mlxsw_sp *mlxsw_sp;
  16        u16 start_index; /* Inclusive */
  17        u16 end_index; /* Exclusive */
  18        struct idr policer_idr;
  19        struct mutex lock; /* Protects policer_idr */
  20        atomic_t policers_count;
  21        const struct mlxsw_sp_policer_family_ops *ops;
  22};
  23
  24struct mlxsw_sp_policer {
  25        struct mlxsw_sp_policer_params params;
  26        u16 index;
  27};
  28
  29struct mlxsw_sp_policer_family_ops {
  30        int (*init)(struct mlxsw_sp_policer_family *family);
  31        void (*fini)(struct mlxsw_sp_policer_family *family);
  32        int (*policer_index_alloc)(struct mlxsw_sp_policer_family *family,
  33                                   struct mlxsw_sp_policer *policer);
  34        struct mlxsw_sp_policer * (*policer_index_free)(struct mlxsw_sp_policer_family *family,
  35                                                        u16 policer_index);
  36        int (*policer_init)(struct mlxsw_sp_policer_family *family,
  37                            const struct mlxsw_sp_policer *policer);
  38        int (*policer_params_check)(const struct mlxsw_sp_policer_family *family,
  39                                    const struct mlxsw_sp_policer_params *params,
  40                                    struct netlink_ext_ack *extack);
  41};
  42
  43struct mlxsw_sp_policer_core {
  44        struct mlxsw_sp_policer_family *family_arr[MLXSW_SP_POLICER_TYPE_MAX + 1];
  45        const struct mlxsw_sp_policer_core_ops *ops;
  46        u8 lowest_bs_bits;
  47        u8 highest_bs_bits;
  48};
  49
  50struct mlxsw_sp_policer_core_ops {
  51        int (*init)(struct mlxsw_sp_policer_core *policer_core);
  52};
  53
  54static u64 mlxsw_sp_policer_rate_bytes_ps_kbps(u64 rate_bytes_ps)
  55{
  56        return div_u64(rate_bytes_ps, 1000) * BITS_PER_BYTE;
  57}
  58
  59static u8 mlxsw_sp_policer_burst_bytes_hw_units(u64 burst_bytes)
  60{
  61        /* Provided burst size is in bytes. The ASIC burst size value is
  62         * (2 ^ bs) * 512 bits. Convert the provided size to 512-bit units.
  63         */
  64        u64 bs512 = div_u64(burst_bytes, 64);
  65
  66        if (!bs512)
  67                return 0;
  68
  69        return fls64(bs512) - 1;
  70}
  71
  72static u64 mlxsw_sp_policer_single_rate_occ_get(void *priv)
  73{
  74        struct mlxsw_sp_policer_family *family = priv;
  75
  76        return atomic_read(&family->policers_count);
  77}
  78
  79static int
  80mlxsw_sp_policer_single_rate_family_init(struct mlxsw_sp_policer_family *family)
  81{
  82        struct mlxsw_core *core = family->mlxsw_sp->core;
  83        struct devlink *devlink;
  84
  85        /* CPU policers are allocated from the first N policers in the global
  86         * range, so skip them.
  87         */
  88        if (!MLXSW_CORE_RES_VALID(core, MAX_GLOBAL_POLICERS) ||
  89            !MLXSW_CORE_RES_VALID(core, MAX_CPU_POLICERS))
  90                return -EIO;
  91
  92        family->start_index = MLXSW_CORE_RES_GET(core, MAX_CPU_POLICERS);
  93        family->end_index = MLXSW_CORE_RES_GET(core, MAX_GLOBAL_POLICERS);
  94
  95        atomic_set(&family->policers_count, 0);
  96        devlink = priv_to_devlink(core);
  97        devlink_resource_occ_get_register(devlink,
  98                                          MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS,
  99                                          mlxsw_sp_policer_single_rate_occ_get,
 100                                          family);
 101
 102        return 0;
 103}
 104
 105static void
 106mlxsw_sp_policer_single_rate_family_fini(struct mlxsw_sp_policer_family *family)
 107{
 108        struct devlink *devlink = priv_to_devlink(family->mlxsw_sp->core);
 109
 110        devlink_resource_occ_get_unregister(devlink,
 111                                            MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS);
 112        WARN_ON(atomic_read(&family->policers_count) != 0);
 113}
 114
 115static int
 116mlxsw_sp_policer_single_rate_index_alloc(struct mlxsw_sp_policer_family *family,
 117                                         struct mlxsw_sp_policer *policer)
 118{
 119        int id;
 120
 121        mutex_lock(&family->lock);
 122        id = idr_alloc(&family->policer_idr, policer, family->start_index,
 123                       family->end_index, GFP_KERNEL);
 124        mutex_unlock(&family->lock);
 125
 126        if (id < 0)
 127                return id;
 128
 129        atomic_inc(&family->policers_count);
 130        policer->index = id;
 131
 132        return 0;
 133}
 134
 135static struct mlxsw_sp_policer *
 136mlxsw_sp_policer_single_rate_index_free(struct mlxsw_sp_policer_family *family,
 137                                        u16 policer_index)
 138{
 139        struct mlxsw_sp_policer *policer;
 140
 141        atomic_dec(&family->policers_count);
 142
 143        mutex_lock(&family->lock);
 144        policer = idr_remove(&family->policer_idr, policer_index);
 145        mutex_unlock(&family->lock);
 146
 147        WARN_ON(!policer);
 148
 149        return policer;
 150}
 151
 152static int
 153mlxsw_sp_policer_single_rate_init(struct mlxsw_sp_policer_family *family,
 154                                  const struct mlxsw_sp_policer *policer)
 155{
 156        u64 rate_kbps = mlxsw_sp_policer_rate_bytes_ps_kbps(policer->params.rate);
 157        u8 bs = mlxsw_sp_policer_burst_bytes_hw_units(policer->params.burst);
 158        struct mlxsw_sp *mlxsw_sp = family->mlxsw_sp;
 159        char qpcr_pl[MLXSW_REG_QPCR_LEN];
 160
 161        mlxsw_reg_qpcr_pack(qpcr_pl, policer->index, MLXSW_REG_QPCR_IR_UNITS_K,
 162                            true, rate_kbps, bs);
 163        mlxsw_reg_qpcr_clear_counter_set(qpcr_pl, true);
 164
 165        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
 166}
 167
 168static int
 169mlxsw_sp_policer_single_rate_params_check(const struct mlxsw_sp_policer_family *family,
 170                                          const struct mlxsw_sp_policer_params *params,
 171                                          struct netlink_ext_ack *extack)
 172{
 173        struct mlxsw_sp_policer_core *policer_core = family->mlxsw_sp->policer_core;
 174        u64 rate_bps = params->rate * BITS_PER_BYTE;
 175        u8 bs;
 176
 177        if (!params->bytes) {
 178                NL_SET_ERR_MSG_MOD(extack, "Only bandwidth policing is currently supported by single rate policers");
 179                return -EINVAL;
 180        }
 181
 182        if (!is_power_of_2(params->burst)) {
 183                NL_SET_ERR_MSG_MOD(extack, "Policer burst size is not power of two");
 184                return -EINVAL;
 185        }
 186
 187        bs = mlxsw_sp_policer_burst_bytes_hw_units(params->burst);
 188
 189        if (bs < policer_core->lowest_bs_bits) {
 190                NL_SET_ERR_MSG_MOD(extack, "Policer burst size lower than limit");
 191                return -EINVAL;
 192        }
 193
 194        if (bs > policer_core->highest_bs_bits) {
 195                NL_SET_ERR_MSG_MOD(extack, "Policer burst size higher than limit");
 196                return -EINVAL;
 197        }
 198
 199        if (rate_bps < MLXSW_REG_QPCR_LOWEST_CIR_BITS) {
 200                NL_SET_ERR_MSG_MOD(extack, "Policer rate lower than limit");
 201                return -EINVAL;
 202        }
 203
 204        if (rate_bps > MLXSW_REG_QPCR_HIGHEST_CIR_BITS) {
 205                NL_SET_ERR_MSG_MOD(extack, "Policer rate higher than limit");
 206                return -EINVAL;
 207        }
 208
 209        return 0;
 210}
 211
 212static const struct mlxsw_sp_policer_family_ops mlxsw_sp_policer_single_rate_ops = {
 213        .init                   = mlxsw_sp_policer_single_rate_family_init,
 214        .fini                   = mlxsw_sp_policer_single_rate_family_fini,
 215        .policer_index_alloc    = mlxsw_sp_policer_single_rate_index_alloc,
 216        .policer_index_free     = mlxsw_sp_policer_single_rate_index_free,
 217        .policer_init           = mlxsw_sp_policer_single_rate_init,
 218        .policer_params_check   = mlxsw_sp_policer_single_rate_params_check,
 219};
 220
 221static const struct mlxsw_sp_policer_family mlxsw_sp_policer_single_rate_family = {
 222        .type           = MLXSW_SP_POLICER_TYPE_SINGLE_RATE,
 223        .qpcr_type      = MLXSW_REG_QPCR_G_GLOBAL,
 224        .ops            = &mlxsw_sp_policer_single_rate_ops,
 225};
 226
 227static const struct mlxsw_sp_policer_family *mlxsw_sp_policer_family_arr[] = {
 228        [MLXSW_SP_POLICER_TYPE_SINGLE_RATE]     = &mlxsw_sp_policer_single_rate_family,
 229};
 230
 231int mlxsw_sp_policer_add(struct mlxsw_sp *mlxsw_sp,
 232                         enum mlxsw_sp_policer_type type,
 233                         const struct mlxsw_sp_policer_params *params,
 234                         struct netlink_ext_ack *extack, u16 *p_policer_index)
 235{
 236        struct mlxsw_sp_policer_family *family;
 237        struct mlxsw_sp_policer *policer;
 238        int err;
 239
 240        family = mlxsw_sp->policer_core->family_arr[type];
 241
 242        err = family->ops->policer_params_check(family, params, extack);
 243        if (err)
 244                return err;
 245
 246        policer = kmalloc(sizeof(*policer), GFP_KERNEL);
 247        if (!policer)
 248                return -ENOMEM;
 249        policer->params = *params;
 250
 251        err = family->ops->policer_index_alloc(family, policer);
 252        if (err) {
 253                NL_SET_ERR_MSG_MOD(extack, "Failed to allocate policer index");
 254                goto err_policer_index_alloc;
 255        }
 256
 257        err = family->ops->policer_init(family, policer);
 258        if (err) {
 259                NL_SET_ERR_MSG_MOD(extack, "Failed to initialize policer");
 260                goto err_policer_init;
 261        }
 262
 263        *p_policer_index = policer->index;
 264
 265        return 0;
 266
 267err_policer_init:
 268        family->ops->policer_index_free(family, policer->index);
 269err_policer_index_alloc:
 270        kfree(policer);
 271        return err;
 272}
 273
 274void mlxsw_sp_policer_del(struct mlxsw_sp *mlxsw_sp,
 275                          enum mlxsw_sp_policer_type type, u16 policer_index)
 276{
 277        struct mlxsw_sp_policer_family *family;
 278        struct mlxsw_sp_policer *policer;
 279
 280        family = mlxsw_sp->policer_core->family_arr[type];
 281        policer = family->ops->policer_index_free(family, policer_index);
 282        kfree(policer);
 283}
 284
 285int mlxsw_sp_policer_drops_counter_get(struct mlxsw_sp *mlxsw_sp,
 286                                       enum mlxsw_sp_policer_type type,
 287                                       u16 policer_index, u64 *p_drops)
 288{
 289        struct mlxsw_sp_policer_family *family;
 290        char qpcr_pl[MLXSW_REG_QPCR_LEN];
 291        int err;
 292
 293        family = mlxsw_sp->policer_core->family_arr[type];
 294
 295        MLXSW_REG_ZERO(qpcr, qpcr_pl);
 296        mlxsw_reg_qpcr_pid_set(qpcr_pl, policer_index);
 297        mlxsw_reg_qpcr_g_set(qpcr_pl, family->qpcr_type);
 298        err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
 299        if (err)
 300                return err;
 301
 302        *p_drops = mlxsw_reg_qpcr_violate_count_get(qpcr_pl);
 303
 304        return 0;
 305}
 306
 307static int
 308mlxsw_sp_policer_family_register(struct mlxsw_sp *mlxsw_sp,
 309                                 const struct mlxsw_sp_policer_family *tmpl)
 310{
 311        struct mlxsw_sp_policer_family *family;
 312        int err;
 313
 314        family = kmemdup(tmpl, sizeof(*family), GFP_KERNEL);
 315        if (!family)
 316                return -ENOMEM;
 317
 318        family->mlxsw_sp = mlxsw_sp;
 319        idr_init(&family->policer_idr);
 320        mutex_init(&family->lock);
 321
 322        err = family->ops->init(family);
 323        if (err)
 324                goto err_family_init;
 325
 326        if (WARN_ON(family->start_index >= family->end_index)) {
 327                err = -EINVAL;
 328                goto err_index_check;
 329        }
 330
 331        mlxsw_sp->policer_core->family_arr[tmpl->type] = family;
 332
 333        return 0;
 334
 335err_index_check:
 336        family->ops->fini(family);
 337err_family_init:
 338        mutex_destroy(&family->lock);
 339        idr_destroy(&family->policer_idr);
 340        kfree(family);
 341        return err;
 342}
 343
 344static void
 345mlxsw_sp_policer_family_unregister(struct mlxsw_sp *mlxsw_sp,
 346                                   struct mlxsw_sp_policer_family *family)
 347{
 348        family->ops->fini(family);
 349        mutex_destroy(&family->lock);
 350        WARN_ON(!idr_is_empty(&family->policer_idr));
 351        idr_destroy(&family->policer_idr);
 352        kfree(family);
 353}
 354
 355int mlxsw_sp_policers_init(struct mlxsw_sp *mlxsw_sp)
 356{
 357        struct mlxsw_sp_policer_core *policer_core;
 358        int i, err;
 359
 360        policer_core = kzalloc(sizeof(*policer_core), GFP_KERNEL);
 361        if (!policer_core)
 362                return -ENOMEM;
 363        mlxsw_sp->policer_core = policer_core;
 364        policer_core->ops = mlxsw_sp->policer_core_ops;
 365
 366        err = policer_core->ops->init(policer_core);
 367        if (err)
 368                goto err_init;
 369
 370        for (i = 0; i < MLXSW_SP_POLICER_TYPE_MAX + 1; i++) {
 371                err = mlxsw_sp_policer_family_register(mlxsw_sp, mlxsw_sp_policer_family_arr[i]);
 372                if (err)
 373                        goto err_family_register;
 374        }
 375
 376        return 0;
 377
 378err_family_register:
 379        for (i--; i >= 0; i--) {
 380                struct mlxsw_sp_policer_family *family;
 381
 382                family = mlxsw_sp->policer_core->family_arr[i];
 383                mlxsw_sp_policer_family_unregister(mlxsw_sp, family);
 384        }
 385err_init:
 386        kfree(mlxsw_sp->policer_core);
 387        return err;
 388}
 389
 390void mlxsw_sp_policers_fini(struct mlxsw_sp *mlxsw_sp)
 391{
 392        int i;
 393
 394        for (i = MLXSW_SP_POLICER_TYPE_MAX; i >= 0; i--) {
 395                struct mlxsw_sp_policer_family *family;
 396
 397                family = mlxsw_sp->policer_core->family_arr[i];
 398                mlxsw_sp_policer_family_unregister(mlxsw_sp, family);
 399        }
 400
 401        kfree(mlxsw_sp->policer_core);
 402}
 403
 404int mlxsw_sp_policer_resources_register(struct mlxsw_core *mlxsw_core)
 405{
 406        u64 global_policers, cpu_policers, single_rate_policers;
 407        struct devlink *devlink = priv_to_devlink(mlxsw_core);
 408        struct devlink_resource_size_params size_params;
 409        int err;
 410
 411        if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_GLOBAL_POLICERS) ||
 412            !MLXSW_CORE_RES_VALID(mlxsw_core, MAX_CPU_POLICERS))
 413                return -EIO;
 414
 415        global_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_GLOBAL_POLICERS);
 416        cpu_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_CPU_POLICERS);
 417        single_rate_policers = global_policers - cpu_policers;
 418
 419        devlink_resource_size_params_init(&size_params, global_policers,
 420                                          global_policers, 1,
 421                                          DEVLINK_RESOURCE_UNIT_ENTRY);
 422        err = devlink_resource_register(devlink, "global_policers",
 423                                        global_policers,
 424                                        MLXSW_SP_RESOURCE_GLOBAL_POLICERS,
 425                                        DEVLINK_RESOURCE_ID_PARENT_TOP,
 426                                        &size_params);
 427        if (err)
 428                return err;
 429
 430        devlink_resource_size_params_init(&size_params, single_rate_policers,
 431                                          single_rate_policers, 1,
 432                                          DEVLINK_RESOURCE_UNIT_ENTRY);
 433        err = devlink_resource_register(devlink, "single_rate_policers",
 434                                        single_rate_policers,
 435                                        MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS,
 436                                        MLXSW_SP_RESOURCE_GLOBAL_POLICERS,
 437                                        &size_params);
 438        if (err)
 439                return err;
 440
 441        return 0;
 442}
 443
 444static int
 445mlxsw_sp1_policer_core_init(struct mlxsw_sp_policer_core *policer_core)
 446{
 447        policer_core->lowest_bs_bits = MLXSW_REG_QPCR_LOWEST_CBS_BITS_SP1;
 448        policer_core->highest_bs_bits = MLXSW_REG_QPCR_HIGHEST_CBS_BITS_SP1;
 449
 450        return 0;
 451}
 452
 453const struct mlxsw_sp_policer_core_ops mlxsw_sp1_policer_core_ops = {
 454        .init = mlxsw_sp1_policer_core_init,
 455};
 456
 457static int
 458mlxsw_sp2_policer_core_init(struct mlxsw_sp_policer_core *policer_core)
 459{
 460        policer_core->lowest_bs_bits = MLXSW_REG_QPCR_LOWEST_CBS_BITS_SP2;
 461        policer_core->highest_bs_bits = MLXSW_REG_QPCR_HIGHEST_CBS_BITS_SP2;
 462
 463        return 0;
 464}
 465
 466const struct mlxsw_sp_policer_core_ops mlxsw_sp2_policer_core_ops = {
 467        .init = mlxsw_sp2_policer_core_init,
 468};
 469