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

net: qed: introduce critical hardware error handler



MCP may signal driver about generic critical failure.
Driver has to collect mdump information (get_retain),
it pushes that to logs and triggers generic notification on
"hardware attention" event.

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 3e99c211
Loading
Loading
Loading
Loading
+27 −1
Original line number Diff line number Diff line
@@ -12400,6 +12400,13 @@ struct load_rsp_stc {
#define LOAD_RSP_FLAGS0_DRV_EXISTS      (0x1 << 0)
};

struct mdump_retain_data_stc {
	u32 valid;
	u32 epoch;
	u32 pf;
	u32 status;
};

union drv_union_data {
	u32 ver_str[MCP_DRV_VER_STR_SIZE_DWORD];
	struct mcp_mac wol_mac;
@@ -12488,6 +12495,8 @@ struct public_drv_mb {
#define DRV_MSG_CODE_BIST_TEST			0x001e0000
#define DRV_MSG_CODE_SET_LED_MODE		0x00200000
#define DRV_MSG_CODE_RESOURCE_CMD		0x00230000
/* Send crash dump commands with param[3:0] - opcode */
#define DRV_MSG_CODE_MDUMP_CMD			0x00250000
#define DRV_MSG_CODE_GET_TLV_DONE		0x002f0000
#define DRV_MSG_CODE_GET_ENGINE_CONFIG		0x00370000
#define DRV_MSG_CODE_GET_PPFID_BITMAP		0x43000000
@@ -12519,6 +12528,21 @@ struct public_drv_mb {

#define RESOURCE_DUMP				0

/* DRV_MSG_CODE_MDUMP_CMD parameters */
#define MDUMP_DRV_PARAM_OPCODE_MASK             0x0000000f
#define DRV_MSG_CODE_MDUMP_ACK                  0x01
#define DRV_MSG_CODE_MDUMP_SET_VALUES           0x02
#define DRV_MSG_CODE_MDUMP_TRIGGER              0x03
#define DRV_MSG_CODE_MDUMP_GET_CONFIG           0x04
#define DRV_MSG_CODE_MDUMP_SET_ENABLE           0x05
#define DRV_MSG_CODE_MDUMP_CLEAR_LOGS           0x06
#define DRV_MSG_CODE_MDUMP_GET_RETAIN           0x07
#define DRV_MSG_CODE_MDUMP_CLR_RETAIN           0x08

#define DRV_MSG_CODE_HW_DUMP_TRIGGER            0x0a
#define DRV_MSG_CODE_MDUMP_GEN_MDUMP2           0x0b
#define DRV_MSG_CODE_MDUMP_FREE_MDUMP2          0x0c

#define DRV_MSG_CODE_GET_PF_RDMA_PROTOCOL	0x002b0000
#define DRV_MSG_CODE_OS_WOL			0x002e0000

@@ -12697,6 +12721,8 @@ struct public_drv_mb {
#define FW_MSG_CODE_DEBUG_NOT_ENABLED		0xb00a0000
#define FW_MSG_CODE_DEBUG_DATA_SEND_OK		0xb00b0000

#define FW_MSG_CODE_MDUMP_INVALID_CMD		0x00030000

	u32 fw_mb_param;
#define FW_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR_MASK	0xFFFF0000
#define FW_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR_SHIFT	16
@@ -12763,7 +12789,7 @@ enum MFW_DRV_MSG_TYPE {
	MFW_DRV_MSG_GET_RDMA_STATS,
	MFW_DRV_MSG_FAILURE_DETECTED,
	MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE,
	MFW_DRV_MSG_BW_UPDATE11,
	MFW_DRV_MSG_CRITICAL_ERROR_OCCURRED,
	MFW_DRV_MSG_RESERVED,
	MFW_DRV_MSG_GET_TLV_REQ,
	MFW_DRV_MSG_OEM_CFG_UPDATE,
+113 −0
Original line number Diff line number Diff line
@@ -1717,6 +1717,116 @@ static void qed_mcp_handle_fan_failure(struct qed_hwfn *p_hwfn,
			  "Fan failure was detected on the network interface card and it's going to be shut down.\n");
}

struct qed_mdump_cmd_params {
	u32 cmd;
	void *p_data_src;
	u8 data_src_size;
	void *p_data_dst;
	u8 data_dst_size;
	u32 mcp_resp;
};

static int
qed_mcp_mdump_cmd(struct qed_hwfn *p_hwfn,
		  struct qed_ptt *p_ptt,
		  struct qed_mdump_cmd_params *p_mdump_cmd_params)
{
	struct qed_mcp_mb_params mb_params;
	int rc;

	memset(&mb_params, 0, sizeof(mb_params));
	mb_params.cmd = DRV_MSG_CODE_MDUMP_CMD;
	mb_params.param = p_mdump_cmd_params->cmd;
	mb_params.p_data_src = p_mdump_cmd_params->p_data_src;
	mb_params.data_src_size = p_mdump_cmd_params->data_src_size;
	mb_params.p_data_dst = p_mdump_cmd_params->p_data_dst;
	mb_params.data_dst_size = p_mdump_cmd_params->data_dst_size;
	rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
	if (rc)
		return rc;

	p_mdump_cmd_params->mcp_resp = mb_params.mcp_resp;

	if (p_mdump_cmd_params->mcp_resp == FW_MSG_CODE_MDUMP_INVALID_CMD) {
		DP_INFO(p_hwfn,
			"The mdump sub command is unsupported by the MFW [mdump_cmd 0x%x]\n",
			p_mdump_cmd_params->cmd);
		rc = -EOPNOTSUPP;
	} else if (p_mdump_cmd_params->mcp_resp == FW_MSG_CODE_UNSUPPORTED) {
		DP_INFO(p_hwfn,
			"The mdump command is not supported by the MFW\n");
		rc = -EOPNOTSUPP;
	}

	return rc;
}

static int qed_mcp_mdump_ack(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
{
	struct qed_mdump_cmd_params mdump_cmd_params;

	memset(&mdump_cmd_params, 0, sizeof(mdump_cmd_params));
	mdump_cmd_params.cmd = DRV_MSG_CODE_MDUMP_ACK;

	return qed_mcp_mdump_cmd(p_hwfn, p_ptt, &mdump_cmd_params);
}

int
qed_mcp_mdump_get_retain(struct qed_hwfn *p_hwfn,
			 struct qed_ptt *p_ptt,
			 struct mdump_retain_data_stc *p_mdump_retain)
{
	struct qed_mdump_cmd_params mdump_cmd_params;
	int rc;

	memset(&mdump_cmd_params, 0, sizeof(mdump_cmd_params));
	mdump_cmd_params.cmd = DRV_MSG_CODE_MDUMP_GET_RETAIN;
	mdump_cmd_params.p_data_dst = p_mdump_retain;
	mdump_cmd_params.data_dst_size = sizeof(*p_mdump_retain);

	rc = qed_mcp_mdump_cmd(p_hwfn, p_ptt, &mdump_cmd_params);
	if (rc)
		return rc;

	if (mdump_cmd_params.mcp_resp != FW_MSG_CODE_OK) {
		DP_INFO(p_hwfn,
			"Failed to get the mdump retained data [mcp_resp 0x%x]\n",
			mdump_cmd_params.mcp_resp);
		return -EINVAL;
	}

	return 0;
}

static void qed_mcp_handle_critical_error(struct qed_hwfn *p_hwfn,
					  struct qed_ptt *p_ptt)
{
	struct mdump_retain_data_stc mdump_retain;
	int rc;

	/* In CMT mode - no need for more than a single acknowledgment to the
	 * MFW, and no more than a single notification to the upper driver.
	 */
	if (p_hwfn != QED_LEADING_HWFN(p_hwfn->cdev))
		return;

	rc = qed_mcp_mdump_get_retain(p_hwfn, p_ptt, &mdump_retain);
	if (rc == 0 && mdump_retain.valid)
		DP_NOTICE(p_hwfn,
			  "The MFW notified that a critical error occurred in the device [epoch 0x%08x, pf 0x%x, status 0x%08x]\n",
			  mdump_retain.epoch,
			  mdump_retain.pf, mdump_retain.status);
	else
		DP_NOTICE(p_hwfn,
			  "The MFW notified that a critical error occurred in the device\n");

	DP_NOTICE(p_hwfn,
		  "Acknowledging the notification to not allow the MFW crash dump [driver debug data collection is preferable]\n");
	qed_mcp_mdump_ack(p_hwfn, p_ptt);

	qed_hw_err_notify(p_hwfn, p_ptt, QED_HW_ERR_HW_ATTN, NULL);
}

void qed_mcp_read_ufp_config(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
{
	struct public_func shmem_info;
@@ -1866,6 +1976,9 @@ int qed_mcp_handle_events(struct qed_hwfn *p_hwfn,
		case MFW_DRV_MSG_FAILURE_DETECTED:
			qed_mcp_handle_fan_failure(p_hwfn, p_ptt);
			break;
		case MFW_DRV_MSG_CRITICAL_ERROR_OCCURRED:
			qed_mcp_handle_critical_error(p_hwfn, p_ptt);
			break;
		case MFW_DRV_MSG_GET_TLV_REQ:
			qed_mfw_tlv_req(p_hwfn);
			break;
+13 −0
Original line number Diff line number Diff line
@@ -1016,6 +1016,19 @@ int __qed_configure_pf_min_bandwidth(struct qed_hwfn *p_hwfn,
int qed_mcp_mask_parities(struct qed_hwfn *p_hwfn,
			  struct qed_ptt *p_ptt, u32 mask_parities);

/* @brief - Gets the mdump retained data from the MFW.
 *
 * @param p_hwfn
 * @param p_ptt
 * @param p_mdump_retain
 *
 * @param return 0 upon success.
 */
int
qed_mcp_mdump_get_retain(struct qed_hwfn *p_hwfn,
			 struct qed_ptt *p_ptt,
			 struct mdump_retain_data_stc *p_mdump_retain);

/**
 * @brief - Sets the MFW's max value for the given resource
 *