net: qed: critical err reporting to management firmware
authorIgor Russkikh <irusskikh@marvell.com>
Thu, 14 May 2020 09:57:20 +0000 (12:57 +0300)
committerDavid S. Miller <davem@davemloft.net>
Thu, 14 May 2020 20:25:46 +0000 (13:25 -0700)
On various critical errors, notification handler should also report
the err information into the management firmware.

MFW can interact with server/motherboard backend agents - these are
used by server manufacturers to monitor server HW health.

Thus, it is important for driver to report on any faulty conditions

Signed-off-by: Ariel Elior <ariel.elior@marvell.com>
Signed-off-by: Michal Kalderon <michal.kalderon@marvell.com>
Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qed/qed_hsi.h
drivers/net/ethernet/qlogic/qed/qed_hw.c
drivers/net/ethernet/qlogic/qed/qed_mcp.c
drivers/net/ethernet/qlogic/qed/qed_mcp.h

index 4597015..21d53b0 100644 (file)
@@ -12492,6 +12492,8 @@ struct public_drv_mb {
 #define DRV_MSG_CODE_GET_ENGINE_CONFIG         0x00370000
 #define DRV_MSG_CODE_GET_PPFID_BITMAP          0x43000000
 
+#define DRV_MSG_CODE_DEBUG_DATA_SEND           0xc0040000
+
 #define RESOURCE_CMD_REQ_RESC_MASK             0x0000001F
 #define RESOURCE_CMD_REQ_RESC_SHIFT            0
 #define RESOURCE_CMD_REQ_OPCODE_MASK           0x000000E0
@@ -12626,6 +12628,17 @@ struct public_drv_mb {
 #define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE          0x00000002
 #define DRV_MB_PARAM_FEATURE_SUPPORT_FUNC_VLINK                0x00010000
 
+/* DRV_MSG_CODE_DEBUG_DATA_SEND parameters */
+#define DRV_MSG_CODE_DEBUG_DATA_SEND_SIZE_OFFSET       0
+#define DRV_MSG_CODE_DEBUG_DATA_SEND_SIZE_MASK         0xFF
+
+/* Driver attributes params */
+#define DRV_MB_PARAM_ATTRIBUTE_KEY_OFFSET              0
+#define DRV_MB_PARAM_ATTRIBUTE_KEY_MASK                        0x00FFFFFF
+#define DRV_MB_PARAM_ATTRIBUTE_CMD_OFFSET              24
+#define DRV_MB_PARAM_ATTRIBUTE_CMD_MASK                        0xFF000000
+
+#define DRV_MB_PARAM_NVM_CFG_OPTION_ID_OFFSET          0
 #define DRV_MB_PARAM_NVM_CFG_OPTION_ID_SHIFT           0
 #define DRV_MB_PARAM_NVM_CFG_OPTION_ID_MASK            0x0000FFFF
 #define DRV_MB_PARAM_NVM_CFG_OPTION_ALL_SHIFT          16
@@ -12678,6 +12691,12 @@ struct public_drv_mb {
 #define FW_MSG_CODE_DRV_CFG_PF_VFS_MSIX_DONE   0x00870000
 #define FW_MSG_SEQ_NUMBER_MASK                 0x0000ffff
 
+#define FW_MSG_CODE_DEBUG_DATA_SEND_INV_ARG    0xb0070000
+#define FW_MSG_CODE_DEBUG_DATA_SEND_BUF_FULL   0xb0080000
+#define FW_MSG_CODE_DEBUG_DATA_SEND_NO_BUF     0xb0090000
+#define FW_MSG_CODE_DEBUG_NOT_ENABLED          0xb00a0000
+#define FW_MSG_CODE_DEBUG_DATA_SEND_OK         0xb00b0000
+
        u32 fw_mb_param;
 #define FW_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR_MASK  0xFFFF0000
 #define FW_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR_SHIFT 16
index 2d176e1..5fa2514 100644 (file)
@@ -868,6 +868,9 @@ void qed_hw_err_notify(struct qed_hwfn *p_hwfn,
        }
 
        qed_hw_error_occurred(p_hwfn, err_type);
+
+       if (fmt)
+               qed_mcp_send_raw_debug_data(p_hwfn, p_ptt, buf, len);
 }
 
 int qed_dmae_sanity(struct qed_hwfn *p_hwfn,
index 46653af..db7cf12 100644 (file)
@@ -3821,3 +3821,127 @@ int qed_mcp_nvm_set_cfg(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
                                  DRV_MSG_CODE_SET_NVM_CFG_OPTION,
                                  mb_param, &resp, &param, len, (u32 *)p_buf);
 }
+
+#define QED_MCP_DBG_DATA_MAX_SIZE               MCP_DRV_NVM_BUF_LEN
+#define QED_MCP_DBG_DATA_MAX_HEADER_SIZE        sizeof(u32)
+#define QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE \
+       (QED_MCP_DBG_DATA_MAX_SIZE - QED_MCP_DBG_DATA_MAX_HEADER_SIZE)
+
+static int
+__qed_mcp_send_debug_data(struct qed_hwfn *p_hwfn,
+                         struct qed_ptt *p_ptt, u8 *p_buf, u8 size)
+{
+       struct qed_mcp_mb_params mb_params;
+       int rc;
+
+       if (size > QED_MCP_DBG_DATA_MAX_SIZE) {
+               DP_ERR(p_hwfn,
+                      "Debug data size is %d while it should not exceed %d\n",
+                      size, QED_MCP_DBG_DATA_MAX_SIZE);
+               return -EINVAL;
+       }
+
+       memset(&mb_params, 0, sizeof(mb_params));
+       mb_params.cmd = DRV_MSG_CODE_DEBUG_DATA_SEND;
+       SET_MFW_FIELD(mb_params.param, DRV_MSG_CODE_DEBUG_DATA_SEND_SIZE, size);
+       mb_params.p_data_src = p_buf;
+       mb_params.data_src_size = size;
+       rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
+       if (rc)
+               return rc;
+
+       if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) {
+               DP_INFO(p_hwfn,
+                       "The DEBUG_DATA_SEND command is unsupported by the MFW\n");
+               return -EOPNOTSUPP;
+       } else if (mb_params.mcp_resp == (u32)FW_MSG_CODE_DEBUG_NOT_ENABLED) {
+               DP_INFO(p_hwfn, "The DEBUG_DATA_SEND command is not enabled\n");
+               return -EBUSY;
+       } else if (mb_params.mcp_resp != (u32)FW_MSG_CODE_DEBUG_DATA_SEND_OK) {
+               DP_NOTICE(p_hwfn,
+                         "Failed to send debug data to the MFW [resp 0x%08x]\n",
+                         mb_params.mcp_resp);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+enum qed_mcp_dbg_data_type {
+       QED_MCP_DBG_DATA_TYPE_RAW,
+};
+
+/* Header format: [31:28] PFID, [27:20] flags, [19:12] type, [11:0] S/N */
+#define QED_MCP_DBG_DATA_HDR_SN_OFFSET  0
+#define QED_MCP_DBG_DATA_HDR_SN_MASK            0x00000fff
+#define QED_MCP_DBG_DATA_HDR_TYPE_OFFSET        12
+#define QED_MCP_DBG_DATA_HDR_TYPE_MASK  0x000ff000
+#define QED_MCP_DBG_DATA_HDR_FLAGS_OFFSET       20
+#define QED_MCP_DBG_DATA_HDR_FLAGS_MASK 0x0ff00000
+#define QED_MCP_DBG_DATA_HDR_PF_OFFSET  28
+#define QED_MCP_DBG_DATA_HDR_PF_MASK            0xf0000000
+
+#define QED_MCP_DBG_DATA_HDR_FLAGS_FIRST        0x1
+#define QED_MCP_DBG_DATA_HDR_FLAGS_LAST 0x2
+
+static int
+qed_mcp_send_debug_data(struct qed_hwfn *p_hwfn,
+                       struct qed_ptt *p_ptt,
+                       enum qed_mcp_dbg_data_type type, u8 *p_buf, u32 size)
+{
+       u8 raw_data[QED_MCP_DBG_DATA_MAX_SIZE], *p_tmp_buf = p_buf;
+       u32 tmp_size = size, *p_header, *p_payload;
+       u8 flags = 0;
+       u16 seq;
+       int rc;
+
+       p_header = (u32 *)raw_data;
+       p_payload = (u32 *)(raw_data + QED_MCP_DBG_DATA_MAX_HEADER_SIZE);
+
+       seq = (u16)atomic_inc_return(&p_hwfn->mcp_info->dbg_data_seq);
+
+       /* First chunk is marked as 'first' */
+       flags |= QED_MCP_DBG_DATA_HDR_FLAGS_FIRST;
+
+       *p_header = 0;
+       SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_SN, seq);
+       SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_TYPE, type);
+       SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_FLAGS, flags);
+       SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_PF, p_hwfn->abs_pf_id);
+
+       while (tmp_size > QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE) {
+               memcpy(p_payload, p_tmp_buf, QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE);
+               rc = __qed_mcp_send_debug_data(p_hwfn, p_ptt, raw_data,
+                                              QED_MCP_DBG_DATA_MAX_SIZE);
+               if (rc)
+                       return rc;
+
+               /* Clear the 'first' marking after sending the first chunk */
+               if (p_tmp_buf == p_buf) {
+                       flags &= ~QED_MCP_DBG_DATA_HDR_FLAGS_FIRST;
+                       SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_FLAGS,
+                                     flags);
+               }
+
+               p_tmp_buf += QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE;
+               tmp_size -= QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE;
+       }
+
+       /* Last chunk is marked as 'last' */
+       flags |= QED_MCP_DBG_DATA_HDR_FLAGS_LAST;
+       SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_FLAGS, flags);
+       memcpy(p_payload, p_tmp_buf, tmp_size);
+
+       /* Casting the left size to u8 is ok since at this point it is <= 32 */
+       return __qed_mcp_send_debug_data(p_hwfn, p_ptt, raw_data,
+                                        (u8)(QED_MCP_DBG_DATA_MAX_HEADER_SIZE +
+                                        tmp_size));
+}
+
+int
+qed_mcp_send_raw_debug_data(struct qed_hwfn *p_hwfn,
+                           struct qed_ptt *p_ptt, u8 *p_buf, u32 size)
+{
+       return qed_mcp_send_debug_data(p_hwfn, p_ptt,
+                                      QED_MCP_DBG_DATA_TYPE_RAW, p_buf, size);
+}
index 9c4c276..bc24841 100644 (file)
@@ -685,6 +685,18 @@ int qed_mcp_bist_nvm_get_image_att(struct qed_hwfn *p_hwfn,
  */
 int qed_mfw_process_tlv_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
 
+/**
+ * @brief Send raw debug data to the MFW
+ *
+ * @param p_hwfn
+ * @param p_ptt
+ * @param p_buf - raw debug data buffer
+ * @param size - buffer size
+ */
+int
+qed_mcp_send_raw_debug_data(struct qed_hwfn *p_hwfn,
+                           struct qed_ptt *p_ptt, u8 *p_buf, u32 size);
+
 /* Using hwfn number (and not pf_num) is required since in CMT mode,
  * same pf_num may be used by two different hwfn
  * TODO - this shouldn't really be in .h file, but until all fields
@@ -731,6 +743,9 @@ struct qed_mcp_info {
 
        /* Capabilties negotiated with the MFW */
        u32                                     capabilities;
+
+       /* S/N for debug data mailbox commands */
+       atomic_t dbg_data_seq;
 };
 
 struct qed_mcp_mb_params {