ASYNC_EVENT_CMPL_EVENT_ID_RESET_NOTIFY,
        ASYNC_EVENT_CMPL_EVENT_ID_ERROR_RECOVERY,
        ASYNC_EVENT_CMPL_EVENT_ID_DEBUG_NOTIFICATION,
+       ASYNC_EVENT_CMPL_EVENT_ID_DEFERRED_RESPONSE,
        ASYNC_EVENT_CMPL_EVENT_ID_RING_MONITOR_MSG,
        ASYNC_EVENT_CMPL_EVENT_ID_ECHO_REQUEST,
        ASYNC_EVENT_CMPL_EVENT_ID_PPS_TIMESTAMP,
                bnxt_event_error_report(bp, data1, data2);
                goto async_event_process_exit;
        }
+       case ASYNC_EVENT_CMPL_EVENT_ID_DEFERRED_RESPONSE: {
+               u16 seq_id = le32_to_cpu(cmpl->event_data2) & 0xffff;
+
+               hwrm_update_token(bp, seq_id, BNXT_HWRM_DEFERRED);
+               goto async_event_process_exit;
+       }
        default:
                goto async_event_process_exit;
        }
        switch (cmpl_type) {
        case CMPL_BASE_TYPE_HWRM_DONE:
                seq_id = le16_to_cpu(h_cmpl->sequence_id);
-               if (seq_id == bp->hwrm_intr_seq_id)
-                       bp->hwrm_intr_seq_id = (u16)~bp->hwrm_intr_seq_id;
-               else
-                       netdev_err(bp->dev, "Invalid hwrm seq id %d\n", seq_id);
+               hwrm_update_token(bp, seq_id, BNXT_HWRM_COMPLETE);
                break;
 
        case CMPL_BASE_TYPE_HWRM_FWD_REQ:
 
 static void bnxt_free_hwrm_resources(struct bnxt *bp)
 {
+       struct bnxt_hwrm_wait_token *token;
+
        dma_pool_destroy(bp->hwrm_dma_pool);
        bp->hwrm_dma_pool = NULL;
+
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(token, &bp->hwrm_pending_list, node)
+               WRITE_ONCE(token->state, BNXT_HWRM_CANCELLED);
+       rcu_read_unlock();
 }
 
 static int bnxt_alloc_hwrm_resources(struct bnxt *bp)
        if (!bp->hwrm_dma_pool)
                return -ENOMEM;
 
+       INIT_HLIST_HEAD(&bp->hwrm_pending_list);
+
        return 0;
 }
 
 
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/kernel.h>
+#include <linux/list.h>
 #include <linux/netdevice.h>
 #include <linux/pci.h>
 #include <linux/skbuff.h>
        }
 }
 
+static struct bnxt_hwrm_wait_token *
+__hwrm_acquire_token(struct bnxt *bp, enum bnxt_hwrm_chnl dst)
+{
+       struct bnxt_hwrm_wait_token *token;
+
+       token = kzalloc(sizeof(*token), GFP_KERNEL);
+       if (!token)
+               return NULL;
+
+       mutex_lock(&bp->hwrm_cmd_lock);
+
+       token->dst = dst;
+       token->state = BNXT_HWRM_PENDING;
+       if (dst == BNXT_HWRM_CHNL_CHIMP) {
+               token->seq_id = bp->hwrm_cmd_seq++;
+               hlist_add_head_rcu(&token->node, &bp->hwrm_pending_list);
+       } else {
+               token->seq_id = bp->hwrm_cmd_kong_seq++;
+       }
+
+       return token;
+}
+
+static void
+__hwrm_release_token(struct bnxt *bp, struct bnxt_hwrm_wait_token *token)
+{
+       if (token->dst == BNXT_HWRM_CHNL_CHIMP) {
+               hlist_del_rcu(&token->node);
+               kfree_rcu(token, rcu);
+       } else {
+               kfree(token);
+       }
+       mutex_unlock(&bp->hwrm_cmd_lock);
+}
+
+void
+hwrm_update_token(struct bnxt *bp, u16 seq_id, enum bnxt_hwrm_wait_state state)
+{
+       struct bnxt_hwrm_wait_token *token;
+
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(token, &bp->hwrm_pending_list, node) {
+               if (token->seq_id == seq_id) {
+                       WRITE_ONCE(token->state, state);
+                       rcu_read_unlock();
+                       return;
+               }
+       }
+       rcu_read_unlock();
+       netdev_err(bp->dev, "Invalid hwrm seq id %d\n", seq_id);
+}
+
 static int __hwrm_send(struct bnxt *bp, struct bnxt_hwrm_ctx *ctx)
 {
        u32 doorbell_offset = BNXT_GRCPF_REG_CHIMP_COMM_TRIGGER;
+       enum bnxt_hwrm_chnl dst = BNXT_HWRM_CHNL_CHIMP;
        u32 bar_offset = BNXT_GRCPF_REG_CHIMP_COMM;
+       struct bnxt_hwrm_wait_token *token = NULL;
        struct hwrm_short_input short_input = {0};
        u16 max_req_len = BNXT_HWRM_MAX_REQ_LEN;
        unsigned int i, timeout, tmo_count;
-       u16 dst = BNXT_HWRM_CHNL_CHIMP;
-       int intr_process, rc = -EBUSY;
        u32 *data = (u32 *)ctx->req;
        u32 msg_len = ctx->req_len;
-       u16 cp_ring_id, len = 0;
+       int rc = -EBUSY;
        u32 req_type;
+       u16 len = 0;
        u8 *valid;
 
        if (ctx->flags & BNXT_HWRM_INTERNAL_RESP_DIRTY)
                }
        }
 
