[v4,4/4] net/qede: add support for get register operation
Checks
Commit Message
Add support for .get_reg eth_dev ops which will be used to collect the
firmware debug data.
PMD on detecting on some HW errors will collect the FW/HW Dump to a
buffer and then it will save it to a file implemented in
qede_save_fw_dump().
Dump file location and name:
Location: <RTE_SDK> or DPDK root
Name: qede_pmd_dump_mm-dd-yy_hh-mm-ss.bin
DPDK applications can initiate a debug data collection by invoking DPDK
library’s rte_eth_dev_get_reg_info() API. This API invokes .get_reg()
interface in the PMD.
PMD implementation of .get_reg() collects the FW/HW Dump, saves it to
data field of rte_dev_reg_info and passes it to the application. It’s
the responsibility of the application to save the FW/HW Dump to a file.
We recommendation using the file name format used by qede_save_fw_dump().
Signed-off-by: Rasesh Mody <rmody@marvell.com>
Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
---
doc/guides/nics/features/qede.ini | 1 +
drivers/net/qede/Makefile | 1 +
drivers/net/qede/base/bcm_osal.c | 25 +++
drivers/net/qede/base/bcm_osal.h | 5 +
drivers/net/qede/qede_ethdev.c | 1 +
drivers/net/qede/qede_ethdev.h | 25 +++
drivers/net/qede/qede_regs.c | 271 ++++++++++++++++++++++++++++++
7 files changed, 329 insertions(+)
create mode 100644 drivers/net/qede/qede_regs.c
Comments
On Wed, Jul 8, 2020 at 2:47 AM Rasesh Mody <rmody@marvell.com> wrote:
>
> Add support for .get_reg eth_dev ops which will be used to collect the
> firmware debug data.
>
> PMD on detecting on some HW errors will collect the FW/HW Dump to a
> buffer and then it will save it to a file implemented in
> qede_save_fw_dump().
>
> Dump file location and name:
> Location: <RTE_SDK> or DPDK root
> Name: qede_pmd_dump_mm-dd-yy_hh-mm-ss.bin
>
> DPDK applications can initiate a debug data collection by invoking DPDK
> library’s rte_eth_dev_get_reg_info() API. This API invokes .get_reg()
> interface in the PMD.
>
> PMD implementation of .get_reg() collects the FW/HW Dump, saves it to
> data field of rte_dev_reg_info and passes it to the application. It’s
> the responsibility of the application to save the FW/HW Dump to a file.
> We recommendation using the file name format used by qede_save_fw_dump().
>
> Signed-off-by: Rasesh Mody <rmody@marvell.com>
> Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
Found meson build failure with gcc 10. Please check.
meson -Dexamples=l3fwd --buildtype=debugoptimized --werror
--default-library=static /export/dpdk-next-net-mrvl/devtools/..
./build-gcc-static
gcc -o drivers/librte_pmd_qede.so.20.0.3
'drivers/a715181@@rte_pmd_qede@sha/meson-generated_.._rte_pmd_qede.pmd.c.o'
'drivers/net/qede/base/f6110d5@@qede_base@sta/bcm_osal.c.o'
'drivers/net/qede/base/f6110d5@@qede_base@sta/ecore_cxt.c.o' '
drivers/net/qede/base/f6110d5@@qede_base@sta/ecore_dcbx.c.o'
'drivers/net/qede/base/f6110d5@@qede_base@sta/ecore_dev.c.o'
'drivers/net/qede/base/f6110d5@@qede_base@sta/ecore_hw.c.o'
'drivers/net/qede/base/f6110d5@@qede_base@sta/ecore_init_f
w_funcs.c.o' 'drivers/net/qede/base/f6110d5@@qede_base@sta/ecore_init_ops.c.o'
'drivers/net/qede/base/f6110d5@@qede_base@sta/ecore_int.c.o'
'drivers/net/qede/base/f6110d5@@qede_base@sta/ecore_l2.c.o'
'drivers/net/qede/base/f6110d5@@qede_bas
e@sta/ecore_mcp.c.o'
'drivers/net/qede/base/f6110d5@@qede_base@sta/ecore_sp_commands.c.o'
'drivers/net/qede/base/f6110d5@@qede_base@sta/ecore_spq.c.o'
'drivers/net/qede/base/f6110d5@@qede_base@sta/ecore_sriov.c.o'
'drivers/net/qede/base/f61
10d5@@qede_base@sta/ecore_vf.c.o'
'drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_ethdev.c.o'
'drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_filter.c.o'
'drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o'
'drivers/a715
181@@tmp_rte_pmd_qede@sta/net_qede_qede_rxtx.c.o' -Wl,--as-needed
-Wl,--no-undefined -shared -fPIC -Wl,--start-group
-Wl,-soname,librte_pmd_qede.so.20.0 -Wl,--no-as-needed -pthread -lm
-ldl -lnuma lib/librte_ethdev.so.20.0.3 lib/librte_eal.
so.20.0.3 lib/librte_kvargs.so.20.0.3 lib/librte_telemetry.so.20.0.3
lib/librte_net.so.20.0.3 lib/librte_mbuf.so.20.0.3
lib/librte_mempool.so.20.0.3 lib/librte_ring.so.20.0.3
lib/librte_meter.so.20.0.3 drivers/librte_bus_pci.so.20.0.3 lib/l
ibrte_pci.so.20.0.3 drivers/librte_bus_vdev.so.20.0.3
-Wl,--version-script=/export/dpdk-next-net-mrvl/drivers/net/qede/rte_pmd_qede_version.map
/usr/lib/libbsd.so -Wl,--end-group
'-Wl,-rpath,$ORIGIN/../lib:$ORIGIN/' -Wl,-rpath-link,/export/
dpdk-next-net-mrvl/build-gcc-static/lib
-Wl,-rpath-link,/export/dpdk-next-net-mrvl/build-gcc-static/drivers
/usr/bin/ld: drivers/net/qede/base/f6110d5@@qede_base@sta/ecore_dev.c.o:
in function `ecore_resc_alloc':
/export/dpdk-next-net-mrvl/build-gcc-static/../drivers/net/qede/base/ecore_dev.c:2516:
undefined reference to `qed_dbg_alloc_user_data'
/usr/bin/ld: /export/dpdk-next-net-mrvl/build-gcc-static/../drivers/net/qede/base/ecore_dev.c:2525:
undefined reference to `qed_dbg_alloc_user_data'
/usr/bin/ld: drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o:
in function `qed_slowpath_start':
/export/dpdk-next-net-mrvl/build-gcc-static/../drivers/net/qede/qede_main.c:285:
undefined reference to `qed_dbg_pf_init'
/usr/bin/ld: drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o:(.data.rel.ro+0xa8):
undefined reference to `qed_dbg_grc'
/usr/bin/ld: drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o:(.data.rel.ro+0xb0):
undefined reference to `qed_dbg_grc_size'
/usr/bin/ld: drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o:(.data.rel.ro+0xb8):
undefined reference to `qed_dbg_idle_chk'
/usr/bin/ld: drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o:(.data.rel.ro+0xc0):
undefined reference to `qed_dbg_idle_chk_size'
/usr/bin/ld: drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o:(.data.rel.ro+0xc8):
undefined reference to `qed_dbg_reg_fifo'
/usr/bin/ld: drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o:(.data.rel.ro+0xd0):
undefined reference to `qed_dbg_reg_fifo_size'
/usr/bin/ld: drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o:(.data.rel.ro+0xd8):
undefined reference to `qed_dbg_mcp_trace'
/usr/bin/ld: drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o:(.data.rel.ro+0xe0):
undefined reference to `qed_dbg_mcp_trace_size'
/usr/bin/ld: drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o:(.data.rel.ro+0xe8):
undefined reference to `qed_dbg_protection_override'
/usr/bin/ld: drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o:(.data.rel.ro+0xf0):
undefined reference to `qed_dbg_protection_override_size'
/usr/bin/ld: drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o:(.data.rel.ro+0xf8):
undefined reference to `qed_dbg_igu_fifo_size'
/usr/bin/ld: drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o:(.data.rel.ro+0x100):
undefined reference to `qed_dbg_igu_fifo'
/usr/bin/ld: drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o:(.data.rel.ro+0x108):
undefined reference to `qed_dbg_fw_asserts'
/usr/bin/ld: drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o:(.data.rel.ro+0x110):
undefined reference to `qed_dbg_fw_asserts_size'
/usr/bin/ld: drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o:(.data.rel.ro+0x118):
undefined reference to `qed_dbg_ilt'
/usr/bin/ld: drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o:(.data.rel.ro+0x120):
undefined reference to `qed_dbg_ilt_size'
/usr/bin/ld: drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o:(.data.rel.ro+0x128):
undefined reference to `qed_get_debug_engine'
/usr/bin/ld: drivers/a715181@@tmp_rte_pmd_qede@sta/net_qede_qede_main.c.o:(.data.rel.ro+0x130):
undefined reference to `qed_set_debug_engine'
> ---
> doc/guides/nics/features/qede.ini | 1 +
> drivers/net/qede/Makefile | 1 +
> drivers/net/qede/base/bcm_osal.c | 25 +++
> drivers/net/qede/base/bcm_osal.h | 5 +
> drivers/net/qede/qede_ethdev.c | 1 +
> drivers/net/qede/qede_ethdev.h | 25 +++
> drivers/net/qede/qede_regs.c | 271 ++++++++++++++++++++++++++++++
> 7 files changed, 329 insertions(+)
> create mode 100644 drivers/net/qede/qede_regs.c
>
> diff --git a/doc/guides/nics/features/qede.ini b/doc/guides/nics/features/qede.ini
> index 20c90e626..f8716523e 100644
> --- a/doc/guides/nics/features/qede.ini
> +++ b/doc/guides/nics/features/qede.ini
> @@ -31,6 +31,7 @@ Packet type parsing = Y
> Basic stats = Y
> Extended stats = Y
> Stats per queue = Y
> +Registers dump = Y
> Multiprocess aware = Y
> Linux UIO = Y
> Linux VFIO = Y
> diff --git a/drivers/net/qede/Makefile b/drivers/net/qede/Makefile
> index 3b00338ff..0e8a67b0d 100644
> --- a/drivers/net/qede/Makefile
> +++ b/drivers/net/qede/Makefile
> @@ -104,5 +104,6 @@ SRCS-$(CONFIG_RTE_LIBRTE_QEDE_PMD) += qede_main.c
> SRCS-$(CONFIG_RTE_LIBRTE_QEDE_PMD) += qede_rxtx.c
> SRCS-$(CONFIG_RTE_LIBRTE_QEDE_PMD) += qede_filter.c
> SRCS-$(CONFIG_RTE_LIBRTE_QEDE_PMD) += qede_debug.c
> +SRCS-$(CONFIG_RTE_LIBRTE_QEDE_PMD) += qede_regs.c
>
> include $(RTE_SDK)/mk/rte.lib.mk
> diff --git a/drivers/net/qede/base/bcm_osal.c b/drivers/net/qede/base/bcm_osal.c
> index 45557fe3c..65837b53d 100644
> --- a/drivers/net/qede/base/bcm_osal.c
> +++ b/drivers/net/qede/base/bcm_osal.c
> @@ -246,6 +246,28 @@ qede_get_mcp_proto_stats(struct ecore_dev *edev,
> }
> }
>
> +static void qede_hw_err_handler(void *dev, enum ecore_hw_err_type err_type)
> +{
> + struct ecore_dev *edev = dev;
> +
> + switch (err_type) {
> + case ECORE_HW_ERR_FAN_FAIL:
> + break;
> +
> + case ECORE_HW_ERR_MFW_RESP_FAIL:
> + case ECORE_HW_ERR_HW_ATTN:
> + case ECORE_HW_ERR_DMAE_FAIL:
> + case ECORE_HW_ERR_RAMROD_FAIL:
> + case ECORE_HW_ERR_FW_ASSERT:
> + OSAL_SAVE_FW_DUMP(0); /* Using port 0 as default port_id */
> + break;
> +
> + default:
> + DP_NOTICE(edev, false, "Unknown HW error [%d]\n", err_type);
> + return;
> + }
> +}
> +
> void
> qede_hw_err_notify(struct ecore_hwfn *p_hwfn, enum ecore_hw_err_type err_type)
> {
> @@ -275,6 +297,9 @@ qede_hw_err_notify(struct ecore_hwfn *p_hwfn, enum ecore_hw_err_type err_type)
> }
>
> DP_ERR(p_hwfn, "HW error occurred [%s]\n", err_str);
> +
> + qede_hw_err_handler(p_hwfn->p_dev, err_type);
> +
> ecore_int_attn_clr_enable(p_hwfn->p_dev, true);
> }
>
> diff --git a/drivers/net/qede/base/bcm_osal.h b/drivers/net/qede/base/bcm_osal.h
> index b4b94231b..5d4df5907 100644
> --- a/drivers/net/qede/base/bcm_osal.h
> +++ b/drivers/net/qede/base/bcm_osal.h
> @@ -371,6 +371,11 @@ void qede_hw_err_notify(struct ecore_hwfn *p_hwfn,
>
> /* TODO: */
> #define OSAL_SCHEDULE_RECOVERY_HANDLER(hwfn) nothing
> +
> +int qede_save_fw_dump(uint8_t port_id);
> +
> +#define OSAL_SAVE_FW_DUMP(port_id) qede_save_fw_dump(port_id)
> +
> #define OSAL_HW_ERROR_OCCURRED(hwfn, err_type) \
> qede_hw_err_notify(hwfn, err_type)
>
> diff --git a/drivers/net/qede/qede_ethdev.c b/drivers/net/qede/qede_ethdev.c
> index b5d6c7c43..e5a2581dd 100644
> --- a/drivers/net/qede/qede_ethdev.c
> +++ b/drivers/net/qede/qede_ethdev.c
> @@ -2426,6 +2426,7 @@ static const struct eth_dev_ops qede_eth_dev_ops = {
> .udp_tunnel_port_add = qede_udp_dst_port_add,
> .udp_tunnel_port_del = qede_udp_dst_port_del,
> .fw_version_get = qede_fw_version_get,
> + .get_reg = qede_get_regs,
> };
>
> static const struct eth_dev_ops qede_eth_vf_dev_ops = {
> diff --git a/drivers/net/qede/qede_ethdev.h b/drivers/net/qede/qede_ethdev.h
> index b988a73f2..76c5dae3b 100644
> --- a/drivers/net/qede/qede_ethdev.h
> +++ b/drivers/net/qede/qede_ethdev.h
> @@ -214,6 +214,8 @@ struct qede_tunn_params {
> uint16_t udp_port;
> };
>
> +#define QEDE_FW_DUMP_FILE_SIZE 128
> +
> /*
> * Structure to store private data for each port.
> */
> @@ -252,6 +254,7 @@ struct qede_dev {
> char drv_ver[QEDE_PMD_DRV_VER_STR_SIZE];
> bool vport_started;
> int vlan_offload_mask;
> + char dump_file[QEDE_FW_DUMP_FILE_SIZE];
> void *ethdev;
> };
>
> @@ -313,4 +316,26 @@ void qede_config_accept_any_vlan(struct qede_dev *qdev, bool flg);
> int qede_ucast_filter(struct rte_eth_dev *eth_dev,
> struct ecore_filter_ucast *ucast,
> bool add);
> +
> +#define REGDUMP_HEADER_SIZE sizeof(u32)
> +#define REGDUMP_HEADER_FEATURE_SHIFT 24
> +#define REGDUMP_HEADER_ENGINE_SHIFT 31
> +#define REGDUMP_HEADER_OMIT_ENGINE_SHIFT 30
> +
> +enum debug_print_features {
> + OLD_MODE = 0,
> + IDLE_CHK = 1,
> + GRC_DUMP = 2,
> + MCP_TRACE = 3,
> + REG_FIFO = 4,
> + PROTECTION_OVERRIDE = 5,
> + IGU_FIFO = 6,
> + PHY = 7,
> + FW_ASSERTS = 8,
> +};
> +
> +int qede_get_regs_len(struct qede_dev *qdev);
> +int qede_get_regs(struct rte_eth_dev *dev, struct rte_dev_reg_info *regs);
> +void qede_config_rx_mode(struct rte_eth_dev *eth_dev);
> +void qed_dbg_dump(struct rte_eth_dev *eth_dev);
> #endif /* _QEDE_ETHDEV_H_ */
> diff --git a/drivers/net/qede/qede_regs.c b/drivers/net/qede/qede_regs.c
> new file mode 100644
> index 000000000..4409d2180
> --- /dev/null
> +++ b/drivers/net/qede/qede_regs.c
> @@ -0,0 +1,271 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright (c) 2020 Marvell Semiconductor Inc.
> + * All rights reserved.
> + * www.marvell.com
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <fcntl.h>
> +#include <time.h>
> +#include <rte_ethdev.h>
> +#include "base/bcm_osal.h"
> +#include "qede_ethdev.h"
> +
> +int
> +qede_get_regs_len(struct qede_dev *qdev)
> +{
> + struct ecore_dev *edev = &qdev->edev;
> + int cur_engine, num_of_hwfns, regs_len = 0;
> + uint8_t org_engine;
> +
> + if (IS_VF(edev))
> + return 0;
> +
> + if (qdev->ops && qdev->ops->common) {
> + num_of_hwfns = qdev->dev_info.common.num_hwfns;
> + org_engine = qdev->ops->common->dbg_get_debug_engine(edev);
> + for (cur_engine = 0; cur_engine < num_of_hwfns; cur_engine++) {
> + /* compute required buffer size for idle_chks and
> + * grcDump for each hw function
> + */
> + DP_NOTICE(edev, false,
> + "Calculating idle_chk and grcdump register length for current engine\n");
> + qdev->ops->common->dbg_set_debug_engine(edev,
> + cur_engine);
> + regs_len += REGDUMP_HEADER_SIZE +
> + qdev->ops->common->dbg_idle_chk_size(edev) +
> + REGDUMP_HEADER_SIZE +
> + qdev->ops->common->dbg_idle_chk_size(edev) +
> + REGDUMP_HEADER_SIZE +
> + qdev->ops->common->dbg_grc_size(edev) +
> + REGDUMP_HEADER_SIZE +
> + qdev->ops->common->dbg_reg_fifo_size(edev) +
> + REGDUMP_HEADER_SIZE +
> + qdev->ops->common->dbg_protection_override_size(edev) +
> + REGDUMP_HEADER_SIZE +
> + qdev->ops->common->dbg_igu_fifo_size(edev) +
> + REGDUMP_HEADER_SIZE +
> + qdev->ops->common->dbg_fw_asserts_size(edev);
> + }
> + /* compute required buffer size for mcp trace and add it to the
> + * total required buffer size
> + */
> + regs_len += REGDUMP_HEADER_SIZE +
> + qdev->ops->common->dbg_mcp_trace_size(edev);
> +
> + qdev->ops->common->dbg_set_debug_engine(edev, org_engine);
> + }
> + DP_NOTICE(edev, false, "Total length = %u\n", regs_len);
> +
> + return regs_len;
> +}
> +
> +static uint32_t
> +qede_calc_regdump_header(enum debug_print_features feature, int engine,
> + uint32_t feature_size, uint8_t omit_engine)
> +{
> + /* insert the engine, feature and mode inside the header and
> + * combine it with feature size
> + */
> + return (feature_size | (feature << REGDUMP_HEADER_FEATURE_SHIFT) |
> + (omit_engine << REGDUMP_HEADER_OMIT_ENGINE_SHIFT) |
> + (engine << REGDUMP_HEADER_ENGINE_SHIFT));
> +}
> +
> +int qede_get_regs(struct rte_eth_dev *eth_dev, struct rte_dev_reg_info *regs)
> +{
> + struct qede_dev *qdev = eth_dev->data->dev_private;
> + struct ecore_dev *edev = &qdev->edev;
> + uint32_t *buffer = regs->data;
> + int cur_engine, num_of_hwfns;
> + /* '1' tells the parser to omit the engine number in the output files */
> + uint8_t omit_engine = 0;
> + uint8_t org_engine;
> + uint32_t feature_size;
> + uint32_t offset = 0;
> +
> + if (IS_VF(edev))
> + return -ENOTSUP;
> +
> + if (buffer == NULL) {
> + regs->length = qede_get_regs_len(qdev);
> + regs->width = sizeof(uint32_t);
> + DP_INFO(edev, "Length %u\n", regs->length);
> + return 0;
> + }
> +
> + memset(buffer, 0, regs->length);
> + num_of_hwfns = qdev->dev_info.common.num_hwfns;
> + if (num_of_hwfns == 1)
> + omit_engine = 1;
> +
> + OSAL_MUTEX_ACQUIRE(&edev->dbg_lock);
> +
> + org_engine = qdev->ops->common->dbg_get_debug_engine(edev);
> + for (cur_engine = 0; cur_engine < num_of_hwfns; cur_engine++) {
> + /* collect idle_chks and grcDump for each hw function */
> + DP_NOTICE(edev, false, "obtaining idle_chk and grcdump for current engine\n");
> + qdev->ops->common->dbg_set_debug_engine(edev, cur_engine);
> +
> + /* first idle_chk */
> + qdev->ops->common->dbg_idle_chk(edev, (uint8_t *)buffer +
> + offset + REGDUMP_HEADER_SIZE, &feature_size);
> + *(uint32_t *)((uint8_t *)buffer + offset) =
> + qede_calc_regdump_header(IDLE_CHK, cur_engine,
> + feature_size, omit_engine);
> + offset += (feature_size + REGDUMP_HEADER_SIZE);
> + DP_NOTICE(edev, false, "Idle Check1 feature_size %u\n",
> + feature_size);
> +
> + /* second idle_chk */
> + qdev->ops->common->dbg_idle_chk(edev, (uint8_t *)buffer +
> + offset + REGDUMP_HEADER_SIZE, &feature_size);
> + *(uint32_t *)((uint8_t *)buffer + offset) =
> + qede_calc_regdump_header(IDLE_CHK, cur_engine,
> + feature_size, omit_engine);
> + offset += (feature_size + REGDUMP_HEADER_SIZE);
> + DP_NOTICE(edev, false, "Idle Check2 feature_size %u\n",
> + feature_size);
> +
> + /* reg_fifo dump */
> + qdev->ops->common->dbg_reg_fifo(edev, (uint8_t *)buffer +
> + offset + REGDUMP_HEADER_SIZE, &feature_size);
> + *(uint32_t *)((uint8_t *)buffer + offset) =
> + qede_calc_regdump_header(REG_FIFO, cur_engine,
> + feature_size, omit_engine);
> + offset += (feature_size + REGDUMP_HEADER_SIZE);
> + DP_NOTICE(edev, false, "Reg fifo feature_size %u\n",
> + feature_size);
> +
> + /* igu_fifo dump */
> + qdev->ops->common->dbg_igu_fifo(edev, (uint8_t *)buffer +
> + offset + REGDUMP_HEADER_SIZE, &feature_size);
> + *(uint32_t *)((uint8_t *)buffer + offset) =
> + qede_calc_regdump_header(IGU_FIFO, cur_engine,
> + feature_size, omit_engine);
> + offset += (feature_size + REGDUMP_HEADER_SIZE);
> + DP_NOTICE(edev, false, "IGU fifo feature_size %u\n",
> + feature_size);
> +
> + /* protection_override dump */
> + qdev->ops->common->dbg_protection_override(edev,
> + (uint8_t *)buffer +
> + offset + REGDUMP_HEADER_SIZE, &feature_size);
> + *(uint32_t *)((uint8_t *)buffer + offset) =
> + qede_calc_regdump_header(PROTECTION_OVERRIDE, cur_engine,
> + feature_size, omit_engine);
> + offset += (feature_size + REGDUMP_HEADER_SIZE);
> + DP_NOTICE(edev, false, "Protection override feature_size %u\n",
> + feature_size);
> +
> + /* fw_asserts dump */
> + qdev->ops->common->dbg_fw_asserts(edev, (uint8_t *)buffer +
> + offset + REGDUMP_HEADER_SIZE, &feature_size);
> + *(uint32_t *)((uint8_t *)buffer + offset) =
> + qede_calc_regdump_header(FW_ASSERTS, cur_engine,
> + feature_size, omit_engine);
> + offset += (feature_size + REGDUMP_HEADER_SIZE);
> + DP_NOTICE(edev, false, "FW assert feature_size %u\n",
> + feature_size);
> +
> + /* grc dump */
> + qdev->ops->common->dbg_grc(edev, (uint8_t *)buffer +
> + offset + REGDUMP_HEADER_SIZE, &feature_size);
> + *(uint32_t *)((uint8_t *)buffer + offset) =
> + qede_calc_regdump_header(GRC_DUMP, cur_engine,
> + feature_size, omit_engine);
> + offset += (feature_size + REGDUMP_HEADER_SIZE);
> + DP_NOTICE(edev, false, "GRC dump feature_size %u\n",
> + feature_size);
> + }
> +
> + /* mcp_trace */
> + qdev->ops->common->dbg_mcp_trace(edev, (uint8_t *)buffer +
> + offset + REGDUMP_HEADER_SIZE, &feature_size);
> + *(uint32_t *)((uint8_t *)buffer + offset) =
> + qede_calc_regdump_header(MCP_TRACE, cur_engine, feature_size,
> + omit_engine);
> + offset += (feature_size + REGDUMP_HEADER_SIZE);
> + DP_NOTICE(edev, false, "MCP trace feature_size %u\n", feature_size);
> +
> + qdev->ops->common->dbg_set_debug_engine(edev, org_engine);
> +
> + OSAL_MUTEX_RELEASE(&edev->dbg_lock);
> +
> + return 0;
> +}
> +
> +static void
> +qede_set_fw_dump_file_name(struct qede_dev *qdev)
> +{
> + time_t ltime;
> + struct tm *tm;
> +
> + ltime = time(NULL);
> + tm = localtime(<ime);
> + snprintf(qdev->dump_file, QEDE_FW_DUMP_FILE_SIZE,
> + "qede_pmd_dump_%02d-%02d-%02d_%02d-%02d-%02d.bin",
> + tm->tm_mon + 1, (int)tm->tm_mday, 1900 + tm->tm_year,
> + tm->tm_hour, tm->tm_min, tm->tm_sec);
> +}
> +
> +static int
> +qede_write_fwdump(const char *dump_file, void *dump, size_t len)
> +{
> + int err = 0;
> + FILE *f;
> + size_t bytes;
> +
> + f = fopen(dump_file, "wb+");
> +
> + if (!f) {
> + fprintf(stderr, "Can't open file %s: %s\n",
> + dump_file, strerror(errno));
> + return 1;
> + }
> + bytes = fwrite(dump, 1, len, f);
> + if (bytes != len) {
> + fprintf(stderr, "Can not write all of dump data bytes=%ld len=%ld\n",
> + bytes, len);
> + err = 1;
> + }
> +
> + if (fclose(f)) {
> + fprintf(stderr, "Can't close file %s: %s\n",
> + dump_file, strerror(errno));
> + err = 1;
> + }
> +
> + return err;
> +}
> +
> +int
> +qede_save_fw_dump(uint8_t port_id)
> +{
> + struct rte_eth_dev *eth_dev = &rte_eth_devices[port_id];
> + struct rte_dev_reg_info regs;
> + struct qede_dev *qdev = eth_dev->data->dev_private;
> + struct ecore_dev *edev = &qdev->edev;
> + int rc = 0;
> +
> + if (!rte_eth_dev_is_valid_port(port_id)) {
> + DP_ERR(edev, "port %u invalid port ID", port_id);
> + return -ENODEV;
> + }
> +
> + memset(®s, 0, sizeof(regs));
> + regs.length = qede_get_regs_len(qdev);
> + regs.data = OSAL_ZALLOC(eth_dev, GFP_KERNEL, regs.length);
> + if (regs.data) {
> + qede_get_regs(eth_dev, ®s);
> + qede_set_fw_dump_file_name(qdev);
> + rc = qede_write_fwdump(qdev->dump_file, regs.data, regs.length);
> + if (!rc)
> + DP_NOTICE(edev, false, "FW dump written to %s file\n",
> + qdev->dump_file);
> + OSAL_FREE(edev, regs.data);
> + }
> +
> + return rc;
> +}
> --
> 2.18.0
>
@@ -31,6 +31,7 @@ Packet type parsing = Y
Basic stats = Y
Extended stats = Y
Stats per queue = Y
+Registers dump = Y
Multiprocess aware = Y
Linux UIO = Y
Linux VFIO = Y
@@ -104,5 +104,6 @@ SRCS-$(CONFIG_RTE_LIBRTE_QEDE_PMD) += qede_main.c
SRCS-$(CONFIG_RTE_LIBRTE_QEDE_PMD) += qede_rxtx.c
SRCS-$(CONFIG_RTE_LIBRTE_QEDE_PMD) += qede_filter.c
SRCS-$(CONFIG_RTE_LIBRTE_QEDE_PMD) += qede_debug.c
+SRCS-$(CONFIG_RTE_LIBRTE_QEDE_PMD) += qede_regs.c
include $(RTE_SDK)/mk/rte.lib.mk
@@ -246,6 +246,28 @@ qede_get_mcp_proto_stats(struct ecore_dev *edev,
}
}
+static void qede_hw_err_handler(void *dev, enum ecore_hw_err_type err_type)
+{
+ struct ecore_dev *edev = dev;
+
+ switch (err_type) {
+ case ECORE_HW_ERR_FAN_FAIL:
+ break;
+
+ case ECORE_HW_ERR_MFW_RESP_FAIL:
+ case ECORE_HW_ERR_HW_ATTN:
+ case ECORE_HW_ERR_DMAE_FAIL:
+ case ECORE_HW_ERR_RAMROD_FAIL:
+ case ECORE_HW_ERR_FW_ASSERT:
+ OSAL_SAVE_FW_DUMP(0); /* Using port 0 as default port_id */
+ break;
+
+ default:
+ DP_NOTICE(edev, false, "Unknown HW error [%d]\n", err_type);
+ return;
+ }
+}
+
void
qede_hw_err_notify(struct ecore_hwfn *p_hwfn, enum ecore_hw_err_type err_type)
{
@@ -275,6 +297,9 @@ qede_hw_err_notify(struct ecore_hwfn *p_hwfn, enum ecore_hw_err_type err_type)
}
DP_ERR(p_hwfn, "HW error occurred [%s]\n", err_str);
+
+ qede_hw_err_handler(p_hwfn->p_dev, err_type);
+
ecore_int_attn_clr_enable(p_hwfn->p_dev, true);
}
@@ -371,6 +371,11 @@ void qede_hw_err_notify(struct ecore_hwfn *p_hwfn,
/* TODO: */
#define OSAL_SCHEDULE_RECOVERY_HANDLER(hwfn) nothing
+
+int qede_save_fw_dump(uint8_t port_id);
+
+#define OSAL_SAVE_FW_DUMP(port_id) qede_save_fw_dump(port_id)
+
#define OSAL_HW_ERROR_OCCURRED(hwfn, err_type) \
qede_hw_err_notify(hwfn, err_type)
@@ -2426,6 +2426,7 @@ static const struct eth_dev_ops qede_eth_dev_ops = {
.udp_tunnel_port_add = qede_udp_dst_port_add,
.udp_tunnel_port_del = qede_udp_dst_port_del,
.fw_version_get = qede_fw_version_get,
+ .get_reg = qede_get_regs,
};
static const struct eth_dev_ops qede_eth_vf_dev_ops = {
@@ -214,6 +214,8 @@ struct qede_tunn_params {
uint16_t udp_port;
};
+#define QEDE_FW_DUMP_FILE_SIZE 128
+
/*
* Structure to store private data for each port.
*/
@@ -252,6 +254,7 @@ struct qede_dev {
char drv_ver[QEDE_PMD_DRV_VER_STR_SIZE];
bool vport_started;
int vlan_offload_mask;
+ char dump_file[QEDE_FW_DUMP_FILE_SIZE];
void *ethdev;
};
@@ -313,4 +316,26 @@ void qede_config_accept_any_vlan(struct qede_dev *qdev, bool flg);
int qede_ucast_filter(struct rte_eth_dev *eth_dev,
struct ecore_filter_ucast *ucast,
bool add);
+
+#define REGDUMP_HEADER_SIZE sizeof(u32)
+#define REGDUMP_HEADER_FEATURE_SHIFT 24
+#define REGDUMP_HEADER_ENGINE_SHIFT 31
+#define REGDUMP_HEADER_OMIT_ENGINE_SHIFT 30
+
+enum debug_print_features {
+ OLD_MODE = 0,
+ IDLE_CHK = 1,
+ GRC_DUMP = 2,
+ MCP_TRACE = 3,
+ REG_FIFO = 4,
+ PROTECTION_OVERRIDE = 5,
+ IGU_FIFO = 6,
+ PHY = 7,
+ FW_ASSERTS = 8,
+};
+
+int qede_get_regs_len(struct qede_dev *qdev);
+int qede_get_regs(struct rte_eth_dev *dev, struct rte_dev_reg_info *regs);
+void qede_config_rx_mode(struct rte_eth_dev *eth_dev);
+void qed_dbg_dump(struct rte_eth_dev *eth_dev);
#endif /* _QEDE_ETHDEV_H_ */
new file mode 100644
@@ -0,0 +1,271 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2020 Marvell Semiconductor Inc.
+ * All rights reserved.
+ * www.marvell.com
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <time.h>
+#include <rte_ethdev.h>
+#include "base/bcm_osal.h"
+#include "qede_ethdev.h"
+
+int
+qede_get_regs_len(struct qede_dev *qdev)
+{
+ struct ecore_dev *edev = &qdev->edev;
+ int cur_engine, num_of_hwfns, regs_len = 0;
+ uint8_t org_engine;
+
+ if (IS_VF(edev))
+ return 0;
+
+ if (qdev->ops && qdev->ops->common) {
+ num_of_hwfns = qdev->dev_info.common.num_hwfns;
+ org_engine = qdev->ops->common->dbg_get_debug_engine(edev);
+ for (cur_engine = 0; cur_engine < num_of_hwfns; cur_engine++) {
+ /* compute required buffer size for idle_chks and
+ * grcDump for each hw function
+ */
+ DP_NOTICE(edev, false,
+ "Calculating idle_chk and grcdump register length for current engine\n");
+ qdev->ops->common->dbg_set_debug_engine(edev,
+ cur_engine);
+ regs_len += REGDUMP_HEADER_SIZE +
+ qdev->ops->common->dbg_idle_chk_size(edev) +
+ REGDUMP_HEADER_SIZE +
+ qdev->ops->common->dbg_idle_chk_size(edev) +
+ REGDUMP_HEADER_SIZE +
+ qdev->ops->common->dbg_grc_size(edev) +
+ REGDUMP_HEADER_SIZE +
+ qdev->ops->common->dbg_reg_fifo_size(edev) +
+ REGDUMP_HEADER_SIZE +
+ qdev->ops->common->dbg_protection_override_size(edev) +
+ REGDUMP_HEADER_SIZE +
+ qdev->ops->common->dbg_igu_fifo_size(edev) +
+ REGDUMP_HEADER_SIZE +
+ qdev->ops->common->dbg_fw_asserts_size(edev);
+ }
+ /* compute required buffer size for mcp trace and add it to the
+ * total required buffer size
+ */
+ regs_len += REGDUMP_HEADER_SIZE +
+ qdev->ops->common->dbg_mcp_trace_size(edev);
+
+ qdev->ops->common->dbg_set_debug_engine(edev, org_engine);
+ }
+ DP_NOTICE(edev, false, "Total length = %u\n", regs_len);
+
+ return regs_len;
+}
+
+static uint32_t
+qede_calc_regdump_header(enum debug_print_features feature, int engine,
+ uint32_t feature_size, uint8_t omit_engine)
+{
+ /* insert the engine, feature and mode inside the header and
+ * combine it with feature size
+ */
+ return (feature_size | (feature << REGDUMP_HEADER_FEATURE_SHIFT) |
+ (omit_engine << REGDUMP_HEADER_OMIT_ENGINE_SHIFT) |
+ (engine << REGDUMP_HEADER_ENGINE_SHIFT));
+}
+
+int qede_get_regs(struct rte_eth_dev *eth_dev, struct rte_dev_reg_info *regs)
+{
+ struct qede_dev *qdev = eth_dev->data->dev_private;
+ struct ecore_dev *edev = &qdev->edev;
+ uint32_t *buffer = regs->data;
+ int cur_engine, num_of_hwfns;
+ /* '1' tells the parser to omit the engine number in the output files */
+ uint8_t omit_engine = 0;
+ uint8_t org_engine;
+ uint32_t feature_size;
+ uint32_t offset = 0;
+
+ if (IS_VF(edev))
+ return -ENOTSUP;
+
+ if (buffer == NULL) {
+ regs->length = qede_get_regs_len(qdev);
+ regs->width = sizeof(uint32_t);
+ DP_INFO(edev, "Length %u\n", regs->length);
+ return 0;
+ }
+
+ memset(buffer, 0, regs->length);
+ num_of_hwfns = qdev->dev_info.common.num_hwfns;
+ if (num_of_hwfns == 1)
+ omit_engine = 1;
+
+ OSAL_MUTEX_ACQUIRE(&edev->dbg_lock);
+
+ org_engine = qdev->ops->common->dbg_get_debug_engine(edev);
+ for (cur_engine = 0; cur_engine < num_of_hwfns; cur_engine++) {
+ /* collect idle_chks and grcDump for each hw function */
+ DP_NOTICE(edev, false, "obtaining idle_chk and grcdump for current engine\n");
+ qdev->ops->common->dbg_set_debug_engine(edev, cur_engine);
+
+ /* first idle_chk */
+ qdev->ops->common->dbg_idle_chk(edev, (uint8_t *)buffer +
+ offset + REGDUMP_HEADER_SIZE, &feature_size);
+ *(uint32_t *)((uint8_t *)buffer + offset) =
+ qede_calc_regdump_header(IDLE_CHK, cur_engine,
+ feature_size, omit_engine);
+ offset += (feature_size + REGDUMP_HEADER_SIZE);
+ DP_NOTICE(edev, false, "Idle Check1 feature_size %u\n",
+ feature_size);
+
+ /* second idle_chk */
+ qdev->ops->common->dbg_idle_chk(edev, (uint8_t *)buffer +
+ offset + REGDUMP_HEADER_SIZE, &feature_size);
+ *(uint32_t *)((uint8_t *)buffer + offset) =
+ qede_calc_regdump_header(IDLE_CHK, cur_engine,
+ feature_size, omit_engine);
+ offset += (feature_size + REGDUMP_HEADER_SIZE);
+ DP_NOTICE(edev, false, "Idle Check2 feature_size %u\n",
+ feature_size);
+
+ /* reg_fifo dump */
+ qdev->ops->common->dbg_reg_fifo(edev, (uint8_t *)buffer +
+ offset + REGDUMP_HEADER_SIZE, &feature_size);
+ *(uint32_t *)((uint8_t *)buffer + offset) =
+ qede_calc_regdump_header(REG_FIFO, cur_engine,
+ feature_size, omit_engine);
+ offset += (feature_size + REGDUMP_HEADER_SIZE);
+ DP_NOTICE(edev, false, "Reg fifo feature_size %u\n",
+ feature_size);
+
+ /* igu_fifo dump */
+ qdev->ops->common->dbg_igu_fifo(edev, (uint8_t *)buffer +
+ offset + REGDUMP_HEADER_SIZE, &feature_size);
+ *(uint32_t *)((uint8_t *)buffer + offset) =
+ qede_calc_regdump_header(IGU_FIFO, cur_engine,
+ feature_size, omit_engine);
+ offset += (feature_size + REGDUMP_HEADER_SIZE);
+ DP_NOTICE(edev, false, "IGU fifo feature_size %u\n",
+ feature_size);
+
+ /* protection_override dump */
+ qdev->ops->common->dbg_protection_override(edev,
+ (uint8_t *)buffer +
+ offset + REGDUMP_HEADER_SIZE, &feature_size);
+ *(uint32_t *)((uint8_t *)buffer + offset) =
+ qede_calc_regdump_header(PROTECTION_OVERRIDE, cur_engine,
+ feature_size, omit_engine);
+ offset += (feature_size + REGDUMP_HEADER_SIZE);
+ DP_NOTICE(edev, false, "Protection override feature_size %u\n",
+ feature_size);
+
+ /* fw_asserts dump */
+ qdev->ops->common->dbg_fw_asserts(edev, (uint8_t *)buffer +
+ offset + REGDUMP_HEADER_SIZE, &feature_size);
+ *(uint32_t *)((uint8_t *)buffer + offset) =
+ qede_calc_regdump_header(FW_ASSERTS, cur_engine,
+ feature_size, omit_engine);
+ offset += (feature_size + REGDUMP_HEADER_SIZE);
+ DP_NOTICE(edev, false, "FW assert feature_size %u\n",
+ feature_size);
+
+ /* grc dump */
+ qdev->ops->common->dbg_grc(edev, (uint8_t *)buffer +
+ offset + REGDUMP_HEADER_SIZE, &feature_size);
+ *(uint32_t *)((uint8_t *)buffer + offset) =
+ qede_calc_regdump_header(GRC_DUMP, cur_engine,
+ feature_size, omit_engine);
+ offset += (feature_size + REGDUMP_HEADER_SIZE);
+ DP_NOTICE(edev, false, "GRC dump feature_size %u\n",
+ feature_size);
+ }
+
+ /* mcp_trace */
+ qdev->ops->common->dbg_mcp_trace(edev, (uint8_t *)buffer +
+ offset + REGDUMP_HEADER_SIZE, &feature_size);
+ *(uint32_t *)((uint8_t *)buffer + offset) =
+ qede_calc_regdump_header(MCP_TRACE, cur_engine, feature_size,
+ omit_engine);
+ offset += (feature_size + REGDUMP_HEADER_SIZE);
+ DP_NOTICE(edev, false, "MCP trace feature_size %u\n", feature_size);
+
+ qdev->ops->common->dbg_set_debug_engine(edev, org_engine);
+
+ OSAL_MUTEX_RELEASE(&edev->dbg_lock);
+
+ return 0;
+}
+
+static void
+qede_set_fw_dump_file_name(struct qede_dev *qdev)
+{
+ time_t ltime;
+ struct tm *tm;
+
+ ltime = time(NULL);
+ tm = localtime(<ime);
+ snprintf(qdev->dump_file, QEDE_FW_DUMP_FILE_SIZE,
+ "qede_pmd_dump_%02d-%02d-%02d_%02d-%02d-%02d.bin",
+ tm->tm_mon + 1, (int)tm->tm_mday, 1900 + tm->tm_year,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+}
+
+static int
+qede_write_fwdump(const char *dump_file, void *dump, size_t len)
+{
+ int err = 0;
+ FILE *f;
+ size_t bytes;
+
+ f = fopen(dump_file, "wb+");
+
+ if (!f) {
+ fprintf(stderr, "Can't open file %s: %s\n",
+ dump_file, strerror(errno));
+ return 1;
+ }
+ bytes = fwrite(dump, 1, len, f);
+ if (bytes != len) {
+ fprintf(stderr, "Can not write all of dump data bytes=%ld len=%ld\n",
+ bytes, len);
+ err = 1;
+ }
+
+ if (fclose(f)) {
+ fprintf(stderr, "Can't close file %s: %s\n",
+ dump_file, strerror(errno));
+ err = 1;
+ }
+
+ return err;
+}
+
+int
+qede_save_fw_dump(uint8_t port_id)
+{
+ struct rte_eth_dev *eth_dev = &rte_eth_devices[port_id];
+ struct rte_dev_reg_info regs;
+ struct qede_dev *qdev = eth_dev->data->dev_private;
+ struct ecore_dev *edev = &qdev->edev;
+ int rc = 0;
+
+ if (!rte_eth_dev_is_valid_port(port_id)) {
+ DP_ERR(edev, "port %u invalid port ID", port_id);
+ return -ENODEV;
+ }
+
+ memset(®s, 0, sizeof(regs));
+ regs.length = qede_get_regs_len(qdev);
+ regs.data = OSAL_ZALLOC(eth_dev, GFP_KERNEL, regs.length);
+ if (regs.data) {
+ qede_get_regs(eth_dev, ®s);
+ qede_set_fw_dump_file_name(qdev);
+ rc = qede_write_fwdump(qdev->dump_file, regs.data, regs.length);
+ if (!rc)
+ DP_NOTICE(edev, false, "FW dump written to %s file\n",
+ qdev->dump_file);
+ OSAL_FREE(edev, regs.data);
+ }
+
+ return rc;
+}