this patch implements function to debug and dump PMD/QDMA specific data. Signed-off-by: Aman Kumar <aman.ku...@vvdntech.in> --- drivers/net/qdma/meson.build | 1 + drivers/net/qdma/qdma_xdebug.c | 1072 ++++++++++++++++++++++++++++++++ 2 files changed, 1073 insertions(+) create mode 100644 drivers/net/qdma/qdma_xdebug.c
diff --git a/drivers/net/qdma/meson.build b/drivers/net/qdma/meson.build index 1dc4392666..7ba2c89442 100644 --- a/drivers/net/qdma/meson.build +++ b/drivers/net/qdma/meson.build @@ -29,6 +29,7 @@ sources = files( 'qdma_user.c', 'qdma_rxtx.c', 'qdma_vf_ethdev.c', + 'qdma_xdebug.c', 'qdma_access/eqdma_soft_access/eqdma_soft_access.c', 'qdma_access/eqdma_soft_access/eqdma_soft_reg_dump.c', 'qdma_access/qdma_s80_hard_access/qdma_s80_hard_access.c', diff --git a/drivers/net/qdma/qdma_xdebug.c b/drivers/net/qdma/qdma_xdebug.c new file mode 100644 index 0000000000..43f8380465 --- /dev/null +++ b/drivers/net/qdma/qdma_xdebug.c @@ -0,0 +1,1072 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017-2022 Xilinx, Inc. All rights reserved. + * Copyright(c) 2022 VVDN Technologies Private Limited. All rights reserved. + */ + +#include <stdint.h> +#include <sys/mman.h> +#include <sys/fcntl.h> +#include <rte_memzone.h> +#include <rte_string_fns.h> +#include <ethdev_pci.h> +#include <rte_malloc.h> +#include <rte_dev.h> +#include <rte_pci.h> +#include <rte_ether.h> +#include <rte_ethdev.h> +#include <rte_cycles.h> +#include <unistd.h> +#include <string.h> +#include <rte_hexdump.h> + +#include "qdma.h" +#include "rte_pmd_qdma.h" +#include "qdma_access_common.h" +#include "qdma_reg_dump.h" +#include "qdma_mbox_protocol.h" +#include "qdma_mbox.h" + +#define xdebug_info(args...) rte_log(RTE_LOG_INFO, RTE_LOGTYPE_USER1,\ + ## args) +#define xdebug_error(args...) rte_log(RTE_LOG_ERR, RTE_LOGTYPE_USER1,\ + ## args) + +struct xdebug_desc_param { + uint16_t queue; + int start; + int end; + enum rte_pmd_qdma_xdebug_desc_type type; +}; + +const char *qdma_desc_eng_mode_info[QDMA_DESC_ENG_MODE_MAX] = { + "Internal and Bypass mode", + "Bypass only mode", + "Internal only mode" +}; + +static void print_header(const char *str) +{ + xdebug_info("\n\n%s\n\n", str); +} + +static int qdma_h2c_struct_dump(uint8_t port_id, uint16_t queue) +{ + struct rte_eth_dev *dev; + struct qdma_tx_queue *tx_q; + + if (port_id >= rte_eth_dev_count_avail()) { + xdebug_error("Wrong port id %d\n", port_id); + return -EINVAL; + } + + dev = &rte_eth_devices[port_id]; + tx_q = (struct qdma_tx_queue *)dev->data->tx_queues[queue]; + + if (queue >= dev->data->nb_tx_queues) { + xdebug_info("TX queue_id=%d not configured\n", queue); + return -EINVAL; + } + + if (tx_q) { + print_header("***********TX Queue struct************"); + xdebug_info("\t\t wb_pidx :%x\n", + tx_q->wb_status->pidx); + xdebug_info("\t\t wb_cidx :%x\n", + tx_q->wb_status->cidx); + xdebug_info("\t\t h2c_pidx :%x\n", + tx_q->q_pidx_info.pidx); + xdebug_info("\t\t tx_fl_tail :%x\n", + tx_q->tx_fl_tail); + xdebug_info("\t\t tx_desc_pend :%x\n", + tx_q->tx_desc_pend); + xdebug_info("\t\t nb_tx_desc :%x\n", + tx_q->nb_tx_desc); + xdebug_info("\t\t st_mode :%x\n", + tx_q->st_mode); + xdebug_info("\t\t tx_deferred_start :%x\n", + tx_q->tx_deferred_start); + xdebug_info("\t\t en_bypass :%x\n", + tx_q->en_bypass); + xdebug_info("\t\t bypass_desc_sz :%x\n", + tx_q->bypass_desc_sz); + xdebug_info("\t\t func_id :%x\n", + tx_q->func_id); + xdebug_info("\t\t port_id :%x\n", + tx_q->port_id); + xdebug_info("\t\t ringszidx :%x\n", + tx_q->ringszidx); + } + + return 0; +} + +static int qdma_c2h_struct_dump(uint8_t port_id, uint16_t queue) +{ + struct rte_eth_dev *dev; + struct qdma_pci_dev *qdma_dev; + struct qdma_rx_queue *rx_q; + enum qdma_ip_type ip_type; + + if (port_id >= rte_eth_dev_count_avail()) { + xdebug_error("Wrong port id %d\n", port_id); + return -EINVAL; + } + + dev = &rte_eth_devices[port_id]; + qdma_dev = dev->data->dev_private; + ip_type = (enum qdma_ip_type)qdma_dev->ip_type; + rx_q = (struct qdma_rx_queue *)dev->data->rx_queues[queue]; + + if (queue >= dev->data->nb_rx_queues) { + xdebug_info("RX queue_id=%d not configured\n", queue); + return -EINVAL; + } + + if (rx_q) { + print_header(" ***********RX Queue struct********** "); + xdebug_info("\t\t wb_pidx :%x\n", + rx_q->wb_status->pidx); + xdebug_info("\t\t wb_cidx :%x\n", + rx_q->wb_status->cidx); + xdebug_info("\t\t rx_tail (ST) :%x\n", + rx_q->rx_tail); + xdebug_info("\t\t c2h_pidx :%x\n", + rx_q->q_pidx_info.pidx); + xdebug_info("\t\t rx_cmpt_cidx :%x\n", + rx_q->cmpt_cidx_info.wrb_cidx); + xdebug_info("\t\t cmpt_desc_len :%x\n", + rx_q->cmpt_desc_len); + xdebug_info("\t\t rx_buff_size :%x\n", + rx_q->rx_buff_size); + xdebug_info("\t\t nb_rx_desc :%x\n", + rx_q->nb_rx_desc); + xdebug_info("\t\t nb_rx_cmpt_desc :%x\n", + rx_q->nb_rx_cmpt_desc); + xdebug_info("\t\t ep_addr :%x\n", + rx_q->ep_addr); + xdebug_info("\t\t st_mode :%x\n", + rx_q->st_mode); + xdebug_info("\t\t rx_deferred_start :%x\n", + rx_q->rx_deferred_start); + xdebug_info("\t\t en_prefetch :%x\n", + rx_q->en_prefetch); + xdebug_info("\t\t en_bypass :%x\n", + rx_q->en_bypass); + xdebug_info("\t\t dump_immediate_data :%x\n", + rx_q->dump_immediate_data); + xdebug_info("\t\t en_bypass_prefetch :%x\n", + rx_q->en_bypass_prefetch); + + if (!(ip_type == QDMA_VERSAL_HARD_IP)) + xdebug_info("\t\t dis_overflow_check :%x\n", + rx_q->dis_overflow_check); + + xdebug_info("\t\t bypass_desc_sz :%x\n", + rx_q->bypass_desc_sz); + xdebug_info("\t\t ringszidx :%x\n", + rx_q->ringszidx); + xdebug_info("\t\t cmpt_ringszidx :%x\n", + rx_q->cmpt_ringszidx); + xdebug_info("\t\t buffszidx :%x\n", + rx_q->buffszidx); + xdebug_info("\t\t threshidx :%x\n", + rx_q->threshidx); + xdebug_info("\t\t timeridx :%x\n", + rx_q->timeridx); + xdebug_info("\t\t triggermode :%x\n", + rx_q->triggermode); + } + + return 0; +} + +static int qdma_config_read_reg_list(struct rte_eth_dev *dev, + uint16_t group_num, + uint16_t *num_regs, struct qdma_reg_data *reg_list) +{ + struct qdma_pci_dev *qdma_dev = dev->data->dev_private; + struct qdma_mbox_msg *m = qdma_mbox_msg_alloc(); + int rv; + + if (!m) + return -ENOMEM; + + qdma_mbox_compose_reg_read(qdma_dev->func_id, group_num, m->raw_data); + + rv = qdma_mbox_msg_send(dev, m, MBOX_OP_RSP_TIMEOUT); + if (rv < 0) { + if (rv != -ENODEV) + xdebug_error("reg read mbox failed with error = %d\n", + rv); + goto err_out; + } + + rv = qdma_mbox_vf_reg_list_get(m->raw_data, num_regs, reg_list); + if (rv < 0) { + xdebug_error("qdma_mbox_vf_reg_list_get failed with error = %d\n", + rv); + goto err_out; + } + +err_out: + qdma_mbox_msg_free(m); + return rv; +} + +static int qdma_config_reg_dump(uint8_t port_id) +{ + struct rte_eth_dev *dev; + struct qdma_pci_dev *qdma_dev; + enum qdma_ip_type ip_type; + char *buf = NULL; + int buflen; + int ret; + struct qdma_reg_data *reg_list; + uint16_t num_regs = 0, group_num = 0; + int len = 0, rcv_len = 0, reg_len = 0; + + if (port_id >= rte_eth_dev_count_avail()) { + xdebug_error("Wrong port id %d\n", port_id); + return -EINVAL; + } + + dev = &rte_eth_devices[port_id]; + qdma_dev = dev->data->dev_private; + ip_type = (enum qdma_ip_type)qdma_dev->ip_type; + + if (qdma_dev->is_vf) { + reg_len = (QDMA_MAX_REGISTER_DUMP * + sizeof(struct qdma_reg_data)); + reg_list = (struct qdma_reg_data *)rte_zmalloc("QDMA_DUMP_REG_VF", + reg_len, RTE_CACHE_LINE_SIZE); + if (!reg_list) { + xdebug_error("Unable to allocate memory for VF dump for reglist " + "size %d\n", reg_len); + return -ENOMEM; + } + + ret = qdma_acc_reg_dump_buf_len(dev, ip_type, &buflen); + if (ret < 0) { + xdebug_error("Failed to get register dump buffer length\n"); + return ret; + } + /* allocate memory for register dump */ + buf = (char *)rte_zmalloc("QDMA_DUMP_BUF_VF", buflen, + RTE_CACHE_LINE_SIZE); + if (!buf) { + xdebug_error("Unable to allocate memory for reg dump " + "size %d\n", buflen); + rte_free(reg_list); + return -ENOMEM; + } + xdebug_info("FPGA Config Registers for port_id: %d\n--------\n", + port_id); + xdebug_info(" Offset Name " + " Value(Hex) Value(Dec)\n"); + + for (group_num = 0; group_num < QDMA_REG_READ_GROUP_3; + group_num++) { + /* Reset the reg_list with 0's */ + memset(reg_list, 0, (QDMA_MAX_REGISTER_DUMP * + sizeof(struct qdma_reg_data))); + ret = qdma_config_read_reg_list(dev, + group_num, &num_regs, reg_list); + if (ret < 0) { + xdebug_error("Failed to read config registers " + "size %d, err = %d\n", buflen, ret); + rte_free(reg_list); + rte_free(buf); + return ret; + } + + rcv_len = qdma_acc_dump_config_reg_list(dev, + ip_type, num_regs, + reg_list, buf + len, buflen - len); + if (len < 0) { + xdebug_error("Failed to dump config regs " + "size %d, err = %d\n", buflen, ret); + rte_free(reg_list); + rte_free(buf); + return ret; + } + len += rcv_len; + } + if (ret < 0) { + xdebug_error("Insufficient space to dump Config Bar register values\n"); + rte_free(reg_list); + rte_free(buf); + return qdma_get_error_code(ret); + } + xdebug_info("%s\n", buf); + rte_free(reg_list); + rte_free(buf); + } else { + ret = qdma_acc_reg_dump_buf_len(dev, + ip_type, &buflen); + if (ret < 0) { + xdebug_error("Failed to get register dump buffer length\n"); + return ret; + } + + /* allocate memory for register dump */ + buf = (char *)rte_zmalloc("QDMA_REG_DUMP", buflen, + RTE_CACHE_LINE_SIZE); + if (!buf) { + xdebug_error("Unable to allocate memory for reg dump " + "size %d\n", buflen); + return -ENOMEM; + } + xdebug_info("FPGA Config Registers for port_id: %d\n--------\n", + port_id); + xdebug_info(" Offset Name " + " Value(Hex) Value(Dec)\n"); + + ret = qdma_acc_dump_config_regs(dev, qdma_dev->is_vf, + ip_type, buf, buflen); + if (ret < 0) { + xdebug_error + ("Insufficient space to dump Config Bar register values\n"); + rte_free(buf); + return qdma_get_error_code(ret); + } + xdebug_info("%s\n", buf); + rte_free(buf); + } + + return 0; +} + +static int qdma_device_dump(uint8_t port_id) +{ + struct rte_eth_dev *dev; + struct qdma_pci_dev *qdma_dev; + + if (port_id >= rte_eth_dev_count_avail()) { + xdebug_error("Wrong port id %d\n", port_id); + return -EINVAL; + } + + dev = &rte_eth_devices[port_id]; + qdma_dev = dev->data->dev_private; + + xdebug_info("\n*** QDMA Device struct for port_id: %d ***\n\n", + port_id); + + xdebug_info("\t\t config BAR index :%x\n", + qdma_dev->config_bar_idx); + xdebug_info("\t\t AXI Master Lite BAR index :%x\n", + qdma_dev->user_bar_idx); + xdebug_info("\t\t AXI Bridge Master BAR index :%x\n", + qdma_dev->bypass_bar_idx); + xdebug_info("\t\t qsets enable :%x\n", + qdma_dev->qsets_en); + xdebug_info("\t\t queue base :%x\n", + qdma_dev->queue_base); + xdebug_info("\t\t pf :%x\n", + qdma_dev->func_id); + xdebug_info("\t\t cmpt desc length :%x\n", + qdma_dev->cmpt_desc_len); + xdebug_info("\t\t c2h bypass mode :%x\n", + qdma_dev->c2h_bypass_mode); + xdebug_info("\t\t h2c bypass mode :%x\n", + qdma_dev->h2c_bypass_mode); + xdebug_info("\t\t trigger mode :%x\n", + qdma_dev->trigger_mode); + xdebug_info("\t\t timer count :%x\n", + qdma_dev->timer_count); + xdebug_info("\t\t is vf :%x\n", + qdma_dev->is_vf); + xdebug_info("\t\t is master :%x\n", + qdma_dev->is_master); + xdebug_info("\t\t enable desc prefetch :%x\n", + qdma_dev->en_desc_prefetch); + xdebug_info("\t\t ip type :%x\n", + qdma_dev->ip_type); + xdebug_info("\t\t vivado release :%x\n", + qdma_dev->vivado_rel); + xdebug_info("\t\t rtl version :%x\n", + qdma_dev->rtl_version); + xdebug_info("\t\t is queue conigured :%x\n", + qdma_dev->init_q_range); + + xdebug_info("\n\t ***** Device Capabilities *****\n"); + xdebug_info("\t\t number of PFs :%x\n", + qdma_dev->dev_cap.num_pfs); + xdebug_info("\t\t number of Queues :%x\n", + qdma_dev->dev_cap.num_qs); + xdebug_info("\t\t FLR present :%x\n", + qdma_dev->dev_cap.flr_present); + xdebug_info("\t\t ST mode enable :%x\n", + qdma_dev->dev_cap.st_en); + xdebug_info("\t\t MM mode enable :%x\n", + qdma_dev->dev_cap.mm_en); + xdebug_info("\t\t MM with compt enable :%x\n", + qdma_dev->dev_cap.mm_cmpt_en); + xdebug_info("\t\t Mailbox enable :%x\n", + qdma_dev->dev_cap.mailbox_en); + xdebug_info("\t\t Num of MM channels :%x\n", + qdma_dev->dev_cap.mm_channel_max); + xdebug_info("\t\t Descriptor engine mode :%s\n", + qdma_desc_eng_mode_info[qdma_dev->dev_cap.desc_eng_mode]); + xdebug_info("\t\t Debug mode enable :%x\n", + qdma_dev->dev_cap.debug_mode); + + return 0; +} + +static int qdma_descq_context_read_vf(struct rte_eth_dev *dev, + unsigned int qid_hw, bool st_mode, + enum qdma_dev_q_type q_type, + struct qdma_descq_context *context) +{ + struct qdma_pci_dev *qdma_dev = dev->data->dev_private; + struct qdma_mbox_msg *m = qdma_mbox_msg_alloc(); + enum mbox_cmpt_ctxt_type cmpt_ctxt_type = QDMA_MBOX_CMPT_CTXT_NONE; + int rv; + + if (!m) + return -ENOMEM; + + if (!st_mode) { + if (q_type == QDMA_DEV_Q_TYPE_CMPT) + cmpt_ctxt_type = QDMA_MBOX_CMPT_CTXT_ONLY; + else + cmpt_ctxt_type = QDMA_MBOX_CMPT_CTXT_NONE; + } else { + if (q_type == QDMA_DEV_Q_TYPE_C2H) + cmpt_ctxt_type = QDMA_MBOX_CMPT_WITH_ST; + } + + qdma_mbox_compose_vf_qctxt_read(qdma_dev->func_id, + qid_hw, st_mode, q_type, cmpt_ctxt_type, m->raw_data); + + rv = qdma_mbox_msg_send(dev, m, MBOX_OP_RSP_TIMEOUT); + if (rv < 0) { + xdebug_error("%x, qid_hw 0x%x, mbox failed for vf q context %d.\n", + qdma_dev->func_id, qid_hw, rv); + goto free_msg; + } + + rv = qdma_mbox_vf_context_get(m->raw_data, context); + if (rv < 0) { + xdebug_error("%x, failed to get vf queue context info %d.\n", + qdma_dev->func_id, rv); + goto free_msg; + } + +free_msg: + qdma_mbox_msg_free(m); + return rv; +} + +static int qdma_c2h_context_dump(uint8_t port_id, uint16_t queue) +{ + struct rte_eth_dev *dev; + struct qdma_pci_dev *qdma_dev; + struct qdma_descq_context queue_context; + enum qdma_dev_q_type q_type; + enum qdma_ip_type ip_type; + uint16_t qid; + uint8_t st_mode; + char *buf = NULL; + uint32_t buflen = 0; + int ret = 0; + + if (port_id >= rte_eth_dev_count_avail()) { + xdebug_error("Wrong port id %d\n", port_id); + return -EINVAL; + } + + dev = &rte_eth_devices[port_id]; + qdma_dev = dev->data->dev_private; + qid = qdma_dev->queue_base + queue; + ip_type = (enum qdma_ip_type)qdma_dev->ip_type; + st_mode = qdma_dev->q_info[qid].queue_mode; + q_type = QDMA_DEV_Q_TYPE_C2H; + + if (queue >= dev->data->nb_rx_queues) { + xdebug_info("RX queue_id=%d not configured\n", queue); + return -EINVAL; + } + + xdebug_info("\n ***** C2H Queue Contexts on port_id: %d for q_id: %d *****\n", + port_id, qid); + + ret = qdma_acc_context_buf_len(dev, ip_type, st_mode, + q_type, &buflen); + if (ret < 0) { + xdebug_error("Failed to get context buffer length,\n"); + return ret; + } + + /* allocate memory for csr dump */ + buf = (char *)rte_zmalloc("QDMA_C2H_CONTEXT_DUMP", + buflen, RTE_CACHE_LINE_SIZE); + if (!buf) { + xdebug_error("Unable to allocate memory for c2h context dump " + "size %d\n", buflen); + return -ENOMEM; + } + + if (qdma_dev->is_vf) { + ret = qdma_descq_context_read_vf(dev, qid, + st_mode, q_type, &queue_context); + if (ret < 0) { + xdebug_error("Failed to read c2h queue context\n"); + rte_free(buf); + return qdma_get_error_code(ret); + } + + ret = qdma_acc_dump_queue_context(dev, ip_type, + st_mode, q_type, &queue_context, buf, buflen); + if (ret < 0) { + xdebug_error("Failed to dump c2h queue context\n"); + rte_free(buf); + return qdma_get_error_code(ret); + } + } else { + ret = qdma_acc_read_dump_queue_context(dev, ip_type, + qid, st_mode, q_type, buf, buflen); + if (ret < 0) { + xdebug_error("Failed to read and dump c2h queue context\n"); + rte_free(buf); + return qdma_get_error_code(ret); + } + } + + xdebug_info("%s\n", buf); + rte_free(buf); + + return 0; +} + +static int qdma_h2c_context_dump(uint8_t port_id, uint16_t queue) +{ + struct rte_eth_dev *dev; + struct qdma_pci_dev *qdma_dev; + struct qdma_descq_context queue_context; + enum qdma_dev_q_type q_type; + enum qdma_ip_type ip_type; + uint32_t buflen = 0; + uint16_t qid; + uint8_t st_mode; + char *buf = NULL; + int ret = 0; + + if (port_id >= rte_eth_dev_count_avail()) { + xdebug_error("Wrong port id %d\n", port_id); + return -EINVAL; + } + + dev = &rte_eth_devices[port_id]; + qdma_dev = dev->data->dev_private; + qid = qdma_dev->queue_base + queue; + ip_type = (enum qdma_ip_type)qdma_dev->ip_type; + st_mode = qdma_dev->q_info[qid].queue_mode; + q_type = QDMA_DEV_Q_TYPE_H2C; + + if (queue >= dev->data->nb_tx_queues) { + xdebug_info("TX queue_id=%d not configured\n", queue); + return -EINVAL; + } + + xdebug_info("\n ***** H2C Queue Contexts on port_id: %d for q_id: %d *****\n", + port_id, qid); + + ret = qdma_acc_context_buf_len(dev, ip_type, st_mode, + q_type, &buflen); + if (ret < 0) { + xdebug_error("Failed to get context buffer length,\n"); + return ret; + } + + /* allocate memory for csr dump */ + buf = (char *)rte_zmalloc("QDMA_H2C_CONTEXT_DUMP", + buflen, RTE_CACHE_LINE_SIZE); + if (!buf) { + xdebug_error("Unable to allocate memory for h2c context dump " + "size %d\n", buflen); + return -ENOMEM; + } + + if (qdma_dev->is_vf) { + ret = qdma_descq_context_read_vf(dev, qid, + st_mode, q_type, &queue_context); + if (ret < 0) { + xdebug_error("Failed to read h2c queue context\n"); + rte_free(buf); + return qdma_get_error_code(ret); + } + + ret = qdma_acc_dump_queue_context(dev, ip_type, + st_mode, q_type, &queue_context, buf, buflen); + if (ret < 0) { + xdebug_error("Failed to dump h2c queue context\n"); + rte_free(buf); + return qdma_get_error_code(ret); + } + } else { + ret = qdma_acc_read_dump_queue_context(dev, ip_type, + qid, st_mode, q_type, buf, buflen); + if (ret < 0) { + xdebug_error("Failed to read and dump h2c queue context\n"); + rte_free(buf); + return qdma_get_error_code(ret); + } + } + + xdebug_info("%s\n", buf); + rte_free(buf); + + return 0; +} + +static int qdma_cmpt_context_dump(uint8_t port_id, uint16_t queue) +{ + struct rte_eth_dev *dev; + struct qdma_pci_dev *qdma_dev; + struct qdma_descq_context queue_context; + enum qdma_dev_q_type q_type; + enum qdma_ip_type ip_type; + uint32_t buflen; + uint16_t qid; + uint8_t st_mode; + char *buf = NULL; + int ret = 0; + + if (port_id >= rte_eth_dev_count_avail()) { + xdebug_error("Wrong port id %d\n", port_id); + return -EINVAL; + } + + dev = &rte_eth_devices[port_id]; + qdma_dev = dev->data->dev_private; + qid = qdma_dev->queue_base + queue; + ip_type = (enum qdma_ip_type)qdma_dev->ip_type; + st_mode = qdma_dev->q_info[qid].queue_mode; + q_type = QDMA_DEV_Q_TYPE_CMPT; + + if (queue >= dev->data->nb_rx_queues) { + xdebug_info("RX queue_id=%d not configured\n", queue); + return -EINVAL; + } + + xdebug_info("\n ***** CMPT Queue Contexts on port_id: %d for q_id: %d *****\n", + port_id, qid); + + ret = qdma_acc_context_buf_len(dev, ip_type, + st_mode, q_type, &buflen); + if (ret < 0) { + xdebug_error("Failed to get context buffer length\n"); + return ret; + } + + /* allocate memory for csr dump */ + buf = (char *)rte_zmalloc("QDMA_CMPT_CONTEXT_DUMP", + buflen, RTE_CACHE_LINE_SIZE); + if (!buf) { + xdebug_error("Unable to allocate memory for cmpt context dump " + "size %d\n", buflen); + return -ENOMEM; + } + + if (qdma_dev->is_vf) { + ret = qdma_descq_context_read_vf(dev, qid, + st_mode, q_type, &queue_context); + if (ret < 0) { + xdebug_error("Failed to read cmpt queue context\n"); + rte_free(buf); + return qdma_get_error_code(ret); + } + + ret = qdma_acc_dump_queue_context(dev, ip_type, + st_mode, q_type, + &queue_context, buf, buflen); + if (ret < 0) { + xdebug_error("Failed to dump cmpt queue context\n"); + rte_free(buf); + return qdma_get_error_code(ret); + } + } else { + ret = qdma_acc_read_dump_queue_context(dev, + ip_type, qid, st_mode, + q_type, buf, buflen); + if (ret < 0) { + xdebug_error("Failed to read and dump cmpt queue context\n"); + rte_free(buf); + return qdma_get_error_code(ret); + } + } + + xdebug_info("%s\n", buf); + rte_free(buf); + + return 0; +} + +static int qdma_queue_desc_dump(uint8_t port_id, + struct xdebug_desc_param *param) +{ + struct rte_eth_dev *dev; + struct qdma_rx_queue *rxq; + struct qdma_tx_queue *txq; + uint8_t *rx_ring_bypass = NULL; + uint8_t *tx_ring_bypass = NULL; + char str[50]; + int x; + + if (port_id >= rte_eth_dev_count_avail()) { + xdebug_error("Wrong port id %d\n", port_id); + return -EINVAL; + } + + dev = &rte_eth_devices[port_id]; + + switch (param->type) { + case RTE_PMD_QDMA_XDEBUG_DESC_C2H: + + if (param->queue >= dev->data->nb_rx_queues) { + xdebug_info("queue_id=%d not configured", + param->queue); + return -1; + } + + rxq = (struct qdma_rx_queue *) + dev->data->rx_queues[param->queue]; + + if (rxq == NULL) { + xdebug_info("Caught NULL pointer for queue_id: %d\n", + param->queue); + return -1; + } + + if (rxq->status != RTE_ETH_QUEUE_STATE_STARTED) { + xdebug_info("Queue_id %d is not yet started\n", + param->queue); + return -1; + } + + if (param->start < 0 || param->start > rxq->nb_rx_desc) + param->start = 0; + if (param->end <= param->start || + param->end > rxq->nb_rx_desc) + param->end = rxq->nb_rx_desc; + + if (rxq->en_bypass && rxq->bypass_desc_sz != 0) { + rx_ring_bypass = (uint8_t *)rxq->rx_ring; + + xdebug_info("\n===== C2H bypass descriptors=====\n"); + for (x = param->start; x < param->end; x++) { + uint8_t *rx_bypass = + &rx_ring_bypass[x]; + snprintf(str, sizeof(str), + "\nDescriptor ID %d\t", x); + rte_hexdump(stdout, str, + (const void *)rx_bypass, + rxq->bypass_desc_sz); + } + } else { + if (rxq->st_mode) { + struct qdma_ul_st_c2h_desc *rx_ring_st = + (struct qdma_ul_st_c2h_desc *)rxq->rx_ring; + + xdebug_info("\n===== C2H ring descriptors=====\n"); + for (x = param->start; x < param->end; x++) { + struct qdma_ul_st_c2h_desc *rx_st = + &rx_ring_st[x]; + snprintf(str, sizeof(str), + "\nDescriptor ID %d\t", x); + rte_hexdump(stdout, str, + (const void *)rx_st, + sizeof(struct qdma_ul_st_c2h_desc)); + } + } else { + struct qdma_ul_mm_desc *rx_ring_mm = + (struct qdma_ul_mm_desc *)rxq->rx_ring; + xdebug_info("\n====== C2H ring descriptors======\n"); + for (x = param->start; x < param->end; x++) { + snprintf(str, sizeof(str), + "\nDescriptor ID %d\t", x); + rte_hexdump(stdout, str, + (const void *)&rx_ring_mm[x], + sizeof(struct qdma_ul_mm_desc)); + } + } + } + break; + case RTE_PMD_QDMA_XDEBUG_DESC_CMPT: + + if (param->queue >= dev->data->nb_rx_queues) { + xdebug_info("queue_id=%d not configured", + param->queue); + return -1; + } + + rxq = (struct qdma_rx_queue *) + dev->data->rx_queues[param->queue]; + + if (rxq) { + if (rxq->status != RTE_ETH_QUEUE_STATE_STARTED) { + xdebug_info("Queue_id %d is not yet started\n", + param->queue); + return -1; + } + + if (param->start < 0 || + param->start > rxq->nb_rx_cmpt_desc) + param->start = 0; + if (param->end <= param->start || + param->end > rxq->nb_rx_cmpt_desc) + param->end = rxq->nb_rx_cmpt_desc; + + if (!rxq->st_mode) { + xdebug_info("Queue_id %d is not initialized " + "in Stream mode\n", param->queue); + return -1; + } + + xdebug_info("\n===== CMPT ring descriptors=====\n"); + for (x = param->start; x < param->end; x++) { + uint32_t *cmpt_ring = (uint32_t *) + ((uint64_t)(rxq->cmpt_ring) + + ((uint64_t)x * rxq->cmpt_desc_len)); + snprintf(str, sizeof(str), + "\nDescriptor ID %d\t", x); + rte_hexdump(stdout, str, + (const void *)cmpt_ring, + rxq->cmpt_desc_len); + } + } + break; + case RTE_PMD_QDMA_XDEBUG_DESC_H2C: + + if (param->queue >= dev->data->nb_tx_queues) { + xdebug_info("queue_id=%d not configured", + param->queue); + return -1; + } + + txq = (struct qdma_tx_queue *) + dev->data->tx_queues[param->queue]; + + if (txq == NULL) { + xdebug_info("Caught NULL pointer for queue_id: %d\n", + param->queue); + return -1; + } + + if (txq->status != RTE_ETH_QUEUE_STATE_STARTED) { + xdebug_info("Queue_id %d is not yet started\n", + param->queue); + return -1; + } + + if (param->start < 0 || param->start > txq->nb_tx_desc) + param->start = 0; + if (param->end <= param->start || + param->end > txq->nb_tx_desc) + param->end = txq->nb_tx_desc; + + if (txq->en_bypass && txq->bypass_desc_sz != 0) { + tx_ring_bypass = (uint8_t *)txq->tx_ring; + + xdebug_info("\n====== H2C bypass descriptors=====\n"); + for (x = param->start; x < param->end; x++) { + uint8_t *tx_bypass = + &tx_ring_bypass[x]; + snprintf(str, sizeof(str), + "\nDescriptor ID %d\t", x); + rte_hexdump(stdout, str, + (const void *)tx_bypass, + txq->bypass_desc_sz); + } + } else { + if (txq->st_mode) { + struct qdma_ul_st_h2c_desc *qdma_h2c_ring = + (struct qdma_ul_st_h2c_desc *)txq->tx_ring; + xdebug_info("\n====== H2C ring descriptors=====\n"); + for (x = param->start; x < param->end; x++) { + snprintf(str, sizeof(str), + "\nDescriptor ID %d\t", x); + rte_hexdump(stdout, str, + (const void *)&qdma_h2c_ring[x], + sizeof(struct qdma_ul_st_h2c_desc)); + } + } else { + struct qdma_ul_mm_desc *tx_ring_mm = + (struct qdma_ul_mm_desc *)txq->tx_ring; + xdebug_info("\n===== H2C ring descriptors=====\n"); + for (x = param->start; x < param->end; x++) { + snprintf(str, sizeof(str), + "\nDescriptor ID %d\t", x); + rte_hexdump(stdout, str, + (const void *)&tx_ring_mm[x], + sizeof(struct qdma_ul_mm_desc)); + } + } + } + break; + default: + xdebug_info("Invalid ring selected\n"); + break; + } + return 0; +} + +int rte_pmd_qdma_dbg_regdump(uint8_t port_id) +{ + int err; + + if (port_id >= rte_eth_dev_count_avail()) { + xdebug_error("Wrong port id %d\n", port_id); + return -EINVAL; + } + + err = qdma_config_reg_dump(port_id); + if (err) { + xdebug_error("Error dumping Global registers\n"); + return err; + } + return 0; +} + +int rte_pmd_qdma_dbg_reg_info_dump(uint8_t port_id, + uint32_t num_regs, uint32_t reg_addr) +{ + struct rte_eth_dev *dev; + struct qdma_pci_dev *qdma_dev; + enum qdma_ip_type ip_type; + char *buf = NULL; + int buflen = QDMA_MAX_BUFLEN; + int ret; + + if (port_id >= rte_eth_dev_count_avail()) { + xdebug_error("Wrong port id %d\n", port_id); + return -EINVAL; + } + + dev = &rte_eth_devices[port_id]; + qdma_dev = dev->data->dev_private; + ip_type = (enum qdma_ip_type)qdma_dev->ip_type; + + /* allocate memory for register dump */ + buf = (char *)rte_zmalloc("QDMA_DUMP_BUF_REG_INFO", buflen, + RTE_CACHE_LINE_SIZE); + if (!buf) { + xdebug_error("Unable to allocate memory for reg info dump " + "size %d\n", buflen); + return -ENOMEM; + } + + ret = qdma_acc_dump_reg_info(dev, ip_type, + reg_addr, num_regs, buf, buflen); + if (ret < 0) { + xdebug_error("Failed to dump reg field values\n"); + rte_free(buf); + return qdma_get_error_code(ret); + } + xdebug_info("%s\n", buf); + rte_free(buf); + + return 0; +} + +int rte_pmd_qdma_dbg_qdevice(uint8_t port_id) +{ + int err; + + if (port_id >= rte_eth_dev_count_avail()) { + xdebug_error("Wrong port id %d\n", port_id); + return -EINVAL; + } + + err = qdma_device_dump(port_id); + if (err) { + xdebug_error("Error dumping QDMA device\n"); + return err; + } + return 0; +} + +int rte_pmd_qdma_dbg_qinfo(uint8_t port_id, uint16_t queue) +{ + struct rte_eth_dev *dev; + struct qdma_pci_dev *qdma_dev; + uint16_t qid; + uint8_t st_mode; + int err; + + if (port_id >= rte_eth_dev_count_avail()) { + xdebug_error("Wrong port id %d\n", port_id); + return -EINVAL; + } + + dev = &rte_eth_devices[port_id]; + qdma_dev = dev->data->dev_private; + qid = qdma_dev->queue_base + queue; + st_mode = qdma_dev->q_info[qid].queue_mode; + + err = qdma_h2c_context_dump(port_id, queue); + if (err) { + xdebug_error("Error dumping %d: %d\n", + queue, err); + return err; + } + + err = qdma_c2h_context_dump(port_id, queue); + if (err) { + xdebug_error("Error dumping %d: %d\n", + queue, err); + return err; + } + + if (!st_mode && qdma_dev->dev_cap.mm_cmpt_en) { + err = qdma_cmpt_context_dump(port_id, queue); + if (err) { + xdebug_error("Error dumping %d: %d\n", + queue, err); + return err; + } + } + + err = qdma_h2c_struct_dump(port_id, queue); + if (err) { + xdebug_error("Error dumping %d: %d\n", + queue, err); + return err; + } + + err = qdma_c2h_struct_dump(port_id, queue); + if (err) { + xdebug_error("Error dumping %d: %d\n", + queue, err); + return err; + } + + return 0; +} + +int rte_pmd_qdma_dbg_qdesc(uint8_t port_id, uint16_t queue, int start, + int end, enum rte_pmd_qdma_xdebug_desc_type type) +{ + struct xdebug_desc_param param; + int err; + + if (port_id >= rte_eth_dev_count_avail()) { + xdebug_error("Wrong port id %d\n", port_id); + return -EINVAL; + } + + param.queue = queue; + param.start = start; + param.end = end; + param.type = type; + + err = qdma_queue_desc_dump(port_id, ¶m); + if (err) { + xdebug_error("Error dumping %d: %d\n", + queue, err); + return err; + } + return 0; +} -- 2.36.1