similarity index 60%
rename from drivers/net/ice/ice_ddp_package.c
rename to drivers/net/ice/ice_diagnose.c
@@ -11,6 +11,7 @@
#include <rte_tailq.h>
#include "ice_ethdev.h"
+#include "ice_rxtx.h"
#define ICE_BLK_MAX_COUNT 512
#define ICE_BUFF_SEG_HEADER_FLAG 0x1
@@ -507,3 +508,375 @@ int rte_pmd_ice_dump_switch(uint16_t port, uint8_t **buff, uint32_t *size)
return ice_dump_switch(dev, buff, size);
}
+
+static void print_rl_profile(struct ice_aqc_rl_profile_elem *prof,
+ FILE *stream)
+{
+ fprintf(stream, "\t\t\t\t\t<td>\n");
+ fprintf(stream, "\t\t\t\t\t\t<table>\n");
+
+ fprintf(stream, "\t\t\t\t\t\t\t<tr>\n");
+ fprintf(stream, "\t\t\t\t\t\t\t\t<td>id</td>\n");
+ fprintf(stream, "\t\t\t\t\t\t\t\t<td>%d</td>\n", prof->profile_id);
+ fprintf(stream, "\t\t\t\t\t\t\t</tr>\n");
+
+ fprintf(stream, "\t\t\t\t\t\t\t<tr>\n");
+ fprintf(stream, "\t\t\t\t\t\t\t\t<td>max burst size</td>\n");
+ fprintf(stream, "\t\t\t\t\t\t\t\t<td>%d</td>\n", prof->max_burst_size);
+ fprintf(stream, "\t\t\t\t\t\t\t</tr>\n");
+
+ fprintf(stream, "\t\t\t\t\t\t\t<tr>\n");
+ fprintf(stream, "\t\t\t\t\t\t\t\t<td>rate limit multiply</td>\n");
+ fprintf(stream, "\t\t\t\t\t\t\t\t<td>%d</td>\n", prof->rl_multiply);
+ fprintf(stream, "\t\t\t\t\t\t\t</tr>\n");
+
+ fprintf(stream, "\t\t\t\t\t\t\t<tr>\n");
+ fprintf(stream, "\t\t\t\t\t\t\t\t<td>wake up calculation</td>\n");
+ fprintf(stream, "\t\t\t\t\t\t\t\t<td>%d</td>\n", prof->wake_up_calc);
+ fprintf(stream, "\t\t\t\t\t\t\t</tr>\n");
+
+ fprintf(stream, "\t\t\t\t\t\t\t<tr>\n");
+ fprintf(stream, "\t\t\t\t\t\t\t\t<td>rate limit encode</td>\n");
+ fprintf(stream, "\t\t\t\t\t\t\t\t<td>%d</td>\n", prof->rl_encode);
+ fprintf(stream, "\t\t\t\t\t\t\t</tr>\n");
+
+ fprintf(stream, "\t\t\t\t\t\t</table>\n");
+ fprintf(stream, "\t\t\t\t\t</td>\n");
+}
+
+static
+void print_elem_type(FILE *stream, u8 type)
+{
+ switch (type) {
+ case 1:
+ fprintf(stream, "root");
+ break;
+ case 2:
+ fprintf(stream, "tc");
+ break;
+ case 3:
+ fprintf(stream, "se_generic");
+ break;
+ case 4:
+ fprintf(stream, "entry_point");
+ break;
+ case 5:
+ fprintf(stream, "leaf");
+ break;
+ default:
+ fprintf(stream, "%d", type);
+ break;
+ }
+}
+
+static
+void print_valid_sections(FILE *stream, u8 vs)
+{
+ if ((vs & 0x1) != 0)
+ fprintf(stream, "generic ");
+ if ((vs & 0x2) != 0)
+ fprintf(stream, "cir ");
+ if ((vs & 0x4) != 0)
+ fprintf(stream, "eir ");
+ if ((vs & 0x8) != 0)
+ fprintf(stream, "shared ");
+}
+
+static
+void print_scheduling_mode(FILE *stream, bool flag)
+{
+ if (flag)
+ fprintf(stream, "pps");
+ else
+ fprintf(stream, "bps");
+}
+
+static
+void print_priority_mode(FILE *stream, bool flag)
+{
+ if (flag)
+ fprintf(stream, "single priority node");
+ else
+ fprintf(stream, "wfq");
+}
+
+static
+void print_node(struct ice_aqc_txsched_elem_data *data,
+ struct ice_aqc_rl_profile_elem *cir_prof,
+ struct ice_aqc_rl_profile_elem *eir_prof,
+ struct ice_aqc_rl_profile_elem *shared_prof,
+ bool detail, FILE *stream)
+{
+ fprintf(stream, "\tNODE_%d [\n", data->node_teid);
+ fprintf(stream, "\t\tlabel=<\n");
+
+ fprintf(stream, "\t\t\t<table>\n");
+
+ fprintf(stream, "\t\t\t\t<tr>\n");
+ fprintf(stream, "\t\t\t\t\t<td> teid </td>\n");
+ fprintf(stream, "\t\t\t\t\t<td> %d </td>\n", data->node_teid);
+ fprintf(stream, "\t\t\t\t</tr>\n");
+
+ fprintf(stream, "\t\t\t\t<tr>\n");
+ fprintf(stream, "\t\t\t\t\t<td> type </td>\n");
+ fprintf(stream, "\t\t\t\t\t<td>");
+ print_elem_type(stream, data->data.elem_type);
+ fprintf(stream, "</td>\n");
+ fprintf(stream, "\t\t\t\t</tr>\n");
+
+ if (!detail)
+ goto brief;
+
+ fprintf(stream, "\t\t\t\t<tr>\n");
+ fprintf(stream, "\t\t\t\t\t<td> valid sections </td>\n");
+ fprintf(stream, "\t\t\t\t\t<td>");
+ print_valid_sections(stream, data->data.valid_sections);
+ fprintf(stream, "</td>\n");
+ fprintf(stream, "\t\t\t\t</tr>\n");
+
+ fprintf(stream, "\t\t\t\t<tr>\n");
+ fprintf(stream, "\t\t\t\t\t<td> scheduling mode </td>\n");
+ fprintf(stream, "\t\t\t\t\t<td>");
+ print_scheduling_mode(stream, (data->data.generic & 0x1) != 0);
+ fprintf(stream, "</td>\n");
+ fprintf(stream, "\t\t\t\t</tr>\n");
+
+ fprintf(stream, "\t\t\t\t<tr>\n");
+ fprintf(stream, "\t\t\t\t\t<td> priority </td>\n");
+ fprintf(stream, "\t\t\t\t\t<td> %d </td>\n", (data->data.generic >> 1) & 0x7);
+ fprintf(stream, "\t\t\t\t</tr>\n");
+
+ fprintf(stream, "\t\t\t\t<tr>\n");
+ fprintf(stream, "\t\t\t\t\t<td> priority mode</td>\n");
+ fprintf(stream, "\t\t\t\t\t<td>");
+ print_priority_mode(stream, ((data->data.generic >> 4) & 0x1) != 0);
+ fprintf(stream, "</td>\n");
+ fprintf(stream, "\t\t\t\t</tr>\n");
+
+ fprintf(stream, "\t\t\t\t<tr>\n");
+ fprintf(stream, "\t\t\t\t\t<td> adjustment value </td>\n");
+ fprintf(stream, "\t\t\t\t\t<td> %d </td>\n", (data->data.generic >> 5) & 0x3);
+ fprintf(stream, "\t\t\t\t</tr>\n");
+
+ fprintf(stream, "\t\t\t\t<tr>\n");
+ fprintf(stream, "\t\t\t\t\t<td> suspended </td>\n");
+ fprintf(stream, "\t\t\t\t\t<td> %d </td>\n", data->data.flags & 0x1);
+ fprintf(stream, "\t\t\t\t</tr>\n");
+
+ fprintf(stream, "\t\t\t\t<tr>\n");
+ fprintf(stream, "\t\t\t\t\t<td> cir bw profile </td>\n");
+ if (cir_prof == NULL)
+ fprintf(stream, "\t\t\t\t\t<td> default </td>\n");
+ else
+ print_rl_profile(cir_prof, stream);
+ fprintf(stream, "\t\t\t\t</tr>\n");
+
+ fprintf(stream, "\t\t\t\t<tr>\n");
+ fprintf(stream, "\t\t\t\t\t<td> cir bw weight </td>\n");
+ fprintf(stream, "\t\t\t\t\t<td> %d </td>\n", data->data.cir_bw.bw_alloc);
+ fprintf(stream, "\t\t\t\t</tr>\n");
+
+ fprintf(stream, "\t\t\t\t<tr>\n");
+ fprintf(stream, "\t\t\t\t\t<td> eir bw profile </td>\n");
+ if (eir_prof == NULL)
+ fprintf(stream, "\t\t\t\t\t<td> default </td>\n");
+ else
+ print_rl_profile(eir_prof, stream);
+ fprintf(stream, "\t\t\t\t</tr>\n");
+
+ fprintf(stream, "\t\t\t\t<tr>\n");
+ fprintf(stream, "\t\t\t\t\t<td> eir bw weight </td>\n");
+ fprintf(stream, "\t\t\t\t\t<td> %d </td>\n", data->data.eir_bw.bw_alloc);
+ fprintf(stream, "\t\t\t\t</tr>\n");
+
+ fprintf(stream, "\t\t\t\t<tr>\n");
+ fprintf(stream, "\t\t\t\t\t<td> shared rl profile </td>\n");
+ if (shared_prof == NULL)
+ fprintf(stream, "\t\t\t\t\t<td> default </td>\n");
+ else
+ print_rl_profile(shared_prof, stream);
+ fprintf(stream, "\t\t\t\t</tr>\n");
+
+brief:
+ fprintf(stream, "\t\t\t</table>\n");
+
+ fprintf(stream, "\t\t>\n");
+ fprintf(stream, "\t\tshape=plain\n");
+ fprintf(stream, "\t]\n");
+
+ if (data->parent_teid != 0xFFFFFFFF)
+ fprintf(stream, "\tNODE_%d -> NODE_%d\n", data->parent_teid, data->node_teid);
+}
+
+static
+int query_rl_profile(struct ice_hw *hw,
+ uint8_t level, uint8_t flags, uint16_t profile_id,
+ struct ice_aqc_rl_profile_elem *data)
+{
+ enum ice_status ice_status;
+
+ data->level = level;
+ data->flags = flags;
+ data->profile_id = profile_id;
+
+ ice_status = ice_aq_query_rl_profile(hw, 1, data,
+ sizeof(struct ice_aqc_rl_profile_elem), NULL);
+
+ if (ice_status != ICE_SUCCESS) {
+ PMD_DRV_LOG(ERR, "Failed to query rl profile.");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static
+int query_node(struct ice_hw *hw, uint32_t child, uint32_t *parent,
+ uint8_t level, bool detail, FILE *stream)
+{
+ struct ice_aqc_txsched_elem_data data;
+ enum ice_status status;
+ struct ice_aqc_rl_profile_elem cir_prof;
+ struct ice_aqc_rl_profile_elem eir_prof;
+ struct ice_aqc_rl_profile_elem shared_prof;
+ struct ice_aqc_rl_profile_elem *cp = NULL;
+ struct ice_aqc_rl_profile_elem *ep = NULL;
+ struct ice_aqc_rl_profile_elem *sp = NULL;
+ int ret;
+
+ status = ice_sched_query_elem(hw, child, &data);
+ if (status != ICE_SUCCESS) {
+ if (level == hw->num_tx_sched_layers) {
+ /* ignore the error when a queue has been stopped. */
+ PMD_DRV_LOG(WARNING, "Failed to query queue node %d.", child);
+ *parent = 0xffffffff;
+ return 0;
+ } else {
+ PMD_DRV_LOG(ERR, "Failed to query scheduling node %d.", child);
+ return -EINVAL;
+ }
+ }
+
+ *parent = data.parent_teid;
+
+ if (data.data.cir_bw.bw_profile_idx != 0) {
+ ret = query_rl_profile(hw, level, 0, data.data.cir_bw.bw_profile_idx, &cir_prof);
+
+ if (ret)
+ return ret;
+ cp = &cir_prof;
+ }
+
+ if (data.data.eir_bw.bw_profile_idx != 0) {
+ ret = query_rl_profile(hw, level, 1, data.data.eir_bw.bw_profile_idx, &eir_prof);
+
+ if (ret)
+ return ret;
+ ep = &eir_prof;
+ }
+
+ if (data.data.srl_id != 0) {
+ ret = query_rl_profile(hw, level, 2, data.data.srl_id, &shared_prof);
+
+ if (ret)
+ return ret;
+ sp = &shared_prof;
+ }
+
+ print_node(&data, cp, ep, sp, detail, stream);
+
+ return 0;
+}
+
+static
+int query_nodes(struct ice_hw *hw,
+ uint32_t *children, int child_num,
+ uint32_t *parents, int *parent_num,
+ uint8_t level, bool detail,
+ FILE *stream)
+{
+ uint32_t parent;
+ int i;
+ int j;
+
+ *parent_num = 0;
+ for (i = 0; i < child_num; i++) {
+ bool exist = false;
+ int ret;
+
+ ret = query_node(hw, children[i], &parent, level, detail, stream);
+ if (ret)
+ return -EINVAL;
+
+ for (j = 0; j < *parent_num; j++) {
+ if (parents[j] == parent) {
+ exist = true;
+ break;
+ }
+ }
+
+ if (!exist && parent != 0xFFFFFFFF)
+ parents[(*parent_num)++] = parent;
+ }
+
+ return 0;
+}
+
+int rte_pmd_ice_dump_txsched(uint16_t port, bool detail, FILE *stream)
+{
+ struct rte_eth_dev *dev;
+ struct ice_hw *hw;
+ struct ice_pf *pf;
+ struct ice_q_ctx *q_ctx;
+ uint16_t q_num;
+ uint16_t i;
+ struct ice_tx_queue *txq;
+ uint32_t buf1[256];
+ uint32_t buf2[256];
+ uint32_t *children = buf1;
+ uint32_t *parents = buf2;
+ int child_num = 0;
+ int parent_num = 0;
+ uint8_t level;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
+
+ dev = &rte_eth_devices[port];
+ if (!is_ice_supported(dev))
+ return -ENOTSUP;
+
+ dev = &rte_eth_devices[port];
+ hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+ level = hw->num_tx_sched_layers;
+
+ q_num = dev->data->nb_tx_queues;
+
+ /* main vsi */
+ for (i = 0; i < q_num; i++) {
+ txq = dev->data->tx_queues[i];
+ q_ctx = ice_get_lan_q_ctx(hw, txq->vsi->idx, 0, i);
+ children[child_num++] = q_ctx->q_teid;
+ }
+
+ /* fdir vsi */
+ q_ctx = ice_get_lan_q_ctx(hw, pf->fdir.fdir_vsi->idx, 0, 0);
+ children[child_num++] = q_ctx->q_teid;
+
+ fprintf(stream, "digraph tx_sched {\n");
+ while (child_num > 0) {
+ int ret;
+ ret = query_nodes(hw, children, child_num,
+ parents, &parent_num,
+ level, detail, stream);
+ if (ret)
+ return ret;
+
+ children = parents;
+ child_num = parent_num;
+ level--;
+ }
+ fprintf(stream, "}\n");
+
+ return 0;
+}
@@ -739,4 +739,7 @@ int rte_pmd_ice_dump_package(uint16_t port, uint8_t **buff, uint32_t *size);
__rte_experimental
int rte_pmd_ice_dump_switch(uint16_t port, uint8_t **buff, uint32_t *size);
+
+__rte_experimental
+int rte_pmd_ice_dump_txsched(uint16_t port, bool detail, FILE *stream);
#endif /* _ICE_ETHDEV_H_ */
@@ -3,6 +3,7 @@
*/
#include <stdlib.h>
+#include <stdio.h>
#include <cmdline_parse_num.h>
#include <cmdline_parse_string.h>
@@ -148,6 +149,63 @@ cmdline_parse_inst_t cmd_ddp_dump_switch = {
},
};
+/* Dump Tx Scheduling Tree configuration, only for ice PF */
+struct cmd_txsched_dump_result {
+ cmdline_fixed_string_t txsched;
+ cmdline_fixed_string_t dump;
+ portid_t port_id;
+ cmdline_fixed_string_t mode;
+ char filepath[];
+};
+
+cmdline_parse_token_string_t cmd_txsched_dump_txsched =
+ TOKEN_STRING_INITIALIZER(struct cmd_txsched_dump_result, txsched, "txsched");
+cmdline_parse_token_string_t cmd_txsched_dump_dump =
+ TOKEN_STRING_INITIALIZER(struct cmd_txsched_dump_result, dump, "dump");
+cmdline_parse_token_num_t cmd_txsched_dump_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_txsched_dump_result, port_id, RTE_UINT16);
+cmdline_parse_token_string_t cmd_txsched_dump_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_txsched_dump_result, mode, "brief#detail");
+cmdline_parse_token_string_t cmd_txsched_dump_filepath =
+ TOKEN_STRING_INITIALIZER(struct cmd_txsched_dump_result, filepath, NULL);
+
+static void
+cmd_txsched_dump_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_txsched_dump_result *res = parsed_result;
+ bool detail = false;
+ FILE *fp;
+
+ if (!strcmp(res->mode, "detail"))
+ detail = true;
+
+ fp = fopen(res->filepath, "w");
+ if (fp == NULL) {
+ fprintf(stderr, "Failed to open file\n");
+ return;
+ }
+
+ if (rte_pmd_ice_dump_txsched(res->port_id, detail, fp))
+ fprintf(stderr, "Failed to dump Tx scheduring runtime configure.\n");
+ fclose(fp);
+}
+
+cmdline_parse_inst_t cmd_txsched_dump = {
+ .f = cmd_txsched_dump_parsed,
+ .data = NULL,
+ .help_str = "txsched dump <port_id> <brief|detail> <config_path>",
+ .tokens = {
+ (void *)&cmd_txsched_dump_txsched,
+ (void *)&cmd_txsched_dump_dump,
+ (void *)&cmd_txsched_dump_port_id,
+ (void *)&cmd_txsched_dump_mode,
+ (void *)&cmd_txsched_dump_filepath,
+ NULL,
+ },
+};
+
static struct testpmd_driver_commands ice_cmds = {
.commands = {
{
@@ -161,8 +219,15 @@ static struct testpmd_driver_commands ice_cmds = {
"ddp dump switch (port_id) (config_path)\n"
" Dump a runtime switch configure on a port\n\n",
+ },
+ {
+ &cmd_txsched_dump,
+ "txsched dump (port_id) <brief|detail> (config_path)\n"
+ " Dump tx scheduling runtime configure on a port\n\n",
+
},
{ NULL, NULL },
},
};
+
TESTPMD_ADD_DRIVER_COMMANDS(ice_cmds)
@@ -6,7 +6,7 @@ objs = [base_objs]
sources = files(
'ice_acl_filter.c',
- 'ice_ddp_package.c',
+ 'ice_diagnose.c',
'ice_ethdev.c',
'ice_fdir_filter.c',
'ice_generic_flow.c',
@@ -8,4 +8,5 @@ EXPERIMENTAL {
# added in 19.11
rte_pmd_ice_dump_package;
rte_pmd_ice_dump_switch;
+ rte_pmd_ice_dump_txsched;
};