net/bnxt: log firmware status on early init failure
authorKalesh AP <kalesh-anakkur.purayil@broadcom.com>
Tue, 21 Apr 2020 21:33:50 +0000 (14:33 -0700)
committerFerruh Yigit <ferruh.yigit@intel.com>
Wed, 22 Apr 2020 11:41:24 +0000 (13:41 +0200)
Firmware reports any fatal error (either ASIC or Firmware related) via a
new status register. This status register can provide more detailed
information about the firmware errors, especially if error occurs before
HWRM_VER_GET is issued. Attempt to map this register if it is present
and check for firmware status when VER_GET command fails.

Refactored the code to allocate the "bp->recovery_info" structure
in bnxt_init_fw() instead of doing in bnxt_hwrm_error_recovery_qcfg().

Signed-off-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
Reviewed-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
drivers/net/bnxt/bnxt.h
drivers/net/bnxt/bnxt_ethdev.c
drivers/net/bnxt/bnxt_hwrm.c
drivers/net/bnxt/hsi_struct_def_dpdk.h

index d55a570..586d3f5 100644 (file)
@@ -507,6 +507,10 @@ struct bnxt_mark_info {
 #define BNXT_GRCP_WINDOW_2_BASE                0x2000
 #define BNXT_GRCP_WINDOW_3_BASE                0x3000
 
+#define BNXT_GRCP_BASE_MASK            0xfffff000
+#define BNXT_GRCP_OFFSET_MASK          0x00000ffc
+
+#define BNXT_FW_STATUS_HEALTHY         0x8000
 #define BNXT_FW_STATUS_SHUTDOWN                0x100000
 
 #define BNXT_HWRM_SHORT_REQ_LEN                sizeof(struct hwrm_short_input)
@@ -564,6 +568,7 @@ struct bnxt {
 #define BNXT_FW_CAP_ERR_RECOVER_RELOAD BIT(3)
 #define BNXT_FW_CAP_ADV_FLOW_MGMT      BIT(5)
 #define BNXT_FW_CAP_ADV_FLOW_COUNTERS  BIT(6)
+#define BNXT_FW_CAP_HCOMM_FW_STATUS    BIT(7)
 
        uint32_t                flow_flags;
 #define BNXT_FLOW_FLAG_L2_HDR_SRC_FILTER_EN    BIT(0)
index 589190b..1a3c7e6 100644 (file)
@@ -155,6 +155,7 @@ static int bnxt_uninit_resources(struct bnxt *bp, bool reconfig_dev);
 static void bnxt_cancel_fw_health_check(struct bnxt *bp);
 static int bnxt_restore_vlan_filters(struct bnxt *bp);
 static void bnxt_dev_recover(void *arg);
+static void bnxt_free_error_recovery_info(struct bnxt *bp);
 
 int is_bnxt_in_error(struct bnxt *bp)
 {
@@ -4967,6 +4968,89 @@ bnxt_get_fw_func_id(uint16_t port)
        return bp->fw_fid;
 }
 
+static void bnxt_alloc_error_recovery_info(struct bnxt *bp)
+{
+       struct bnxt_error_recovery_info *info = bp->recovery_info;
+
+       if (info) {
+               if (!(bp->fw_cap & BNXT_FW_CAP_HCOMM_FW_STATUS))
+                       memset(info, 0, sizeof(*info));
+               return;
+       }
+
+       if (!(bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY))
+               return;
+
+       info = rte_zmalloc("bnxt_hwrm_error_recovery_qcfg",
+                          sizeof(*info), 0);
+       if (!info)
+               bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY;
+
+       bp->recovery_info = info;
+}
+
+static void bnxt_check_fw_status(struct bnxt *bp)
+{
+       uint32_t fw_status;
+
+       if (!(bp->recovery_info &&
+             (bp->fw_cap & BNXT_FW_CAP_HCOMM_FW_STATUS)))
+               return;
+
+       fw_status = bnxt_read_fw_status_reg(bp, BNXT_FW_STATUS_REG);
+       if (fw_status != BNXT_FW_STATUS_HEALTHY)
+               PMD_DRV_LOG(ERR, "Firmware not responding, status: %#x\n",
+                           fw_status);
+}
+
+static int bnxt_map_hcomm_fw_status_reg(struct bnxt *bp)
+{
+       struct bnxt_error_recovery_info *info = bp->recovery_info;
+       uint32_t status_loc;
+       uint32_t sig_ver;
+
+       rte_write32(HCOMM_STATUS_STRUCT_LOC, (uint8_t *)bp->bar0 +
+                   BNXT_GRCPF_REG_WINDOW_BASE_OUT + 4);
+       sig_ver = rte_le_to_cpu_32(rte_read32((uint8_t *)bp->bar0 +
+                                  BNXT_GRCP_WINDOW_2_BASE +
+                                  offsetof(struct hcomm_status,
+                                           sig_ver)));
+       /* If the signature is absent, then FW does not support this feature */
+       if ((sig_ver & HCOMM_STATUS_SIGNATURE_MASK) !=
+           HCOMM_STATUS_SIGNATURE_VAL)
+               return 0;
+
+       if (!info) {
+               info = rte_zmalloc("bnxt_hwrm_error_recovery_qcfg",
+                                  sizeof(*info), 0);
+               if (!info)
+                       return -ENOMEM;
+               bp->recovery_info = info;
+       } else {
+               memset(info, 0, sizeof(*info));
+       }
+
+       status_loc = rte_le_to_cpu_32(rte_read32((uint8_t *)bp->bar0 +
+                                     BNXT_GRCP_WINDOW_2_BASE +
+                                     offsetof(struct hcomm_status,
+                                              fw_status_loc)));
+
+       /* Only pre-map the FW health status GRC register */
+       if (BNXT_FW_STATUS_REG_TYPE(status_loc) != BNXT_FW_STATUS_REG_TYPE_GRC)
+               return 0;
+
+       info->status_regs[BNXT_FW_STATUS_REG] = status_loc;
+       info->mapped_status_regs[BNXT_FW_STATUS_REG] =
+               BNXT_GRCP_WINDOW_2_BASE + (status_loc & BNXT_GRCP_OFFSET_MASK);
+
+       rte_write32((status_loc & BNXT_GRCP_BASE_MASK), (uint8_t *)bp->bar0 +
+                   BNXT_GRCPF_REG_WINDOW_BASE_OUT + 4);
+
+       bp->fw_cap |= BNXT_FW_CAP_HCOMM_FW_STATUS;
+
+       return 0;
+}
+
 static int bnxt_init_fw(struct bnxt *bp)
 {
        uint16_t mtu;
@@ -4974,10 +5058,16 @@ static int bnxt_init_fw(struct bnxt *bp)
 
        bp->fw_cap = 0;
 
-       rc = bnxt_hwrm_ver_get(bp, DFLT_HWRM_CMD_TIMEOUT);
+       rc = bnxt_map_hcomm_fw_status_reg(bp);
        if (rc)
                return rc;
 
+       rc = bnxt_hwrm_ver_get(bp, DFLT_HWRM_CMD_TIMEOUT);
+       if (rc) {
+               bnxt_check_fw_status(bp);
+               return rc;
+       }
+
        rc = bnxt_hwrm_func_reset(bp);
        if (rc)
                return -EIO;
@@ -5008,6 +5098,7 @@ static int bnxt_init_fw(struct bnxt *bp)
        if (rc)
                return rc;
 
+       bnxt_alloc_error_recovery_info(bp);
        /* Get the adapter error recovery support info */
        rc = bnxt_hwrm_error_recovery_qcfg(bp);
        if (rc)
@@ -5343,6 +5434,14 @@ static void bnxt_uninit_ctx_mem(struct bnxt *bp)
        bnxt_uninit_fc_ctx_mem(bp);
 }
 
+static void
+bnxt_free_error_recovery_info(struct bnxt *bp)
+{
+       rte_free(bp->recovery_info);
+       bp->recovery_info = NULL;
+       bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY;
+}
+
 static void
 bnxt_uninit_locks(struct bnxt *bp)
 {
@@ -5363,11 +5462,7 @@ bnxt_uninit_resources(struct bnxt *bp, bool reconfig_dev)
        bnxt_free_ctx_mem(bp);
        if (!reconfig_dev) {
                bnxt_free_hwrm_resources(bp);
-
-               if (bp->recovery_info != NULL) {
-                       rte_free(bp->recovery_info);
-                       bp->recovery_info = NULL;
-               }
+               bnxt_free_error_recovery_info(bp);
        }
 
        bnxt_uninit_ctx_mem(bp);
index dc0b405..666056a 100644 (file)
@@ -5076,16 +5076,6 @@ int bnxt_hwrm_error_recovery_qcfg(struct bnxt *bp)
        if (!(bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY))
                return 0;
 
-       if (!info) {
-               info = rte_zmalloc("bnxt_hwrm_error_recovery_qcfg",
-                                  sizeof(*info), 0);
-               bp->recovery_info = info;
-               if (info == NULL)
-                       return -ENOMEM;
-       } else {
-               memset(info, 0, sizeof(*info));
-       }
-
        HWRM_PREP(&req, HWRM_ERROR_RECOVERY_QCFG, BNXT_USE_CHIMP_MB);
 
        rc = bnxt_hwrm_send_message(bp, &req, sizeof(req), BNXT_USE_CHIMP_MB);
index da22b62..7e30c9f 100644 (file)
@@ -38622,4 +38622,53 @@ struct hwrm_cfa_counter_qstats_output {
        uint8_t valid;
 } __rte_packed;
 
+/*
+ * This structure is fixed at the beginning of the ChiMP SRAM (GRC
+ * offset: 0x31001F0). Host software is expected to read from this
+ * location for a defined signature. If it exists, the software can
+ * assume the presence of this structure and the validity of the
+ * FW_STATUS location in the next field.
+ */
+/* hcomm_status (size:64b/8B) */
+struct hcomm_status {
+       uint32_t        sig_ver;
+       /*
+        * This field defines the version of the structure. The latest
+        * version value is 1.
+        */
+       #define HCOMM_STATUS_VER_MASK           UINT32_C(0xff)
+       #define HCOMM_STATUS_VER_SFT            0
+       #define HCOMM_STATUS_VER_LATEST         UINT32_C(0x1)
+       #define HCOMM_STATUS_VER_LAST           HCOMM_STATUS_VER_LATEST
+       /*
+        * This field is to store the signature value to indicate the
+        * presence of the structure.
+        */
+       #define HCOMM_STATUS_SIGNATURE_MASK     UINT32_C(0xffffff00)
+       #define HCOMM_STATUS_SIGNATURE_SFT      8
+       #define HCOMM_STATUS_SIGNATURE_VAL      (UINT32_C(0x484353) << 8)
+       #define HCOMM_STATUS_SIGNATURE_LAST     HCOMM_STATUS_SIGNATURE_VAL
+       uint32_t        fw_status_loc;
+       #define HCOMM_STATUS_TRUE_ADDR_SPACE_MASK       UINT32_C(0x3)
+       #define HCOMM_STATUS_TRUE_ADDR_SPACE_SFT        0
+       /* PCIE configuration space */
+       #define HCOMM_STATUS_FW_STATUS_LOC_ADDR_SPACE_PCIE_CFG  UINT32_C(0x0)
+       /* GRC space */
+       #define HCOMM_STATUS_FW_STATUS_LOC_ADDR_SPACE_GRC       UINT32_C(0x1)
+       /* BAR0 space */
+       #define HCOMM_STATUS_FW_STATUS_LOC_ADDR_SPACE_BAR0      UINT32_C(0x2)
+       /* BAR1 space */
+       #define HCOMM_STATUS_FW_STATUS_LOC_ADDR_SPACE_BAR1      UINT32_C(0x3)
+       #define HCOMM_STATUS_FW_STATUS_LOC_ADDR_SPACE_LAST      \
+               HCOMM_STATUS_FW_STATUS_LOC_ADDR_SPACE_BAR1
+       /*
+        * This offset where the fw_status register is located. The value
+        * is generally 4-byte aligned.
+        */
+       #define HCOMM_STATUS_TRUE_OFFSET_MASK           UINT32_C(0xfffffffc)
+       #define HCOMM_STATUS_TRUE_OFFSET_SFT            2
+} __rte_packed;
+/* This is the GRC offset where the hcomm_status struct resides. */
+#define HCOMM_STATUS_STRUCT_LOC                0x31001F0UL
+
 #endif /* _HSI_STRUCT_DEF_DPDK_H_ */