/* CPT mbox IDs (range 0xA00 - 0xBFF) */                               \
 /* NPC mbox IDs (range 0x6000 - 0x7FFF) */                             \
 /* NIX mbox IDs (range 0x8000 - 0xFFFF) */                             \
+M(NIX_LF_ALLOC,                0x8000, nix_lf_alloc_req, nix_lf_alloc_rsp)     \
+M(NIX_LF_FREE,         0x8001, msg_req, msg_rsp)
 
 /* Messages initiated by AF (range 0xC00 - 0xDFF) */
 #define MBOX_UP_CGX_MESSAGES                                           \
 
 /* Mailbox message formats */
 
+#define RVU_DEFAULT_PF_FUNC     0xFFFF
+
 /* Generic request msg used for those mbox messages which
  * don't send any data in the request.
  */
        u8 ctype;
 };
 
+/* NIX mailbox error codes
+ * Range 401 - 500.
+ */
+enum nix_af_status {
+       NIX_AF_ERR_PARAM            = -401,
+       NIX_AF_ERR_AQ_FULL          = -402,
+       NIX_AF_ERR_AQ_ENQUEUE       = -403,
+       NIX_AF_ERR_AF_LF_INVALID    = -404,
+       NIX_AF_ERR_AF_LF_ALLOC      = -405,
+       NIX_AF_ERR_TLX_ALLOC_FAIL   = -406,
+       NIX_AF_ERR_TLX_INVALID      = -407,
+       NIX_AF_ERR_RSS_SIZE_INVALID = -408,
+       NIX_AF_ERR_RSS_GRPS_INVALID = -409,
+       NIX_AF_ERR_FRS_INVALID      = -410,
+       NIX_AF_ERR_RX_LINK_INVALID  = -411,
+       NIX_AF_INVAL_TXSCHQ_CFG     = -412,
+       NIX_AF_SMQ_FLUSH_FAILED     = -413,
+       NIX_AF_ERR_LF_RESET         = -414,
+};
+
+/* For NIX LF context alloc and init */
+struct nix_lf_alloc_req {
+       struct mbox_msghdr hdr;
+       int node;
+       u32 rq_cnt;   /* No of receive queues */
+       u32 sq_cnt;   /* No of send queues */
+       u32 cq_cnt;   /* No of completion queues */
+       u8  xqe_sz;
+       u16 rss_sz;
+       u8  rss_grps;
+       u16 npa_func;
+       u16 sso_func;
+       u64 rx_cfg;   /* See NIX_AF_LF(0..127)_RX_CFG */
+};
+
+struct nix_lf_alloc_rsp {
+       struct mbox_msghdr hdr;
+       u16     sqb_size;
+       u8      mac_addr[ETH_ALEN];
+};
+
 #endif /* MBOX_H */
 
 #include "rvu.h"
 #include "cgx.h"
 
