Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / net / ethernet / brocade / bna / bfa_msgq.c
diff --git a/kernel/drivers/net/ethernet/brocade/bna/bfa_msgq.c b/kernel/drivers/net/ethernet/brocade/bna/bfa_msgq.c
new file mode 100644 (file)
index 0000000..c07d5b9
--- /dev/null
@@ -0,0 +1,668 @@
+/*
+ * Linux network driver for QLogic BR-series Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014-2015 QLogic Corporation
+ * All rights reserved
+ * www.qlogic.com
+ */
+
+/* MSGQ module source file. */
+
+#include "bfi.h"
+#include "bfa_msgq.h"
+#include "bfa_ioc.h"
+
+#define call_cmdq_ent_cbfn(_cmdq_ent, _status)                         \
+{                                                                      \
+       bfa_msgq_cmdcbfn_t cbfn;                                        \
+       void *cbarg;                                                    \
+       cbfn = (_cmdq_ent)->cbfn;                                       \
+       cbarg = (_cmdq_ent)->cbarg;                                     \
+       (_cmdq_ent)->cbfn = NULL;                                       \
+       (_cmdq_ent)->cbarg = NULL;                                      \
+       if (cbfn) {                                                     \
+               cbfn(cbarg, (_status));                                 \
+       }                                                               \
+}
+
+static void bfa_msgq_cmdq_dbell(struct bfa_msgq_cmdq *cmdq);
+static void bfa_msgq_cmdq_copy_rsp(struct bfa_msgq_cmdq *cmdq);
+
+enum cmdq_event {
+       CMDQ_E_START                    = 1,
+       CMDQ_E_STOP                     = 2,
+       CMDQ_E_FAIL                     = 3,
+       CMDQ_E_POST                     = 4,
+       CMDQ_E_INIT_RESP                = 5,
+       CMDQ_E_DB_READY                 = 6,
+};
+
+bfa_fsm_state_decl(cmdq, stopped, struct bfa_msgq_cmdq, enum cmdq_event);
+bfa_fsm_state_decl(cmdq, init_wait, struct bfa_msgq_cmdq, enum cmdq_event);
+bfa_fsm_state_decl(cmdq, ready, struct bfa_msgq_cmdq, enum cmdq_event);
+bfa_fsm_state_decl(cmdq, dbell_wait, struct bfa_msgq_cmdq,
+                       enum cmdq_event);
+
+static void
+cmdq_sm_stopped_entry(struct bfa_msgq_cmdq *cmdq)
+{
+       struct bfa_msgq_cmd_entry *cmdq_ent;
+
+       cmdq->producer_index = 0;
+       cmdq->consumer_index = 0;
+       cmdq->flags = 0;
+       cmdq->token = 0;
+       cmdq->offset = 0;
+       cmdq->bytes_to_copy = 0;
+       while (!list_empty(&cmdq->pending_q)) {
+               bfa_q_deq(&cmdq->pending_q, &cmdq_ent);
+               bfa_q_qe_init(&cmdq_ent->qe);
+               call_cmdq_ent_cbfn(cmdq_ent, BFA_STATUS_FAILED);
+       }
+}
+
+static void
+cmdq_sm_stopped(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
+{
+       switch (event) {
+       case CMDQ_E_START:
+               bfa_fsm_set_state(cmdq, cmdq_sm_init_wait);
+               break;
+
+       case CMDQ_E_STOP:
+       case CMDQ_E_FAIL:
+               /* No-op */
+               break;
+
+       case CMDQ_E_POST:
+               cmdq->flags |= BFA_MSGQ_CMDQ_F_DB_UPDATE;
+               break;
+
+       default:
+               bfa_sm_fault(event);
+       }
+}
+
+static void
+cmdq_sm_init_wait_entry(struct bfa_msgq_cmdq *cmdq)
+{
+       bfa_wc_down(&cmdq->msgq->init_wc);
+}
+
+static void
+cmdq_sm_init_wait(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
+{
+       switch (event) {
+       case CMDQ_E_STOP:
+       case CMDQ_E_FAIL:
+               bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
+               break;
+
+       case CMDQ_E_POST:
+               cmdq->flags |= BFA_MSGQ_CMDQ_F_DB_UPDATE;
+               break;
+
+       case CMDQ_E_INIT_RESP:
+               if (cmdq->flags & BFA_MSGQ_CMDQ_F_DB_UPDATE) {
+                       cmdq->flags &= ~BFA_MSGQ_CMDQ_F_DB_UPDATE;
+                       bfa_fsm_set_state(cmdq, cmdq_sm_dbell_wait);
+               } else
+                       bfa_fsm_set_state(cmdq, cmdq_sm_ready);
+               break;
+
+       default:
+               bfa_sm_fault(event);
+       }
+}
+
+static void
+cmdq_sm_ready_entry(struct bfa_msgq_cmdq *cmdq)
+{
+}
+
+static void
+cmdq_sm_ready(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
+{
+       switch (event) {
+       case CMDQ_E_STOP:
+       case CMDQ_E_FAIL:
+               bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
+               break;
+
+       case CMDQ_E_POST:
+               bfa_fsm_set_state(cmdq, cmdq_sm_dbell_wait);
+               break;
+
+       default:
+               bfa_sm_fault(event);
+       }
+}
+
+static void
+cmdq_sm_dbell_wait_entry(struct bfa_msgq_cmdq *cmdq)
+{
+       bfa_msgq_cmdq_dbell(cmdq);
+}
+
+static void
+cmdq_sm_dbell_wait(struct bfa_msgq_cmdq *cmdq, enum cmdq_event event)
+{
+       switch (event) {
+       case CMDQ_E_STOP:
+       case CMDQ_E_FAIL:
+               bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
+               break;
+
+       case CMDQ_E_POST:
+               cmdq->flags |= BFA_MSGQ_CMDQ_F_DB_UPDATE;
+               break;
+
+       case CMDQ_E_DB_READY:
+               if (cmdq->flags & BFA_MSGQ_CMDQ_F_DB_UPDATE) {
+                       cmdq->flags &= ~BFA_MSGQ_CMDQ_F_DB_UPDATE;
+                       bfa_fsm_set_state(cmdq, cmdq_sm_dbell_wait);
+               } else
+                       bfa_fsm_set_state(cmdq, cmdq_sm_ready);
+               break;
+
+       default:
+               bfa_sm_fault(event);
+       }
+}
+
+static void
+bfa_msgq_cmdq_dbell_ready(void *arg)
+{
+       struct bfa_msgq_cmdq *cmdq = (struct bfa_msgq_cmdq *)arg;
+       bfa_fsm_send_event(cmdq, CMDQ_E_DB_READY);
+}
+
+static void
+bfa_msgq_cmdq_dbell(struct bfa_msgq_cmdq *cmdq)
+{
+       struct bfi_msgq_h2i_db *dbell =
+               (struct bfi_msgq_h2i_db *)(&cmdq->dbell_mb.msg[0]);
+
+       memset(dbell, 0, sizeof(struct bfi_msgq_h2i_db));
+       bfi_h2i_set(dbell->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_DOORBELL_PI, 0);
+       dbell->mh.mtag.i2htok = 0;
+       dbell->idx.cmdq_pi = htons(cmdq->producer_index);
+
+       if (!bfa_nw_ioc_mbox_queue(cmdq->msgq->ioc, &cmdq->dbell_mb,
+                               bfa_msgq_cmdq_dbell_ready, cmdq)) {
+               bfa_msgq_cmdq_dbell_ready(cmdq);
+       }
+}
+
+static void
+__cmd_copy(struct bfa_msgq_cmdq *cmdq, struct bfa_msgq_cmd_entry *cmd)
+{
+       size_t len = cmd->msg_size;
+       int num_entries = 0;
+       size_t to_copy;
+       u8 *src, *dst;
+
+       src = (u8 *)cmd->msg_hdr;
+       dst = (u8 *)cmdq->addr.kva;
+       dst += (cmdq->producer_index * BFI_MSGQ_CMD_ENTRY_SIZE);
+
+       while (len) {
+               to_copy = (len < BFI_MSGQ_CMD_ENTRY_SIZE) ?
+                               len : BFI_MSGQ_CMD_ENTRY_SIZE;
+               memcpy(dst, src, to_copy);
+               len -= to_copy;
+               src += BFI_MSGQ_CMD_ENTRY_SIZE;
+               BFA_MSGQ_INDX_ADD(cmdq->producer_index, 1, cmdq->depth);
+               dst = (u8 *)cmdq->addr.kva;
+               dst += (cmdq->producer_index * BFI_MSGQ_CMD_ENTRY_SIZE);
+               num_entries++;
+       }
+
+}
+
+static void
+bfa_msgq_cmdq_ci_update(struct bfa_msgq_cmdq *cmdq, struct bfi_mbmsg *mb)
+{
+       struct bfi_msgq_i2h_db *dbell = (struct bfi_msgq_i2h_db *)mb;
+       struct bfa_msgq_cmd_entry *cmd;
+       int posted = 0;
+
+       cmdq->consumer_index = ntohs(dbell->idx.cmdq_ci);
+
+       /* Walk through pending list to see if the command can be posted */
+       while (!list_empty(&cmdq->pending_q)) {
+               cmd =
+               (struct bfa_msgq_cmd_entry *)bfa_q_first(&cmdq->pending_q);
+               if (ntohs(cmd->msg_hdr->num_entries) <=
+                       BFA_MSGQ_FREE_CNT(cmdq)) {
+                       list_del(&cmd->qe);
+                       __cmd_copy(cmdq, cmd);
+                       posted = 1;
+                       call_cmdq_ent_cbfn(cmd, BFA_STATUS_OK);
+               } else {
+                       break;
+               }
+       }
+
+       if (posted)
+               bfa_fsm_send_event(cmdq, CMDQ_E_POST);
+}
+
+static void
+bfa_msgq_cmdq_copy_next(void *arg)
+{
+       struct bfa_msgq_cmdq *cmdq = (struct bfa_msgq_cmdq *)arg;
+
+       if (cmdq->bytes_to_copy)
+               bfa_msgq_cmdq_copy_rsp(cmdq);
+}
+
+static void
+bfa_msgq_cmdq_copy_req(struct bfa_msgq_cmdq *cmdq, struct bfi_mbmsg *mb)
+{
+       struct bfi_msgq_i2h_cmdq_copy_req *req =
+               (struct bfi_msgq_i2h_cmdq_copy_req *)mb;
+
+       cmdq->token = 0;
+       cmdq->offset = ntohs(req->offset);
+       cmdq->bytes_to_copy = ntohs(req->len);
+       bfa_msgq_cmdq_copy_rsp(cmdq);
+}
+
+static void
+bfa_msgq_cmdq_copy_rsp(struct bfa_msgq_cmdq *cmdq)
+{
+       struct bfi_msgq_h2i_cmdq_copy_rsp *rsp =
+               (struct bfi_msgq_h2i_cmdq_copy_rsp *)&cmdq->copy_mb.msg[0];
+       int copied;
+       u8 *addr = (u8 *)cmdq->addr.kva;
+
+       memset(rsp, 0, sizeof(struct bfi_msgq_h2i_cmdq_copy_rsp));
+       bfi_h2i_set(rsp->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_CMDQ_COPY_RSP, 0);
+       rsp->mh.mtag.i2htok = htons(cmdq->token);
+       copied = (cmdq->bytes_to_copy >= BFI_CMD_COPY_SZ) ? BFI_CMD_COPY_SZ :
+               cmdq->bytes_to_copy;
+       addr += cmdq->offset;
+       memcpy(rsp->data, addr, copied);
+
+       cmdq->token++;
+       cmdq->offset += copied;
+       cmdq->bytes_to_copy -= copied;
+
+       if (!bfa_nw_ioc_mbox_queue(cmdq->msgq->ioc, &cmdq->copy_mb,
+                               bfa_msgq_cmdq_copy_next, cmdq)) {
+               bfa_msgq_cmdq_copy_next(cmdq);
+       }
+}
+
+static void
+bfa_msgq_cmdq_attach(struct bfa_msgq_cmdq *cmdq, struct bfa_msgq *msgq)
+{
+       cmdq->depth = BFA_MSGQ_CMDQ_NUM_ENTRY;
+       INIT_LIST_HEAD(&cmdq->pending_q);
+       cmdq->msgq = msgq;
+       bfa_fsm_set_state(cmdq, cmdq_sm_stopped);
+}
+
+static void bfa_msgq_rspq_dbell(struct bfa_msgq_rspq *rspq);
+
+enum rspq_event {
+       RSPQ_E_START                    = 1,
+       RSPQ_E_STOP                     = 2,
+       RSPQ_E_FAIL                     = 3,
+       RSPQ_E_RESP                     = 4,
+       RSPQ_E_INIT_RESP                = 5,
+       RSPQ_E_DB_READY                 = 6,
+};
+
+bfa_fsm_state_decl(rspq, stopped, struct bfa_msgq_rspq, enum rspq_event);
+bfa_fsm_state_decl(rspq, init_wait, struct bfa_msgq_rspq,
+                       enum rspq_event);
+bfa_fsm_state_decl(rspq, ready, struct bfa_msgq_rspq, enum rspq_event);
+bfa_fsm_state_decl(rspq, dbell_wait, struct bfa_msgq_rspq,
+                       enum rspq_event);
+
+static void
+rspq_sm_stopped_entry(struct bfa_msgq_rspq *rspq)
+{
+       rspq->producer_index = 0;
+       rspq->consumer_index = 0;
+       rspq->flags = 0;
+}
+
+static void
+rspq_sm_stopped(struct bfa_msgq_rspq *rspq, enum rspq_event event)
+{
+       switch (event) {
+       case RSPQ_E_START:
+               bfa_fsm_set_state(rspq, rspq_sm_init_wait);
+               break;
+
+       case RSPQ_E_STOP:
+       case RSPQ_E_FAIL:
+               /* No-op */
+               break;
+
+       default:
+               bfa_sm_fault(event);
+       }
+}
+
+static void
+rspq_sm_init_wait_entry(struct bfa_msgq_rspq *rspq)
+{
+       bfa_wc_down(&rspq->msgq->init_wc);
+}
+
+static void
+rspq_sm_init_wait(struct bfa_msgq_rspq *rspq, enum rspq_event event)
+{
+       switch (event) {
+       case RSPQ_E_FAIL:
+       case RSPQ_E_STOP:
+               bfa_fsm_set_state(rspq, rspq_sm_stopped);
+               break;
+
+       case RSPQ_E_INIT_RESP:
+               bfa_fsm_set_state(rspq, rspq_sm_ready);
+               break;
+
+       default:
+               bfa_sm_fault(event);
+       }
+}
+
+static void
+rspq_sm_ready_entry(struct bfa_msgq_rspq *rspq)
+{
+}
+
+static void
+rspq_sm_ready(struct bfa_msgq_rspq *rspq, enum rspq_event event)
+{
+       switch (event) {
+       case RSPQ_E_STOP:
+       case RSPQ_E_FAIL:
+               bfa_fsm_set_state(rspq, rspq_sm_stopped);
+               break;
+
+       case RSPQ_E_RESP:
+               bfa_fsm_set_state(rspq, rspq_sm_dbell_wait);
+               break;
+
+       default:
+               bfa_sm_fault(event);
+       }
+}
+
+static void
+rspq_sm_dbell_wait_entry(struct bfa_msgq_rspq *rspq)
+{
+       if (!bfa_nw_ioc_is_disabled(rspq->msgq->ioc))
+               bfa_msgq_rspq_dbell(rspq);
+}
+
+static void
+rspq_sm_dbell_wait(struct bfa_msgq_rspq *rspq, enum rspq_event event)
+{
+       switch (event) {
+       case RSPQ_E_STOP:
+       case RSPQ_E_FAIL:
+               bfa_fsm_set_state(rspq, rspq_sm_stopped);
+               break;
+
+       case RSPQ_E_RESP:
+               rspq->flags |= BFA_MSGQ_RSPQ_F_DB_UPDATE;
+               break;
+
+       case RSPQ_E_DB_READY:
+               if (rspq->flags & BFA_MSGQ_RSPQ_F_DB_UPDATE) {
+                       rspq->flags &= ~BFA_MSGQ_RSPQ_F_DB_UPDATE;
+                       bfa_fsm_set_state(rspq, rspq_sm_dbell_wait);
+               } else
+                       bfa_fsm_set_state(rspq, rspq_sm_ready);
+               break;
+
+       default:
+               bfa_sm_fault(event);
+       }
+}
+
+static void
+bfa_msgq_rspq_dbell_ready(void *arg)
+{
+       struct bfa_msgq_rspq *rspq = (struct bfa_msgq_rspq *)arg;
+       bfa_fsm_send_event(rspq, RSPQ_E_DB_READY);
+}
+
+static void
+bfa_msgq_rspq_dbell(struct bfa_msgq_rspq *rspq)
+{
+       struct bfi_msgq_h2i_db *dbell =
+               (struct bfi_msgq_h2i_db *)(&rspq->dbell_mb.msg[0]);
+
+       memset(dbell, 0, sizeof(struct bfi_msgq_h2i_db));
+       bfi_h2i_set(dbell->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_DOORBELL_CI, 0);
+       dbell->mh.mtag.i2htok = 0;
+       dbell->idx.rspq_ci = htons(rspq->consumer_index);
+
+       if (!bfa_nw_ioc_mbox_queue(rspq->msgq->ioc, &rspq->dbell_mb,
+                               bfa_msgq_rspq_dbell_ready, rspq)) {
+               bfa_msgq_rspq_dbell_ready(rspq);
+       }
+}
+
+static void
+bfa_msgq_rspq_pi_update(struct bfa_msgq_rspq *rspq, struct bfi_mbmsg *mb)
+{
+       struct bfi_msgq_i2h_db *dbell = (struct bfi_msgq_i2h_db *)mb;
+       struct bfi_msgq_mhdr *msghdr;
+       int num_entries;
+       int mc;
+       u8 *rspq_qe;
+
+       rspq->producer_index = ntohs(dbell->idx.rspq_pi);
+
+       while (rspq->consumer_index != rspq->producer_index) {
+               rspq_qe = (u8 *)rspq->addr.kva;
+               rspq_qe += (rspq->consumer_index * BFI_MSGQ_RSP_ENTRY_SIZE);
+               msghdr = (struct bfi_msgq_mhdr *)rspq_qe;
+
+               mc = msghdr->msg_class;
+               num_entries = ntohs(msghdr->num_entries);
+
+               if ((mc >= BFI_MC_MAX) || (rspq->rsphdlr[mc].cbfn == NULL))
+                       break;
+
+               (rspq->rsphdlr[mc].cbfn)(rspq->rsphdlr[mc].cbarg, msghdr);
+
+               BFA_MSGQ_INDX_ADD(rspq->consumer_index, num_entries,
+                               rspq->depth);
+       }
+
+       bfa_fsm_send_event(rspq, RSPQ_E_RESP);
+}
+
+static void
+bfa_msgq_rspq_attach(struct bfa_msgq_rspq *rspq, struct bfa_msgq *msgq)
+{
+       rspq->depth = BFA_MSGQ_RSPQ_NUM_ENTRY;
+       rspq->msgq = msgq;
+       bfa_fsm_set_state(rspq, rspq_sm_stopped);
+}
+
+static void
+bfa_msgq_init_rsp(struct bfa_msgq *msgq,
+                struct bfi_mbmsg *mb)
+{
+       bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_INIT_RESP);
+       bfa_fsm_send_event(&msgq->rspq, RSPQ_E_INIT_RESP);
+}
+
+static void
+bfa_msgq_init(void *arg)
+{
+       struct bfa_msgq *msgq = (struct bfa_msgq *)arg;
+       struct bfi_msgq_cfg_req *msgq_cfg =
+               (struct bfi_msgq_cfg_req *)&msgq->init_mb.msg[0];
+
+       memset(msgq_cfg, 0, sizeof(struct bfi_msgq_cfg_req));
+       bfi_h2i_set(msgq_cfg->mh, BFI_MC_MSGQ, BFI_MSGQ_H2I_INIT_REQ, 0);
+       msgq_cfg->mh.mtag.i2htok = 0;
+
+       bfa_dma_be_addr_set(msgq_cfg->cmdq.addr, msgq->cmdq.addr.pa);
+       msgq_cfg->cmdq.q_depth = htons(msgq->cmdq.depth);
+       bfa_dma_be_addr_set(msgq_cfg->rspq.addr, msgq->rspq.addr.pa);
+       msgq_cfg->rspq.q_depth = htons(msgq->rspq.depth);
+
+       bfa_nw_ioc_mbox_queue(msgq->ioc, &msgq->init_mb, NULL, NULL);
+}
+
+static void
+bfa_msgq_isr(void *cbarg, struct bfi_mbmsg *msg)
+{
+       struct bfa_msgq *msgq = (struct bfa_msgq *)cbarg;
+
+       switch (msg->mh.msg_id) {
+       case BFI_MSGQ_I2H_INIT_RSP:
+               bfa_msgq_init_rsp(msgq, msg);
+               break;
+
+       case BFI_MSGQ_I2H_DOORBELL_PI:
+               bfa_msgq_rspq_pi_update(&msgq->rspq, msg);
+               break;
+
+       case BFI_MSGQ_I2H_DOORBELL_CI:
+               bfa_msgq_cmdq_ci_update(&msgq->cmdq, msg);
+               break;
+
+       case BFI_MSGQ_I2H_CMDQ_COPY_REQ:
+               bfa_msgq_cmdq_copy_req(&msgq->cmdq, msg);
+               break;
+
+       default:
+               BUG_ON(1);
+       }
+}
+
+static void
+bfa_msgq_notify(void *cbarg, enum bfa_ioc_event event)
+{
+       struct bfa_msgq *msgq = (struct bfa_msgq *)cbarg;
+
+       switch (event) {
+       case BFA_IOC_E_ENABLED:
+               bfa_wc_init(&msgq->init_wc, bfa_msgq_init, msgq);
+               bfa_wc_up(&msgq->init_wc);
+               bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_START);
+               bfa_wc_up(&msgq->init_wc);
+               bfa_fsm_send_event(&msgq->rspq, RSPQ_E_START);
+               bfa_wc_wait(&msgq->init_wc);
+               break;
+
+       case BFA_IOC_E_DISABLED:
+               bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_STOP);
+               bfa_fsm_send_event(&msgq->rspq, RSPQ_E_STOP);
+               break;
+
+       case BFA_IOC_E_FAILED:
+               bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_FAIL);
+               bfa_fsm_send_event(&msgq->rspq, RSPQ_E_FAIL);
+               break;
+
+       default:
+               break;
+       }
+}
+
+u32
+bfa_msgq_meminfo(void)
+{
+       return roundup(BFA_MSGQ_CMDQ_SIZE, BFA_DMA_ALIGN_SZ) +
+               roundup(BFA_MSGQ_RSPQ_SIZE, BFA_DMA_ALIGN_SZ);
+}
+
+void
+bfa_msgq_memclaim(struct bfa_msgq *msgq, u8 *kva, u64 pa)
+{
+       msgq->cmdq.addr.kva = kva;
+       msgq->cmdq.addr.pa  = pa;
+
+       kva += roundup(BFA_MSGQ_CMDQ_SIZE, BFA_DMA_ALIGN_SZ);
+       pa += roundup(BFA_MSGQ_CMDQ_SIZE, BFA_DMA_ALIGN_SZ);
+
+       msgq->rspq.addr.kva = kva;
+       msgq->rspq.addr.pa = pa;
+}
+
+void
+bfa_msgq_attach(struct bfa_msgq *msgq, struct bfa_ioc *ioc)
+{
+       msgq->ioc    = ioc;
+
+       bfa_msgq_cmdq_attach(&msgq->cmdq, msgq);
+       bfa_msgq_rspq_attach(&msgq->rspq, msgq);
+
+       bfa_nw_ioc_mbox_regisr(msgq->ioc, BFI_MC_MSGQ, bfa_msgq_isr, msgq);
+       bfa_q_qe_init(&msgq->ioc_notify);
+       bfa_ioc_notify_init(&msgq->ioc_notify, bfa_msgq_notify, msgq);
+       bfa_nw_ioc_notify_register(msgq->ioc, &msgq->ioc_notify);
+}
+
+void
+bfa_msgq_regisr(struct bfa_msgq *msgq, enum bfi_mclass mc,
+               bfa_msgq_mcfunc_t cbfn, void *cbarg)
+{
+       msgq->rspq.rsphdlr[mc].cbfn     = cbfn;
+       msgq->rspq.rsphdlr[mc].cbarg    = cbarg;
+}
+
+void
+bfa_msgq_cmd_post(struct bfa_msgq *msgq,  struct bfa_msgq_cmd_entry *cmd)
+{
+       if (ntohs(cmd->msg_hdr->num_entries) <=
+               BFA_MSGQ_FREE_CNT(&msgq->cmdq)) {
+               __cmd_copy(&msgq->cmdq, cmd);
+               call_cmdq_ent_cbfn(cmd, BFA_STATUS_OK);
+               bfa_fsm_send_event(&msgq->cmdq, CMDQ_E_POST);
+       } else {
+               list_add_tail(&cmd->qe, &msgq->cmdq.pending_q);
+       }
+}
+
+void
+bfa_msgq_rsp_copy(struct bfa_msgq *msgq, u8 *buf, size_t buf_len)
+{
+       struct bfa_msgq_rspq *rspq = &msgq->rspq;
+       size_t len = buf_len;
+       size_t to_copy;
+       int ci;
+       u8 *src, *dst;
+
+       ci = rspq->consumer_index;
+       src = (u8 *)rspq->addr.kva;
+       src += (ci * BFI_MSGQ_RSP_ENTRY_SIZE);
+       dst = buf;
+
+       while (len) {
+               to_copy = (len < BFI_MSGQ_RSP_ENTRY_SIZE) ?
+                               len : BFI_MSGQ_RSP_ENTRY_SIZE;
+               memcpy(dst, src, to_copy);
+               len -= to_copy;
+               dst += BFI_MSGQ_RSP_ENTRY_SIZE;
+               BFA_MSGQ_INDX_ADD(ci, 1, rspq->depth);
+               src = (u8 *)rspq->addr.kva;
+               src += (ci * BFI_MSGQ_RSP_ENTRY_SIZE);
+       }
+}