From bc6e952463a8ff739d2c19e2bf244b2fc20333e5 Mon Sep 17 00:00:00 2001 From: Jonathan Toppins Date: Wed, 2 Oct 2019 18:23:33 -0400 Subject: [PATCH 78/96] [netdrv] bnxt_en: Add bnxt_fw_exception() to handle fatal firmware errors Message-id: <7d2820df47f74feb4d96b3892f2ac534344a8293.1570027456.git.jtoppins@redhat.com> Patchwork-id: 276501 O-Subject: [RHEL-8.2 PATCH 71/78] bnxt_en: Add bnxt_fw_exception() to handle fatal firmware errors. Bugzilla: 1724766 RH-Acked-by: John Linville RH-Acked-by: Jarod Wilson This call will handle fatal firmware errors by forcing a reset on the firmware. The master function driver will carry out the forced reset. The sequence will go through the same bnxt_fw_reset_task() workqueue. This fatal reset differs from the non-fatal reset at the beginning stages. From the BNXT_FW_RESET_STATE_ENABLE_DEV state onwards where the firmware is coming out of reset, it is practically identical to the non-fatal reset. The next patch will add the periodic heartbeat check and the devlink reporter to report the fatal event and to initiate the bnxt_fw_exception() call. Signed-off-by: Vasundhara Volam Signed-off-by: Michael Chan Signed-off-by: David S. Miller (cherry picked from commit d1db9e166bf6a50e1e6713f3fd3b4de6007e3671) Bugzilla: 1724766 Build Info: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=23809532 Tested: build, boot, basic ping Signed-off-by: Jonathan Toppins Signed-off-by: Bruno Meneguele --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 44 +++++++++++++++++++++++++++++++ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + 2 files changed, 45 insertions(+) Index: src/drivers/net/ethernet/broadcom/bnxt/bnxt.c =================================================================== --- src.orig/drivers/net/ethernet/broadcom/bnxt/bnxt.c 2020-02-06 16:23:20.736467018 +0100 +++ src/drivers/net/ethernet/broadcom/bnxt/bnxt.c 2020-02-06 16:23:20.864465843 +0100 @@ -10008,6 +10008,40 @@ bp->ctx = NULL; } +/* rtnl_lock is acquired before calling this function */ +static void bnxt_force_fw_reset(struct bnxt *bp) +{ + struct bnxt_fw_health *fw_health = bp->fw_health; + u32 wait_dsecs; + + if (!test_bit(BNXT_STATE_OPEN, &bp->state) || + test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) + return; + + set_bit(BNXT_STATE_IN_FW_RESET, &bp->state); + bnxt_fw_reset_close(bp); + wait_dsecs = fw_health->master_func_wait_dsecs; + if (fw_health->master) { + if (fw_health->flags & ERROR_RECOVERY_QCFG_RESP_FLAGS_CO_CPU) + wait_dsecs = 0; + bp->fw_reset_state = BNXT_FW_RESET_STATE_RESET_FW; + } else { + bp->fw_reset_timestamp = jiffies + wait_dsecs * HZ / 10; + wait_dsecs = fw_health->normal_func_wait_dsecs; + bp->fw_reset_state = BNXT_FW_RESET_STATE_ENABLE_DEV; + } + bp->fw_reset_max_dsecs = fw_health->post_reset_max_wait_dsecs; + bnxt_queue_fw_reset_work(bp, wait_dsecs * HZ / 10); +} + +void bnxt_fw_exception(struct bnxt *bp) +{ + set_bit(BNXT_STATE_FW_FATAL_COND, &bp->state); + bnxt_rtnl_lock_sp(bp); + bnxt_force_fw_reset(bp); + bnxt_rtnl_unlock_sp(bp); +} + void bnxt_fw_reset(struct bnxt *bp) { int rc; @@ -10511,6 +10545,16 @@ return; } case BNXT_FW_RESET_STATE_ENABLE_DEV: + if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state) && + bp->fw_health) { + u32 val; + + val = bnxt_fw_health_readl(bp, + BNXT_FW_RESET_INPROG_REG); + if (val) + netdev_warn(bp->dev, "FW reset inprog %x after min wait time.\n", + val); + } clear_bit(BNXT_STATE_FW_FATAL_COND, &bp->state); if (pci_enable_device(bp->pdev)) { netdev_err(bp->dev, "Cannot re-enable PCI device\n"); Index: src/drivers/net/ethernet/broadcom/bnxt/bnxt.h =================================================================== --- src.orig/drivers/net/ethernet/broadcom/bnxt/bnxt.h 2020-02-06 16:23:20.602468248 +0100 +++ src/drivers/net/ethernet/broadcom/bnxt/bnxt.h 2020-02-06 16:23:20.864465843 +0100 @@ -1982,6 +1982,7 @@ int bnxt_half_open_nic(struct bnxt *bp); void bnxt_half_close_nic(struct bnxt *bp); int bnxt_close_nic(struct bnxt *, bool, bool); +void bnxt_fw_exception(struct bnxt *bp); void bnxt_fw_reset(struct bnxt *bp); int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs, int tx_xdp);