Commit d8d6c5a7 authored by Igor Russkikh's avatar Igor Russkikh Committed by David S. Miller
Browse files

net: qed: critical err reporting to management firmware



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: default avatarAriel Elior <ariel.elior@marvell.com>
Signed-off-by: default avatarMichal Kalderon <michal.kalderon@marvell.com>
Signed-off-by: default avatarIgor Russkikh <irusskikh@marvell.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2ec276d5
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -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
+3 −0
Original line number Diff line number Diff line
@@ -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,
+124 −0
Original line number Diff line number Diff line
@@ -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);
}
+15 −0
Original line number Diff line number Diff line
@@ -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 {