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