Skip to content

Commit 230d1f0

Browse files
Michael Chandavem330
authored andcommitted
bnxt_en: Handle firmware reset.
Add the bnxt_fw_reset() main function to handle firmware reset. This is triggered by firmware to initiate an orderly reset, for example when a non-fatal exception condition has been detected. bnxt_fw_reset() will first wait for all VFs to shutdown and then start the bnxt_fw_reset_task() work queue to go through the sequence of reset, re-probe, and re-initialization. The next patch will add the devlink reporter to start the sequence and call bnxt_fw_reset(). Signed-off-by: Michael Chan <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 2151fe0 commit 230d1f0

File tree

3 files changed

+164
-0
lines changed

3 files changed

+164
-0
lines changed

drivers/net/ethernet/broadcom/bnxt/bnxt.c

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,6 +1140,14 @@ static int bnxt_discard_rx(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
11401140
return 0;
11411141
}
11421142

1143+
static void bnxt_queue_fw_reset_work(struct bnxt *bp, unsigned long delay)
1144+
{
1145+
if (BNXT_PF(bp))
1146+
queue_delayed_work(bnxt_pf_wq, &bp->fw_reset_task, delay);
1147+
else
1148+
schedule_delayed_work(&bp->fw_reset_task, delay);
1149+
}
1150+
11431151
static void bnxt_queue_sp_work(struct bnxt *bp)
11441152
{
11451153
if (BNXT_PF(bp))
@@ -6355,6 +6363,8 @@ static int bnxt_hwrm_func_qcfg(struct bnxt *bp)
63556363
struct bnxt_vf_info *vf = &bp->vf;
63566364

63576365
vf->vlan = le16_to_cpu(resp->vlan) & VLAN_VID_MASK;
6366+
} else {
6367+
bp->pf.registered_vfs = le16_to_cpu(resp->registered_vfs);
63586368
}
63596369
#endif
63606370
flags = le16_to_cpu(resp->flags);
@@ -9980,6 +9990,53 @@ static void bnxt_reset(struct bnxt *bp, bool silent)
99809990
bnxt_rtnl_unlock_sp(bp);
99819991
}
99829992

9993+
static void bnxt_fw_reset_close(struct bnxt *bp)
9994+
{
9995+
__bnxt_close_nic(bp, true, false);
9996+
bnxt_ulp_irq_stop(bp);
9997+
bnxt_clear_int_mode(bp);
9998+
bnxt_hwrm_func_drv_unrgtr(bp);
9999+
bnxt_free_ctx_mem(bp);
10000+
kfree(bp->ctx);
10001+
bp->ctx = NULL;
10002+
}
10003+
10004+
void bnxt_fw_reset(struct bnxt *bp)
10005+
{
10006+
int rc;
10007+
10008+
bnxt_rtnl_lock_sp(bp);
10009+
if (test_bit(BNXT_STATE_OPEN, &bp->state) &&
10010+
!test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) {
10011+
set_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
10012+
if (BNXT_PF(bp) && bp->pf.active_vfs) {
10013+
rc = bnxt_hwrm_func_qcfg(bp);
10014+
if (rc) {
10015+
netdev_err(bp->dev, "Firmware reset aborted, first func_qcfg cmd failed, rc = %d\n",
10016+
rc);
10017+
clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
10018+
dev_close(bp->dev);
10019+
goto fw_reset_exit;
10020+
}
10021+
if (bp->pf.registered_vfs || bp->sriov_cfg) {
10022+
u16 vf_tmo_dsecs = bp->pf.registered_vfs * 10;
10023+
10024+
if (bp->fw_reset_max_dsecs < vf_tmo_dsecs)
10025+
bp->fw_reset_max_dsecs = vf_tmo_dsecs;
10026+
bp->fw_reset_state =
10027+
BNXT_FW_RESET_STATE_POLL_VF;
10028+
bnxt_queue_fw_reset_work(bp, HZ / 10);
10029+
goto fw_reset_exit;
10030+
}
10031+
}
10032+
bnxt_fw_reset_close(bp);
10033+
bp->fw_reset_state = BNXT_FW_RESET_STATE_ENABLE_DEV;
10034+
bnxt_queue_fw_reset_work(bp, bp->fw_reset_min_dsecs * HZ / 10);
10035+
}
10036+
fw_reset_exit:
10037+
bnxt_rtnl_unlock_sp(bp);
10038+
}
10039+
998310040
static void bnxt_chk_missed_irq(struct bnxt *bp)
998410041
{
998510042
int i;
@@ -10339,6 +10396,98 @@ static int bnxt_fw_init_one(struct bnxt *bp)
1033910396
return 0;
1034010397
}
1034110398

