Skip to content

Commit

Permalink
RDMA/hns: Support rq record doorbell for the user space
Browse files Browse the repository at this point in the history
This patch adds interfaces and definitions to support the rq record
doorbell for the user space.

Signed-off-by: Yixian Liu <liuyixian@huawei.com>
Signed-off-by: Lijun Ou <oulijun@huawei.com>
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Shaobo Xu <xushaobo2@huawei.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
  • Loading branch information
Yixian Liu authored and Doug Ledford committed Mar 13, 2018
1 parent 036ef0a commit e088a68
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 5 deletions.
2 changes: 1 addition & 1 deletion drivers/infiniband/hw/hns/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ccflags-y := -Idrivers/net/ethernet/hisilicon/hns3
obj-$(CONFIG_INFINIBAND_HNS) += hns-roce.o
hns-roce-objs := hns_roce_main.o hns_roce_cmd.o hns_roce_pd.o \
hns_roce_ah.o hns_roce_hem.o hns_roce_mr.o hns_roce_qp.o \
hns_roce_cq.o hns_roce_alloc.o
hns_roce_cq.o hns_roce_alloc.o hns_roce_db.o
obj-$(CONFIG_INFINIBAND_HNS_HIP06) += hns-roce-hw-v1.o
hns-roce-hw-v1-objs := hns_roce_hw_v1.o
obj-$(CONFIG_INFINIBAND_HNS_HIP08) += hns-roce-hw-v2.o
Expand Down
68 changes: 68 additions & 0 deletions drivers/infiniband/hw/hns/hns_roce_db.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */
/*
* Copyright (c) 2017 Hisilicon Limited.
* Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
*/

#include <linux/platform_device.h>
#include <rdma/ib_umem.h>
#include "hns_roce_device.h"

int hns_roce_db_map_user(struct hns_roce_ucontext *context, unsigned long virt,
struct hns_roce_db *db)
{
struct hns_roce_user_db_page *page;
int ret = 0;

mutex_lock(&context->page_mutex);

list_for_each_entry(page, &context->page_list, list)
if (page->user_virt == (virt & PAGE_MASK))
goto found;

page = kmalloc(sizeof(*page), GFP_KERNEL);
if (!page) {
ret = -ENOMEM;
goto out;
}

refcount_set(&page->refcount, 1);
page->user_virt = (virt & PAGE_MASK);
page->umem = ib_umem_get(&context->ibucontext, virt & PAGE_MASK,
PAGE_SIZE, 0, 0);
if (IS_ERR(page->umem)) {
ret = PTR_ERR(page->umem);
kfree(page);
goto out;
}

list_add(&page->list, &context->page_list);

found:
db->dma = sg_dma_address(page->umem->sg_head.sgl) +
(virt & ~PAGE_MASK);
db->u.user_page = page;
refcount_inc(&page->refcount);

out:
mutex_unlock(&context->page_mutex);

return ret;
}
EXPORT_SYMBOL(hns_roce_db_map_user);

void hns_roce_db_unmap_user(struct hns_roce_ucontext *context,
struct hns_roce_db *db)
{
mutex_lock(&context->page_mutex);

refcount_dec(&db->u.user_page->refcount);
if (refcount_dec_if_one(&db->u.user_page->refcount)) {
list_del(&db->u.user_page->list);
ib_umem_release(db->u.user_page->umem);
kfree(db->u.user_page);
}

mutex_unlock(&context->page_mutex);
}
EXPORT_SYMBOL(hns_roce_db_unmap_user);
46 changes: 45 additions & 1 deletion drivers/infiniband/hw/hns/hns_roce_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@
#define PAGES_SHIFT_24 24
#define PAGES_SHIFT_32 32

enum {
HNS_ROCE_SUPPORT_RQ_RECORD_DB = 1 << 0,
};

