diff mbox series

[for-next,3/7] RDMA/hns: Configure DCA mode for the userspace QP

Message ID 1620650889-61650-4-git-send-email-liweihang@huawei.com (mailing list archive)
State Superseded
Headers show
Series RDMA/hns: Add support for Dynamic Context Attachment | expand

Commit Message

Weihang Li May 10, 2021, 12:48 p.m. UTC
From: Xi Wang <wangxi11@huawei.com>

If the userspace driver assign a NULL to the field of 'buf_addr' in
'struct hns_roce_ib_create_qp' when creating QP, this means the kernel
driver need setup the QP as DCA mode. So add a QP capability bit in
response to indicate the userspace driver that the DCA mode has been
enabled.

Signed-off-by: Xi Wang <wangxi11@huawei.com>
Signed-off-by: Weihang Li <liweihang@huawei.com>
---
 drivers/infiniband/hw/hns/hns_roce_dca.c    |  17 +++++
 drivers/infiniband/hw/hns/hns_roce_dca.h    |   3 +
 drivers/infiniband/hw/hns/hns_roce_device.h |   5 ++
 drivers/infiniband/hw/hns/hns_roce_hw_v2.c  |  23 +++++-
 drivers/infiniband/hw/hns/hns_roce_hw_v2.h  |   2 +
 drivers/infiniband/hw/hns/hns_roce_qp.c     | 110 ++++++++++++++++++++++------
 include/uapi/rdma/hns-abi.h                 |   1 +
 7 files changed, 137 insertions(+), 24 deletions(-)

Comments