10399+
static void bnxt_fw_reset_task(struct work_struct *work)
10400+
{
10401+
struct bnxt *bp = container_of(work, struct bnxt, fw_reset_task.work);
10402+
int rc;
10403+
10404+
if (!test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) {
10405+
netdev_err(bp->dev, "bnxt_fw_reset_task() called when not in fw reset mode!\n");
10406+
return;
10407+
}
10408+
10409+
switch (bp->fw_reset_state) {
10410+
case BNXT_FW_RESET_STATE_POLL_VF:
10411+
rc = bnxt_hwrm_func_qcfg(bp);
10412+
if (rc) {
10413+
netdev_err(bp->dev, "Firmware reset aborted, subsequent func_qcfg cmd failed, rc = %d, %d msecs since reset timestamp\n",
10414+
rc, jiffies_to_msecs(jiffies -
10415+
bp->fw_reset_timestamp));
10416+
goto fw_reset_abort;
10417+
}
10418+
if (bp->pf.registered_vfs || bp->sriov_cfg) {
10419+
if (time_after(jiffies, bp->fw_reset_timestamp +
10420+
(bp->fw_reset_max_dsecs * HZ / 10))) {
10421+
clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
10422+
bp->fw_reset_state = 0;
10423+
netdev_err(bp->dev, "Firmware reset aborted, %d VFs still registered, sriov_cfg %d\n",
10424+
bp->pf.registered_vfs,
10425+
bp->sriov_cfg);
10426+
return;
10427+
}
10428+
bnxt_queue_fw_reset_work(bp, HZ / 10);
10429+
return;
10430+
}
10431+
bp->fw_reset_timestamp = jiffies;
10432+
rtnl_lock();
10433+
bnxt_fw_reset_close(bp);
10434+
bp->fw_reset_state = BNXT_FW_RESET_STATE_ENABLE_DEV;
10435+
rtnl_unlock();
10436+
bnxt_queue_fw_reset_work(bp, bp->fw_reset_min_dsecs * HZ / 10);
10437+
return;
10438+
case BNXT_FW_RESET_STATE_ENABLE_DEV:
10439+
if (pci_enable_device(bp->pdev)) {
10440+
netdev_err(bp->dev, "Cannot re-enable PCI device\n");
10441+
goto fw_reset_abort;
10442+
}
10443+
pci_set_master(bp->pdev);
10444+
bp->fw_reset_state = BNXT_FW_RESET_STATE_POLL_FW;
10445+
/* fall through */
10446+
case BNXT_FW_RESET_STATE_POLL_FW:
10447+
bp->hwrm_cmd_timeout = SHORT_HWRM_CMD_TIMEOUT;
10448+
rc = __bnxt_hwrm_ver_get(bp, true);
10449+
if (rc) {
10450+
if (time_after(jiffies, bp->fw_reset_timestamp +
10451+
(bp->fw_reset_max_dsecs * HZ / 10))) {
10452+
netdev_err(bp->dev, "Firmware reset aborted\n");
10453+
goto fw_reset_abort;
10454+
}
10455+
bnxt_queue_fw_reset_work(bp, HZ / 5);
10456+
return;
10457+
}
10458+
bp->hwrm_cmd_timeout = DFLT_HWRM_CMD_TIMEOUT;
10459+
bp->fw_reset_state = BNXT_FW_RESET_STATE_OPENING;
10460+
/* fall through */
10461+
case BNXT_FW_RESET_STATE_OPENING:
10462+
while (!rtnl_trylock()) {
10463+
bnxt_queue_fw_reset_work(bp, HZ / 10);
10464+
return;
10465+
}
10466+
rc = bnxt_open(bp->dev);
10467+
if (rc) {
10468+
netdev_err(bp->dev, "bnxt_open_nic() failed\n");
10469+
clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
10470+
dev_close(bp->dev);
10471+
}
10472+
bnxt_ulp_irq_restart(bp, rc);
10473+
rtnl_unlock();
10474+
10475+
bp->fw_reset_state = 0;
10476+
/* Make sure fw_reset_state is 0 before clearing the flag */
10477+
smp_mb__before_atomic();
10478+
clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
10479+
break;
10480+
}
10481+
return;
10482+
10483+
fw_reset_abort:
10484+
clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
10485+
bp->fw_reset_state = 0;
10486+
rtnl_lock();
10487+
dev_close(bp->dev);
10488+
rtnl_unlock();
10489+
}
10490+
1034210491
static int bnxt_init_board(struct pci_dev *pdev, struct net_device *dev)
1034310492
{
1034410493
int rc;
@@ -10401,6 +10550,7 @@ static int bnxt_init_board(struct pci_dev *pdev, struct net_device *dev)
1040110550
pci_enable_pcie_error_reporting(pdev);
1040210551

1040310552
INIT_WORK(&bp->sp_task, bnxt_sp_task);
10553+
INIT_DELAYED_WORK(&bp->fw_reset_task, bnxt_fw_reset_task);
1040410554

1040510555
spin_lock_init(&bp->ntp_fltr_lock);
1040610556
#if BITS_PER_LONG == 32

drivers/net/ethernet/broadcom/bnxt/bnxt.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,7 @@ struct nqe_cn {
640640
#define BNXT_HWRM_MAX_REQ_LEN (bp->hwrm_max_req_len)
641641
#define BNXT_HWRM_SHORT_REQ_LEN sizeof(struct hwrm_short_input)
642642
#define DFLT_HWRM_CMD_TIMEOUT 500
643+
#define SHORT_HWRM_CMD_TIMEOUT 20
643644
#define HWRM_CMD_TIMEOUT (bp->hwrm_cmd_timeout)
644645
#define HWRM_RESET_TIMEOUT ((HWRM_CMD_TIMEOUT) * 4)
645646
#define HWRM_RESP_ERR_CODE_MASK 0xffff
@@ -1066,6 +1067,7 @@ struct bnxt_pf_info {
10661067
u8 mac_addr[ETH_ALEN];
10671068
u32 first_vf_id;
10681069
u16 active_vfs;
1070+
u16 registered_vfs;
10691071
u16 max_vfs;
10701072
u32 max_encap_records;
10711073
u32 max_decap_records;
@@ -1721,6 +1723,14 @@ struct bnxt {
17211723
#define BNXT_RING_COAL_NOW_SP_EVENT 17
17221724
#define BNXT_FW_RESET_NOTIFY_SP_EVENT 18
17231725

1726+
struct delayed_work fw_reset_task;
1727+
int fw_reset_state;
1728+
#define BNXT_FW_RESET_STATE_POLL_VF 1
1729+
#define BNXT_FW_RESET_STATE_RESET_FW 2
1730+
#define BNXT_FW_RESET_STATE_ENABLE_DEV 3
1731+
#define BNXT_FW_RESET_STATE_POLL_FW 4
1732+
#define BNXT_FW_RESET_STATE_OPENING 5
1733+
17241734
u16 fw_reset_min_dsecs;
17251735
#define BNXT_DFLT_FW_RST_MIN_DSECS 20
17261736
u16 fw_reset_max_dsecs;
@@ -1966,6 +1976,7 @@ int bnxt_open_nic(struct bnxt *, bool, bool);
19661976
int bnxt_half_open_nic(struct bnxt *bp);
19671977
void bnxt_half_close_nic(struct bnxt *bp);
19681978
int bnxt_close_nic(struct bnxt *, bool, bool);
1979+
void bnxt_fw_reset(struct bnxt *bp);
19691980
int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
19701981
int tx_xdp);
19711982
int bnxt_setup_mq_tc(struct net_device *dev, u8 tc);

drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ static int bnxt_send_msg(struct bnxt_en_dev *edev, int ulp_id,
226226
struct input *req;
227227
int rc;
228228

229+
if (ulp_id != BNXT_ROCE_ULP && bp->fw_reset_state)
230+
return -EBUSY;
231+
229232
mutex_lock(&bp->hwrm_cmd_lock);
230233
req = fw_msg->msg;
231234
req->resp_addr = cpu_to_le64(bp->hwrm_cmd_resp_dma_addr);

0 commit comments

Comments
 (0)