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 */ 35 static int 36 mrvl_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 */ 71 int 72 mrvl_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 */ 90 void 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 */ 121 static struct mrvl_tm_node * 122 mrvl_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 */ 142 static int 143 mrvl_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 */ 173 static int 174 mrvl_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 */ 223 static int 224 mrvl_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 */ 289 static int 290 mrvl_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 */ 340 static struct mrvl_tm_shaper_profile * 341 mrvl_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 */ 361 static int 362 mrvl_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 */ 430 static int 431 mrvl_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 */ 466 static int 467 mrvl_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 */ 572 static int 573 mrvl_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 */ 661 static int 662 mrvl_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 */ 704 static 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 */ 724 static int 725 mrvl_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 */ 765 static int 766 mrvl_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 */ 801 static int 802 mrvl_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; 884 out: 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 */ 906 static int 907 mrvl_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 */ 977 static int 978 mrvl_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 1009 const 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