From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id E8220A0350; Sun, 28 Jun 2020 07:59:31 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id DE2391C1D9; Sun, 28 Jun 2020 07:59:03 +0200 (CEST) Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) by dpdk.org (Postfix) with ESMTP id 5B41C1C1CB for ; Sun, 28 Jun 2020 07:59:02 +0200 (CEST) Received: from pps.filterd (m0045851.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 05S5tfIq029784; Sat, 27 Jun 2020 22:59:01 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type : content-transfer-encoding; s=pfpt0818; bh=RX8rZYF9RQ7nRTaAWyUR5l714/+VknzYiOy4RjCd1RU=; b=QoTj+uI+P4svPGGYqrTPL/5gLxL9Zj0KtYkhQwmadQ/TR4oGgFAGCVQj6CpvXqsk53Xb c9ENr9BhyoH2VXAMsM+BcDHjhvL/pJRiQnKDVwEFm8PO2JWOMsmpoqnttMxgRbmrmCRO 5McmijbgCAghBpnJEJwKxmR35qnW6ejLeWMLXNXQIPoQTtRWElmDJCRM8mFyphrHUqrv iCpxyMhvPXlNRBsQTHs74Y7PH8b0ZAJQbnSmdPr9m0Q07FHSnrKIn8xfTVGjSX64avYt hkIkGkfjn71/aNJzofyEBe2jV5eYSrSQmlwlfhhiynYaEkjBGvWQMmH+KY5oODkib3Bw 5A== Received: from sc-exch04.marvell.com ([199.233.58.184]) by mx0b-0016f401.pphosted.com with ESMTP id 31x5mnaekg-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Sat, 27 Jun 2020 22:59:01 -0700 Received: from DC5-EXCH01.marvell.com (10.69.176.38) by SC-EXCH04.marvell.com (10.93.176.84) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 27 Jun 2020 22:58:58 -0700 Received: from DC5-EXCH02.marvell.com (10.69.176.39) by DC5-EXCH01.marvell.com (10.69.176.38) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 27 Jun 2020 22:58:56 -0700 Received: from maili.marvell.com (10.69.176.80) by DC5-EXCH02.marvell.com (10.69.176.39) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 27 Jun 2020 22:58:56 -0700 Received: from irv1user08.caveonetworks.com (unknown [10.104.116.105]) by maili.marvell.com (Postfix) with ESMTP id 8453A3F7040; Sat, 27 Jun 2020 22:58:56 -0700 (PDT) Received: (from rmody@localhost) by irv1user08.caveonetworks.com (8.14.4/8.14.4/Submit) id 05S5wuNH005369; Sat, 27 Jun 2020 22:58:56 -0700 X-Authentication-Warning: irv1user08.caveonetworks.com: rmody set sender to rmody@marvell.com using -f From: Rasesh Mody To: , CC: Rasesh Mody , , , Igor Russkikh Date: Sat, 27 Jun 2020 22:58:50 -0700 Message-ID: <20200628055850.5275-5-rmody@marvell.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20200628055850.5275-1-rmody@marvell.com> References: <20200628055850.5275-1-rmody@marvell.com> MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 8bit X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.216, 18.0.687 definitions=2020-06-28_01:2020-06-26, 2020-06-28 signatures=0 Subject: [dpdk-dev] [PATCH 4/4] net/qede: add support for get register operation X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" 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: 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 Signed-off-by: Igor Russkikh --- 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 +++++++++++++++++++++++++++++++ 6 files changed, 328 insertions(+) create mode 100644 drivers/net/qede/qede_regs.c 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 717b80839..52a4f046b 100644 --- a/drivers/net/qede/qede_ethdev.c +++ b/drivers/net/qede/qede_ethdev.c @@ -2430,6 +2430,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 +#include +#include +#include +#include +#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 requierd 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 requierd buffer size for mcp trace and add it to the + * total requierd 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