-       cp_ring_id = le16_to_cpu(ctx->req->cmpl_ring);
-       intr_process = (cp_ring_id == INVALID_HW_RING_ID) ? 0 : 1;
-
-       ctx->req->seq_id = cpu_to_le16(bnxt_get_hwrm_seq_id(bp, dst));
-       /* currently supports only one outstanding message */
-       if (intr_process)
-               bp->hwrm_intr_seq_id = le16_to_cpu(ctx->req->seq_id);
+       token = __hwrm_acquire_token(bp, dst);
+       if (!token) {
+               rc = -ENOMEM;
+               goto exit;
+       }
+       ctx->req->seq_id = cpu_to_le16(token->seq_id);
 
        if ((bp->fw_cap & BNXT_FW_CAP_SHORT_CMD) ||
            msg_len > BNXT_HWRM_MAX_REQ_LEN) {
        timeout = timeout - HWRM_SHORT_MIN_TIMEOUT * HWRM_SHORT_TIMEOUT_COUNTER;
        tmo_count += DIV_ROUND_UP(timeout, HWRM_MIN_TIMEOUT);
 
-       if (intr_process) {
-               u16 seq_id = bp->hwrm_intr_seq_id;
-
+       if (le16_to_cpu(ctx->req->cmpl_ring) != INVALID_HW_RING_ID) {
                /* Wait until hwrm response cmpl interrupt is processed */
-               while (bp->hwrm_intr_seq_id != (u16)~seq_id &&
+               while (READ_ONCE(token->state) < BNXT_HWRM_COMPLETE &&
                       i++ < tmo_count) {
                        /* Abort the wait for completion if the FW health
                         * check has failed.
                        }
                }
 
-               if (bp->hwrm_intr_seq_id != (u16)~seq_id) {
+               if (READ_ONCE(token->state) != BNXT_HWRM_COMPLETE) {
                        if (!(ctx->flags & BNXT_HWRM_CTX_SILENT))
                                netdev_err(bp->dev, "Resp cmpl intr err msg: 0x%x\n",
                                           le16_to_cpu(ctx->req->req_type));
                         */
                        if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state))
                                goto exit;
+
+                       if (token &&
+                           READ_ONCE(token->state) == BNXT_HWRM_DEFERRED) {
+                               __hwrm_release_token(bp, token);
+                               token = NULL;
+                       }
+
                        len = le16_to_cpu(READ_ONCE(ctx->resp->resp_len));
                        if (len) {
                                __le16 resp_seq = READ_ONCE(ctx->resp->seq_id);
        }
        rc = __hwrm_to_stderr(rc);
 exit:
+       if (token)
+               __hwrm_release_token(bp, token);
        if (ctx->flags & BNXT_HWRM_INTERNAL_CTX_OWNED)
                ctx->flags |= BNXT_HWRM_INTERNAL_RESP_DIRTY;
        else
 int hwrm_req_send(struct bnxt *bp, void *req)
 {
        struct bnxt_hwrm_ctx *ctx = __hwrm_ctx(bp, req);
-       int rc;
 
        if (!ctx)
                return -EINVAL;
 
-       mutex_lock(&bp->hwrm_cmd_lock);
-       rc = __hwrm_send(bp, ctx);
-       mutex_unlock(&bp->hwrm_cmd_lock);
-       return rc;
+       return __hwrm_send(bp, ctx);
 }
 
 /**
 
        gfp_t gfp;
 };
 
+enum bnxt_hwrm_wait_state {
+       BNXT_HWRM_PENDING,
+       BNXT_HWRM_DEFERRED,
+       BNXT_HWRM_COMPLETE,
+       BNXT_HWRM_CANCELLED,
+};
+
+enum bnxt_hwrm_chnl { BNXT_HWRM_CHNL_CHIMP, BNXT_HWRM_CHNL_KONG };
+
+struct bnxt_hwrm_wait_token {
+       struct rcu_head rcu;
+       struct hlist_node node;
+       enum bnxt_hwrm_wait_state state;
+       enum bnxt_hwrm_chnl dst;
+       u16 seq_id;
+};
+
+void hwrm_update_token(struct bnxt *bp, u16 seq, enum bnxt_hwrm_wait_state s);
+
 #define BNXT_HWRM_MAX_REQ_LEN          (bp->hwrm_max_req_len)
 #define BNXT_HWRM_SHORT_REQ_LEN                sizeof(struct hwrm_short_input)
 #define HWRM_CMD_MAX_TIMEOUT           40000
 
 #define HWRM_VALID_BIT_DELAY_USEC      150
 
-#define BNXT_HWRM_CHNL_CHIMP   0
-#define BNXT_HWRM_CHNL_KONG    1
-
 static inline bool bnxt_cfa_hwrm_message(u16 req_type)
 {
        switch (req_type) {
                 le16_to_cpu(req->target_id) == HWRM_TARGET_ID_KONG));
 }
 
-static inline u16 bnxt_get_hwrm_seq_id(struct bnxt *bp, u16 dst)
-{
-       u16 seq_id;
-
-       if (dst == BNXT_HWRM_CHNL_CHIMP)
-               seq_id = bp->hwrm_cmd_seq++;
-       else
-               seq_id = bp->hwrm_cmd_kong_seq++;
-       return seq_id;
-}
-
 int __hwrm_req_init(struct bnxt *bp, void **req, u16 req_type, u32 req_len);
 #define hwrm_req_init(bp, req, req_type) \
        __hwrm_req_init((bp), (void **)&(req), (req_type), sizeof(*(req)))