bnxt_en: Fix bp->fw_health allocation and free logic.
authorVasundhara Volam <vasundhara-v.volam@broadcom.com>
Tue, 10 Dec 2019 07:49:10 +0000 (02:49 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 4 Jan 2020 18:18:53 +0000 (19:18 +0100)
[ Upstream commit 8280b38e01f71e0f89389ccad3fa43b79e57c604 ]

bp->fw_health needs to be allocated for either the firmware initiated
reset feature or the driver initiated error recovery feature.  The
current code is not allocating bp->fw_health for all the necessary cases.
This patch corrects the logic to allocate bp->fw_health correctly when
needed.  If allocation fails, we clear the feature flags.

We also add the the missing kfree(bp->fw_health) when the driver is
unloaded.  If we get an async reset message from the firmware, we also
need to make sure that we have a valid bp->fw_health before proceeding.

Fixes: 07f83d72d238 ("bnxt_en: Discover firmware error recovery capabilities.")
Signed-off-by: Vasundhara Volam <vasundhara-v.volam@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt.h

index a23f582..a5e47b6 100644 (file)
@@ -1995,6 +1995,9 @@ static int bnxt_async_event_process(struct bnxt *bp,
        case ASYNC_EVENT_CMPL_EVENT_ID_RESET_NOTIFY: {
                u32 data1 = le32_to_cpu(cmpl->event_data1);
 
+               if (!bp->fw_health)
+                       goto async_event_process_exit;
+
                bp->fw_reset_timestamp = jiffies;
                bp->fw_reset_min_dsecs = cmpl->timestamp_lo;
                if (!bp->fw_reset_min_dsecs)
@@ -4438,8 +4441,9 @@ static int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp)
                            FUNC_DRV_RGTR_REQ_ENABLES_VER);
 
        req.os_type = cpu_to_le16(FUNC_DRV_RGTR_REQ_OS_TYPE_LINUX);
-       flags = FUNC_DRV_RGTR_REQ_FLAGS_16BIT_VER_MODE |
-               FUNC_DRV_RGTR_REQ_FLAGS_HOT_RESET_SUPPORT;
+       flags = FUNC_DRV_RGTR_REQ_FLAGS_16BIT_VER_MODE;
+       if (bp->fw_cap & BNXT_FW_CAP_HOT_RESET)
+               flags |= FUNC_DRV_RGTR_REQ_FLAGS_HOT_RESET_SUPPORT;
        if (bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY)
                flags |= FUNC_DRV_RGTR_REQ_FLAGS_ERROR_RECOVERY_SUPPORT;
        req.flags = cpu_to_le32(flags);
@@ -7096,14 +7100,6 @@ static int bnxt_hwrm_error_recovery_qcfg(struct bnxt *bp)
        rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
        if (rc)
                goto err_recovery_out;
-       if (!fw_health) {
-               fw_health = kzalloc(sizeof(*fw_health), GFP_KERNEL);
-               bp->fw_health = fw_health;
-               if (!fw_health) {
-                       rc = -ENOMEM;
-                       goto err_recovery_out;
-               }
-       }
        fw_health->flags = le32_to_cpu(resp->flags);
        if ((fw_health->flags & ERROR_RECOVERY_QCFG_RESP_FLAGS_CO_CPU) &&
            !(bp->fw_cap & BNXT_FW_CAP_KONG_MB_CHNL)) {
@@ -10419,6 +10415,23 @@ static void bnxt_init_dflt_coal(struct bnxt *bp)
        bp->stats_coal_ticks = BNXT_DEF_STATS_COAL_TICKS;
 }
 
+static void bnxt_alloc_fw_health(struct bnxt *bp)
+{
+       if (bp->fw_health)
+               return;
+
+       if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET) &&
+           !(bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY))
+               return;
+
+       bp->fw_health = kzalloc(sizeof(*bp->fw_health), GFP_KERNEL);
+       if (!bp->fw_health) {
+               netdev_warn(bp->dev, "Failed to allocate fw_health\n");
+               bp->fw_cap &= ~BNXT_FW_CAP_HOT_RESET;
+               bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY;
+       }
+}
+
 static int bnxt_fw_init_one_p1(struct bnxt *bp)
 {
        int rc;
@@ -10465,6 +10478,7 @@ static int bnxt_fw_init_one_p2(struct bnxt *bp)
                netdev_warn(bp->dev, "hwrm query adv flow mgnt failure rc: %d\n",
                            rc);
 
+       bnxt_alloc_fw_health(bp);
        rc = bnxt_hwrm_error_recovery_qcfg(bp);
        if (rc)
                netdev_warn(bp->dev, "hwrm query error recovery failure rc: %d\n",
@@ -11344,6 +11358,8 @@ static void bnxt_remove_one(struct pci_dev *pdev)
        bnxt_dcb_free(bp);
        kfree(bp->edev);
        bp->edev = NULL;
+       kfree(bp->fw_health);
+       bp->fw_health = NULL;
        bnxt_cleanup_pci(bp);
        bnxt_free_ctx_mem(bp);
        kfree(bp->ctx);
index 5163bb8..dc26e3a 100644 (file)
@@ -1658,6 +1658,7 @@ struct bnxt {
        #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_FW_CAP_HOT_RESET                   0x00200000
 
 #define BNXT_NEW_RM(bp)                ((bp)->fw_cap & BNXT_FW_CAP_NEW_RM)
        u32                     hwrm_spec_code;