@@ -284,6 +284,9 @@ static void cmd_help_long_parsed(void *parsed_result,
"dump_log_types\n"
" Dumps the log level for all the dpdk modules\n\n"
+
+ "show port (port_id) speed_lanes capabilities"
+ " Show speed lanes capabilities of a port.\n\n"
);
}
@@ -823,6 +826,9 @@ static void cmd_help_long_parsed(void *parsed_result,
"port config (port_id) txq (queue_id) affinity (value)\n"
" Map a Tx queue with an aggregated port "
"of the DPDK port\n\n"
+
+ "port config (port_id|all) speed_lanes (0|1|4|8)\n"
+ " Set number of lanes for all ports or port_id for a forced speed\n\n"
);
}
@@ -1560,6 +1566,244 @@ static cmdline_parse_inst_t cmd_config_speed_specific = {
},
};
+static int
+parse_speed_lanes_cfg(portid_t pid, uint32_t lanes)
+{
+ int ret;
+
+ ret = rte_eth_speed_lanes_set(pid, lanes);
+ if (ret == -ENOTSUP) {
+ fprintf(stderr, "Function not implemented\n");
+ return -1;
+ } else if (ret < 0) {
+ fprintf(stderr, "Set speed lanes failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+show_speed_lanes_capability(unsigned int num, struct rte_eth_speed_lanes_capa *speed_lanes_capa)
+{
+ unsigned int i;
+ uint32_t capa;
+
+ printf("\n%-15s %-10s", "Supported-speeds", "Valid-lanes");
+ printf("\n-----------------------------------\n");
+ for (i = 0; i < num; i++) {
+ printf("%-17s ",
+ rte_eth_link_speed_to_str(speed_lanes_capa[i].speed));
+ capa = speed_lanes_capa[i].capa;
+ int s = 0;
+
+ while (capa) {
+ if (capa & 0x1)
+ printf("%-2d ", s);
+ s++;
+ capa = capa >> 1;
+ }
+ printf("\n");
+ }
+}
+
+/* *** display speed lanes per port capabilities *** */
+struct cmd_show_speed_lanes_result {
+ cmdline_fixed_string_t cmd_show;
+ cmdline_fixed_string_t cmd_port;
+ cmdline_fixed_string_t cmd_keyword;
+ portid_t cmd_pid;
+};
+
+static void
+cmd_show_speed_lanes_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_show_speed_lanes_result *res = parsed_result;
+ struct rte_eth_speed_lanes_capa *speed_lanes_capa;
+ unsigned int num;
+ int ret;
+
+ if (!rte_eth_dev_is_valid_port(res->cmd_pid)) {
+ fprintf(stderr, "Invalid port id %u\n", res->cmd_pid);
+ return;
+ }
+
+ ret = rte_eth_speed_lanes_get_capability(res->cmd_pid, NULL, 0);
+ if (ret == -ENOTSUP) {
+ fprintf(stderr, "Function not implemented\n");
+ return;
+ } else if (ret < 0) {
+ fprintf(stderr, "Get speed lanes capability failed: %d\n", ret);
+ return;
+ }
+
+ num = (unsigned int)ret;
+ speed_lanes_capa = calloc(num, sizeof(*speed_lanes_capa));
+ if (speed_lanes_capa == NULL) {
+ fprintf(stderr, "Failed to alloc speed lanes capability buffer\n");
+ return;
+ }
+
+ ret = rte_eth_speed_lanes_get_capability(res->cmd_pid, speed_lanes_capa, num);
+ if (ret < 0) {
+ fprintf(stderr, "Error getting speed lanes capability: %d\n", ret);
+ goto out;
+ }
+
+ show_speed_lanes_capability(num, speed_lanes_capa);
+out:
+ free(speed_lanes_capa);
+}
+
+static cmdline_parse_token_string_t cmd_show_speed_lanes_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_speed_lanes_result,
+ cmd_show, "show");
+static cmdline_parse_token_string_t cmd_show_speed_lanes_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_speed_lanes_result,
+ cmd_port, "port");
+static cmdline_parse_token_num_t cmd_show_speed_lanes_pid =
+ TOKEN_NUM_INITIALIZER(struct cmd_show_speed_lanes_result,
+ cmd_pid, RTE_UINT16);
+static cmdline_parse_token_string_t cmd_show_speed_lanes_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_speed_lanes_result,
+ cmd_keyword, "speed_lanes");
+static cmdline_parse_token_string_t cmd_show_speed_lanes_cap_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_speed_lanes_result,
+ cmd_keyword, "capabilities");
+
+static cmdline_parse_inst_t cmd_show_speed_lanes = {
+ .f = cmd_show_speed_lanes_parsed,
+ .data = NULL,
+ .help_str = "show port <port_id> speed_lanes capabilities",
+ .tokens = {
+ (void *)&cmd_show_speed_lanes_show,
+ (void *)&cmd_show_speed_lanes_port,
+ (void *)&cmd_show_speed_lanes_pid,
+ (void *)&cmd_show_speed_lanes_keyword,
+ (void *)&cmd_show_speed_lanes_cap_keyword,
+ NULL,
+ },
+};
+
+/* *** configure speed_lanes for all ports *** */
+struct cmd_config_speed_lanes_all {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ cmdline_fixed_string_t all;
+ cmdline_fixed_string_t item;
+ uint32_t lanes;
+};
+
+static void
+cmd_config_speed_lanes_all_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_speed_lanes_all *res = parsed_result;
+ portid_t pid;
+
+ if (!all_ports_stopped()) {
+ fprintf(stderr, "Please stop all ports first\n");
+ return;
+ }
+
+ RTE_ETH_FOREACH_DEV(pid) {
+ if (parse_speed_lanes_cfg(pid, res->lanes))
+ return;
+ }
+
+ cmd_reconfig_device_queue(RTE_PORT_ALL, 1, 1);
+}
+
+static cmdline_parse_token_string_t cmd_config_speed_lanes_all_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_lanes_all, port, "port");
+static cmdline_parse_token_string_t cmd_config_speed_lanes_all_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_lanes_all, keyword,
+ "config");
+static cmdline_parse_token_string_t cmd_config_speed_lanes_all_all =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_lanes_all, all, "all");
+static cmdline_parse_token_string_t cmd_config_speed_lanes_all_item =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_lanes_all, item,
+ "speed_lanes");
+static cmdline_parse_token_num_t cmd_config_speed_lanes_all_lanes =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_speed_lanes_all, lanes, RTE_UINT32);
+
+static cmdline_parse_inst_t cmd_config_speed_lanes_all = {
+ .f = cmd_config_speed_lanes_all_parsed,
+ .data = NULL,
+ .help_str = "port config all speed_lanes <value>",
+ .tokens = {
+ (void *)&cmd_config_speed_lanes_all_port,
+ (void *)&cmd_config_speed_lanes_all_keyword,
+ (void *)&cmd_config_speed_lanes_all_all,
+ (void *)&cmd_config_speed_lanes_all_item,
+ (void *)&cmd_config_speed_lanes_all_lanes,
+ NULL,
+ },
+};
+
+/* *** configure speed_lanes for specific port *** */
+struct cmd_config_speed_lanes_specific {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t keyword;
+ uint16_t port_id;
+ cmdline_fixed_string_t item;
+ uint32_t lanes;
+};
+
+static void
+cmd_config_speed_lanes_specific_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_config_speed_lanes_specific *res = parsed_result;
+
+ if (port_id_is_invalid(res->port_id, ENABLED_WARN))
+ return;
+
+ if (!port_is_stopped(res->port_id)) {
+ fprintf(stderr, "Please stop port %u first\n", res->port_id);
+ return;
+ }
+
+ if (parse_speed_lanes_cfg(res->port_id, res->lanes))
+ return;
+
+ cmd_reconfig_device_queue(res->port_id, 1, 1);
+}
+
+static cmdline_parse_token_string_t cmd_config_speed_lanes_specific_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_lanes_specific, port,
+ "port");
+static cmdline_parse_token_string_t cmd_config_speed_lanes_specific_keyword =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_lanes_specific, keyword,
+ "config");
+static cmdline_parse_token_num_t cmd_config_speed_lanes_specific_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_speed_lanes_specific, port_id,
+ RTE_UINT16);
+static cmdline_parse_token_string_t cmd_config_speed_lanes_specific_item =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_lanes_specific, item,
+ "speed_lanes");
+static cmdline_parse_token_num_t cmd_config_speed_lanes_specific_lanes =
+ TOKEN_NUM_INITIALIZER(struct cmd_config_speed_lanes_specific, lanes,
+ RTE_UINT32);
+
+static cmdline_parse_inst_t cmd_config_speed_lanes_specific = {
+ .f = cmd_config_speed_lanes_specific_parsed,
+ .data = NULL,
+ .help_str = "port config <port_id> speed_lanes <value>",
+ .tokens = {
+ (void *)&cmd_config_speed_lanes_specific_port,
+ (void *)&cmd_config_speed_lanes_specific_keyword,
+ (void *)&cmd_config_speed_lanes_specific_id,
+ (void *)&cmd_config_speed_lanes_specific_item,
+ (void *)&cmd_config_speed_lanes_specific_lanes,
+ NULL,
+ },
+};
+
/* *** configure loopback for all ports *** */
struct cmd_config_loopback_all {
cmdline_fixed_string_t port;
@@ -1645,7 +1889,6 @@ cmd_config_loopback_specific_parsed(void *parsed_result,
cmd_reconfig_device_queue(res->port_id, 1, 1);
}
-
static cmdline_parse_token_string_t cmd_config_loopback_specific_port =
TOKEN_STRING_INITIALIZER(struct cmd_config_loopback_specific, port,
"port");
@@ -13238,6 +13481,9 @@ static cmdline_parse_ctx_t builtin_ctx[] = {
(cmdline_parse_inst_t *)&cmd_set_port_setup_on,
(cmdline_parse_inst_t *)&cmd_config_speed_all,
(cmdline_parse_inst_t *)&cmd_config_speed_specific,
+ (cmdline_parse_inst_t *)&cmd_config_speed_lanes_all,
+ (cmdline_parse_inst_t *)&cmd_config_speed_lanes_specific,
+ (cmdline_parse_inst_t *)&cmd_show_speed_lanes,
(cmdline_parse_inst_t *)&cmd_config_loopback_all,
(cmdline_parse_inst_t *)&cmd_config_loopback_specific,
(cmdline_parse_inst_t *)&cmd_config_rx_tx,
@@ -786,6 +786,7 @@ port_infos_display(portid_t port_id)
char name[RTE_ETH_NAME_MAX_LEN];
int ret;
char fw_version[ETHDEV_FWVERS_LEN];
+ uint32_t lanes;
if (port_id_is_invalid(port_id, ENABLED_WARN)) {
print_valid_ports();
@@ -828,6 +829,8 @@ port_infos_display(portid_t port_id)
printf("\nLink status: %s\n", (link.link_status) ? ("up") : ("down"));
printf("Link speed: %s\n", rte_eth_link_speed_to_str(link.link_speed));
+ if (rte_eth_speed_lanes_get(port_id, &lanes) == 0)
+ printf("Active Lanes: %d\n", lanes);
printf("Link duplex: %s\n", (link.link_duplex == RTE_ETH_LINK_FULL_DUPLEX) ?
("full-duplex") : ("half-duplex"));
printf("Autoneg status: %s\n", (link.link_autoneg == RTE_ETH_LINK_AUTONEG) ?
@@ -7244,3 +7247,4 @@ show_mcast_macs(portid_t port_id)
printf(" %s\n", buf);
}
}
+
@@ -339,6 +339,93 @@ typedef int (*eth_allmulticast_disable_t)(struct rte_eth_dev *dev);
typedef int (*eth_link_update_t)(struct rte_eth_dev *dev,
int wait_to_complete);
+/**
+ * @internal
+ * Get number of current active lanes
+ *
+ * @param dev
+ * ethdev handle of port.
+ * @param speed_lanes
+ * Number of active lanes that the link has trained up. This information
+ * is displayed for Autonegotiated or Fixed speed trained link.
+ * @return
+ * Negative errno value on error, 0 on success.
+ *
+ * @retval 0
+ * Success, get speed_lanes data success.
+ * @retval -ENOTSUP
+ * Operation is not supported.
+ * @retval -EIO
+ * Device is removed.
+ */
+typedef int (*eth_speed_lanes_get_t)(struct rte_eth_dev *dev, uint32_t *speed_lanes);
+
+/**
+ * @internal
+ * Set speed lanes supported by the NIC. This configuration is applicable only when
+ * fix speed is already configured and or will be configured. This api requires the
+ * port be stopped, since driver has to re-configure PHY with fixed speed and lanes.
+ * If no lanes are configured prior or after "port config X speed Y duplex Z", the
+ * driver will choose the default lane for that speed to bring up the link.
+ *
+ * @param dev
+ * ethdev handle of port.
+ * @param speed_lanes
+ * Non-negative number of lanes
+ *
+ * @return
+ * Negative errno value on error, 0 on success.
+ *
+ * @retval 0
+ * Success, set lanes success.
+ * @retval -ENOTSUP
+ * Operation is not supported.
+ * @retval -EINVAL
+ * Unsupported number of lanes for fixed speed requested.
+ * @retval -EIO
+ * Device is removed.
+ */
+typedef int (*eth_speed_lanes_set_t)(struct rte_eth_dev *dev, uint32_t speed_lanes);
+
+/**
+ * @internal
+ * Get supported link speed lanes capability. The driver returns number of lanes
+ * supported per speed in the form of lanes capability bitmap per speed.
+ *
+ * @param speed_lanes_capa
+ * A pointer to num of rte_eth_speed_lanes_capa struct array which carries the
+ * bit map of lanes supported per speed. The number of supported speeds is the
+ * size of this speed_lanes_capa table. In link up condition, only active supported
+ * speeds lanes bitmap information will be displayed. In link down condition, all
+ * the supported speeds and its supported lanes bitmap would be fetched and displayed.
+ *
+ * This api is overloaded to fetch the size of the speed_lanes_capa array if
+ * testpmd calls the driver with speed_lanes_capa = NULL and num = 0
+ *
+ * @param num
+ * Number of elements in a speed_speed_lanes_capa array. This num is equal to the
+ * number of supported speeds by the controller. This value will vary in link up
+ * and link down condition. num is updated by the driver if speed_lanes_capa is NULL.
+ *
+ * @return
+ * Negative errno value on error, positive value on success.
+ *
+ * @retval positive value
+ * A non-negative value lower or equal to num: success. The return value
+ * is the number of entries filled in the speed lanes array.
+ * A non-negative value higher than num: error, the given speed lanes capa array
+ * is too small. The return value corresponds to the num that should
+ * be given to succeed. The entries in the speed lanes capa array are not valid
+ * and shall not be used by the caller.
+ * @retval -ENOTSUP
+ * Operation is not supported.
+ * @retval -EINVAL
+ * *num* or *speed_lanes_capa* invalid.
+ */
+typedef int (*eth_speed_lanes_get_capability_t)(struct rte_eth_dev *dev,
+ struct rte_eth_speed_lanes_capa *speed_lanes_capa,
+ unsigned int num);
+
/** @internal Get global I/O statistics of an Ethernet device. */
typedef int (*eth_stats_get_t)(struct rte_eth_dev *dev,
struct rte_eth_stats *igb_stats);
@@ -1247,6 +1334,10 @@ struct eth_dev_ops {
eth_dev_close_t dev_close; /**< Close device */
eth_dev_reset_t dev_reset; /**< Reset device */
eth_link_update_t link_update; /**< Get device link state */
+ eth_speed_lanes_get_t speed_lanes_get; /**<Get link speed active lanes */
+ eth_speed_lanes_set_t speed_lanes_set; /**<set the link speeds supported lanes */
+ /** Get link speed lanes capability */
+ eth_speed_lanes_get_capability_t speed_lanes_get_capa;
/** Check if the device was physically removed */
eth_is_removed_t is_removed;
@@ -1849,6 +1849,58 @@ rte_eth_dev_set_link_down(uint16_t port_id)
return ret;
}
+int
+rte_eth_speed_lanes_get(uint16_t port_id, uint32_t *lane)
+{
+ struct rte_eth_dev *dev;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+ dev = &rte_eth_devices[port_id];
+
+ if (*dev->dev_ops->speed_lanes_get == NULL)
+ return -ENOTSUP;
+ return eth_err(port_id, (*dev->dev_ops->speed_lanes_get)(dev, lane));
+}
+
+int
+rte_eth_speed_lanes_get_capability(uint16_t port_id,
+ struct rte_eth_speed_lanes_capa *speed_lanes_capa,
+ unsigned int num)
+{
+ struct rte_eth_dev *dev;
+ int ret;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+ dev = &rte_eth_devices[port_id];
+
+ if (*dev->dev_ops->speed_lanes_get_capa == NULL)
+ return -ENOTSUP;
+
+ if (speed_lanes_capa == NULL && num > 0) {
+ RTE_ETHDEV_LOG_LINE(ERR,
+ "Cannot get ethdev port %u speed lanes capability to NULL when array size is non zero",
+ port_id);
+ return -EINVAL;
+ }
+
+ ret = (*dev->dev_ops->speed_lanes_get_capa)(dev, speed_lanes_capa, num);
+
+ return ret;
+}
+
+int
+rte_eth_speed_lanes_set(uint16_t port_id, uint32_t speed_lanes_capa)
+{
+ struct rte_eth_dev *dev;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+ dev = &rte_eth_devices[port_id];
+
+ if (*dev->dev_ops->speed_lanes_set == NULL)
+ return -ENOTSUP;
+ return eth_err(port_id, (*dev->dev_ops->speed_lanes_set)(dev, speed_lanes_capa));
+}
+
int
rte_eth_dev_close(uint16_t port_id)
{
@@ -357,6 +357,27 @@ struct rte_eth_link {
#define RTE_ETH_LINK_MAX_STR_LEN 40 /**< Max length of default link string. */
/**@}*/
+/**
+ * Constants used to indicate the possible link speed lanes of an ethdev port.
+ */
+#define RTE_ETH_SPEED_LANE_UNKNOWN 0 /**< speed lanes unsupported mode or default */
+#define RTE_ETH_SPEED_LANE_1 1 /**< Link speed lane 1 */
+#define RTE_ETH_SPEED_LANE_2 2 /**< Link speed lanes 2 */
+#define RTE_ETH_SPEED_LANE_4 4 /**< Link speed lanes 4 */
+#define RTE_ETH_SPEED_LANE_8 8 /**< Link speed lanes 8 */
+
+/* Translate from link speed lanes to speed lanes capa */
+#define RTE_ETH_SPEED_LANES_TO_CAPA(x) RTE_BIT32(x)
+
+/* This macro indicates link speed lanes capa mask */
+#define RTE_ETH_SPEED_LANES_CAPA_MASK(x) RTE_BIT32(RTE_ETH_SPEED_ ## x)
+
+/* A structure used to get and set lanes capabilities per link speed */
+struct rte_eth_speed_lanes_capa {
+ uint32_t speed;
+ uint32_t capa;
+};
+
/**
* A structure used to configure the ring threshold registers of an Rx/Tx
* queue for an Ethernet port.
@@ -3114,6 +3135,80 @@ __rte_experimental
int rte_eth_link_to_str(char *str, size_t len,
const struct rte_eth_link *eth_link);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Get Active lanes.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param lanes
+ * Driver updates lanes with the number of active lanes.
+ * On a supported NIC on link up, lanes will be a non-zero value irrespective whether the
+ * link is Autonegotiated or Fixed speed. No information is dispalyed for error.
+ *
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if underlying hardware OR driver doesn't support.
+ * that operation.
+ * - (-EIO) if device is removed.
+ * - (-ENODEV) if *port_id* invalid.
+ */
+__rte_experimental
+int rte_eth_speed_lanes_get(uint16_t port_id, uint32_t *lanes);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Set speed lanes supported by the NIC.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param speed_lanes
+ * A non-zero number of speed lanes, that will be applied to the ethernet PHY
+ * along with the fixed speed configuration. Driver returns error if the user
+ * lanes is not in speeds capability list.
+ *
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if underlying hardware OR driver doesn't support.
+ * that operation.
+ * - (-EIO) if device is removed.
+ * - (-ENODEV) if *port_id* invalid.
+ * - (-EINVAL) if *lanes* count not in speeds capability list.
+ */
+__rte_experimental
+int rte_eth_speed_lanes_set(uint16_t port_id, uint32_t speed_lanes);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Get speed lanes supported by the NIC.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param speed_lanes_capa
+ * An array of supported speed and its supported lanes.
+ * @param num
+ * Size of the speed_lanes_capa array. The size is equal to the supported speeds list size.
+ * Value of num is derived by calling this api with speed_lanes_capa=NULL and num=0
+ *
+ * @return
+ * - (0) if successful.
+ * - (-ENOTSUP) if underlying hardware OR driver doesn't support.
+ * that operation.
+ * - (-EIO) if device is removed.
+ * - (-ENODEV) if *port_id* invalid.
+ * - (-EINVAL) if *speed_lanes* invalid
+ */
+__rte_experimental
+int rte_eth_speed_lanes_get_capability(uint16_t port_id,
+ struct rte_eth_speed_lanes_capa *speed_lanes_capa,
+ unsigned int num);
+
/**
* Retrieve the general I/O statistics of an Ethernet device.
*
@@ -325,6 +325,11 @@ EXPERIMENTAL {
rte_flow_template_table_resizable;
rte_flow_template_table_resize;
rte_flow_template_table_resize_complete;
+
+ # added in 24.11
+ rte_eth_speed_lanes_get;
+ rte_eth_speed_lanes_get_capability;
+ rte_eth_speed_lanes_set;
};
INTERNAL {