summaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c48
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.h3
2 files changed, 46 insertions, 5 deletions
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 58831dd07c84..b4a8cf620a0c 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -6947,6 +6947,8 @@ static int __bnxt_hwrm_func_qcaps(struct bnxt *bp)
bp->fw_cap |= BNXT_FW_CAP_EXT_STATS_SUPPORTED;
if (flags & FUNC_QCAPS_RESP_FLAGS_ERROR_RECOVERY_CAPABLE)
bp->fw_cap |= BNXT_FW_CAP_ERROR_RECOVERY;
+ if (flags & FUNC_QCAPS_RESP_FLAGS_ERR_RECOVER_RELOAD)
+ bp->fw_cap |= BNXT_FW_CAP_ERR_RECOVER_RELOAD;
bp->tx_push_thresh = 0;
if (flags & FUNC_QCAPS_RESP_FLAGS_PUSH_MODE_SUPPORTED)
@@ -10097,6 +10099,8 @@ static void bnxt_force_fw_reset(struct bnxt *bp)
wait_dsecs = fw_health->normal_func_wait_dsecs;
bp->fw_reset_state = BNXT_FW_RESET_STATE_ENABLE_DEV;
}
+
+ bp->fw_reset_min_dsecs = fw_health->post_reset_wait_dsecs;
bp->fw_reset_max_dsecs = fw_health->post_reset_max_wait_dsecs;
bnxt_queue_fw_reset_work(bp, wait_dsecs * HZ / 10);
}
@@ -10138,7 +10142,7 @@ void bnxt_fw_reset(struct bnxt *bp)
bnxt_rtnl_lock_sp(bp);
if (test_bit(BNXT_STATE_OPEN, &bp->state) &&
!test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) {
- int n = 0;
+ int n = 0, tmo;
set_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
if (bp->pf.active_vfs &&
@@ -10161,8 +10165,14 @@ void bnxt_fw_reset(struct bnxt *bp)
goto fw_reset_exit;
}
bnxt_fw_reset_close(bp);
- bp->fw_reset_state = BNXT_FW_RESET_STATE_ENABLE_DEV;
- bnxt_queue_fw_reset_work(bp, bp->fw_reset_min_dsecs * HZ / 10);
+ if (bp->fw_cap & BNXT_FW_CAP_ERR_RECOVER_RELOAD) {
+ bp->fw_reset_state = BNXT_FW_RESET_STATE_POLL_FW_DOWN;
+ tmo = HZ / 10;
+ } else {
+ bp->fw_reset_state = BNXT_FW_RESET_STATE_ENABLE_DEV;
+ tmo = bp->fw_reset_min_dsecs * HZ / 10;
+ }
+ bnxt_queue_fw_reset_work(bp, tmo);
}
fw_reset_exit:
bnxt_rtnl_unlock_sp(bp);
@@ -10605,6 +10615,7 @@ static void bnxt_fw_reset_task(struct work_struct *work)
switch (bp->fw_reset_state) {
case BNXT_FW_RESET_STATE_POLL_VF: {
int n = bnxt_get_registered_vfs(bp);
+ int tmo;
if (n < 0) {
netdev_err(bp->dev, "Firmware reset aborted, subsequent func_qcfg cmd failed, rc = %d, %d msecs since reset timestamp\n",
@@ -10626,11 +10637,38 @@ static void bnxt_fw_reset_task(struct work_struct *work)
bp->fw_reset_timestamp = jiffies;
rtnl_lock();
bnxt_fw_reset_close(bp);
- bp->fw_reset_state = BNXT_FW_RESET_STATE_ENABLE_DEV;
+ if (bp->fw_cap & BNXT_FW_CAP_ERR_RECOVER_RELOAD) {
+ bp->fw_reset_state = BNXT_FW_RESET_STATE_POLL_FW_DOWN;
+ tmo = HZ / 10;
+ } else {
+ bp->fw_reset_state = BNXT_FW_RESET_STATE_ENABLE_DEV;
+ tmo = bp->fw_reset_min_dsecs * HZ / 10;
+ }
rtnl_unlock();
- bnxt_queue_fw_reset_work(bp, bp->fw_reset_min_dsecs * HZ / 10);
+ bnxt_queue_fw_reset_work(bp, tmo);
return;
}
+ case BNXT_FW_RESET_STATE_POLL_FW_DOWN: {
+ u32 val;
+
+ val = bnxt_fw_health_readl(bp, BNXT_FW_HEALTH_REG);
+ if (!(val & BNXT_FW_STATUS_SHUTDOWN) &&
+ !time_after(jiffies, bp->fw_reset_timestamp +
+ (bp->fw_reset_max_dsecs * HZ / 10))) {
+ bnxt_queue_fw_reset_work(bp, HZ / 5);
+ return;
+ }
+
+ if (!bp->fw_health->master) {
+ u32 wait_dsecs = bp->fw_health->normal_func_wait_dsecs;
+
+ bp->fw_reset_state = BNXT_FW_RESET_STATE_ENABLE_DEV;
+ bnxt_queue_fw_reset_work(bp, wait_dsecs * HZ / 10);
+ return;
+ }
+ bp->fw_reset_state = BNXT_FW_RESET_STATE_RESET_FW;
+ }
+ /* fall through */
case BNXT_FW_RESET_STATE_RESET_FW: {
u32 wait_dsecs = bp->fw_health->post_reset_wait_dsecs;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index 42a8a7574570..d333589811a5 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -1398,6 +1398,7 @@ struct bnxt_fw_reporter_ctx {
#define BNXT_FW_HEALTH_WIN_MAP_OFF 8
#define BNXT_FW_STATUS_HEALTHY 0x8000
+#define BNXT_FW_STATUS_SHUTDOWN 0x100000
struct bnxt {
void __iomem *bar0;
@@ -1655,6 +1656,7 @@ struct bnxt {
#define BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX 0x00010000
#define BNXT_FW_CAP_PCIE_STATS_SUPPORTED 0x00020000
#define BNXT_FW_CAP_EXT_STATS_SUPPORTED 0x00040000
+ #define BNXT_FW_CAP_ERR_RECOVER_RELOAD 0x00100000
#define BNXT_NEW_RM(bp) ((bp)->fw_cap & BNXT_FW_CAP_NEW_RM)
u32 hwrm_spec_code;
@@ -1744,6 +1746,7 @@ struct bnxt {
#define BNXT_FW_RESET_STATE_ENABLE_DEV 3
#define BNXT_FW_RESET_STATE_POLL_FW 4
#define BNXT_FW_RESET_STATE_OPENING 5
+#define BNXT_FW_RESET_STATE_POLL_FW_DOWN 6
u16 fw_reset_min_dsecs;
#define BNXT_DFLT_FW_RST_MIN_DSECS 20