idx_que->head++;
 }
 
-static void update_srq_db(struct hns_roce_v2_db *db, struct hns_roce_srq *srq)
+static void update_srq_db(struct hns_roce_srq *srq)
 {
-       hr_reg_write(db, DB_TAG, srq->srqn);
-       hr_reg_write(db, DB_CMD, HNS_ROCE_V2_SRQ_DB);
-       hr_reg_write(db, DB_PI, srq->idx_que.head);
+       struct hns_roce_dev *hr_dev = to_hr_dev(srq->ibsrq.device);
+       struct hns_roce_v2_db db;
+
+       hr_reg_write(&db, DB_TAG, srq->srqn);
+       hr_reg_write(&db, DB_CMD, HNS_ROCE_V2_SRQ_DB);
+       hr_reg_write(&db, DB_PI, srq->idx_que.head);
+
+       hns_roce_write64(hr_dev, (__le32 *)&db, srq->db_reg);
 }
 
 static int hns_roce_v2_post_srq_recv(struct ib_srq *ibsrq,
                                     const struct ib_recv_wr *wr,
                                     const struct ib_recv_wr **bad_wr)
 {
-       struct hns_roce_dev *hr_dev = to_hr_dev(ibsrq->device);
        struct hns_roce_srq *srq = to_hr_srq(ibsrq);
-       struct hns_roce_v2_db srq_db;
        unsigned long flags;
        int ret = 0;
        u32 max_sge;
        }
 
        if (likely(nreq)) {
-               update_srq_db(&srq_db, srq);
-
-               hns_roce_write64(hr_dev, (__le32 *)&srq_db, srq->db_reg);
+               if (srq->cap_flags & HNS_ROCE_SRQ_CAP_RECORD_DB)
+                       *srq->rdb.db_record = srq->idx_que.head &
+                                             V2_DB_PRODUCER_IDX_M;
+               else
+                       update_srq_db(srq);
        }
 
        spin_unlock_irqrestore(&srq->lock, flags);
        hr_reg_write(ctx, SRQC_WQE_BUF_PG_SZ,
                     to_hr_hw_page_shift(srq->buf_mtr.hem_cfg.buf_pg_shift));
 
+       if (srq->cap_flags & HNS_ROCE_SRQ_CAP_RECORD_DB) {
+               hr_reg_enable(ctx, SRQC_DB_RECORD_EN);
+               hr_reg_write(ctx, SRQC_DB_RECORD_ADDR_L,
+                            lower_32_bits(srq->rdb.dma) >> 1);
+               hr_reg_write(ctx, SRQC_DB_RECORD_ADDR_H,
+                            upper_32_bits(srq->rdb.dma));
+       }
+
        return hns_roce_v2_write_srqc_index_queue(srq, ctx);
 }
 
 
 
 #include <linux/pci.h>
 #include <rdma/ib_umem.h>
+#include <rdma/uverbs_ioctl.h>
 #include "hns_roce_device.h"
 #include "hns_roce_cmd.h"
 #include "hns_roce_hem.h"
        free_srq_idx(hr_dev, srq);
 }
 
+static int get_srq_ucmd(struct hns_roce_srq *srq, struct ib_udata *udata,
+                       struct hns_roce_ib_create_srq *ucmd)
+{
+       struct ib_device *ibdev = srq->ibsrq.device;
+       int ret;
+
+       ret = ib_copy_from_udata(ucmd, udata, min(udata->inlen, sizeof(*ucmd)));
+       if (ret) {
+               ibdev_err(ibdev, "failed to copy SRQ udata, ret = %d.\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void free_srq_db(struct hns_roce_dev *hr_dev, struct hns_roce_srq *srq,
+                       struct ib_udata *udata)
+{
+       struct hns_roce_ucontext *uctx;
+
+       if (!(srq->cap_flags & HNS_ROCE_SRQ_CAP_RECORD_DB))
+               return;
+
+       srq->cap_flags &= ~HNS_ROCE_SRQ_CAP_RECORD_DB;
+       if (udata) {
+               uctx = rdma_udata_to_drv_context(udata,
+                                                struct hns_roce_ucontext,
+                                                ibucontext);
+               hns_roce_db_unmap_user(uctx, &srq->rdb);
+       } else {
+               hns_roce_free_db(hr_dev, &srq->rdb);
+       }
+}
+
+static int alloc_srq_db(struct hns_roce_dev *hr_dev, struct hns_roce_srq *srq,
+                       struct ib_udata *udata,
+                       struct hns_roce_ib_create_srq_resp *resp)
+{
+       struct hns_roce_ib_create_srq ucmd = {};
+       struct hns_roce_ucontext *uctx;
+       int ret;
+
+       if (udata) {
+               ret = get_srq_ucmd(srq, udata, &ucmd);
+               if (ret)
+                       return ret;
+
+               if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_SRQ_RECORD_DB) &&
+                   (ucmd.req_cap_flags & HNS_ROCE_SRQ_CAP_RECORD_DB)) {
+                       uctx = rdma_udata_to_drv_context(udata,
+                                       struct hns_roce_ucontext, ibucontext);
+                       ret = hns_roce_db_map_user(uctx, ucmd.db_addr,
+                                                  &srq->rdb);
+                       if (ret)
+                               return ret;
+
+                       srq->cap_flags |= HNS_ROCE_RSP_SRQ_CAP_RECORD_DB;
+               }
+       } else {
+               if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_SRQ_RECORD_DB) {
+                       ret = hns_roce_alloc_db(hr_dev, &srq->rdb, 1);
+                       if (ret)
+                               return ret;
+
+                       *srq->rdb.db_record = 0;
+                       srq->cap_flags |= HNS_ROCE_RSP_SRQ_CAP_RECORD_DB;
+               }
+               srq->db_reg = hr_dev->reg_base + SRQ_DB_REG;
+       }
+
+       return 0;
+}
+
 int hns_roce_create_srq(struct ib_srq *ib_srq,
                        struct ib_srq_init_attr *init_attr,
                        struct ib_udata *udata)
        if (ret)
                return ret;
 
-       ret = alloc_srqn(hr_dev, srq);
+       ret = alloc_srq_db(hr_dev, srq, udata, &resp);
        if (ret)
                goto err_srq_buf;
 
+       ret = alloc_srqn(hr_dev, srq);
+       if (ret)
+               goto err_srq_db;
+
        ret = alloc_srqc(hr_dev, srq);
        if (ret)
                goto err_srqn;
 
        if (udata) {
+               resp.cap_flags = srq->cap_flags;
                resp.srqn = srq->srqn;
                if (ib_copy_to_udata(udata, &resp,
                                     min(udata->outlen, sizeof(resp)))) {
                }
        }
 
-       srq->db_reg = hr_dev->reg_base + SRQ_DB_REG;
        srq->event = hns_roce_ib_srq_event;
        refcount_set(&srq->refcount, 1);
        init_completion(&srq->free);
        free_srqc(hr_dev, srq);
 err_srqn:
        free_srqn(hr_dev, srq);
+err_srq_db:
+       free_srq_db(hr_dev, srq, udata);
 err_srq_buf:
        free_srq_buf(hr_dev, srq);
 
 
        free_srqc(hr_dev, srq);
        free_srqn(hr_dev, srq);
+       free_srq_db(hr_dev, srq, udata);
        free_srq_buf(hr_dev, srq);
        return 0;
 }