enum hns_roce_qp_state {
HNS_ROCE_QP_STATE_RST,
HNS_ROCE_QP_STATE_INIT,
Expand Down Expand Up @@ -178,14 +182,19 @@ enum {
enum {
HNS_ROCE_CAP_FLAG_REREG_MR = BIT(0),
HNS_ROCE_CAP_FLAG_ROCE_V1_V2 = BIT(1),
HNS_ROCE_CAP_FLAG_RQ_INLINE = BIT(2)
HNS_ROCE_CAP_FLAG_RQ_INLINE = BIT(2),
HNS_ROCE_CAP_FLAG_RECORD_DB = BIT(3)
};

enum hns_roce_mtt_type {
MTT_TYPE_WQE,
MTT_TYPE_CQE,
};

enum {
HNS_ROCE_DB_PER_PAGE = PAGE_SIZE / 4
};

#define HNS_ROCE_CMD_SUCCESS 1

#define HNS_ROCE_PORT_DOWN 0
Expand All @@ -203,6 +212,8 @@ struct hns_roce_uar {
struct hns_roce_ucontext {
struct ib_ucontext ibucontext;
struct hns_roce_uar uar;
struct list_head page_list;
struct mutex page_mutex;
};

struct hns_roce_pd {
Expand Down Expand Up @@ -335,6 +346,33 @@ struct hns_roce_buf {
int page_shift;
};

struct hns_roce_db_pgdir {
struct list_head list;
DECLARE_BITMAP(order0, HNS_ROCE_DB_PER_PAGE);
DECLARE_BITMAP(order1, HNS_ROCE_DB_PER_PAGE / 2);
unsigned long *bits[2];
u32 *page;
dma_addr_t db_dma;
};

struct hns_roce_user_db_page {
struct list_head list;
struct ib_umem *umem;
unsigned long user_virt;
refcount_t refcount;
};

struct hns_roce_db {
u32 *db_record;
union {
struct hns_roce_db_pgdir *pgdir;
struct hns_roce_user_db_page *user_page;
} u;
dma_addr_t dma;
int index;
int order;
};

struct hns_roce_cq_buf {
struct hns_roce_buf hr_buf;
struct hns_roce_mtt hr_mtt;
Expand Down Expand Up @@ -466,6 +504,8 @@ struct hns_roce_qp {
struct ib_qp ibqp;
struct hns_roce_buf hr_buf;
struct hns_roce_wq rq;
struct hns_roce_db rdb;
u8 rdb_en;
u32 doorbell_qpn;
__le32 sq_signal_bits;
u32 sq_next_wqe;
Expand Down Expand Up @@ -930,6 +970,10 @@ struct ib_cq *hns_roce_ib_create_cq(struct ib_device *ib_dev,
int hns_roce_ib_destroy_cq(struct ib_cq *ib_cq);
void hns_roce_free_cq(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq);

int hns_roce_db_map_user(struct hns_roce_ucontext *context, unsigned long virt,
struct hns_roce_db *db);
void hns_roce_db_unmap_user(struct hns_roce_ucontext *context,
struct hns_roce_db *db);
void hns_roce_cq_completion(struct hns_roce_dev *hr_dev, u32 cqn);
void hns_roce_cq_event(struct hns_roce_dev *hr_dev, u32 cqn, int event_type);
void hns_roce_qp_event(struct hns_roce_dev *hr_dev, u32 qpn, int event_type);
Expand Down
26 changes: 25 additions & 1 deletion drivers/infiniband/hw/hns/hns_roce_hw_v2.c
Original file line number Diff line number Diff line change
Expand Up @@ -1168,7 +1168,8 @@ static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev)

caps->flags = HNS_ROCE_CAP_FLAG_REREG_MR |
HNS_ROCE_CAP_FLAG_ROCE_V1_V2 |
HNS_ROCE_CAP_FLAG_RQ_INLINE;
HNS_ROCE_CAP_FLAG_RQ_INLINE |
HNS_ROCE_CAP_FLAG_RECORD_DB;
caps->pkey_table_len[0] = 1;
caps->gid_table_len[0] = HNS_ROCE_V2_GID_INDEX_NUM;
caps->ceqe_depth = HNS_ROCE_V2_COMP_EQE_NUM;
Expand Down Expand Up @@ -2274,6 +2275,23 @@ static void modify_qp_reset_to_init(struct ib_qp *ibqp,
hr_qp->qkey = attr->qkey;
}

if (hr_qp->rdb_en) {
roce_set_bit(context->byte_68_rq_db,
V2_QPC_BYTE_68_RQ_RECORD_EN_S, 1);
roce_set_bit(qpc_mask->byte_68_rq_db,
V2_QPC_BYTE_68_RQ_RECORD_EN_S, 0);
}

roce_set_field(context->byte_68_rq_db,
V2_QPC_BYTE_68_RQ_DB_RECORD_ADDR_M,
V2_QPC_BYTE_68_RQ_DB_RECORD_ADDR_S,
((u32)hr_qp->rdb.dma) >> 1);
roce_set_field(qpc_mask->byte_68_rq_db,
V2_QPC_BYTE_68_RQ_DB_RECORD_ADDR_M,
V2_QPC_BYTE_68_RQ_DB_RECORD_ADDR_S, 0);
context->rq_db_record_addr = hr_qp->rdb.dma >> 32;
qpc_mask->rq_db_record_addr = 0;

roce_set_bit(context->byte_76_srqn_op_en, V2_QPC_BYTE_76_RQIE_S, 1);
roce_set_bit(qpc_mask->byte_76_srqn_op_en, V2_QPC_BYTE_76_RQIE_S, 0);

Expand Down Expand Up @@ -3211,6 +3229,8 @@ static int hns_roce_v2_modify_qp(struct ib_qp *ibqp,
hr_qp->sq.tail = 0;
hr_qp->sq_next_wqe = 0;
hr_qp->next_sge = 0;
if (hr_qp->rq.wqe_cnt)
*hr_qp->rdb.db_record = 0;
}

out:
Expand Down Expand Up @@ -3437,6 +3457,10 @@ static int hns_roce_v2_destroy_qp_common(struct hns_roce_dev *hr_dev,
hns_roce_mtt_cleanup(hr_dev, &hr_qp->mtt);

if (is_user) {
if (hr_qp->rq.wqe_cnt && (hr_qp->rdb_en == 1))
hns_roce_db_unmap_user(
to_hr_ucontext(hr_qp->ibqp.uobject->context),
&hr_qp->rdb);
ib_umem_release(hr_qp->umem);
} else {
kfree(hr_qp->sq.wrid);
Expand Down
5 changes: 5 additions & 0 deletions drivers/infiniband/hw/hns/hns_roce_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,11 @@ static struct ib_ucontext *hns_roce_alloc_ucontext(struct ib_device *ib_dev,
if (ret)
goto error_fail_uar_alloc;

if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB) {
INIT_LIST_HEAD(&context->page_list);
mutex_init(&context->page_mutex);
}

ret = ib_copy_to_udata(udata, &resp, sizeof(resp));
if (ret)
goto error_fail_copy_to_udata;
Expand Down
53 changes: 51 additions & 2 deletions drivers/infiniband/hw/hns/hns_roce_qp.c
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,15 @@ static int hns_roce_set_kernel_sq_size(struct hns_roce_dev *hr_dev,
return 0;
}

static int hns_roce_qp_has_rq(struct ib_qp_init_attr *attr)
{
if (attr->qp_type == IB_QPT_XRC_INI ||
attr->qp_type == IB_QPT_XRC_TGT || attr->srq)
return 0;

return 1;
}

static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
struct ib_pd *ib_pd,
struct ib_qp_init_attr *init_attr,
Expand All @@ -497,6 +506,7 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
{
struct device *dev = hr_dev->dev;
struct hns_roce_ib_create_qp ucmd;
struct hns_roce_ib_create_qp_resp resp;
unsigned long qpn = 0;
int ret = 0;
u32 page_shift;
Expand Down Expand Up @@ -602,6 +612,18 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
dev_err(dev, "hns_roce_ib_umem_write_mtt error for create qp\n");
goto err_mtt;
}

if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB) &&
(udata->outlen == sizeof(resp)) &&
hns_roce_qp_has_rq(init_attr)) {
ret = hns_roce_db_map_user(
to_hr_ucontext(ib_pd->uobject->context),
ucmd.db_addr, &hr_qp->rdb);
if (ret) {
dev_err(dev, "rp record doorbell map failed!\n");
goto err_mtt;
}
}
} else {
if (init_attr->create_flags &
IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) {
Expand Down Expand Up @@ -698,17 +720,44 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
else
hr_qp->doorbell_qpn = cpu_to_le64(hr_qp->qpn);

if (ib_pd->uobject && (udata->outlen == sizeof(resp)) &&
(hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB)) {

/* indicate kernel supports record db */
resp.cap_flags |= HNS_ROCE_SUPPORT_RQ_RECORD_DB;
ret = ib_copy_to_udata(udata, &resp, sizeof(resp));
if (ret)
goto err_qp;

hr_qp->rdb_en = 1;
}
hr_qp->event = hns_roce_ib_qp_event;

return 0;

err_qp:
if (init_attr->qp_type == IB_QPT_GSI &&
hr_dev->hw_rev == HNS_ROCE_HW_VER1)
hns_roce_qp_remove(hr_dev, hr_qp);
else
hns_roce_qp_free(hr_dev, hr_qp);

err_qpn:
if (!sqpn)
hns_roce_release_range_qp(hr_dev, qpn, 1);

err_wrid:
kfree(hr_qp->sq.wrid);
kfree(hr_qp->rq.wrid);
if (ib_pd->uobject) {
if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB) &&
(udata->outlen == sizeof(resp)) &&
hns_roce_qp_has_rq(init_attr))
hns_roce_db_unmap_user(
to_hr_ucontext(ib_pd->uobject->context),
&hr_qp->rdb);
} else {
kfree(hr_qp->sq.wrid);
kfree(hr_qp->rq.wrid);
}

err_mtt:
hns_roce_mtt_cleanup(hr_dev, &hr_qp->mtt);
Expand Down
5 changes: 5 additions & 0 deletions include/uapi/rdma/hns-abi.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ struct hns_roce_ib_create_qp {
__u8 reserved[5];
};

struct hns_roce_ib_create_qp_resp {
__u64 cap_flags;
};

struct hns_roce_ib_alloc_ucontext_resp {
__u32 qp_tab_size;
__u32 reserved;
};
#endif /* HNS_ABI_USER_H */

0 comments on commit e088a68

Please sign in to comment.