qed: Fix error flow on slowpath start
In case of problems when initializing the chip, the error flows aren't being properly done. Specifically, it's possible that the chip would be left in a configuration allowing it [internally] to access the host memory, causing fatal problems in the device that would require power cycle to overcome. Signed-off-by: Yuval Mintz <Yuval.Mintz@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
86622ee753
commit
8c925c4438
@ -756,10 +756,54 @@ int qed_hw_init(struct qed_dev *cdev,
|
||||
}
|
||||
|
||||
#define QED_HW_STOP_RETRY_LIMIT (10)
|
||||
static inline void qed_hw_timers_stop(struct qed_dev *cdev,
|
||||
struct qed_hwfn *p_hwfn,
|
||||
struct qed_ptt *p_ptt)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* close timers */
|
||||
qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_CONN, 0x0);
|
||||
qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_TASK, 0x0);
|
||||
|
||||
for (i = 0; i < QED_HW_STOP_RETRY_LIMIT; i++) {
|
||||
if ((!qed_rd(p_hwfn, p_ptt,
|
||||
TM_REG_PF_SCAN_ACTIVE_CONN)) &&
|
||||
(!qed_rd(p_hwfn, p_ptt,
|
||||
TM_REG_PF_SCAN_ACTIVE_TASK)))
|
||||
break;
|
||||
|
||||
/* Dependent on number of connection/tasks, possibly
|
||||
* 1ms sleep is required between polls
|
||||
*/
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
|
||||
if (i < QED_HW_STOP_RETRY_LIMIT)
|
||||
return;
|
||||
|
||||
DP_NOTICE(p_hwfn,
|
||||
"Timers linear scans are not over [Connection %02x Tasks %02x]\n",
|
||||
(u8)qed_rd(p_hwfn, p_ptt, TM_REG_PF_SCAN_ACTIVE_CONN),
|
||||
(u8)qed_rd(p_hwfn, p_ptt, TM_REG_PF_SCAN_ACTIVE_TASK));
|
||||
}
|
||||
|
||||
void qed_hw_timers_stop_all(struct qed_dev *cdev)
|
||||
{
|
||||
int j;
|
||||
|
||||
for_each_hwfn(cdev, j) {
|
||||
struct qed_hwfn *p_hwfn = &cdev->hwfns[j];
|
||||
struct qed_ptt *p_ptt = p_hwfn->p_main_ptt;
|
||||
|
||||
qed_hw_timers_stop(cdev, p_hwfn, p_ptt);
|
||||
}
|
||||
}
|
||||
|
||||
int qed_hw_stop(struct qed_dev *cdev)
|
||||
{
|
||||
int rc = 0, t_rc;
|
||||
int i, j;
|
||||
int j;
|
||||
|
||||
for_each_hwfn(cdev, j) {
|
||||
struct qed_hwfn *p_hwfn = &cdev->hwfns[j];
|
||||
@ -772,7 +816,8 @@ int qed_hw_stop(struct qed_dev *cdev)
|
||||
|
||||
rc = qed_sp_pf_stop(p_hwfn);
|
||||
if (rc)
|
||||
return rc;
|
||||
DP_NOTICE(p_hwfn,
|
||||
"Failed to close PF against FW. Continue to stop HW to prevent illegal host access by the device\n");
|
||||
|
||||
qed_wr(p_hwfn, p_ptt,
|
||||
NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF, 0x1);
|
||||
@ -783,24 +828,7 @@ int qed_hw_stop(struct qed_dev *cdev)
|
||||
qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_ROCE, 0x0);
|
||||
qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_OPENFLOW, 0x0);
|
||||
|
||||
qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_CONN, 0x0);
|
||||
qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_TASK, 0x0);
|
||||
for (i = 0; i < QED_HW_STOP_RETRY_LIMIT; i++) {
|
||||
if ((!qed_rd(p_hwfn, p_ptt,
|
||||
TM_REG_PF_SCAN_ACTIVE_CONN)) &&
|
||||
(!qed_rd(p_hwfn, p_ptt,
|
||||
TM_REG_PF_SCAN_ACTIVE_TASK)))
|
||||
break;
|
||||
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
if (i == QED_HW_STOP_RETRY_LIMIT)
|
||||
DP_NOTICE(p_hwfn,
|
||||
"Timers linear scans are not over [Connection %02x Tasks %02x]\n",
|
||||
(u8)qed_rd(p_hwfn, p_ptt,
|
||||
TM_REG_PF_SCAN_ACTIVE_CONN),
|
||||
(u8)qed_rd(p_hwfn, p_ptt,
|
||||
TM_REG_PF_SCAN_ACTIVE_TASK));
|
||||
qed_hw_timers_stop(cdev, p_hwfn, p_ptt);
|
||||
|
||||
/* Disable Attention Generation */
|
||||
qed_int_igu_disable_int(p_hwfn, p_ptt);
|
||||
@ -829,7 +857,7 @@ int qed_hw_stop(struct qed_dev *cdev)
|
||||
|
||||
void qed_hw_stop_fastpath(struct qed_dev *cdev)
|
||||
{
|
||||
int i, j;
|
||||
int j;
|
||||
|
||||
for_each_hwfn(cdev, j) {
|
||||
struct qed_hwfn *p_hwfn = &cdev->hwfns[j];
|
||||
@ -848,25 +876,6 @@ void qed_hw_stop_fastpath(struct qed_dev *cdev)
|
||||
qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_ROCE, 0x0);
|
||||
qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_OPENFLOW, 0x0);
|
||||
|
||||
qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_CONN, 0x0);
|
||||
qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_TASK, 0x0);
|
||||
for (i = 0; i < QED_HW_STOP_RETRY_LIMIT; i++) {
|
||||
if ((!qed_rd(p_hwfn, p_ptt,
|
||||
TM_REG_PF_SCAN_ACTIVE_CONN)) &&
|
||||
(!qed_rd(p_hwfn, p_ptt,
|
||||
TM_REG_PF_SCAN_ACTIVE_TASK)))
|
||||
break;
|
||||
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
if (i == QED_HW_STOP_RETRY_LIMIT)
|
||||
DP_NOTICE(p_hwfn,
|
||||
"Timers linear scans are not over [Connection %02x Tasks %02x]\n",
|
||||
(u8)qed_rd(p_hwfn, p_ptt,
|
||||
TM_REG_PF_SCAN_ACTIVE_CONN),
|
||||
(u8)qed_rd(p_hwfn, p_ptt,
|
||||
TM_REG_PF_SCAN_ACTIVE_TASK));
|
||||
|
||||
qed_int_igu_init_pure_rt(p_hwfn, p_ptt, false, false);
|
||||
|
||||
/* Need to wait 1ms to guarantee SBs are cleared */
|
||||
|
@ -77,6 +77,15 @@ int qed_hw_init(struct qed_dev *cdev,
|
||||
bool allow_npar_tx_switch,
|
||||
const u8 *bin_fw_data);
|
||||
|
||||
/**
|
||||
* @brief qed_hw_timers_stop_all - stop the timers HW block
|
||||
*
|
||||
* @param cdev
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
void qed_hw_timers_stop_all(struct qed_dev *cdev);
|
||||
|
||||
/**
|
||||
* @brief qed_hw_stop -
|
||||
*
|
||||
|
@ -779,7 +779,7 @@ static int qed_slowpath_start(struct qed_dev *cdev,
|
||||
rc = qed_hw_init(cdev, true, cdev->int_params.out.int_mode,
|
||||
true, data);
|
||||
if (rc)
|
||||
goto err3;
|
||||
goto err2;
|
||||
|
||||
DP_INFO(cdev,
|
||||
"HW initialization and function start completed successfully\n");
|
||||
@ -798,12 +798,14 @@ static int qed_slowpath_start(struct qed_dev *cdev,
|
||||
return rc;
|
||||
}
|
||||
|
||||
qed_reset_vport_stats(cdev);
|
||||
|
||||
return 0;
|
||||
|
||||
err3:
|
||||
qed_free_stream_mem(cdev);
|
||||
qed_slowpath_irq_free(cdev);
|
||||
err2:
|
||||
qed_hw_timers_stop_all(cdev);
|
||||
qed_slowpath_irq_free(cdev);
|
||||
qed_free_stream_mem(cdev);
|
||||
qed_disable_msix(cdev);
|
||||
err1:
|
||||
qed_resc_free(cdev);
|
||||
|
Loading…
x
Reference in New Issue
Block a user