1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2021 6WIND S.A. 3 * Copyright 2021 Mellanox Technologies, Ltd 4 */ 5 6 #include <stdint.h> 7 #include <string.h> 8 #include <stdlib.h> 9 #include <unistd.h> 10 #ifndef RTE_EXEC_ENV_WINDOWS 11 #include <sys/socket.h> 12 #include <sys/un.h> 13 #endif 14 15 #include <rte_prefetch.h> 16 #include <rte_common.h> 17 #include <rte_branch_prediction.h> 18 #include <rte_ether.h> 19 #include <rte_alarm.h> 20 #include <rte_pmd_mlx5.h> 21 #include <rte_ethdev.h> 22 23 #include "mlx5_testpmd.h" 24 #include "testpmd.h" 25 26 static uint8_t host_shaper_avail_thresh_triggered[RTE_MAX_ETHPORTS]; 27 #define SHAPER_DISABLE_DELAY_US 100000 /* 100ms */ 28 29 /** 30 * Disable the host shaper and re-arm available descriptor threshold event. 31 * 32 * @param[in] args 33 * uint32_t integer combining port_id and rxq_id. 34 */ 35 static void 36 mlx5_test_host_shaper_disable(void *args) 37 { 38 uint32_t port_rxq_id = (uint32_t)(uintptr_t)args; 39 uint16_t port_id = port_rxq_id & 0xffff; 40 uint16_t qid = (port_rxq_id >> 16) & 0xffff; 41 struct rte_eth_rxq_info qinfo; 42 struct rte_port *port; 43 44 port = &ports[port_id]; 45 if (port->port_status != RTE_PORT_STARTED) { 46 printf("%s port_status(%d) is incorrect, stop avail_thresh " 47 "event processing.\n", 48 __func__, port->port_status); 49 return; 50 } 51 printf("%s disable shaper\n", __func__); 52 if (rte_eth_rx_queue_info_get(port_id, qid, &qinfo)) { 53 printf("rx_queue_info_get returns error\n"); 54 return; 55 } 56 /* Rearm the available descriptor threshold event. */ 57 if (rte_eth_rx_avail_thresh_set(port_id, qid, qinfo.avail_thresh)) { 58 printf("config avail_thresh returns error\n"); 59 return; 60 } 61 /* Only disable the shaper when avail_thresh_triggered is set. */ 62 if (host_shaper_avail_thresh_triggered[port_id] && 63 rte_pmd_mlx5_host_shaper_config(port_id, 0, 0)) 64 printf("%s disable shaper returns error\n", __func__); 65 } 66 67 void 68 mlx5_test_avail_thresh_event_handler(uint16_t port_id, uint16_t rxq_id) 69 { 70 struct rte_eth_dev_info dev_info; 71 uint32_t port_rxq_id = port_id | (rxq_id << 16); 72 73 /* Ensure it's MLX5 port. */ 74 if (rte_eth_dev_info_get(port_id, &dev_info) != 0 || 75 (strncmp(dev_info.driver_name, "mlx5", 4) != 0)) 76 return; 77 rte_eal_alarm_set(SHAPER_DISABLE_DELAY_US, 78 mlx5_test_host_shaper_disable, 79 (void *)(uintptr_t)port_rxq_id); 80 printf("%s port_id:%u rxq_id:%u\n", __func__, port_id, rxq_id); 81 } 82 83 /** 84 * Configure host shaper's avail_thresh_triggered and current rate. 85 * 86 * @param[in] avail_thresh_triggered 87 * Disable/enable avail_thresh_triggered. 88 * @param[in] rate 89 * Configure current host shaper rate. 90 * @return 91 * On success, returns 0. 92 * On failure, returns < 0. 93 */ 94 static int 95 mlx5_test_set_port_host_shaper(uint16_t port_id, uint16_t avail_thresh_triggered, uint8_t rate) 96 { 97 struct rte_eth_link link; 98 bool port_id_valid = false; 99 uint16_t pid; 100 int ret; 101 102 RTE_ETH_FOREACH_DEV(pid) 103 if (port_id == pid) { 104 port_id_valid = true; 105 break; 106 } 107 if (!port_id_valid) 108 return -EINVAL; 109 ret = rte_eth_link_get_nowait(port_id, &link); 110 if (ret < 0) 111 return ret; 112 host_shaper_avail_thresh_triggered[port_id] = avail_thresh_triggered ? 1 : 0; 113 if (!avail_thresh_triggered) { 114 ret = rte_pmd_mlx5_host_shaper_config(port_id, 0, 115 RTE_BIT32(MLX5_HOST_SHAPER_FLAG_AVAIL_THRESH_TRIGGERED)); 116 } else { 117 ret = rte_pmd_mlx5_host_shaper_config(port_id, 1, 118 RTE_BIT32(MLX5_HOST_SHAPER_FLAG_AVAIL_THRESH_TRIGGERED)); 119 } 120 if (ret) 121 return ret; 122 ret = rte_pmd_mlx5_host_shaper_config(port_id, rate, 0); 123 if (ret) 124 return ret; 125 return 0; 126 } 127 128 #ifndef RTE_EXEC_ENV_WINDOWS 129 static const char* 130 mlx5_test_get_socket_path(char *extend) 131 { 132 if (strstr(extend, "socket=") == extend) { 133 const char *socket_path = strchr(extend, '=') + 1; 134 135 TESTPMD_LOG(DEBUG, "MLX5 socket path is %s\n", socket_path); 136 return socket_path; 137 } 138 139 TESTPMD_LOG(ERR, "Failed to extract a valid socket path from %s\n", 140 extend); 141 return NULL; 142 } 143 144 static int 145 mlx5_test_extend_devargs(char *identifier, char *extend) 146 { 147 struct sockaddr_un un = { 148 .sun_family = AF_UNIX, 149 }; 150 int cmd_fd; 151 int pd_handle; 152 struct iovec iov = { 153 .iov_base = &pd_handle, 154 .iov_len = sizeof(int), 155 }; 156 union { 157 char buf[CMSG_SPACE(sizeof(int))]; 158 struct cmsghdr align; 159 } control; 160 struct msghdr msgh = { 161 .msg_iov = NULL, 162 .msg_iovlen = 0, 163 }; 164 struct cmsghdr *cmsg; 165 const char *path = mlx5_test_get_socket_path(extend + 1); 166 size_t len = 1; 167 int socket_fd; 168 int ret; 169 170 if (path == NULL) { 171 TESTPMD_LOG(ERR, "Invalid devargs extension is specified\n"); 172 return -1; 173 } 174 175 /* Initialize IPC channel. */ 176 socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); 177 if (socket_fd < 0) { 178 TESTPMD_LOG(ERR, "Failed to create unix socket: %s\n", 179 strerror(errno)); 180 return -1; 181 } 182 rte_strlcpy(un.sun_path, path, sizeof(un.sun_path)); 183 if (connect(socket_fd, (struct sockaddr *)&un, sizeof(un)) < 0) { 184 TESTPMD_LOG(ERR, "Failed to connect %s: %s\n", un.sun_path, 185 strerror(errno)); 186 close(socket_fd); 187 return -1; 188 } 189 190 /* Send the request message. */ 191 do { 192 ret = sendmsg(socket_fd, &msgh, 0); 193 } while (ret < 0 && errno == EINTR); 194 if (ret < 0) { 195 TESTPMD_LOG(ERR, "Failed to send request to (%s): %s\n", path, 196 strerror(errno)); 197 close(socket_fd); 198 return -1; 199 } 200 201 msgh.msg_iov = &iov; 202 msgh.msg_iovlen = 1; 203 msgh.msg_control = control.buf; 204 msgh.msg_controllen = sizeof(control.buf); 205 do { 206 ret = recvmsg(socket_fd, &msgh, 0); 207 } while (ret < 0); 208 if (ret != sizeof(int) || (msgh.msg_flags & (MSG_TRUNC | MSG_CTRUNC))) { 209 TESTPMD_LOG(ERR, "truncated msg"); 210 close(socket_fd); 211 return -1; 212 } 213 214 /* Translate the FD. */ 215 cmsg = CMSG_FIRSTHDR(&msgh); 216 if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || 217 cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { 218 TESTPMD_LOG(ERR, "Fail to get FD using SCM_RIGHTS mechanism\n"); 219 close(socket_fd); 220 unlink(un.sun_path); 221 return -1; 222 } 223 memcpy(&cmd_fd, CMSG_DATA(cmsg), sizeof(int)); 224 225 TESTPMD_LOG(DEBUG, "Command FD (%d) and PD handle (%d) " 226 "are successfully imported from remote process\n", 227 cmd_fd, pd_handle); 228 229 /* Cleanup IPC channel. */ 230 close(socket_fd); 231 232 /* Calculate the new length of devargs string. */ 233 len += snprintf(NULL, 0, ",cmd_fd=%d,pd_handle=%d", cmd_fd, pd_handle); 234 /* Extend the devargs string. */ 235 snprintf(extend, len, ",cmd_fd=%d,pd_handle=%d", cmd_fd, pd_handle); 236 237 TESTPMD_LOG(DEBUG, "Attach port with extra devargs %s\n", identifier); 238 return 0; 239 } 240 241 static bool 242 is_delimiter_path_spaces(char *extend) 243 { 244 while (*extend != '\0') { 245 if (*extend != ' ') 246 return true; 247 extend++; 248 } 249 return false; 250 } 251 252 /* 253 * Extend devargs list with "cmd_fd" and "pd_handle" coming from external 254 * process. It happens only in this format: 255 * testpmd> mlx5 port attach (identifier) socket=<socket path> 256 * all "(identifier) socket=<socket path>" is in the same string pointed 257 * by the input parameter 'identifier'. 258 * 259 * @param identifier 260 * Identifier of port attach command line. 261 */ 262 static void 263 mlx5_test_attach_port_extend_devargs(char *identifier) 264 { 265 char *extend; 266 267 if (identifier == NULL) { 268 fprintf(stderr, "Invalid parameters are specified\n"); 269 return; 270 } 271 272 extend = strchr(identifier, ' '); 273 if (extend != NULL && is_delimiter_path_spaces(extend) && 274 mlx5_test_extend_devargs(identifier, extend) < 0) { 275 TESTPMD_LOG(ERR, "Failed to extend devargs for port %s\n", 276 identifier); 277 return; 278 } 279 280 attach_port(identifier); 281 } 282 #endif 283 284 /* *** SET HOST_SHAPER FOR A PORT *** */ 285 struct cmd_port_host_shaper_result { 286 cmdline_fixed_string_t mlx5; 287 cmdline_fixed_string_t set; 288 cmdline_fixed_string_t port; 289 uint16_t port_num; 290 cmdline_fixed_string_t host_shaper; 291 cmdline_fixed_string_t avail_thresh_triggered; 292 uint16_t fr; 293 cmdline_fixed_string_t rate; 294 uint8_t rate_num; 295 }; 296 297 static void cmd_port_host_shaper_parsed(void *parsed_result, 298 __rte_unused struct cmdline *cl, 299 __rte_unused void *data) 300 { 301 struct cmd_port_host_shaper_result *res = parsed_result; 302 int ret = 0; 303 304 if ((strcmp(res->mlx5, "mlx5") == 0) && 305 (strcmp(res->set, "set") == 0) && 306 (strcmp(res->port, "port") == 0) && 307 (strcmp(res->host_shaper, "host_shaper") == 0) && 308 (strcmp(res->avail_thresh_triggered, "avail_thresh_triggered") == 0) && 309 (strcmp(res->rate, "rate") == 0)) 310 ret = mlx5_test_set_port_host_shaper(res->port_num, res->fr, 311 res->rate_num); 312 if (ret < 0) 313 printf("cmd_port_host_shaper error: (%s)\n", strerror(-ret)); 314 } 315 316 static cmdline_parse_token_string_t cmd_port_host_shaper_mlx5 = 317 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, 318 mlx5, "mlx5"); 319 static cmdline_parse_token_string_t cmd_port_host_shaper_set = 320 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, 321 set, "set"); 322 static cmdline_parse_token_string_t cmd_port_host_shaper_port = 323 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, 324 port, "port"); 325 static cmdline_parse_token_num_t cmd_port_host_shaper_portnum = 326 TOKEN_NUM_INITIALIZER(struct cmd_port_host_shaper_result, 327 port_num, RTE_UINT16); 328 static cmdline_parse_token_string_t cmd_port_host_shaper_host_shaper = 329 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, 330 host_shaper, "host_shaper"); 331 static cmdline_parse_token_string_t cmd_port_host_shaper_avail_thresh_triggered = 332 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, 333 avail_thresh_triggered, "avail_thresh_triggered"); 334 static cmdline_parse_token_num_t cmd_port_host_shaper_fr = 335 TOKEN_NUM_INITIALIZER(struct cmd_port_host_shaper_result, 336 fr, RTE_UINT16); 337 static cmdline_parse_token_string_t cmd_port_host_shaper_rate = 338 TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, 339 rate, "rate"); 340 static cmdline_parse_token_num_t cmd_port_host_shaper_rate_num = 341 TOKEN_NUM_INITIALIZER(struct cmd_port_host_shaper_result, 342 rate_num, RTE_UINT8); 343 static cmdline_parse_inst_t mlx5_test_cmd_port_host_shaper = { 344 .f = cmd_port_host_shaper_parsed, 345 .data = (void *)0, 346 .help_str = "mlx5 set port <port_id> host_shaper avail_thresh_triggered <0|1> " 347 "rate <rate_num>: Set HOST_SHAPER avail_thresh_triggered and rate with port_id", 348 .tokens = { 349 (void *)&cmd_port_host_shaper_mlx5, 350 (void *)&cmd_port_host_shaper_set, 351 (void *)&cmd_port_host_shaper_port, 352 (void *)&cmd_port_host_shaper_portnum, 353 (void *)&cmd_port_host_shaper_host_shaper, 354 (void *)&cmd_port_host_shaper_avail_thresh_triggered, 355 (void *)&cmd_port_host_shaper_fr, 356 (void *)&cmd_port_host_shaper_rate, 357 (void *)&cmd_port_host_shaper_rate_num, 358 NULL, 359 } 360 }; 361 362 #ifndef RTE_EXEC_ENV_WINDOWS 363 /* *** attach a specified port *** */ 364 struct mlx5_cmd_operate_attach_port_result { 365 cmdline_fixed_string_t mlx5; 366 cmdline_fixed_string_t port; 367 cmdline_fixed_string_t keyword; 368 cmdline_multi_string_t identifier; 369 }; 370 371 static void mlx5_cmd_operate_attach_port_parsed(void *parsed_result, 372 __rte_unused struct cmdline *cl, 373 __rte_unused void *data) 374 { 375 struct mlx5_cmd_operate_attach_port_result *res = parsed_result; 376 377 if (!strcmp(res->keyword, "attach")) 378 mlx5_test_attach_port_extend_devargs(res->identifier); 379 else 380 fprintf(stderr, "Unknown parameter\n"); 381 } 382 383 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_mlx5 = 384 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result, 385 mlx5, "mlx5"); 386 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_port = 387 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result, 388 port, "port"); 389 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_keyword = 390 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result, 391 keyword, "attach"); 392 static cmdline_parse_token_string_t mlx5_cmd_operate_attach_port_identifier = 393 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_operate_attach_port_result, 394 identifier, TOKEN_STRING_MULTI); 395 396 static cmdline_parse_inst_t mlx5_cmd_operate_attach_port = { 397 .f = mlx5_cmd_operate_attach_port_parsed, 398 .data = NULL, 399 .help_str = "mlx5 port attach <identifier> socket=<path>: " 400 "(identifier: pci address or virtual dev name" 401 ", path (optional): socket path to get cmd FD and PD handle)", 402 .tokens = { 403 (void *)&mlx5_cmd_operate_attach_port_mlx5, 404 (void *)&mlx5_cmd_operate_attach_port_port, 405 (void *)&mlx5_cmd_operate_attach_port_keyword, 406 (void *)&mlx5_cmd_operate_attach_port_identifier, 407 NULL, 408 }, 409 }; 410 #endif 411 412 /* Map HW queue index to rte queue index. */ 413 struct mlx5_cmd_map_ext_rxq { 414 cmdline_fixed_string_t mlx5; 415 cmdline_fixed_string_t port; 416 portid_t port_id; 417 cmdline_fixed_string_t ext_rxq; 418 cmdline_fixed_string_t map; 419 uint16_t sw_queue_id; 420 uint32_t hw_queue_id; 421 }; 422 423 cmdline_parse_token_string_t mlx5_cmd_map_ext_rxq_mlx5 = 424 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_map_ext_rxq, mlx5, "mlx5"); 425 cmdline_parse_token_string_t mlx5_cmd_map_ext_rxq_port = 426 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_map_ext_rxq, port, "port"); 427 cmdline_parse_token_num_t mlx5_cmd_map_ext_rxq_port_id = 428 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_map_ext_rxq, port_id, RTE_UINT16); 429 cmdline_parse_token_string_t mlx5_cmd_map_ext_rxq_ext_rxq = 430 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_map_ext_rxq, ext_rxq, 431 "ext_rxq"); 432 cmdline_parse_token_string_t mlx5_cmd_map_ext_rxq_map = 433 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_map_ext_rxq, map, "map"); 434 cmdline_parse_token_num_t mlx5_cmd_map_ext_rxq_sw_queue_id = 435 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_map_ext_rxq, sw_queue_id, 436 RTE_UINT16); 437 cmdline_parse_token_num_t mlx5_cmd_map_ext_rxq_hw_queue_id = 438 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_map_ext_rxq, hw_queue_id, 439 RTE_UINT32); 440 441 static void 442 mlx5_cmd_map_ext_rxq_parsed(void *parsed_result, 443 __rte_unused struct cmdline *cl, 444 __rte_unused void *data) 445 { 446 struct mlx5_cmd_map_ext_rxq *res = parsed_result; 447 int ret; 448 449 if (port_id_is_invalid(res->port_id, ENABLED_WARN)) 450 return; 451 ret = rte_pmd_mlx5_external_rx_queue_id_map(res->port_id, 452 res->sw_queue_id, 453 res->hw_queue_id); 454 switch (ret) { 455 case 0: 456 break; 457 case -EINVAL: 458 fprintf(stderr, "invalid ethdev index (%u), out of range\n", 459 res->sw_queue_id); 460 break; 461 case -ENODEV: 462 fprintf(stderr, "invalid port_id %u\n", res->port_id); 463 break; 464 case -ENOTSUP: 465 fprintf(stderr, "function not implemented or supported\n"); 466 break; 467 case -EEXIST: 468 fprintf(stderr, "mapping with index %u already exists\n", 469 res->sw_queue_id); 470 break; 471 default: 472 fprintf(stderr, "programming error: (%s)\n", strerror(-ret)); 473 } 474 } 475 476 cmdline_parse_inst_t mlx5_cmd_map_ext_rxq = { 477 .f = mlx5_cmd_map_ext_rxq_parsed, 478 .data = NULL, 479 .help_str = "mlx5 port <port_id> ext_rxq map <sw_queue_id> <hw_queue_id>", 480 .tokens = { 481 (void *)&mlx5_cmd_map_ext_rxq_mlx5, 482 (void *)&mlx5_cmd_map_ext_rxq_port, 483 (void *)&mlx5_cmd_map_ext_rxq_port_id, 484 (void *)&mlx5_cmd_map_ext_rxq_ext_rxq, 485 (void *)&mlx5_cmd_map_ext_rxq_map, 486 (void *)&mlx5_cmd_map_ext_rxq_sw_queue_id, 487 (void *)&mlx5_cmd_map_ext_rxq_hw_queue_id, 488 NULL, 489 } 490 }; 491 492 /* Unmap HW queue index to rte queue index. */ 493 struct mlx5_cmd_unmap_ext_rxq { 494 cmdline_fixed_string_t mlx5; 495 cmdline_fixed_string_t port; 496 portid_t port_id; 497 cmdline_fixed_string_t ext_rxq; 498 cmdline_fixed_string_t unmap; 499 uint16_t queue_id; 500 }; 501 502 cmdline_parse_token_string_t mlx5_cmd_unmap_ext_rxq_mlx5 = 503 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, mlx5, "mlx5"); 504 cmdline_parse_token_string_t mlx5_cmd_unmap_ext_rxq_port = 505 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, port, "port"); 506 cmdline_parse_token_num_t mlx5_cmd_unmap_ext_rxq_port_id = 507 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, port_id, 508 RTE_UINT16); 509 cmdline_parse_token_string_t mlx5_cmd_unmap_ext_rxq_ext_rxq = 510 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, ext_rxq, 511 "ext_rxq"); 512 cmdline_parse_token_string_t mlx5_cmd_unmap_ext_rxq_unmap = 513 TOKEN_STRING_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, unmap, "unmap"); 514 cmdline_parse_token_num_t mlx5_cmd_unmap_ext_rxq_queue_id = 515 TOKEN_NUM_INITIALIZER(struct mlx5_cmd_unmap_ext_rxq, queue_id, 516 RTE_UINT16); 517 518 static void 519 mlx5_cmd_unmap_ext_rxq_parsed(void *parsed_result, 520 __rte_unused struct cmdline *cl, 521 __rte_unused void *data) 522 { 523 struct mlx5_cmd_unmap_ext_rxq *res = parsed_result; 524 int ret; 525 526 if (port_id_is_invalid(res->port_id, ENABLED_WARN)) 527 return; 528 ret = rte_pmd_mlx5_external_rx_queue_id_unmap(res->port_id, 529 res->queue_id); 530 switch (ret) { 531 case 0: 532 break; 533 case -EINVAL: 534 fprintf(stderr, "invalid rte_flow index (%u), " 535 "out of range, doesn't exist or still referenced\n", 536 res->queue_id); 537 break; 538 case -ENODEV: 539 fprintf(stderr, "invalid port_id %u\n", res->port_id); 540 break; 541 case -ENOTSUP: 542 fprintf(stderr, "function not implemented or supported\n"); 543 break; 544 default: 545 fprintf(stderr, "programming error: (%s)\n", strerror(-ret)); 546 } 547 } 548 549 cmdline_parse_inst_t mlx5_cmd_unmap_ext_rxq = { 550 .f = mlx5_cmd_unmap_ext_rxq_parsed, 551 .data = NULL, 552 .help_str = "mlx5 port <port_id> ext_rxq unmap <queue_id>", 553 .tokens = { 554 (void *)&mlx5_cmd_unmap_ext_rxq_mlx5, 555 (void *)&mlx5_cmd_unmap_ext_rxq_port, 556 (void *)&mlx5_cmd_unmap_ext_rxq_port_id, 557 (void *)&mlx5_cmd_unmap_ext_rxq_ext_rxq, 558 (void *)&mlx5_cmd_unmap_ext_rxq_unmap, 559 (void *)&mlx5_cmd_unmap_ext_rxq_queue_id, 560 NULL, 561 } 562 }; 563 564 static struct testpmd_driver_commands mlx5_driver_cmds = { 565 .commands = { 566 { 567 .ctx = &mlx5_test_cmd_port_host_shaper, 568 .help = "mlx5 set port (port_id) host_shaper avail_thresh_triggered (on|off)" 569 "rate (rate_num):\n" 570 " Set HOST_SHAPER avail_thresh_triggered and rate with port_id\n\n", 571 }, 572 #ifndef RTE_EXEC_ENV_WINDOWS 573 { 574 .ctx = &mlx5_cmd_operate_attach_port, 575 .help = "mlx5 port attach (ident) socket=(path)\n" 576 " Attach physical or virtual dev by pci address or virtual device name " 577 "and add \"cmd_fd\" and \"pd_handle\" devargs before attaching\n\n", 578 }, 579 #endif 580 { 581 .ctx = &mlx5_cmd_map_ext_rxq, 582 .help = "mlx5 port (port_id) ext_rxq map (sw_queue_id) (hw_queue_id)\n" 583 " Map HW queue index (32-bit) to ethdev" 584 " queue index (16-bit) for external RxQ\n\n", 585 }, 586 { 587 .ctx = &mlx5_cmd_unmap_ext_rxq, 588 .help = "mlx5 port (port_id) ext_rxq unmap (sw_queue_id)\n" 589 " Unmap external Rx queue ethdev index mapping\n\n", 590 }, 591 { 592 .ctx = NULL, 593 }, 594 } 595 }; 596 TESTPMD_ADD_DRIVER_COMMANDS(mlx5_driver_cmds); 597