Zhu Yanjun May 10, 2021, 2:36 p.m. UTC | #1
On Mon, May 10, 2021 at 9:28 PM Weihang Li <liweihang@huawei.com> wrote:
>
> From: Xi Wang <wangxi11@huawei.com>
>
> If the userspace driver assign a NULL to the field of 'buf_addr' in
> 'struct hns_roce_ib_create_qp' when creating QP, this means the kernel
> driver need setup the QP as DCA mode. So add a QP capability bit in
> response to indicate the userspace driver that the DCA mode has been
> enabled.
>
> Signed-off-by: Xi Wang <wangxi11@huawei.com>
> Signed-off-by: Weihang Li <liweihang@huawei.com>
> ---
>  drivers/infiniband/hw/hns/hns_roce_dca.c    |  17 +++++
>  drivers/infiniband/hw/hns/hns_roce_dca.h    |   3 +
>  drivers/infiniband/hw/hns/hns_roce_device.h |   5 ++
>  drivers/infiniband/hw/hns/hns_roce_hw_v2.c  |  23 +++++-
>  drivers/infiniband/hw/hns/hns_roce_hw_v2.h  |   2 +
>  drivers/infiniband/hw/hns/hns_roce_qp.c     | 110 ++++++++++++++++++++++------
>  include/uapi/rdma/hns-abi.h                 |   1 +
>  7 files changed, 137 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/infiniband/hw/hns/hns_roce_dca.c b/drivers/infiniband/hw/hns/hns_roce_dca.c
> index 604d6cf..5eec1fb 100644
> --- a/drivers/infiniband/hw/hns/hns_roce_dca.c
> +++ b/drivers/infiniband/hw/hns/hns_roce_dca.c
> @@ -386,6 +386,23 @@ static void free_dca_mem(struct dca_mem *mem)
>         spin_unlock(&mem->lock);
>  }
>
> +int hns_roce_enable_dca(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
> +{
> +       struct hns_roce_dca_cfg *cfg = &hr_qp->dca_cfg;
> +
> +       cfg->buf_id = HNS_DCA_INVALID_BUF_ID;
> +
> +       return 0;

The returned value is always 0?

> +}
> +
> +void hns_roce_disable_dca(struct hns_roce_dev *hr_dev,
> +                         struct hns_roce_qp *hr_qp)
> +{
> +       struct hns_roce_dca_cfg *cfg = &hr_qp->dca_cfg;
> +
> +       cfg->buf_id = HNS_DCA_INVALID_BUF_ID;
> +}
> +
>  static inline struct hns_roce_ucontext *
>  uverbs_attr_to_hr_uctx(struct uverbs_attr_bundle *attrs)
>  {
> diff --git a/drivers/infiniband/hw/hns/hns_roce_dca.h b/drivers/infiniband/hw/hns/hns_roce_dca.h
> index 97caf03..419606ef 100644
> --- a/drivers/infiniband/hw/hns/hns_roce_dca.h
> +++ b/drivers/infiniband/hw/hns/hns_roce_dca.h
> @@ -26,4 +26,7 @@ void hns_roce_register_udca(struct hns_roce_dev *hr_dev,
>  void hns_roce_unregister_udca(struct hns_roce_dev *hr_dev,
>                               struct hns_roce_ucontext *uctx);
>
> +int hns_roce_enable_dca(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp);
> +void hns_roce_disable_dca(struct hns_roce_dev *hr_dev,
> +                         struct hns_roce_qp *hr_qp);
>  #endif
> diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h
> index 28fe33f..d1ca142 100644
> --- a/drivers/infiniband/hw/hns/hns_roce_device.h
> +++ b/drivers/infiniband/hw/hns/hns_roce_device.h
> @@ -332,6 +332,10 @@ struct hns_roce_mtr {
>         struct hns_roce_hem_cfg  hem_cfg; /* config for hardware addressing */
>  };
>
> +struct hns_roce_dca_cfg {
> +       u32 buf_id;
> +};
> +
>  struct hns_roce_mw {
>         struct ib_mw            ibmw;
>         u32                     pdn;
> @@ -633,6 +637,7 @@ struct hns_roce_qp {
>         struct hns_roce_wq      sq;
>
>         struct hns_roce_mtr     mtr;
> +       struct hns_roce_dca_cfg dca_cfg;
>
>         u32                     buff_size;
>         struct mutex            mutex;
> diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
> index edcfd39..9adac50 100644
> --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
> +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
> @@ -350,6 +350,11 @@ static int set_rwqe_data_seg(struct ib_qp *ibqp, const struct ib_send_wr *wr,
>         return 0;
>  }
>
> +static inline bool check_qp_dca_enable(struct hns_roce_qp *hr_qp)
> +{
> +       return !!(hr_qp->en_flags & HNS_ROCE_QP_CAP_DCA);
> +}
> +
>  static int check_send_valid(struct hns_roce_dev *hr_dev,
>                             struct hns_roce_qp *hr_qp)
>  {
> @@ -4531,6 +4536,21 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
>         roce_set_field(qpc_mask->byte_140_raq, V2_QPC_BYTE_140_TRRL_BA_M,
>                        V2_QPC_BYTE_140_TRRL_BA_S, 0);
>
> +       /* hip09 reused the IRRL_HEAD fileds in hip08 */
> +       if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP09) {
> +               if (check_qp_dca_enable(hr_qp)) {
> +                       roce_set_bit(context->byte_196_sq_psn,
> +                                    V2_QPC_BYTE_196_DCA_MODE_S, 1);
> +                       roce_set_bit(qpc_mask->byte_196_sq_psn,
> +                                    V2_QPC_BYTE_196_DCA_MODE_S, 0);
> +               }
> +       } else {
> +               /* reset IRRL_HEAD */
> +               roce_set_field(qpc_mask->byte_196_sq_psn,
> +                              V2_QPC_BYTE_196_IRRL_HEAD_M,
> +                              V2_QPC_BYTE_196_IRRL_HEAD_S, 0);
> +       }
> +
>         context->irrl_ba = cpu_to_le32(irrl_ba >> 6);
>         qpc_mask->irrl_ba = 0;
>         roce_set_field(context->byte_208_irrl, V2_QPC_BYTE_208_IRRL_BA_M,
> @@ -4688,9 +4708,6 @@ static int modify_qp_rtr_to_rts(struct ib_qp *ibqp,
>         roce_set_field(qpc_mask->byte_212_lsn, V2_QPC_BYTE_212_LSN_M,
>                        V2_QPC_BYTE_212_LSN_S, 0);
>
> -       roce_set_field(qpc_mask->byte_196_sq_psn, V2_QPC_BYTE_196_IRRL_HEAD_M,
> -                      V2_QPC_BYTE_196_IRRL_HEAD_S, 0);
> -
>         return 0;
>  }
>
> diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
> index a2100a6..eecf27c 100644
> --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
> +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
> @@ -853,6 +853,8 @@ struct hns_roce_v2_qp_context {
>  #define        V2_QPC_BYTE_196_IRRL_HEAD_S 0
>  #define V2_QPC_BYTE_196_IRRL_HEAD_M GENMASK(7, 0)
>
> +#define V2_QPC_BYTE_196_DCA_MODE_S 6
> +
>  #define        V2_QPC_BYTE_196_SQ_MAX_PSN_S 8
>  #define V2_QPC_BYTE_196_SQ_MAX_PSN_M GENMASK(31, 8)
>
> diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c
> index 230a909..a8740ef 100644
> --- a/drivers/infiniband/hw/hns/hns_roce_qp.c
> +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c
> @@ -39,6 +39,7 @@
>  #include "hns_roce_common.h"
>  #include "hns_roce_device.h"
>  #include "hns_roce_hem.h"
> +#include "hns_roce_dca.h"
>
>  static void flush_work_handle(struct work_struct *work)
>  {
> @@ -589,8 +590,21 @@ static int set_user_sq_size(struct hns_roce_dev *hr_dev,
>         return 0;
>  }
>
> +static bool check_dca_is_enable(struct hns_roce_dev *hr_dev, bool is_user,
> +                               unsigned long addr)
> +{
> +       if (!(hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_DCA_MODE))
> +               return false;
> +
> +       /* If the user QP's buffer addr is 0, the DCA mode should be enabled */
> +       if (is_user)
> +               return !addr;
> +
> +       return false;
> +}
> +
>  static int set_wqe_buf_attr(struct hns_roce_dev *hr_dev,
> -                           struct hns_roce_qp *hr_qp,
> +                           struct hns_roce_qp *hr_qp, bool dca_en,
>                             struct hns_roce_buf_attr *buf_attr)
>  {
>         int buf_size;
> @@ -637,6 +651,19 @@ static int set_wqe_buf_attr(struct hns_roce_dev *hr_dev,
>         buf_attr->page_shift = HNS_HW_PAGE_SHIFT + hr_dev->caps.mtt_buf_pg_sz;
>         buf_attr->region_count = idx;
>
> +       if (dca_en) {
> +               /*
> +                * When enable DCA, there's no need to alloc buffer now, and
> +                * the page shift should be fixed to 4K.
> +                */
> +               buf_attr->mtt_only = true;
> +               buf_attr->page_shift = HNS_HW_PAGE_SHIFT;
> +       } else {
> +               buf_attr->mtt_only = false;
> +               buf_attr->page_shift = HNS_HW_PAGE_SHIFT +
> +                                      hr_dev->caps.mtt_buf_pg_sz;
> +       }
> +
>         return 0;
>  }
>
> @@ -735,12 +762,53 @@ static void free_rq_inline_buf(struct hns_roce_qp *hr_qp)
>         kfree(hr_qp->rq_inl_buf.wqe_list);
>  }
>
> -static int alloc_qp_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
> +static int alloc_wqe_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
> +                        bool dca_en, struct hns_roce_buf_attr *buf_attr,
> +                        struct ib_udata *udata, unsigned long addr)
> +{
> +       struct ib_device *ibdev = &hr_dev->ib_dev;
> +       int ret;
> +
> +       if (dca_en) {
> +               /* DCA must be enabled after the buffer size is configured. */
> +               ret = hns_roce_enable_dca(hr_dev, hr_qp);

ret is always 0. The following will not be reached.

Zhu Yanjun

> +               if (ret) {
> +                       ibdev_err(ibdev, "failed to enable DCA, ret = %d.\n",
> +                                 ret);
> +                       return ret;
> +               }
> +
> +               hr_qp->en_flags |= HNS_ROCE_QP_CAP_DCA;
> +       }
> +
> +       ret = hns_roce_mtr_create(hr_dev, &hr_qp->mtr, buf_attr,
> +                                 HNS_HW_PAGE_SHIFT + hr_dev->caps.mtt_ba_pg_sz,
> +                                 udata, addr);
> +       if (ret) {
> +               ibdev_err(ibdev, "failed to create WQE mtr, ret = %d.\n", ret);
> +               if (dca_en)
> +                       hns_roce_disable_dca(hr_dev, hr_qp);
> +       }
> +
> +       return ret;
> +}
> +
> +static void free_wqe_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
> +                        struct ib_udata *udata)
> +{
> +       hns_roce_mtr_destroy(hr_dev, &hr_qp->mtr);
> +
> +       if (hr_qp->en_flags & HNS_ROCE_QP_CAP_DCA)
> +               hns_roce_disable_dca(hr_dev, hr_qp);
> +}
> +
> +static int alloc_qp_wqe(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
>                         struct ib_qp_init_attr *init_attr,
>                         struct ib_udata *udata, unsigned long addr)
>  {
>         struct ib_device *ibdev = &hr_dev->ib_dev;
>         struct hns_roce_buf_attr buf_attr = {};
> +       bool dca_en;
>         int ret;
>
>         if (!udata && hr_qp->rq_inl_buf.wqe_cnt) {
> @@ -755,16 +823,16 @@ static int alloc_qp_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
>                 hr_qp->rq_inl_buf.wqe_list = NULL;
>         }
>
> -       ret = set_wqe_buf_attr(hr_dev, hr_qp, &buf_attr);
> +       dca_en = check_dca_is_enable(hr_dev, !!udata, addr);
> +       ret = set_wqe_buf_attr(hr_dev, hr_qp, dca_en, &buf_attr);
>         if (ret) {
> -               ibdev_err(ibdev, "failed to split WQE buf, ret = %d.\n", ret);
> +               ibdev_err(ibdev, "failed to set WQE attr, ret = %d.\n", ret);
>                 goto err_inline;
>         }
> -       ret = hns_roce_mtr_create(hr_dev, &hr_qp->mtr, &buf_attr,
> -                                 HNS_HW_PAGE_SHIFT + hr_dev->caps.mtt_ba_pg_sz,
> -                                 udata, addr);
> +
> +       ret = alloc_wqe_buf(hr_dev, hr_qp, dca_en, &buf_attr, udata, addr);
>         if (ret) {
> -               ibdev_err(ibdev, "failed to create WQE mtr, ret = %d.\n", ret);
> +               ibdev_err(ibdev, "failed to alloc WQE buf, ret = %d.\n", ret);
>                 goto err_inline;
>         }
>
> @@ -775,9 +843,10 @@ static int alloc_qp_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
>         return ret;
>  }
>
> -static void free_qp_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
> +static void free_qp_wqe(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
> +                       struct ib_udata *udata)
>  {
> -       hns_roce_mtr_destroy(hr_dev, &hr_qp->mtr);
> +       free_wqe_buf(hr_dev, hr_qp, udata);
>         free_rq_inline_buf(hr_qp);
>  }
>
> @@ -835,7 +904,6 @@ static int alloc_qp_db(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
>                                 goto err_out;
>                         }
>                         hr_qp->en_flags |= HNS_ROCE_QP_CAP_SQ_RECORD_DB;
> -                       resp->cap_flags |= HNS_ROCE_QP_CAP_SQ_RECORD_DB;
>                 }
>
>                 if (user_qp_has_rdb(hr_dev, init_attr, udata, resp)) {
> @@ -848,7 +916,6 @@ static int alloc_qp_db(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
>                                 goto err_sdb;
>                         }
>                         hr_qp->en_flags |= HNS_ROCE_QP_CAP_RQ_RECORD_DB;
> -                       resp->cap_flags |= HNS_ROCE_QP_CAP_RQ_RECORD_DB;
>                 }
>         } else {
>                 if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP09)
> @@ -1027,18 +1094,18 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
>                 }
>         }
>
> -       ret = alloc_qp_buf(hr_dev, hr_qp, init_attr, udata, ucmd.buf_addr);
> -       if (ret) {
> -               ibdev_err(ibdev, "failed to alloc QP buffer, ret = %d.\n", ret);
> -               goto err_buf;
> -       }
> -
>         ret = alloc_qpn(hr_dev, hr_qp);
>         if (ret) {
>                 ibdev_err(ibdev, "failed to alloc QPN, ret = %d.\n", ret);
>                 goto err_qpn;
>         }
>
> +       ret = alloc_qp_wqe(hr_dev, hr_qp, init_attr, udata, ucmd.buf_addr);
> +       if (ret) {
> +               ibdev_err(ibdev, "failed to alloc QP buffer, ret = %d.\n", ret);
> +               goto err_buf;
> +       }
> +
>         ret = alloc_qp_db(hr_dev, hr_qp, init_attr, udata, &ucmd, &resp);
>         if (ret) {
>                 ibdev_err(ibdev, "failed to alloc QP doorbell, ret = %d.\n",
> @@ -1060,6 +1127,7 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
>         }
>
>         if (udata) {
> +               resp.cap_flags = hr_qp->en_flags;
>                 ret = ib_copy_to_udata(udata, &resp,
>                                        min(udata->outlen, sizeof(resp)));
>                 if (ret) {
> @@ -1088,10 +1156,10 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
>  err_qpc:
>         free_qp_db(hr_dev, hr_qp, udata);
>  err_db:
> +       free_qp_wqe(hr_dev, hr_qp, udata);
> +err_buf:
>         free_qpn(hr_dev, hr_qp);
>  err_qpn:
> -       free_qp_buf(hr_dev, hr_qp);
> -err_buf:
>         free_kernel_wrid(hr_qp);
>         return ret;
>  }
> @@ -1105,7 +1173,7 @@ void hns_roce_qp_destroy(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
>
>         free_qpc(hr_dev, hr_qp);
>         free_qpn(hr_dev, hr_qp);
> -       free_qp_buf(hr_dev, hr_qp);
> +       free_qp_wqe(hr_dev, hr_qp, udata);
>         free_kernel_wrid(hr_qp);
>         free_qp_db(hr_dev, hr_qp, udata);
>
> diff --git a/include/uapi/rdma/hns-abi.h b/include/uapi/rdma/hns-abi.h
> index bcca5be..99da481 100644
> --- a/include/uapi/rdma/hns-abi.h
> +++ b/include/uapi/rdma/hns-abi.h
> @@ -77,6 +77,7 @@ enum hns_roce_qp_cap_flags {
>         HNS_ROCE_QP_CAP_RQ_RECORD_DB = 1 << 0,
>         HNS_ROCE_QP_CAP_SQ_RECORD_DB = 1 << 1,
>         HNS_ROCE_QP_CAP_OWNER_DB = 1 << 2,
> +       HNS_ROCE_QP_CAP_DCA = 1 << 4,
>  };
>
>  struct hns_roce_ib_create_qp_resp {
> --
> 2.7.4
>
Weihang Li May 11, 2021, 2 a.m. UTC | #2
On 2021/5/10 22:36, Zhu Yanjun wrote:
> On Mon, May 10, 2021 at 9:28 PM Weihang Li <liweihang@huawei.com> wrote:
>> From: Xi Wang <wangxi11@huawei.com>
>>
>> If the userspace driver assign a NULL to the field of 'buf_addr' in
>> 'struct hns_roce_ib_create_qp' when creating QP, this means the kernel
>> driver need setup the QP as DCA mode. So add a QP capability bit in
>> response to indicate the userspace driver that the DCA mode has been
>> enabled.
>>
>> Signed-off-by: Xi Wang <wangxi11@huawei.com>
>> Signed-off-by: Weihang Li <liweihang@huawei.com>
>> ---
>>  drivers/infiniband/hw/hns/hns_roce_dca.c    |  17 +++++
>>  drivers/infiniband/hw/hns/hns_roce_dca.h    |   3 +
>>  drivers/infiniband/hw/hns/hns_roce_device.h |   5 ++
>>  drivers/infiniband/hw/hns/hns_roce_hw_v2.c  |  23 +++++-
>>  drivers/infiniband/hw/hns/hns_roce_hw_v2.h  |   2 +
>>  drivers/infiniband/hw/hns/hns_roce_qp.c     | 110 ++++++++++++++++++++++------
>>  include/uapi/rdma/hns-abi.h                 |   1 +
>>  7 files changed, 137 insertions(+), 24 deletions(-)
>>
>> diff --git a/drivers/infiniband/hw/hns/hns_roce_dca.c b/drivers/infiniband/hw/hns/hns_roce_dca.c
>> index 604d6cf..5eec1fb 100644
>> --- a/drivers/infiniband/hw/hns/hns_roce_dca.c
>> +++ b/drivers/infiniband/hw/hns/hns_roce_dca.c
>> @@ -386,6 +386,23 @@ static void free_dca_mem(struct dca_mem *mem)
>>         spin_unlock(&mem->lock);
>>  }
>>
>> +int hns_roce_enable_dca(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
>> +{
>> +       struct hns_roce_dca_cfg *cfg = &hr_qp->dca_cfg;
>> +
>> +       cfg->buf_id = HNS_DCA_INVALID_BUF_ID;
>> +
>> +       return 0;
> The returned value is always 0?

You're right, I will change it to void, thank you.

> 
>> +}
>> +
>> +void hns_roce_disable_dca(struct hns_roce_dev *hr_dev,
>> +                         struct hns_roce_qp *hr_qp)
>> +{
>> +       struct hns_roce_dca_cfg *cfg = &hr_qp->dca_cfg;
>> +
>> +       cfg->buf_id = HNS_DCA_INVALID_BUF_ID;
>> +}
>> +
>>  static inline struct hns_roce_ucontext *
>>  uverbs_attr_to_hr_uctx(struct uverbs_attr_bundle *attrs)
>>  {
>> diff --git a/drivers/infiniband/hw/hns/hns_roce_dca.h b/drivers/infiniband/hw/hns/hns_roce_dca.h
>> index 97caf03..419606ef 100644
>> --- a/drivers/infiniband/hw/hns/hns_roce_dca.h
>> +++ b/drivers/infiniband/hw/hns/hns_roce_dca.h
>> @@ -26,4 +26,7 @@ void hns_roce_register_udca(struct hns_roce_dev *hr_dev,
>>  void hns_roce_unregister_udca(struct hns_roce_dev *hr_dev,
>>                               struct hns_roce_ucontext *uctx);
>>
>> +int hns_roce_enable_dca(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp);
>> +void hns_roce_disable_dca(struct hns_roce_dev *hr_dev,
>> +                         struct hns_roce_qp *hr_qp);
>>  #endif
>> diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h
>> index 28fe33f..d1ca142 100644
>> --- a/drivers/infiniband/hw/hns/hns_roce_device.h
>> +++ b/drivers/infiniband/hw/hns/hns_roce_device.h
>> @@ -332,6 +332,10 @@ struct hns_roce_mtr {
>>         struct hns_roce_hem_cfg  hem_cfg; /* config for hardware addressing */
>>  };
>>
>> +struct hns_roce_dca_cfg {
>> +       u32 buf_id;
>> +};
>> +
>>  struct hns_roce_mw {
>>         struct ib_mw            ibmw;
>>         u32                     pdn;
>> @@ -633,6 +637,7 @@ struct hns_roce_qp {
>>         struct hns_roce_wq      sq;
>>
>>         struct hns_roce_mtr     mtr;
>> +       struct hns_roce_dca_cfg dca_cfg;
>>
>>         u32                     buff_size;
>>         struct mutex            mutex;
>> diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
>> index edcfd39..9adac50 100644
>> --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
>> +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
>> @@ -350,6 +350,11 @@ static int set_rwqe_data_seg(struct ib_qp *ibqp, const struct ib_send_wr *wr,
>>         return 0;
>>  }
>>
>> +static inline bool check_qp_dca_enable(struct hns_roce_qp *hr_qp)
>> +{
>> +       return !!(hr_qp->en_flags & HNS_ROCE_QP_CAP_DCA);
>> +}
>> +
>>  static int check_send_valid(struct hns_roce_dev *hr_dev,
>>                             struct hns_roce_qp *hr_qp)
>>  {
>> @@ -4531,6 +4536,21 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
>>         roce_set_field(qpc_mask->byte_140_raq, V2_QPC_BYTE_140_TRRL_BA_M,
>>                        V2_QPC_BYTE_140_TRRL_BA_S, 0);
>>
>> +       /* hip09 reused the IRRL_HEAD fileds in hip08 */
>> +       if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP09) {
>> +               if (check_qp_dca_enable(hr_qp)) {
>> +                       roce_set_bit(context->byte_196_sq_psn,
>> +                                    V2_QPC_BYTE_196_DCA_MODE_S, 1);
>> +                       roce_set_bit(qpc_mask->byte_196_sq_psn,
>> +                                    V2_QPC_BYTE_196_DCA_MODE_S, 0);
>> +               }
>> +       } else {
>> +               /* reset IRRL_HEAD */
>> +               roce_set_field(qpc_mask->byte_196_sq_psn,
>> +                              V2_QPC_BYTE_196_IRRL_HEAD_M,
>> +                              V2_QPC_BYTE_196_IRRL_HEAD_S, 0);
>> +       }
>> +
>>         context->irrl_ba = cpu_to_le32(irrl_ba >> 6);
>>         qpc_mask->irrl_ba = 0;
>>         roce_set_field(context->byte_208_irrl, V2_QPC_BYTE_208_IRRL_BA_M,
>> @@ -4688,9 +4708,6 @@ static int modify_qp_rtr_to_rts(struct ib_qp *ibqp,
>>         roce_set_field(qpc_mask->byte_212_lsn, V2_QPC_BYTE_212_LSN_M,
>>                        V2_QPC_BYTE_212_LSN_S, 0);
>>
>> -       roce_set_field(qpc_mask->byte_196_sq_psn, V2_QPC_BYTE_196_IRRL_HEAD_M,
>> -                      V2_QPC_BYTE_196_IRRL_HEAD_S, 0);
>> -
>>         return 0;
>>  }
>>
>> diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
>> index a2100a6..eecf27c 100644
>> --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
>> +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
>> @@ -853,6 +853,8 @@ struct hns_roce_v2_qp_context {
>>  #define        V2_QPC_BYTE_196_IRRL_HEAD_S 0
>>  #define V2_QPC_BYTE_196_IRRL_HEAD_M GENMASK(7, 0)
>>
>> +#define V2_QPC_BYTE_196_DCA_MODE_S 6
>> +
>>  #define        V2_QPC_BYTE_196_SQ_MAX_PSN_S 8
>>  #define V2_QPC_BYTE_196_SQ_MAX_PSN_M GENMASK(31, 8)
>>
>> diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c
>> index 230a909..a8740ef 100644
>> --- a/drivers/infiniband/hw/hns/hns_roce_qp.c
>> +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c
>> @@ -39,6 +39,7 @@
>>  #include "hns_roce_common.h"
>>  #include "hns_roce_device.h"
>>  #include "hns_roce_hem.h"
>> +#include "hns_roce_dca.h"
>>
>>  static void flush_work_handle(struct work_struct *work)
>>  {
>> @@ -589,8 +590,21 @@ static int set_user_sq_size(struct hns_roce_dev *hr_dev,
>>         return 0;
>>  }
>>
>> +static bool check_dca_is_enable(struct hns_roce_dev *hr_dev, bool is_user,
>> +                               unsigned long addr)
>> +{
>> +       if (!(hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_DCA_MODE))
>> +               return false;
>> +
>> +       /* If the user QP's buffer addr is 0, the DCA mode should be enabled */
>> +       if (is_user)
>> +               return !addr;
>> +
>> +       return false;
>> +}
>> +
>>  static int set_wqe_buf_attr(struct hns_roce_dev *hr_dev,
>> -                           struct hns_roce_qp *hr_qp,
>> +                           struct hns_roce_qp *hr_qp, bool dca_en,
>>                             struct hns_roce_buf_attr *buf_attr)
>>  {
>>         int buf_size;
>> @@ -637,6 +651,19 @@ static int set_wqe_buf_attr(struct hns_roce_dev *hr_dev,
>>         buf_attr->page_shift = HNS_HW_PAGE_SHIFT + hr_dev->caps.mtt_buf_pg_sz;
>>         buf_attr->region_count = idx;
>>
>> +       if (dca_en) {
>> +               /*
>> +                * When enable DCA, there's no need to alloc buffer now, and
>> +                * the page shift should be fixed to 4K.
>> +                */
>> +               buf_attr->mtt_only = true;
>> +               buf_attr->page_shift = HNS_HW_PAGE_SHIFT;
>> +       } else {
>> +               buf_attr->mtt_only = false;
>> +               buf_attr->page_shift = HNS_HW_PAGE_SHIFT +
>> +                                      hr_dev->caps.mtt_buf_pg_sz;
>> +       }
>> +
>>         return 0;
>>  }
>>
>> @@ -735,12 +762,53 @@ static void free_rq_inline_buf(struct hns_roce_qp *hr_qp)
>>         kfree(hr_qp->rq_inl_buf.wqe_list);
>>  }
>>
>> -static int alloc_qp_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
>> +static int alloc_wqe_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
>> +                        bool dca_en, struct hns_roce_buf_attr *buf_attr,
>> +                        struct ib_udata *udata, unsigned long addr)
>> +{
>> +       struct ib_device *ibdev = &hr_dev->ib_dev;
>> +       int ret;
>> +
>> +       if (dca_en) {
>> +               /* DCA must be enabled after the buffer size is configured. */
>> +               ret = hns_roce_enable_dca(hr_dev, hr_qp);
> ret is always 0. The following will not be reached.
> 
> Zhu Yanjun
> 

Thanks for the reminder, I will fix this.

Weihang

>> +               if (ret) {
>> +                       ibdev_err(ibdev, "failed to enable DCA, ret = %d.\n",
>> +                                 ret);
>> +                       return ret;
>> +               }
>> +
>> +               hr_qp->en_flags |= HNS_ROCE_QP_CAP_DCA;
>> +       }
diff mbox series

Patch

diff --git a/drivers/infiniband/hw/hns/hns_roce_dca.c b/drivers/infiniband/hw/hns/hns_roce_dca.c
index 604d6cf..5eec1fb 100644
--- a/drivers/infiniband/hw/hns/hns_roce_dca.c
+++ b/drivers/infiniband/hw/hns/hns_roce_dca.c
@@ -386,6 +386,23 @@  static void free_dca_mem(struct dca_mem *mem)
 	spin_unlock(&mem->lock);
 }
 
+int hns_roce_enable_dca(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
+{
+	struct hns_roce_dca_cfg *cfg = &hr_qp->dca_cfg;
+
+	cfg->buf_id = HNS_DCA_INVALID_BUF_ID;
+
+	return 0;
+}
+
+void hns_roce_disable_dca(struct hns_roce_dev *hr_dev,
+			  struct hns_roce_qp *hr_qp)
+{
+	struct hns_roce_dca_cfg *cfg = &hr_qp->dca_cfg;
+
+	cfg->buf_id = HNS_DCA_INVALID_BUF_ID;
+}
+
 static inline struct hns_roce_ucontext *
 uverbs_attr_to_hr_uctx(struct uverbs_attr_bundle *attrs)
 {
diff --git a/drivers/infiniband/hw/hns/hns_roce_dca.h b/drivers/infiniband/hw/hns/hns_roce_dca.h
index 97caf03..419606ef 100644
--- a/drivers/infiniband/hw/hns/hns_roce_dca.h
+++ b/drivers/infiniband/hw/hns/hns_roce_dca.h
@@ -26,4 +26,7 @@  void hns_roce_register_udca(struct hns_roce_dev *hr_dev,
 void hns_roce_unregister_udca(struct hns_roce_dev *hr_dev,
 			      struct hns_roce_ucontext *uctx);
 
+int hns_roce_enable_dca(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp);
+void hns_roce_disable_dca(struct hns_roce_dev *hr_dev,
+			  struct hns_roce_qp *hr_qp);
 #endif
diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h
index 28fe33f..d1ca142 100644
--- a/drivers/infiniband/hw/hns/hns_roce_device.h
+++ b/drivers/infiniband/hw/hns/hns_roce_device.h
@@ -332,6 +332,10 @@  struct hns_roce_mtr {
 	struct hns_roce_hem_cfg  hem_cfg; /* config for hardware addressing */
 };
 
+struct hns_roce_dca_cfg {
+	u32 buf_id;
+};
+
 struct hns_roce_mw {
 	struct ib_mw		ibmw;
 	u32			pdn;
@@ -633,6 +637,7 @@  struct hns_roce_qp {
 	struct hns_roce_wq	sq;
 
 	struct hns_roce_mtr	mtr;
+	struct hns_roce_dca_cfg	dca_cfg;
 
 	u32			buff_size;
 	struct mutex		mutex;
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
index edcfd39..9adac50 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
@@ -350,6 +350,11 @@  static int set_rwqe_data_seg(struct ib_qp *ibqp, const struct ib_send_wr *wr,
 	return 0;
 }
 
+static inline bool check_qp_dca_enable(struct hns_roce_qp *hr_qp)
+{
+	return !!(hr_qp->en_flags & HNS_ROCE_QP_CAP_DCA);
+}
+
 static int check_send_valid(struct hns_roce_dev *hr_dev,
 			    struct hns_roce_qp *hr_qp)
 {
@@ -4531,6 +4536,21 @@  static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
 	roce_set_field(qpc_mask->byte_140_raq, V2_QPC_BYTE_140_TRRL_BA_M,
 		       V2_QPC_BYTE_140_TRRL_BA_S, 0);
 
+	/* hip09 reused the IRRL_HEAD fileds in hip08 */
+	if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP09) {
+		if (check_qp_dca_enable(hr_qp)) {
+			roce_set_bit(context->byte_196_sq_psn,
+				     V2_QPC_BYTE_196_DCA_MODE_S, 1);
+			roce_set_bit(qpc_mask->byte_196_sq_psn,
+				     V2_QPC_BYTE_196_DCA_MODE_S, 0);
+		}
+	} else {
+		/* reset IRRL_HEAD */
+		roce_set_field(qpc_mask->byte_196_sq_psn,
+			       V2_QPC_BYTE_196_IRRL_HEAD_M,
+			       V2_QPC_BYTE_196_IRRL_HEAD_S, 0);
+	}
+
 	context->irrl_ba = cpu_to_le32(irrl_ba >> 6);
 	qpc_mask->irrl_ba = 0;
 	roce_set_field(context->byte_208_irrl, V2_QPC_BYTE_208_IRRL_BA_M,
@@ -4688,9 +4708,6 @@  static int modify_qp_rtr_to_rts(struct ib_qp *ibqp,
 	roce_set_field(qpc_mask->byte_212_lsn, V2_QPC_BYTE_212_LSN_M,
 		       V2_QPC_BYTE_212_LSN_S, 0);
 
-	roce_set_field(qpc_mask->byte_196_sq_psn, V2_QPC_BYTE_196_IRRL_HEAD_M,
-		       V2_QPC_BYTE_196_IRRL_HEAD_S, 0);
-
 	return 0;
 }
 
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
index a2100a6..eecf27c 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
@@ -853,6 +853,8 @@  struct hns_roce_v2_qp_context {
 #define	V2_QPC_BYTE_196_IRRL_HEAD_S 0
 #define V2_QPC_BYTE_196_IRRL_HEAD_M GENMASK(7, 0)
 
+#define V2_QPC_BYTE_196_DCA_MODE_S 6
+
 #define	V2_QPC_BYTE_196_SQ_MAX_PSN_S 8
 #define V2_QPC_BYTE_196_SQ_MAX_PSN_M GENMASK(31, 8)
 
diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c
index 230a909..a8740ef 100644
--- a/drivers/infiniband/hw/hns/hns_roce_qp.c
+++ b/drivers/infiniband/hw/hns/hns_roce_qp.c
@@ -39,6 +39,7 @@ 
 #include "hns_roce_common.h"
 #include "hns_roce_device.h"
 #include "hns_roce_hem.h"
+#include "hns_roce_dca.h"
 
 static void flush_work_handle(struct work_struct *work)
 {
@@ -589,8 +590,21 @@  static int set_user_sq_size(struct hns_roce_dev *hr_dev,
 	return 0;
 }
 
+static bool check_dca_is_enable(struct hns_roce_dev *hr_dev, bool is_user,
+				unsigned long addr)
+{
+	if (!(hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_DCA_MODE))
+		return false;
+
+	/* If the user QP's buffer addr is 0, the DCA mode should be enabled */
+	if (is_user)
+		return !addr;
+
+	return false;
+}
+
 static int set_wqe_buf_attr(struct hns_roce_dev *hr_dev,
-			    struct hns_roce_qp *hr_qp,
+			    struct hns_roce_qp *hr_qp, bool dca_en,
 			    struct hns_roce_buf_attr *buf_attr)
 {
 	int buf_size;
@@ -637,6 +651,19 @@  static int set_wqe_buf_attr(struct hns_roce_dev *hr_dev,
 	buf_attr->page_shift = HNS_HW_PAGE_SHIFT + hr_dev->caps.mtt_buf_pg_sz;
 	buf_attr->region_count = idx;
 
+	if (dca_en) {
+		/*
+		 * When enable DCA, there's no need to alloc buffer now, and
+		 * the page shift should be fixed to 4K.
+		 */
+		buf_attr->mtt_only = true;
+		buf_attr->page_shift = HNS_HW_PAGE_SHIFT;
+	} else {
+		buf_attr->mtt_only = false;
+		buf_attr->page_shift = HNS_HW_PAGE_SHIFT +
+				       hr_dev->caps.mtt_buf_pg_sz;
+	}
+
 	return 0;
 }
 
@@ -735,12 +762,53 @@  static void free_rq_inline_buf(struct hns_roce_qp *hr_qp)
 	kfree(hr_qp->rq_inl_buf.wqe_list);
 }
 
-static int alloc_qp_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
+static int alloc_wqe_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
+			 bool dca_en, struct hns_roce_buf_attr *buf_attr,
+			 struct ib_udata *udata, unsigned long addr)
+{
+	struct ib_device *ibdev = &hr_dev->ib_dev;
+	int ret;
+
+	if (dca_en) {
+		/* DCA must be enabled after the buffer size is configured. */
+		ret = hns_roce_enable_dca(hr_dev, hr_qp);
+		if (ret) {
+			ibdev_err(ibdev, "failed to enable DCA, ret = %d.\n",
+				  ret);
+			return ret;
+		}
+
+		hr_qp->en_flags |= HNS_ROCE_QP_CAP_DCA;
+	}
+
+	ret = hns_roce_mtr_create(hr_dev, &hr_qp->mtr, buf_attr,
+				  HNS_HW_PAGE_SHIFT + hr_dev->caps.mtt_ba_pg_sz,
+				  udata, addr);
+	if (ret) {
+		ibdev_err(ibdev, "failed to create WQE mtr, ret = %d.\n", ret);
+		if (dca_en)
+			hns_roce_disable_dca(hr_dev, hr_qp);
+	}
+
+	return ret;
+}
+
+static void free_wqe_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
+			 struct ib_udata *udata)
+{
+	hns_roce_mtr_destroy(hr_dev, &hr_qp->mtr);
+
+	if (hr_qp->en_flags & HNS_ROCE_QP_CAP_DCA)
+		hns_roce_disable_dca(hr_dev, hr_qp);
+}
+
+static int alloc_qp_wqe(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
 			struct ib_qp_init_attr *init_attr,
 			struct ib_udata *udata, unsigned long addr)
 {
 	struct ib_device *ibdev = &hr_dev->ib_dev;
 	struct hns_roce_buf_attr buf_attr = {};
+	bool dca_en;
 	int ret;
 
 	if (!udata && hr_qp->rq_inl_buf.wqe_cnt) {
@@ -755,16 +823,16 @@  static int alloc_qp_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
 		hr_qp->rq_inl_buf.wqe_list = NULL;
 	}
 
-	ret = set_wqe_buf_attr(hr_dev, hr_qp, &buf_attr);
+	dca_en = check_dca_is_enable(hr_dev, !!udata, addr);
+	ret = set_wqe_buf_attr(hr_dev, hr_qp, dca_en, &buf_attr);
 	if (ret) {
-		ibdev_err(ibdev, "failed to split WQE buf, ret = %d.\n", ret);
+		ibdev_err(ibdev, "failed to set WQE attr, ret = %d.\n", ret);
 		goto err_inline;
 	}
-	ret = hns_roce_mtr_create(hr_dev, &hr_qp->mtr, &buf_attr,
-				  HNS_HW_PAGE_SHIFT + hr_dev->caps.mtt_ba_pg_sz,
-				  udata, addr);
+
+	ret = alloc_wqe_buf(hr_dev, hr_qp, dca_en, &buf_attr, udata, addr);
 	if (ret) {
-		ibdev_err(ibdev, "failed to create WQE mtr, ret = %d.\n", ret);
+		ibdev_err(ibdev, "failed to alloc WQE buf, ret = %d.\n", ret);
 		goto err_inline;
 	}
 
@@ -775,9 +843,10 @@  static int alloc_qp_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
 	return ret;
 }
 
-static void free_qp_buf(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
+static void free_qp_wqe(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
+			struct ib_udata *udata)
 {
-	hns_roce_mtr_destroy(hr_dev, &hr_qp->mtr);
+	free_wqe_buf(hr_dev, hr_qp, udata);
 	free_rq_inline_buf(hr_qp);
 }
 
@@ -835,7 +904,6 @@  static int alloc_qp_db(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
 				goto err_out;
 			}
 			hr_qp->en_flags |= HNS_ROCE_QP_CAP_SQ_RECORD_DB;
-			resp->cap_flags |= HNS_ROCE_QP_CAP_SQ_RECORD_DB;
 		}
 
 		if (user_qp_has_rdb(hr_dev, init_attr, udata, resp)) {
@@ -848,7 +916,6 @@  static int alloc_qp_db(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
 				goto err_sdb;
 			}
 			hr_qp->en_flags |= HNS_ROCE_QP_CAP_RQ_RECORD_DB;
-			resp->cap_flags |= HNS_ROCE_QP_CAP_RQ_RECORD_DB;
 		}
 	} else {
 		if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP09)
@@ -1027,18 +1094,18 @@  static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
 		}
 	}
 
-	ret = alloc_qp_buf(hr_dev, hr_qp, init_attr, udata, ucmd.buf_addr);
-	if (ret) {
-		ibdev_err(ibdev, "failed to alloc QP buffer, ret = %d.\n", ret);
-		goto err_buf;
-	}
-
 	ret = alloc_qpn(hr_dev, hr_qp);
 	if (ret) {
 		ibdev_err(ibdev, "failed to alloc QPN, ret = %d.\n", ret);
 		goto err_qpn;
 	}
 
+	ret = alloc_qp_wqe(hr_dev, hr_qp, init_attr, udata, ucmd.buf_addr);
+	if (ret) {
+		ibdev_err(ibdev, "failed to alloc QP buffer, ret = %d.\n", ret);
+		goto err_buf;
+	}
+
 	ret = alloc_qp_db(hr_dev, hr_qp, init_attr, udata, &ucmd, &resp);
 	if (ret) {
 		ibdev_err(ibdev, "failed to alloc QP doorbell, ret = %d.\n",
@@ -1060,6 +1127,7 @@  static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
 	}
 
 	if (udata) {
+		resp.cap_flags = hr_qp->en_flags;
 		ret = ib_copy_to_udata(udata, &resp,
 				       min(udata->outlen, sizeof(resp)));
 		if (ret) {
@@ -1088,10 +1156,10 @@  static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
 err_qpc:
 	free_qp_db(hr_dev, hr_qp, udata);
 err_db:
+	free_qp_wqe(hr_dev, hr_qp, udata);
+err_buf:
 	free_qpn(hr_dev, hr_qp);
 err_qpn:
-	free_qp_buf(hr_dev, hr_qp);
-err_buf:
 	free_kernel_wrid(hr_qp);
 	return ret;
 }
@@ -1105,7 +1173,7 @@  void hns_roce_qp_destroy(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
 
 	free_qpc(hr_dev, hr_qp);
 	free_qpn(hr_dev, hr_qp);
-	free_qp_buf(hr_dev, hr_qp);
+	free_qp_wqe(hr_dev, hr_qp, udata);
 	free_kernel_wrid(hr_qp);
 	free_qp_db(hr_dev, hr_qp, udata);
 
diff --git a/include/uapi/rdma/hns-abi.h b/include/uapi/rdma/hns-abi.h
index bcca5be..99da481 100644
--- a/include/uapi/rdma/hns-abi.h
+++ b/include/uapi/rdma/hns-abi.h
@@ -77,6 +77,7 @@  enum hns_roce_qp_cap_flags {
 	HNS_ROCE_QP_CAP_RQ_RECORD_DB = 1 << 0,
 	HNS_ROCE_QP_CAP_SQ_RECORD_DB = 1 << 1,
 	HNS_ROCE_QP_CAP_OWNER_DB = 1 << 2,
+	HNS_ROCE_QP_CAP_DCA = 1 << 4,
 };
 
 struct hns_roce_ib_create_qp_resp {