dpdk/drivers/net/mvpp2/mrvl_tm.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2018 Marvell International Ltd.
   3 * Copyright(c) 2018 Semihalf.
   4 * All rights reserved.
   5 */
   6
   7#include <rte_malloc.h>
   8
   9#include <linux/ethtool.h>
  10#include <linux/sockios.h>
  11#include <net/if.h>
  12#include <sys/ioctl.h>
  13
  14#include "mrvl_tm.h"
  15
  16/** Minimum rate value in Bytes/s */
  17#define MRVL_RATE_MIN (PP2_PPIO_MIN_CIR * 1000 / 8)
  18
  19/** Minimum burst size in Bytes */
  20#define MRVL_BURST_MIN (PP2_PPIO_MIN_CBS * 1000)
  21
  22/** Maximum burst size in Bytes */
  23#define MRVL_BURST_MAX 256000000
  24
  25/** Maximum WRR weight */
  26#define MRVL_WEIGHT_MAX 255
  27
  28/**
  29 * Get maximum port rate in Bytes/s.
  30 *
  31 * @param dev Pointer to the device.
  32 * @param rate Pointer to the rate.
  33 * @returns 0 on success, negative value otherwise.
  34 */
  35static int
  36mrvl_get_max_rate(struct rte_eth_dev *dev, uint64_t *rate)
  37{
  38        struct ethtool_cmd edata;
  39        struct ifreq req;
  40        int ret, fd;
  41
  42        memset(&edata, 0, sizeof(edata));
  43        memset(&req, 0, sizeof(req));
  44        edata.cmd = ETHTOOL_GSET;
  45        strcpy(req.ifr_name, dev->data->name);
  46        req.ifr_data = (void *)&edata;
  47
  48        fd = socket(AF_INET, SOCK_DGRAM, 0);
  49        if (fd == -1)
  50                return -1;
  51
  52        ret = ioctl(fd, SIOCETHTOOL, &req);
  53        if (ret == -1) {
  54                close(fd);
  55                return -1;
  56        }
  57
  58        close(fd);
  59
  60        *rate = (uint64_t)ethtool_cmd_speed(&edata) * 1000 * 1000 / 8;
  61
  62        return 0;
  63}
  64
  65/**
  66 * Initialize traffic manager related data.
  67 *
  68 * @param dev Pointer to the device.
  69 * @returns 0 on success, failure otherwise.
  70 */
  71int
  72mrvl_tm_init(struct rte_eth_dev *dev)
  73{
  74        struct mrvl_priv *priv = dev->data->dev_private;
  75
  76        LIST_INIT(&priv->shaper_profiles);
  77        LIST_INIT(&priv->nodes);
  78
  79        if (priv->rate_max)
  80                return 0;
  81
  82        return mrvl_get_max_rate(dev, &priv->rate_max);
  83}
  84
  85/**
  86 * Cleanup traffic manager related data.
  87 *
  88 * @param dev Pointer to the device.
  89 */
  90void mrvl_tm_deinit(struct rte_eth_dev *dev)
  91{
  92        struct mrvl_priv *priv = dev->data->dev_private;
  93        struct mrvl_tm_shaper_profile *profile =
  94                LIST_FIRST(&priv->shaper_profiles);
  95        struct mrvl_tm_node *node = LIST_FIRST(&priv->nodes);
  96
  97        while (profile) {
  98                struct mrvl_tm_shaper_profile *next = LIST_NEXT(profile, next);
  99
 100                LIST_REMOVE(profile, next);
 101                rte_free(profile);
 102                profile = next;
 103        }
 104
 105        while (node) {
 106                struct mrvl_tm_node *next = LIST_NEXT(node, next);
 107
 108                LIST_REMOVE(node, next);
 109                rte_free(node);
 110                node = next;
 111        }
 112}
 113
 114/**
 115 * Get node using its id.
 116 *
 117 * @param priv Pointer to the port's private data.
 118 * @param node_id Id used by this node.
 119 * @returns Pointer to the node if exists, NULL otherwise.
 120 */
 121static struct mrvl_tm_node *
 122mrvl_node_from_id(struct mrvl_priv *priv, uint32_t node_id)
 123{
 124        struct mrvl_tm_node *node;
 125
 126        LIST_FOREACH(node, &priv->nodes, next)
 127                if (node->id == node_id)
 128                        return node;
 129
 130        return NULL;
 131}
 132
 133/**
 134 * Check whether node is leaf or root.
 135 *
 136 * @param dev Pointer to the device.
 137 * @param node_id Id used by this node.
 138 * @param is_leaf Pointer to flag indicating whether node is a leaf.
 139 * @param error Pointer to the error.
 140 * @returns 0 on success, negative value otherwise.
 141 */
 142static int
 143mrvl_node_type_get(struct rte_eth_dev *dev, uint32_t node_id, int *is_leaf,
 144                   struct rte_tm_error *error)
 145{
 146        struct mrvl_priv *priv = dev->data->dev_private;
 147        struct mrvl_tm_node *node;
 148
 149        if (!priv->configured)
 150                return -rte_tm_error_set(error, ENODEV,
 151                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 152                                         NULL, "Port didn't configured\n");
 153
 154        if (!is_leaf)
 155                return -rte_tm_error_set(error, EINVAL,
 156                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 157                                         NULL, NULL);
 158
 159        node = mrvl_node_from_id(priv, node_id);
 160        if (!node)
 161                return -rte_tm_error_set(error, ENODEV,
 162                                         RTE_TM_ERROR_TYPE_NODE_ID,
 163                                         NULL, "Node id does not exist\n");
 164
 165        *is_leaf = node->type == MRVL_NODE_QUEUE ? 1 : 0;
 166
 167        return 0;
 168}
 169
 170/**
 171 * Get traffic manager capabilities.
 172 *
 173 * @param dev Pointer to the device (unused).
 174 * @param cap Pointer to the capabilities.
 175 * @param error Pointer to the error.
 176 * @returns 0 on success, negative value otherwise.
 177 */
 178static int
 179mrvl_capabilities_get(struct rte_eth_dev *dev,
 180                      struct rte_tm_capabilities *cap,
 181                      struct rte_tm_error *error)
 182{
 183        struct mrvl_priv *priv = dev->data->dev_private;
 184
 185        if (!priv->configured)
 186                return -rte_tm_error_set(error, ENODEV,
 187                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 188                                         NULL, "Port didn't configured\n");
 189
 190        if (!cap)
 191                return -rte_tm_error_set(error, EINVAL,
 192                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 193                                         NULL, "Capabilities are missing\n");
 194
 195        memset(cap, 0, sizeof(*cap));
 196
 197        cap->n_nodes_max = 1 + dev->data->nb_tx_queues; /* port + txqs number */
 198        cap->n_levels_max = 2; /* port level + txqs level */
 199        cap->non_leaf_nodes_identical = 1;
 200        cap->leaf_nodes_identical = 1;
 201
 202        cap->shaper_n_max = cap->n_nodes_max;
 203        cap->shaper_private_n_max = cap->shaper_n_max;
 204        cap->shaper_private_rate_min = MRVL_RATE_MIN;
 205        cap->shaper_private_rate_max = priv->rate_max;
 206        cap->shaper_private_packet_mode_supported = 0;
 207        cap->shaper_private_byte_mode_supported = 1;
 208
 209        cap->sched_n_children_max = dev->data->nb_tx_queues;
 210        cap->sched_sp_n_priorities_max = dev->data->nb_tx_queues;
 211        cap->sched_wfq_n_children_per_group_max = dev->data->nb_tx_queues;
 212        cap->sched_wfq_n_groups_max = 1;
 213        cap->sched_wfq_weight_max = MRVL_WEIGHT_MAX;
 214        cap->sched_wfq_packet_mode_supported = 0;
 215        cap->sched_wfq_byte_mode_supported = 1;
 216
 217        cap->dynamic_update_mask = RTE_TM_UPDATE_NODE_SUSPEND_RESUME |
 218                                   RTE_TM_UPDATE_NODE_STATS;
 219        cap->stats_mask = RTE_TM_STATS_N_PKTS | RTE_TM_STATS_N_BYTES;
 220
 221        return 0;
 222}
 223
 224/**
 225 * Get traffic manager hierarchy level capabilities.
 226 *
 227 * @param dev Pointer to the device.
 228 * @param level_id Id of the level.
 229 * @param cap Pointer to the level capabilities.
 230 * @param error Pointer to the error.
 231 * @returns 0 on success, negative value otherwise.
 232 */
 233static int
 234mrvl_level_capabilities_get(struct rte_eth_dev *dev,
 235                            uint32_t level_id,
 236                            struct rte_tm_level_capabilities *cap,
 237                            struct rte_tm_error *error)
 238{
 239        struct mrvl_priv *priv = dev->data->dev_private;
 240
 241        if (!priv->configured)
 242                return -rte_tm_error_set(error, ENODEV,
 243                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 244                                         NULL, "Port didn't configured\n");
 245
 246        if (!cap)
 247                return -rte_tm_error_set(error, EINVAL,
 248                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 249                                         NULL, NULL);
 250
 251        memset(cap, 0, sizeof(*cap));
 252
 253        if (level_id != MRVL_NODE_PORT && level_id != MRVL_NODE_QUEUE)
 254                return -rte_tm_error_set(error, EINVAL,
 255                                         RTE_TM_ERROR_TYPE_LEVEL_ID,
 256                                         NULL, "Wrong level id\n");
 257
 258        if (level_id == MRVL_NODE_PORT) {
 259                cap->n_nodes_max = 1;
 260                cap->n_nodes_nonleaf_max = 1;
 261                cap->non_leaf_nodes_identical = 1;
 262
 263                cap->nonleaf.shaper_private_supported = 1;
 264                cap->nonleaf.shaper_private_rate_min = MRVL_RATE_MIN;
 265                cap->nonleaf.shaper_private_rate_max = priv->rate_max;
 266                cap->nonleaf.shaper_private_packet_mode_supported = 0;
 267                cap->nonleaf.shaper_private_byte_mode_supported = 1;
 268
 269                cap->nonleaf.sched_n_children_max = dev->data->nb_tx_queues;
 270                cap->nonleaf.sched_sp_n_priorities_max = 1;
 271                cap->nonleaf.sched_wfq_n_children_per_group_max =
 272                        dev->data->nb_tx_queues;
 273                cap->nonleaf.sched_wfq_n_groups_max = 1;
 274                cap->nonleaf.sched_wfq_weight_max = MRVL_WEIGHT_MAX;
 275                cap->nonleaf.sched_wfq_packet_mode_supported = 0;
 276                cap->nonleaf.sched_wfq_byte_mode_supported = 1;
 277                cap->nonleaf.stats_mask = RTE_TM_STATS_N_PKTS |
 278                                          RTE_TM_STATS_N_BYTES;
 279        } else { /* level_id == MRVL_NODE_QUEUE */
 280                cap->n_nodes_max = dev->data->nb_tx_queues;
 281                cap->n_nodes_leaf_max = dev->data->nb_tx_queues;
 282                cap->leaf_nodes_identical = 1;
 283
 284                cap->leaf.shaper_private_supported = 1;
 285                cap->leaf.shaper_private_rate_min = MRVL_RATE_MIN;
 286                cap->leaf.shaper_private_rate_max = priv->rate_max;
 287                cap->leaf.shaper_private_packet_mode_supported = 0;
 288                cap->leaf.shaper_private_byte_mode_supported = 1;
 289                cap->leaf.stats_mask = RTE_TM_STATS_N_PKTS;
 290        }
 291
 292        return 0;
 293}
 294
 295/**
 296 * Get node capabilities.
 297 *
 298 * @param dev Pointer to the device.
 299 * @param node_id Id of the node.
 300 * @param cap Pointer to the capabilities.
 301 * @param error Pointer to the error.
 302 * @returns 0 on success, negative value otherwise.
 303 */
 304static int
 305mrvl_node_capabilities_get(struct rte_eth_dev *dev, uint32_t node_id,
 306                           struct rte_tm_node_capabilities *cap,
 307                           struct rte_tm_error *error)
 308{
 309        struct mrvl_priv *priv = dev->data->dev_private;
 310        struct mrvl_tm_node *node;
 311
 312        if (!priv->configured)
 313                return -rte_tm_error_set(error, ENODEV,
 314                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 315                                         NULL, "Port didn't configured\n");
 316
 317        if (!cap)
 318                return -rte_tm_error_set(error, EINVAL,
 319                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 320                                         NULL, NULL);
 321
 322        memset(cap, 0, sizeof(*cap));
 323
 324        node = mrvl_node_from_id(priv, node_id);
 325        if (!node)
 326                return -rte_tm_error_set(error, ENODEV,
 327                                         RTE_TM_ERROR_TYPE_NODE_ID,
 328                                         NULL, "Node id does not exist\n");
 329
 330        cap->shaper_private_supported = 1;
 331        cap->shaper_private_rate_min = MRVL_RATE_MIN;
 332        cap->shaper_private_rate_max = priv->rate_max;
 333        cap->shaper_private_packet_mode_supported = 0;
 334        cap->shaper_private_byte_mode_supported = 1;
 335
 336        if (node->type == MRVL_NODE_PORT) {
 337                cap->nonleaf.sched_n_children_max = dev->data->nb_tx_queues;
 338                cap->nonleaf.sched_sp_n_priorities_max = 1;
 339                cap->nonleaf.sched_wfq_n_children_per_group_max =
 340                        dev->data->nb_tx_queues;
 341                cap->nonleaf.sched_wfq_n_groups_max = 1;
 342                cap->nonleaf.sched_wfq_weight_max = MRVL_WEIGHT_MAX;
 343                cap->nonleaf.sched_wfq_packet_mode_supported = 0;
 344                cap->nonleaf.sched_wfq_byte_mode_supported = 1;
 345                cap->stats_mask = RTE_TM_STATS_N_PKTS | RTE_TM_STATS_N_BYTES;
 346        } else {
 347                cap->stats_mask = RTE_TM_STATS_N_PKTS;
 348        }
 349
 350        return 0;
 351}
 352
 353/**
 354 * Get shaper profile using its id.
 355 *
 356 * @param priv Pointer to the port's private data.
 357 * @param shaper_profile_id Id used by the shaper.
 358 * @returns Pointer to the shaper profile if exists, NULL otherwise.
 359 */
 360static struct mrvl_tm_shaper_profile *
 361mrvl_shaper_profile_from_id(struct mrvl_priv *priv, uint32_t shaper_profile_id)
 362{
 363        struct mrvl_tm_shaper_profile *profile;
 364
 365        LIST_FOREACH(profile, &priv->shaper_profiles, next)
 366                if (profile->id == shaper_profile_id)
 367                        return profile;
 368
 369        return NULL;
 370}
 371
 372/**
 373 * Add a new shaper profile.
 374 *
 375 * @param dev Pointer to the device.
 376 * @param shaper_profile_id Id of the new profile.
 377 * @param params Pointer to the shaper profile parameters.
 378 * @param error Pointer to the error.
 379 * @returns 0 on success, negative value otherwise.
 380 */
 381static int
 382mrvl_shaper_profile_add(struct rte_eth_dev *dev, uint32_t shaper_profile_id,
 383                        struct rte_tm_shaper_params *params,
 384                        struct rte_tm_error *error)
 385{
 386        struct mrvl_priv *priv = dev->data->dev_private;
 387        struct mrvl_tm_shaper_profile *profile;
 388
 389        if (!priv->configured)
 390                return -rte_tm_error_set(error, ENODEV,
 391                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 392                                         NULL, "Port didn't configured\n");
 393
 394        if (!params)
 395                return -rte_tm_error_set(error, EINVAL,
 396                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 397                                         NULL, NULL);
 398
 399        if (params->committed.rate)
 400                return -rte_tm_error_set(error, EINVAL,
 401                                RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE,
 402                                NULL, "Committed rate not supported\n");
 403
 404        if (params->committed.size)
 405                return -rte_tm_error_set(error, EINVAL,
 406                                RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE,
 407                                NULL, "Committed bucket size not supported\n");
 408
 409        if (params->peak.rate < MRVL_RATE_MIN ||
 410            params->peak.rate > priv->rate_max)
 411                return -rte_tm_error_set(error, EINVAL,
 412                                RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE,
 413                                NULL, "Peak rate is out of range\n");
 414
 415        if (params->peak.size < MRVL_BURST_MIN ||
 416            params->peak.size > MRVL_BURST_MAX)
 417                return -rte_tm_error_set(error, EINVAL,
 418                                RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE,
 419                                NULL, "Peak size is out of range\n");
 420
 421        if (shaper_profile_id == RTE_TM_SHAPER_PROFILE_ID_NONE)
 422                return -rte_tm_error_set(error, EINVAL,
 423                                         RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
 424                                         NULL, "Wrong shaper profile id\n");
 425
 426        profile = mrvl_shaper_profile_from_id(priv, shaper_profile_id);
 427        if (profile)
 428                return -rte_tm_error_set(error, EEXIST,
 429                                         RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
 430                                         NULL, "Profile id already exists\n");
 431
 432        profile = rte_zmalloc_socket(NULL, sizeof(*profile), 0,
 433                                     rte_socket_id());
 434        if (!profile)
 435                return -rte_tm_error_set(error, ENOMEM,
 436                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 437                                         NULL, NULL);
 438
 439        profile->id = shaper_profile_id;
 440        rte_memcpy(&profile->params, params, sizeof(profile->params));
 441
 442        LIST_INSERT_HEAD(&priv->shaper_profiles, profile, next);
 443
 444        return 0;
 445}
 446
 447/**
 448 * Remove a shaper profile.
 449 *
 450 * @param dev Pointer to the device.
 451 * @param shaper_profile_id Id of the shaper profile.
 452 * @param error Pointer to the error.
 453 * @returns 0 on success, negative value otherwise.
 454 */
 455static int
 456mrvl_shaper_profile_delete(struct rte_eth_dev *dev, uint32_t shaper_profile_id,
 457                           struct rte_tm_error *error)
 458{
 459        struct mrvl_priv *priv = dev->data->dev_private;
 460        struct mrvl_tm_shaper_profile *profile;
 461
 462        if (!priv->configured)
 463                return -rte_tm_error_set(error, ENODEV,
 464                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 465                                         NULL, "Port didn't configured\n");
 466
 467        profile = mrvl_shaper_profile_from_id(priv, shaper_profile_id);
 468        if (!profile)
 469                return -rte_tm_error_set(error, ENODEV,
 470                                         RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
 471                                         NULL, "Profile id does not exist\n");
 472
 473        if (profile->refcnt)
 474                return -rte_tm_error_set(error, EPERM,
 475                                         RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
 476                                         NULL, "Profile is used\n");
 477
 478        LIST_REMOVE(profile, next);
 479        rte_free(profile);
 480
 481        return 0;
 482}
 483
 484/**
 485 * Check node parameters.
 486 *
 487 * @param dev Pointer to the device.
 488 * @param node_id Id used by the node.
 489 * @param priority Priority value.
 490 * @param weight Weight value.
 491 * @param level_id Id of the level.
 492 * @param params Pointer to the node parameters.
 493 * @param error Pointer to the error.
 494 * @returns 0 on success, negative value otherwise.
 495 */
 496static int
 497mrvl_node_check_params(struct rte_eth_dev *dev, uint32_t node_id,
 498                       uint32_t priority, uint32_t weight, uint32_t level_id,
 499                       struct rte_tm_node_params *params,
 500                       struct rte_tm_error *error)
 501{
 502        if (node_id == RTE_TM_NODE_ID_NULL)
 503                return -rte_tm_error_set(error, EINVAL, RTE_TM_NODE_ID_NULL,
 504                                         NULL, "Node id is invalid\n");
 505
 506        if (priority)
 507                return -rte_tm_error_set(error, EINVAL,
 508                                         RTE_TM_ERROR_TYPE_NODE_PRIORITY,
 509                                         NULL, "Priority should be 0\n");
 510
 511        if (weight > MRVL_WEIGHT_MAX)
 512                return -rte_tm_error_set(error, EINVAL,
 513                                         RTE_TM_ERROR_TYPE_NODE_WEIGHT,
 514                                         NULL, "Weight is out of range\n");
 515
 516        if (level_id != MRVL_NODE_PORT && level_id != MRVL_NODE_QUEUE)
 517                return -rte_tm_error_set(error, EINVAL,
 518                                         RTE_TM_ERROR_TYPE_LEVEL_ID,
 519                                         NULL, "Wrong level id\n");
 520
 521        if (!params)
 522                return -rte_tm_error_set(error, EINVAL,
 523                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 524                                         NULL, NULL);
 525
 526        if (params->shared_shaper_id)
 527                return -rte_tm_error_set(error, EINVAL,
 528                                RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID,
 529                                NULL, "Shared shaper is not supported\n");
 530
 531        if (params->n_shared_shapers)
 532                return -rte_tm_error_set(error, EINVAL,
 533                                RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS,
 534                                NULL, "Shared shaper is not supported\n");
 535
 536        /* verify port (root node) settings */
 537        if (node_id >= dev->data->nb_tx_queues) {
 538                if (params->nonleaf.wfq_weight_mode)
 539                        return -rte_tm_error_set(error, EINVAL,
 540                                RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE,
 541                                NULL, "WFQ is not supported\n");
 542
 543                if (params->nonleaf.n_sp_priorities != 1)
 544                        return -rte_tm_error_set(error, EINVAL,
 545                                RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES,
 546                                NULL, "SP is not supported\n");
 547
 548                if (params->stats_mask & ~(RTE_TM_STATS_N_PKTS |
 549                                           RTE_TM_STATS_N_BYTES))
 550                        return -rte_tm_error_set(error, EINVAL,
 551                                RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
 552                                NULL,
 553                                "Requested port stats are not supported\n");
 554
 555                return 0;
 556        }
 557
 558        /* verify txq (leaf node) settings */
 559        if (params->leaf.cman)
 560                return -rte_tm_error_set(error, EINVAL,
 561                                         RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN,
 562                                         NULL,
 563                                         "Congestion mngmt is not supported\n");
 564
 565        if (params->leaf.wred.wred_profile_id)
 566                return -rte_tm_error_set(error, EINVAL,
 567                                RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID,
 568                                NULL, "WRED is not supported\n");
 569
 570        if (params->leaf.wred.shared_wred_context_id)
 571                return -rte_tm_error_set(error, EINVAL,
 572                        RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID,
 573                        NULL, "WRED is not supported\n");
 574
 575        if (params->leaf.wred.n_shared_wred_contexts)
 576                return -rte_tm_error_set(error, EINVAL,
 577                        RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS,
 578                        NULL, "WRED is not supported\n");
 579
 580        if (params->stats_mask & ~RTE_TM_STATS_N_PKTS)
 581                return -rte_tm_error_set(error, EINVAL,
 582                        RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
 583                        NULL,
 584                        "Requested txq stats are not supported\n");
 585
 586        return 0;
 587}
 588
 589/**
 590 * Add a new node.
 591 *
 592 * @param dev Pointer to the device.
 593 * @param node_id Id of the node.
 594 * @param parent_node_id Id of the parent node.
 595 * @param priority Priority value.
 596 * @param weight Weight value.
 597 * @param level_id Id of the level.
 598 * @param params Pointer to the node parameters.
 599 * @param error Pointer to the error.
 600 * @returns 0 on success, negative value otherwise.
 601 */
 602static int
 603mrvl_node_add(struct rte_eth_dev *dev, uint32_t node_id,
 604              uint32_t parent_node_id, uint32_t priority, uint32_t weight,
 605              uint32_t level_id, struct rte_tm_node_params *params,
 606              struct rte_tm_error *error)
 607{
 608        struct mrvl_priv *priv = dev->data->dev_private;
 609        struct mrvl_tm_shaper_profile *profile = NULL;
 610        struct mrvl_tm_node *node, *parent = NULL;
 611        int ret;
 612
 613        if (!priv->configured)
 614                return -rte_tm_error_set(error, ENODEV,
 615                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 616                                         NULL, "Port didn't configured\n");
 617
 618        if (priv->ppio)
 619                return -rte_tm_error_set(error, EPERM,
 620                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 621                                         NULL, "Port is already started\n");
 622
 623        ret = mrvl_node_check_params(dev, node_id, priority, weight, level_id,
 624                                     params, error);
 625        if (ret)
 626                return ret;
 627
 628        if (params->shaper_profile_id != RTE_TM_SHAPER_PROFILE_ID_NONE) {
 629                profile = mrvl_shaper_profile_from_id(priv,
 630                                                 params->shaper_profile_id);
 631                if (!profile)
 632                        return -rte_tm_error_set(error, ENODEV,
 633                                        RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
 634                                        NULL, "Shaper id does not exist\n");
 635        }
 636
 637        if (parent_node_id == RTE_TM_NODE_ID_NULL) {
 638                LIST_FOREACH(node, &priv->nodes, next) {
 639                        if (node->type != MRVL_NODE_PORT)
 640                                continue;
 641
 642                        return -rte_tm_error_set(error, EINVAL,
 643                                                 RTE_TM_ERROR_TYPE_UNSPECIFIED,
 644                                                 NULL, "Root node exists\n");
 645                }
 646        } else {
 647                parent = mrvl_node_from_id(priv, parent_node_id);
 648                if (!parent)
 649                        return -rte_tm_error_set(error, EINVAL,
 650                                        RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
 651                                        NULL, "Node id does not exist\n");
 652        }
 653
 654        node = mrvl_node_from_id(priv, node_id);
 655        if (node)
 656                return -rte_tm_error_set(error, ENODEV,
 657                                         RTE_TM_ERROR_TYPE_NODE_ID,
 658                                         NULL, "Node id already exists\n");
 659
 660        node = rte_zmalloc_socket(NULL, sizeof(*node), 0, rte_socket_id());
 661        if (!node)
 662                return -rte_tm_error_set(error, ENOMEM,
 663                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 664                                         NULL, NULL);
 665
 666        node->id = node_id;
 667        node->type = parent_node_id == RTE_TM_NODE_ID_NULL ? MRVL_NODE_PORT :
 668                                                             MRVL_NODE_QUEUE;
 669
 670        if (parent) {
 671                node->parent = parent;
 672                parent->refcnt++;
 673        }
 674
 675        if (profile) {
 676                node->profile = profile;
 677                profile->refcnt++;
 678        }
 679
 680        node->weight = weight;
 681        node->stats_mask = params->stats_mask;
 682
 683        LIST_INSERT_HEAD(&priv->nodes, node, next);
 684
 685        return 0;
 686}
 687
 688/**
 689 * Delete a node.
 690 *
 691 * @param dev Pointer to the device.
 692 * @param node_id Id of the node.
 693 * @param error Pointer to the error.
 694 * @returns 0 on success, negative value otherwise.
 695 */
 696static int
 697mrvl_node_delete(struct rte_eth_dev *dev, uint32_t node_id,
 698                 struct rte_tm_error *error)
 699{
 700        struct mrvl_priv *priv = dev->data->dev_private;
 701        struct mrvl_tm_node *node;
 702
 703        if (!priv->configured)
 704                return -rte_tm_error_set(error, ENODEV,
 705                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 706                                         NULL, "Port didn't configured\n");
 707
 708        if (priv->ppio) {
 709                return -rte_tm_error_set(error, EPERM,
 710                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 711                                         NULL, "Port is already started\n");
 712        }
 713
 714        node = mrvl_node_from_id(priv, node_id);
 715        if (!node)
 716                return -rte_tm_error_set(error, ENODEV,
 717                                         RTE_TM_ERROR_TYPE_NODE_ID,
 718                                         NULL, "Node id does not exist\n");
 719
 720        if (node->refcnt)
 721                return -rte_tm_error_set(error, EPERM,
 722                                         RTE_TM_ERROR_TYPE_NODE_ID,
 723                                         NULL, "Node id is used\n");
 724
 725        if (node->parent)
 726                node->parent->refcnt--;
 727
 728        if (node->profile)
 729                node->profile->refcnt--;
 730
 731        LIST_REMOVE(node, next);
 732        rte_free(node);
 733
 734        return 0;
 735}
 736
 737/**
 738 * Helper for suspending specific tx queue.
 739 *
 740 * @param dev Pointer to the device.
 741 * @param node_id Id used by this node.
 742 * @returns 0 on success, negative value otherwise.
 743 */
 744static int mrvl_node_suspend_one(struct rte_eth_dev *dev, uint32_t node_id,
 745                                 struct rte_tm_error *error)
 746{
 747        int ret = dev->dev_ops->tx_queue_stop(dev, node_id);
 748        if (ret)
 749                return -rte_tm_error_set(error, ret,
 750                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 751                                         NULL, "Failed to suspend a txq\n");
 752
 753        return 0;
 754}
 755
 756/**
 757 * Suspend a node.
 758 *
 759 * @param dev Pointer to the device.
 760 * @param node_id Id of the node.
 761 * @param error Pointer to the error.
 762 * returns 0 on success, negative value otherwise.
 763 */
 764static int
 765mrvl_node_suspend(struct rte_eth_dev *dev, uint32_t node_id,
 766                  struct rte_tm_error *error)
 767{
 768        struct mrvl_priv *priv = dev->data->dev_private;
 769        struct mrvl_tm_node *node, *tmp;
 770        int ret;
 771
 772        if (!priv->configured)
 773                return -rte_tm_error_set(error, ENODEV,
 774                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 775                                         NULL, "Port didn't configured\n");
 776
 777        node = mrvl_node_from_id(priv, node_id);
 778        if (!node)
 779                return -rte_tm_error_set(error, ENODEV,
 780                                         RTE_TM_ERROR_TYPE_NODE_ID,
 781                                         NULL, "Node id does not exist\n");
 782
 783        if (!node->parent) {
 784                LIST_FOREACH(tmp, &priv->nodes, next) {
 785                        if (!tmp->parent)
 786                                continue;
 787
 788                        if (node != tmp->parent)
 789                                continue;
 790
 791                        ret = mrvl_node_suspend_one(dev, tmp->id, error);
 792                        if (ret)
 793                                return ret;
 794                }
 795
 796                return 0;
 797        }
 798
 799        return mrvl_node_suspend_one(dev, node_id, error);
 800}
 801
 802/**
 803 * Resume a node.
 804 *
 805 * @param dev Pointer to the device.
 806 * @param node_id Id of the node.
 807 * @param error Pointer to the error.
 808 * returns 0 on success, negative value otherwise.
 809 */
 810static int
 811mrvl_node_resume(struct rte_eth_dev *dev, uint32_t node_id,
 812                 struct rte_tm_error *error)
 813{
 814        struct mrvl_priv *priv = dev->data->dev_private;
 815        struct mrvl_tm_node *node;
 816        int ret;
 817
 818        if (!priv->configured)
 819                return -rte_tm_error_set(error, ENODEV,
 820                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 821                                         NULL, "Port didn't configured\n");
 822
 823        node = mrvl_node_from_id(priv, node_id);
 824        if (!node)
 825                return -rte_tm_error_set(error, ENODEV,
 826                                         RTE_TM_ERROR_TYPE_NODE_ID,
 827                                         NULL, "Node id does not exist\n");
 828
 829
 830        if (!node->parent)
 831                return -rte_tm_error_set(error, EPERM,
 832                                         RTE_TM_ERROR_TYPE_NODE_ID,
 833                                         NULL, "Cannot suspend a port\n");
 834
 835        ret = dev->dev_ops->tx_queue_start(dev, node_id);
 836        if (ret)
 837                return -rte_tm_error_set(error, ret,
 838                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 839                                         NULL, "Failed to resume a txq\n");
 840        return 0;
 841}
 842
 843/**
 844 * Apply traffic manager hierarchy.
 845 *
 846 * @param dev Pointer to the device.
 847 * @param clear_on_fail Flag indicating whether to do cleanup on the failure.
 848 * @param error Pointer to the error.
 849 * @returns 0 on success, negative value otherwise.
 850 */
 851static int
 852mrvl_hierarchy_commit(struct rte_eth_dev *dev, int clear_on_fail,
 853                      struct rte_tm_error *error)
 854{
 855        struct mrvl_priv *priv = dev->data->dev_private;
 856        struct mrvl_tm_node *node;
 857        int ret;
 858
 859        if (!priv->configured)
 860                return -rte_tm_error_set(error, ENODEV,
 861                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 862                                         NULL, "Port didn't configured\n");
 863
 864        if (priv->ppio) {
 865                ret = -rte_tm_error_set(error, EPERM,
 866                                        RTE_TM_ERROR_TYPE_UNSPECIFIED,
 867                                        NULL, "Port is already started\n");
 868                goto out;
 869        }
 870
 871        LIST_FOREACH(node, &priv->nodes, next) {
 872                struct pp2_ppio_outq_params *p;
 873
 874                if (node->type == MRVL_NODE_PORT) {
 875                        if (!node->profile)
 876                                continue;
 877
 878                        priv->ppio_params.rate_limit_enable = 1;
 879                        priv->ppio_params.rate_limit_params.cir =
 880                                node->profile->params.peak.rate * 8 / 1000;
 881                        priv->ppio_params.rate_limit_params.cbs =
 882                                node->profile->params.peak.size / 1000;
 883
 884                        MRVL_LOG(INFO,
 885                                "Port rate limit overrides txqs rate limit");
 886
 887                        continue;
 888                }
 889
 890                if (node->id >= dev->data->nb_tx_queues) {
 891                        ret = -rte_tm_error_set(error, EINVAL,
 892                                        RTE_TM_ERROR_TYPE_NODE_ID, NULL,
 893                                        "Not enough txqs are configured\n");
 894                        goto out;
 895                }
 896
 897                p = &priv->ppio_params.outqs_params.outqs_params[node->id];
 898
 899                if (node->weight) {
 900                        p->sched_mode = PP2_PPIO_SCHED_M_WRR;
 901                        p->weight = node->weight;
 902                } else {
 903                        p->sched_mode = PP2_PPIO_SCHED_M_SP;
 904                        p->weight = 0;
 905                }
 906
 907                if (node->profile) {
 908                        p->rate_limit_enable = 1;
 909                        /* convert Bytes/s to kilo bits/s */
 910                        p->rate_limit_params.cir =
 911                                node->profile->params.peak.rate * 8 / 1000;
 912                        /* convert bits to kilo bits */
 913                        p->rate_limit_params.cbs =
 914                                node->profile->params.peak.size / 1000;
 915                } else {
 916                        p->rate_limit_enable = 0;
 917                        p->rate_limit_params.cir = 0;
 918                        p->rate_limit_params.cbs = 0;
 919                }
 920        }
 921
 922        /* reset to defaults in case applied tm hierarchy is empty */
 923        if (LIST_EMPTY(&priv->nodes)) {
 924                int i;
 925
 926                for (i = 0; i < priv->ppio_params.outqs_params.num_outqs; i++) {
 927                        struct pp2_ppio_outq_params *p =
 928                                &priv->ppio_params.outqs_params.outqs_params[i];
 929
 930                        p->sched_mode = PP2_PPIO_SCHED_M_WRR;
 931                        p->weight = 0;
 932                        p->rate_limit_enable = 0;
 933                        p->rate_limit_params.cir = 0;
 934                        p->rate_limit_params.cbs = 0;
 935                }
 936        }
 937
 938        return 0;
 939out:
 940        if (clear_on_fail) {
 941                mrvl_tm_deinit(dev);
 942                mrvl_tm_init(dev);
 943        }
 944
 945        return ret;
 946}
 947
 948/**
 949 * Read statistics counters for current node.
 950 *
 951 * @param dev Pointer to the device.
 952 * @param node_id Id of the node.
 953 * @param stats Pointer to the statistics counters.
 954 * @param stats_mask Pointer to mask of enabled statistics counters
 955 *                   that are retrieved.
 956 * @param clear Flag indicating whether to clear statistics.
 957 *              Non-zero value clears statistics.
 958 * @param error Pointer to the error.
 959 * @returns 0 on success, negative value otherwise.
 960 */
 961static int
 962mrvl_node_stats_read(struct rte_eth_dev *dev, uint32_t node_id,
 963                     struct rte_tm_node_stats *stats, uint64_t *stats_mask,
 964                     int clear, struct rte_tm_error *error)
 965{
 966        struct mrvl_priv *priv = dev->data->dev_private;
 967        struct mrvl_tm_node *node;
 968        int ret;
 969
 970        if (!priv->configured)
 971                return -rte_tm_error_set(error, ENODEV,
 972                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 973                                         NULL, "Port didn't configured\n");
 974
 975        if (!priv->ppio) {
 976                return -rte_tm_error_set(error, EPERM,
 977                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
 978                                         NULL, "Port is not started\n");
 979        }
 980
 981        node = mrvl_node_from_id(priv, node_id);
 982        if (!node)
 983                return -rte_tm_error_set(error, ENODEV,
 984                                         RTE_TM_ERROR_TYPE_NODE_ID,
 985                                         NULL, "Node id does not exist\n");
 986
 987        if (stats_mask)
 988                *stats_mask = node->stats_mask;
 989
 990        if (!stats)
 991                return 0;
 992
 993        memset(stats, 0, sizeof(*stats));
 994
 995        if (!node->parent) {
 996                struct pp2_ppio_statistics s;
 997
 998                memset(&s, 0, sizeof(s));
 999                ret = pp2_ppio_get_statistics(priv->ppio, &s, clear);
1000                if (ret)
1001                        return -rte_tm_error_set(error, -ret,
1002                                        RTE_TM_ERROR_TYPE_UNSPECIFIED, NULL,
1003                                        "Failed to read port statistics\n");
1004
1005                if (node->stats_mask & RTE_TM_STATS_N_PKTS)
1006                        stats->n_pkts = s.tx_packets;
1007
1008                if (node->stats_mask & RTE_TM_STATS_N_BYTES)
1009                        stats->n_bytes = s.tx_bytes;
1010        } else {
1011                struct pp2_ppio_outq_statistics s;
1012
1013                memset(&s, 0, sizeof(s));
1014                ret = pp2_ppio_outq_get_statistics(priv->ppio, node_id, &s,
1015                                                   clear);
1016                if (ret)
1017                        return -rte_tm_error_set(error, -ret,
1018                                        RTE_TM_ERROR_TYPE_UNSPECIFIED, NULL,
1019                                        "Failed to read txq statistics\n");
1020
1021                if (node->stats_mask & RTE_TM_STATS_N_PKTS)
1022                        stats->n_pkts = s.deq_desc;
1023        }
1024
1025        return 0;
1026}
1027
1028/**
1029 * Update node statistics.
1030 *
1031 * @param dev Pointer to the device.
1032 * @param node_id Id of the node.
1033 * @param stats_mask Bitmask of statistics counters to be enabled.
1034 * @param error Pointer to the error.
1035 * @returns 0 on success, negative value otherwise.
1036 */
1037static int
1038mrvl_node_stats_update(struct rte_eth_dev *dev, uint32_t node_id,
1039                       uint64_t stats_mask, struct rte_tm_error *error)
1040{
1041        struct mrvl_priv *priv = dev->data->dev_private;
1042        struct mrvl_tm_node *node;
1043
1044        if (!priv->configured)
1045                return -rte_tm_error_set(error, ENODEV,
1046                                         RTE_TM_ERROR_TYPE_UNSPECIFIED,
1047                                         NULL, "Port didn't configured\n");
1048
1049        node = mrvl_node_from_id(priv, node_id);
1050        if (!node)
1051                return -rte_tm_error_set(error, ENODEV,
1052                                         RTE_TM_ERROR_TYPE_NODE_ID,
1053                                         NULL, "Node id does not exist\n");
1054
1055        if (!node->parent) {
1056                if (stats_mask & ~(RTE_TM_STATS_N_PKTS | RTE_TM_STATS_N_BYTES))
1057                        return -rte_tm_error_set(error, EINVAL,
1058                                RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
1059                                NULL,
1060                                "Requested port stats are not supported\n");
1061        } else {
1062                if (stats_mask & ~RTE_TM_STATS_N_PKTS)
1063                        return -rte_tm_error_set(error, EINVAL,
1064                                RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
1065                                NULL,
1066                                "Requested txq stats are not supported\n");
1067        }
1068
1069        node->stats_mask = stats_mask;
1070
1071        return 0;
1072}
1073
1074const struct rte_tm_ops mrvl_tm_ops = {
1075        .node_type_get = mrvl_node_type_get,
1076        .capabilities_get = mrvl_capabilities_get,
1077        .level_capabilities_get = mrvl_level_capabilities_get,
1078        .node_capabilities_get = mrvl_node_capabilities_get,
1079        .shaper_profile_add = mrvl_shaper_profile_add,
1080        .shaper_profile_delete = mrvl_shaper_profile_delete,
1081        .node_add = mrvl_node_add,
1082        .node_delete = mrvl_node_delete,
1083        .node_suspend = mrvl_node_suspend,
1084        .node_resume = mrvl_node_resume,
1085        .hierarchy_commit = mrvl_hierarchy_commit,
1086        .node_stats_update = mrvl_node_stats_update,
1087        .node_stats_read = mrvl_node_stats_read,
1088};
1089