+static void nix_ctx_free(struct rvu *rvu, struct rvu_pfvf *pfvf)
+{
+       if (pfvf->rq_ctx)
+               qmem_free(rvu->dev, pfvf->rq_ctx);
+       if (pfvf->sq_ctx)
+               qmem_free(rvu->dev, pfvf->sq_ctx);
+       if (pfvf->cq_ctx)
+               qmem_free(rvu->dev, pfvf->cq_ctx);
+       if (pfvf->rss_ctx)
+               qmem_free(rvu->dev, pfvf->rss_ctx);
+       if (pfvf->nix_qints_ctx)
+               qmem_free(rvu->dev, pfvf->nix_qints_ctx);
+       if (pfvf->cq_ints_ctx)
+               qmem_free(rvu->dev, pfvf->cq_ints_ctx);
+
+       pfvf->rq_ctx = NULL;
+       pfvf->sq_ctx = NULL;
+       pfvf->cq_ctx = NULL;
+       pfvf->rss_ctx = NULL;
+       pfvf->nix_qints_ctx = NULL;
+       pfvf->cq_ints_ctx = NULL;
+}
+
+static int nixlf_rss_ctx_init(struct rvu *rvu, int blkaddr,
+                             struct rvu_pfvf *pfvf, int nixlf,
+                             int rss_sz, int rss_grps, int hwctx_size)
+{
+       int err, grp, num_indices;
+
+       /* RSS is not requested for this NIXLF */
+       if (!rss_sz)
+               return 0;
+       num_indices = rss_sz * rss_grps;
+
+       /* Alloc NIX RSS HW context memory and config the base */
+       err = qmem_alloc(rvu->dev, &pfvf->rss_ctx, num_indices, hwctx_size);
+       if (err)
+               return err;
+
+       rvu_write64(rvu, blkaddr, NIX_AF_LFX_RSS_BASE(nixlf),
+                   (u64)pfvf->rss_ctx->iova);
+
+       /* Config full RSS table size, enable RSS and caching */
+       rvu_write64(rvu, blkaddr, NIX_AF_LFX_RSS_CFG(nixlf),
+                   BIT_ULL(36) | BIT_ULL(4) |
+                   ilog2(num_indices / MAX_RSS_INDIR_TBL_SIZE));
+       /* Config RSS group offset and sizes */
+       for (grp = 0; grp < rss_grps; grp++)
+               rvu_write64(rvu, blkaddr, NIX_AF_LFX_RSS_GRPX(nixlf, grp),
+                           ((ilog2(rss_sz) - 1) << 16) | (rss_sz * grp));
+       return 0;
+}
+
+int rvu_mbox_handler_NIX_LF_ALLOC(struct rvu *rvu,
+                                 struct nix_lf_alloc_req *req,
+                                 struct nix_lf_alloc_rsp *rsp)
+{
+       int nixlf, qints, hwctx_size, err, rc = 0;
+       struct rvu_hwinfo *hw = rvu->hw;
+       u16 pcifunc = req->hdr.pcifunc;
+       struct rvu_block *block;
+       struct rvu_pfvf *pfvf;
+       u64 cfg, ctx_cfg;
+       int blkaddr;
+
+       if (!req->rq_cnt || !req->sq_cnt || !req->cq_cnt)
+               return NIX_AF_ERR_PARAM;
+
+       pfvf = rvu_get_pfvf(rvu, pcifunc);
+       blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc);
+       if (!pfvf->nixlf || blkaddr < 0)
+               return NIX_AF_ERR_AF_LF_INVALID;
+
+       block = &hw->block[blkaddr];
+       nixlf = rvu_get_lf(rvu, block, pcifunc, 0);
+       if (nixlf < 0)
+               return NIX_AF_ERR_AF_LF_INVALID;
+
+       /* If RSS is being enabled, check if requested config is valid.
+        * RSS table size should be power of two, otherwise
+        * RSS_GRP::OFFSET + adder might go beyond that group or
+        * won't be able to use entire table.
+        */
+       if (req->rss_sz && (req->rss_sz > MAX_RSS_INDIR_TBL_SIZE ||
+                           !is_power_of_2(req->rss_sz)))
+               return NIX_AF_ERR_RSS_SIZE_INVALID;
+
+       if (req->rss_sz &&
+           (!req->rss_grps || req->rss_grps > MAX_RSS_GROUPS))
+               return NIX_AF_ERR_RSS_GRPS_INVALID;
+
+       /* Reset this NIX LF */
+       err = rvu_lf_reset(rvu, block, nixlf);
+       if (err) {
+               dev_err(rvu->dev, "Failed to reset NIX%d LF%d\n",
+                       block->addr - BLKADDR_NIX0, nixlf);
+               return NIX_AF_ERR_LF_RESET;
+       }
+
+       ctx_cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST3);
+
+       /* Alloc NIX RQ HW context memory and config the base */
+       hwctx_size = 1UL << ((ctx_cfg >> 4) & 0xF);
+       err = qmem_alloc(rvu->dev, &pfvf->rq_ctx, req->rq_cnt, hwctx_size);
+       if (err)
+               goto free_mem;
+
+       rvu_write64(rvu, blkaddr, NIX_AF_LFX_RQS_BASE(nixlf),
+                   (u64)pfvf->rq_ctx->iova);
+
+       /* Set caching and queue count in HW */
+       cfg = BIT_ULL(36) | (req->rq_cnt - 1);
+       rvu_write64(rvu, blkaddr, NIX_AF_LFX_RQS_CFG(nixlf), cfg);
+
+       /* Alloc NIX SQ HW context memory and config the base */
+       hwctx_size = 1UL << (ctx_cfg & 0xF);
+       err = qmem_alloc(rvu->dev, &pfvf->sq_ctx, req->sq_cnt, hwctx_size);
+       if (err)
+               goto free_mem;
+
+       rvu_write64(rvu, blkaddr, NIX_AF_LFX_SQS_BASE(nixlf),
+                   (u64)pfvf->sq_ctx->iova);
+       cfg = BIT_ULL(36) | (req->sq_cnt - 1);
+       rvu_write64(rvu, blkaddr, NIX_AF_LFX_SQS_CFG(nixlf), cfg);
+
+       /* Alloc NIX CQ HW context memory and config the base */
+       hwctx_size = 1UL << ((ctx_cfg >> 8) & 0xF);
+       err = qmem_alloc(rvu->dev, &pfvf->cq_ctx, req->cq_cnt, hwctx_size);
+       if (err)
+               goto free_mem;
+
+       rvu_write64(rvu, blkaddr, NIX_AF_LFX_CQS_BASE(nixlf),
+                   (u64)pfvf->cq_ctx->iova);
+       cfg = BIT_ULL(36) | (req->cq_cnt - 1);
+       rvu_write64(rvu, blkaddr, NIX_AF_LFX_CQS_CFG(nixlf), cfg);
+
+       /* Initialize receive side scaling (RSS) */
+       hwctx_size = 1UL << ((ctx_cfg >> 12) & 0xF);
+       err = nixlf_rss_ctx_init(rvu, blkaddr, pfvf, nixlf,
+                                req->rss_sz, req->rss_grps, hwctx_size);
+       if (err)
+               goto free_mem;
+
+       /* Alloc memory for CQINT's HW contexts */
+       cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST2);
+       qints = (cfg >> 24) & 0xFFF;
+       hwctx_size = 1UL << ((ctx_cfg >> 24) & 0xF);
+       err = qmem_alloc(rvu->dev, &pfvf->cq_ints_ctx, qints, hwctx_size);
+       if (err)
+               goto free_mem;
+
+       rvu_write64(rvu, blkaddr, NIX_AF_LFX_CINTS_BASE(nixlf),
+                   (u64)pfvf->cq_ints_ctx->iova);
+       rvu_write64(rvu, blkaddr, NIX_AF_LFX_CINTS_CFG(nixlf), BIT_ULL(36));
+
+       /* Alloc memory for QINT's HW contexts */
+       cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST2);
+       qints = (cfg >> 12) & 0xFFF;
+       hwctx_size = 1UL << ((ctx_cfg >> 20) & 0xF);
+       err = qmem_alloc(rvu->dev, &pfvf->nix_qints_ctx, qints, hwctx_size);
+       if (err)
+               goto free_mem;
+
+       rvu_write64(rvu, blkaddr, NIX_AF_LFX_QINTS_BASE(nixlf),
+                   (u64)pfvf->nix_qints_ctx->iova);
+       rvu_write64(rvu, blkaddr, NIX_AF_LFX_QINTS_CFG(nixlf), BIT_ULL(36));
+
+       /* Enable LMTST for this NIX LF */
+       rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_CFG2(nixlf), BIT_ULL(0));
+
+       /* Set CQE/WQE size, NPA_PF_FUNC for SQBs and also SSO_PF_FUNC
+        * If requester has sent a 'RVU_DEFAULT_PF_FUNC' use this NIX LF's
+        * PCIFUNC itself.
+        */
+       if (req->npa_func == RVU_DEFAULT_PF_FUNC)
+               cfg = pcifunc;
+       else
+               cfg = req->npa_func;
+
+       if (req->sso_func == RVU_DEFAULT_PF_FUNC)
+               cfg |= (u64)pcifunc << 16;
+       else
+               cfg |= (u64)req->sso_func << 16;
+
+       cfg |= (u64)req->xqe_sz << 33;
+       rvu_write64(rvu, blkaddr, NIX_AF_LFX_CFG(nixlf), cfg);
+
+       /* Config Rx pkt length, csum checks and apad  enable / disable */
+       rvu_write64(rvu, blkaddr, NIX_AF_LFX_RX_CFG(nixlf), req->rx_cfg);
+
+       goto exit;
+
+free_mem:
+       nix_ctx_free(rvu, pfvf);
+       rc = -ENOMEM;
+
+exit:
+       /* Set macaddr of this PF/VF */
+       ether_addr_copy(rsp->mac_addr, pfvf->mac_addr);
+
+       /* set SQB size info */
+       cfg = rvu_read64(rvu, blkaddr, NIX_AF_SQ_CONST);
+       rsp->sqb_size = (cfg >> 34) & 0xFFFF;
+       return rc;
+}
+
+int rvu_mbox_handler_NIX_LF_FREE(struct rvu *rvu, struct msg_req *req,
+                                struct msg_rsp *rsp)
+{
+       struct rvu_hwinfo *hw = rvu->hw;
+       u16 pcifunc = req->hdr.pcifunc;
+       struct rvu_block *block;
+       int blkaddr, nixlf, err;
+       struct rvu_pfvf *pfvf;
+
+       pfvf = rvu_get_pfvf(rvu, pcifunc);
+       blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc);
+       if (!pfvf->nixlf || blkaddr < 0)
+               return NIX_AF_ERR_AF_LF_INVALID;
+
+       block = &hw->block[blkaddr];
+       nixlf = rvu_get_lf(rvu, block, pcifunc, 0);
+       if (nixlf < 0)
+               return NIX_AF_ERR_AF_LF_INVALID;
+
+       /* Reset this NIX LF */
+       err = rvu_lf_reset(rvu, block, nixlf);
+       if (err) {
+               dev_err(rvu->dev, "Failed to reset NIX%d LF%d\n",
+                       block->addr - BLKADDR_NIX0, nixlf);
+               return NIX_AF_ERR_LF_RESET;
+       }
+
+       nix_ctx_free(rvu, pfvf);
+
+       return 0;
+}
+
 static int nix_calibrate_x2p(struct rvu *rvu, int blkaddr)
 {
        int idx, err;