ice: Handle critical FW error during admin queue initialization
A race condition between FW and SW can occur between admin queue setup and the first command sent. A link event may occur and FW attempts to notify a non-existent queue. FW will set the critical error bit and disable the queue. When this happens retry queue setup. Signed-off-by: Evan Swanson <evan.swanson@intel.com> Signed-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com> Tested-by: Andrew Bowers <andrewx.bowers@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
committed by
Jeff Kirsher
parent
1960827570
commit
b5c7f857e5
@@ -12,6 +12,7 @@ do { \
|
|||||||
(qinfo)->sq.bal = prefix##_ATQBAL; \
|
(qinfo)->sq.bal = prefix##_ATQBAL; \
|
||||||
(qinfo)->sq.len_mask = prefix##_ATQLEN_ATQLEN_M; \
|
(qinfo)->sq.len_mask = prefix##_ATQLEN_ATQLEN_M; \
|
||||||
(qinfo)->sq.len_ena_mask = prefix##_ATQLEN_ATQENABLE_M; \
|
(qinfo)->sq.len_ena_mask = prefix##_ATQLEN_ATQENABLE_M; \
|
||||||
|
(qinfo)->sq.len_crit_mask = prefix##_ATQLEN_ATQCRIT_M; \
|
||||||
(qinfo)->sq.head_mask = prefix##_ATQH_ATQH_M; \
|
(qinfo)->sq.head_mask = prefix##_ATQH_ATQH_M; \
|
||||||
(qinfo)->rq.head = prefix##_ARQH; \
|
(qinfo)->rq.head = prefix##_ARQH; \
|
||||||
(qinfo)->rq.tail = prefix##_ARQT; \
|
(qinfo)->rq.tail = prefix##_ARQT; \
|
||||||
@@ -20,6 +21,7 @@ do { \
|
|||||||
(qinfo)->rq.bal = prefix##_ARQBAL; \
|
(qinfo)->rq.bal = prefix##_ARQBAL; \
|
||||||
(qinfo)->rq.len_mask = prefix##_ARQLEN_ARQLEN_M; \
|
(qinfo)->rq.len_mask = prefix##_ARQLEN_ARQLEN_M; \
|
||||||
(qinfo)->rq.len_ena_mask = prefix##_ARQLEN_ARQENABLE_M; \
|
(qinfo)->rq.len_ena_mask = prefix##_ARQLEN_ARQENABLE_M; \
|
||||||
|
(qinfo)->rq.len_crit_mask = prefix##_ARQLEN_ARQCRIT_M; \
|
||||||
(qinfo)->rq.head_mask = prefix##_ARQH_ARQH_M; \
|
(qinfo)->rq.head_mask = prefix##_ARQH_ARQH_M; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@@ -641,72 +643,6 @@ init_ctrlq_free_sq:
|
|||||||
return ret_code;
|
return ret_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ice_init_all_ctrlq - main initialization routine for all control queues
|
|
||||||
* @hw: pointer to the hardware structure
|
|
||||||
*
|
|
||||||
* Prior to calling this function, the driver MUST* set the following fields
|
|
||||||
* in the cq->structure for all control queues:
|
|
||||||
* - cq->num_sq_entries
|
|
||||||
* - cq->num_rq_entries
|
|
||||||
* - cq->rq_buf_size
|
|
||||||
* - cq->sq_buf_size
|
|
||||||
*
|
|
||||||
* NOTE: this function does not initialize the controlq locks.
|
|
||||||
*/
|
|
||||||
enum ice_status ice_init_all_ctrlq(struct ice_hw *hw)
|
|
||||||
{
|
|
||||||
enum ice_status ret_code;
|
|
||||||
|
|
||||||
/* Init FW admin queue */
|
|
||||||
ret_code = ice_init_ctrlq(hw, ICE_CTL_Q_ADMIN);
|
|
||||||
if (ret_code)
|
|
||||||
return ret_code;
|
|
||||||
|
|
||||||
ret_code = ice_init_check_adminq(hw);
|
|
||||||
if (ret_code)
|
|
||||||
return ret_code;
|
|
||||||
|
|
||||||
/* Init Mailbox queue */
|
|
||||||
return ice_init_ctrlq(hw, ICE_CTL_Q_MAILBOX);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ice_init_ctrlq_locks - Initialize locks for a control queue
|
|
||||||
* @cq: pointer to the control queue
|
|
||||||
*
|
|
||||||
* Initializes the send and receive queue locks for a given control queue.
|
|
||||||
*/
|
|
||||||
static void ice_init_ctrlq_locks(struct ice_ctl_q_info *cq)
|
|
||||||
{
|
|
||||||
mutex_init(&cq->sq_lock);
|
|
||||||
mutex_init(&cq->rq_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ice_create_all_ctrlq - main initialization routine for all control queues
|
|
||||||
* @hw: pointer to the hardware structure
|
|
||||||
*
|
|
||||||
* Prior to calling this function, the driver *MUST* set the following fields
|
|
||||||
* in the cq->structure for all control queues:
|
|
||||||
* - cq->num_sq_entries
|
|
||||||
* - cq->num_rq_entries
|
|
||||||
* - cq->rq_buf_size
|
|
||||||
* - cq->sq_buf_size
|
|
||||||
*
|
|
||||||
* This function creates all the control queue locks and then calls
|
|
||||||
* ice_init_all_ctrlq. It should be called once during driver load. If the
|
|
||||||
* driver needs to re-initialize control queues at run time it should call
|
|
||||||
* ice_init_all_ctrlq instead.
|
|
||||||
*/
|
|
||||||
enum ice_status ice_create_all_ctrlq(struct ice_hw *hw)
|
|
||||||
{
|
|
||||||
ice_init_ctrlq_locks(&hw->adminq);
|
|
||||||
ice_init_ctrlq_locks(&hw->mailboxq);
|
|
||||||
|
|
||||||
return ice_init_all_ctrlq(hw);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ice_shutdown_ctrlq - shutdown routine for any control queue
|
* ice_shutdown_ctrlq - shutdown routine for any control queue
|
||||||
* @hw: pointer to the hardware structure
|
* @hw: pointer to the hardware structure
|
||||||
@@ -751,6 +687,82 @@ void ice_shutdown_all_ctrlq(struct ice_hw *hw)
|
|||||||
ice_shutdown_ctrlq(hw, ICE_CTL_Q_MAILBOX);
|
ice_shutdown_ctrlq(hw, ICE_CTL_Q_MAILBOX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ice_init_all_ctrlq - main initialization routine for all control queues
|
||||||
|
* @hw: pointer to the hardware structure
|
||||||
|
*
|
||||||
|
* Prior to calling this function, the driver MUST* set the following fields
|
||||||
|
* in the cq->structure for all control queues:
|
||||||
|
* - cq->num_sq_entries
|
||||||
|
* - cq->num_rq_entries
|
||||||
|
* - cq->rq_buf_size
|
||||||
|
* - cq->sq_buf_size
|
||||||
|
*
|
||||||
|
* NOTE: this function does not initialize the controlq locks.
|
||||||
|
*/
|
||||||
|
enum ice_status ice_init_all_ctrlq(struct ice_hw *hw)
|
||||||
|
{
|
||||||
|
enum ice_status status;
|
||||||
|
u32 retry = 0;
|
||||||
|
|
||||||
|
/* Init FW admin queue */
|
||||||
|
do {
|
||||||
|
status = ice_init_ctrlq(hw, ICE_CTL_Q_ADMIN);
|
||||||
|
if (status)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
status = ice_init_check_adminq(hw);
|
||||||
|
if (status != ICE_ERR_AQ_FW_CRITICAL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ice_debug(hw, ICE_DBG_AQ_MSG,
|
||||||
|
"Retry Admin Queue init due to FW critical error\n");
|
||||||
|
ice_shutdown_ctrlq(hw, ICE_CTL_Q_ADMIN);
|
||||||
|
msleep(ICE_CTL_Q_ADMIN_INIT_MSEC);
|
||||||
|
} while (retry++ < ICE_CTL_Q_ADMIN_INIT_TIMEOUT);
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
return status;
|
||||||
|
/* Init Mailbox queue */
|
||||||
|
return ice_init_ctrlq(hw, ICE_CTL_Q_MAILBOX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ice_init_ctrlq_locks - Initialize locks for a control queue
|
||||||
|
* @cq: pointer to the control queue
|
||||||
|
*
|
||||||
|
* Initializes the send and receive queue locks for a given control queue.
|
||||||
|
*/
|
||||||
|
static void ice_init_ctrlq_locks(struct ice_ctl_q_info *cq)
|
||||||
|
{
|
||||||
|
mutex_init(&cq->sq_lock);
|
||||||
|
mutex_init(&cq->rq_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ice_create_all_ctrlq - main initialization routine for all control queues
|
||||||
|
* @hw: pointer to the hardware structure
|
||||||
|
*
|
||||||
|
* Prior to calling this function, the driver *MUST* set the following fields
|
||||||
|
* in the cq->structure for all control queues:
|
||||||
|
* - cq->num_sq_entries
|
||||||
|
* - cq->num_rq_entries
|
||||||
|
* - cq->rq_buf_size
|
||||||
|
* - cq->sq_buf_size
|
||||||
|
*
|
||||||
|
* This function creates all the control queue locks and then calls
|
||||||
|
* ice_init_all_ctrlq. It should be called once during driver load. If the
|
||||||
|
* driver needs to re-initialize control queues at run time it should call
|
||||||
|
* ice_init_all_ctrlq instead.
|
||||||
|
*/
|
||||||
|
enum ice_status ice_create_all_ctrlq(struct ice_hw *hw)
|
||||||
|
{
|
||||||
|
ice_init_ctrlq_locks(&hw->adminq);
|
||||||
|
ice_init_ctrlq_locks(&hw->mailboxq);
|
||||||
|
|
||||||
|
return ice_init_all_ctrlq(hw);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ice_destroy_ctrlq_locks - Destroy locks for a control queue
|
* ice_destroy_ctrlq_locks - Destroy locks for a control queue
|
||||||
* @cq: pointer to the control queue
|
* @cq: pointer to the control queue
|
||||||
@@ -1049,9 +1061,15 @@ ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq,
|
|||||||
|
|
||||||
/* update the error if time out occurred */
|
/* update the error if time out occurred */
|
||||||
if (!cmd_completed) {
|
if (!cmd_completed) {
|
||||||
ice_debug(hw, ICE_DBG_AQ_MSG,
|
if (rd32(hw, cq->rq.len) & cq->rq.len_crit_mask ||
|
||||||
"Control Send Queue Writeback timeout.\n");
|
rd32(hw, cq->sq.len) & cq->sq.len_crit_mask) {
|
||||||
status = ICE_ERR_AQ_TIMEOUT;
|
ice_debug(hw, ICE_DBG_AQ_MSG, "Critical FW error.\n");
|
||||||
|
status = ICE_ERR_AQ_FW_CRITICAL;
|
||||||
|
} else {
|
||||||
|
ice_debug(hw, ICE_DBG_AQ_MSG,
|
||||||
|
"Control Send Queue Writeback timeout.\n");
|
||||||
|
status = ICE_ERR_AQ_TIMEOUT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sq_send_command_error:
|
sq_send_command_error:
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ enum ice_ctl_q {
|
|||||||
/* Control Queue timeout settings - max delay 250ms */
|
/* Control Queue timeout settings - max delay 250ms */
|
||||||
#define ICE_CTL_Q_SQ_CMD_TIMEOUT 2500 /* Count 2500 times */
|
#define ICE_CTL_Q_SQ_CMD_TIMEOUT 2500 /* Count 2500 times */
|
||||||
#define ICE_CTL_Q_SQ_CMD_USEC 100 /* Check every 100usec */
|
#define ICE_CTL_Q_SQ_CMD_USEC 100 /* Check every 100usec */
|
||||||
|
#define ICE_CTL_Q_ADMIN_INIT_TIMEOUT 10 /* Count 10 times */
|
||||||
|
#define ICE_CTL_Q_ADMIN_INIT_MSEC 100 /* Check every 100msec */
|
||||||
|
|
||||||
struct ice_ctl_q_ring {
|
struct ice_ctl_q_ring {
|
||||||
void *dma_head; /* Virtual address to DMA head */
|
void *dma_head; /* Virtual address to DMA head */
|
||||||
@@ -59,6 +61,7 @@ struct ice_ctl_q_ring {
|
|||||||
u32 bal;
|
u32 bal;
|
||||||
u32 len_mask;
|
u32 len_mask;
|
||||||
u32 len_ena_mask;
|
u32 len_ena_mask;
|
||||||
|
u32 len_crit_mask;
|
||||||
u32 head_mask;
|
u32 head_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
#define PF_MBX_ARQH_ARQH_M ICE_M(0x3FF, 0)
|
#define PF_MBX_ARQH_ARQH_M ICE_M(0x3FF, 0)
|
||||||
#define PF_MBX_ARQLEN 0x0022E480
|
#define PF_MBX_ARQLEN 0x0022E480
|
||||||
#define PF_MBX_ARQLEN_ARQLEN_M ICE_M(0x3FF, 0)
|
#define PF_MBX_ARQLEN_ARQLEN_M ICE_M(0x3FF, 0)
|
||||||
|
#define PF_MBX_ARQLEN_ARQCRIT_M BIT(30)
|
||||||
#define PF_MBX_ARQLEN_ARQENABLE_M BIT(31)
|
#define PF_MBX_ARQLEN_ARQENABLE_M BIT(31)
|
||||||
#define PF_MBX_ARQT 0x0022E580
|
#define PF_MBX_ARQT 0x0022E580
|
||||||
#define PF_MBX_ATQBAH 0x0022E180
|
#define PF_MBX_ATQBAH 0x0022E180
|
||||||
@@ -47,6 +48,7 @@
|
|||||||
#define PF_MBX_ATQH_ATQH_M ICE_M(0x3FF, 0)
|
#define PF_MBX_ATQH_ATQH_M ICE_M(0x3FF, 0)
|
||||||
#define PF_MBX_ATQLEN 0x0022E200
|
#define PF_MBX_ATQLEN 0x0022E200
|
||||||
#define PF_MBX_ATQLEN_ATQLEN_M ICE_M(0x3FF, 0)
|
#define PF_MBX_ATQLEN_ATQLEN_M ICE_M(0x3FF, 0)
|
||||||
|
#define PF_MBX_ATQLEN_ATQCRIT_M BIT(30)
|
||||||
#define PF_MBX_ATQLEN_ATQENABLE_M BIT(31)
|
#define PF_MBX_ATQLEN_ATQENABLE_M BIT(31)
|
||||||
#define PF_MBX_ATQT 0x0022E300
|
#define PF_MBX_ATQT 0x0022E300
|
||||||
#define PRTDCB_GENC 0x00083000
|
#define PRTDCB_GENC 0x00083000
|
||||||
|
|||||||
@@ -5207,6 +5207,8 @@ const char *ice_stat_str(enum ice_status stat_err)
|
|||||||
return "ICE_ERR_AQ_NO_WORK";
|
return "ICE_ERR_AQ_NO_WORK";
|
||||||
case ICE_ERR_AQ_EMPTY:
|
case ICE_ERR_AQ_EMPTY:
|
||||||
return "ICE_ERR_AQ_EMPTY";
|
return "ICE_ERR_AQ_EMPTY";
|
||||||
|
case ICE_ERR_AQ_FW_CRITICAL:
|
||||||
|
return "ICE_ERR_AQ_FW_CRITICAL";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "ICE_ERR_UNKNOWN";
|
return "ICE_ERR_UNKNOWN";
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ enum ice_status {
|
|||||||
ICE_ERR_AQ_FULL = -102,
|
ICE_ERR_AQ_FULL = -102,
|
||||||
ICE_ERR_AQ_NO_WORK = -103,
|
ICE_ERR_AQ_NO_WORK = -103,
|
||||||
ICE_ERR_AQ_EMPTY = -104,
|
ICE_ERR_AQ_EMPTY = -104,
|
||||||
|
ICE_ERR_AQ_FW_CRITICAL = -105,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _ICE_STATUS_H_ */
|
#endif /* _ICE_STATUS_H_ */
|
||||||
|
|||||||
Reference in New Issue
Block a user