Skip to content

Commit

Permalink
RDMA/vmw_pvrdma: Add shared receive queue support
Browse files Browse the repository at this point in the history
Add the required functions needed to support SRQs. Currently, kernel
clients are not supported. SRQs will only be available in userspace.

Reviewed-by: Adit Ranadive <aditr@vmware.com>
Reviewed-by: Aditya Sarwade <asarwade@vmware.com>
Reviewed-by: Jorgen Hansen <jhansen@vmware.com>
Reviewed-by: Nitish Bhat <bnitish@vmware.com>
Signed-off-by: Bryan Tan <bryantan@vmware.com>
Reviewed-by: Yuval Shaia <yuval.shaia@oracle.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
  • Loading branch information
Bryan Tan authored and Doug Ledford committed Nov 13, 2017
1 parent cb9fd89 commit 8b10ba7
Show file tree
Hide file tree
Showing 9 changed files with 523 additions and 14 deletions.
2 changes: 1 addition & 1 deletion drivers/infiniband/hw/vmw_pvrdma/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
obj-$(CONFIG_INFINIBAND_VMWARE_PVRDMA) += vmw_pvrdma.o

vmw_pvrdma-y := pvrdma_cmd.o pvrdma_cq.o pvrdma_doorbell.o pvrdma_main.o pvrdma_misc.o pvrdma_mr.o pvrdma_qp.o pvrdma_verbs.o
vmw_pvrdma-y := pvrdma_cmd.o pvrdma_cq.o pvrdma_doorbell.o pvrdma_main.o pvrdma_misc.o pvrdma_mr.o pvrdma_qp.o pvrdma_srq.o pvrdma_verbs.o
25 changes: 25 additions & 0 deletions drivers/infiniband/hw/vmw_pvrdma/pvrdma.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,22 @@ struct pvrdma_ah {
struct pvrdma_av av;
};

struct pvrdma_srq {
struct ib_srq ibsrq;
int offset;
spinlock_t lock; /* SRQ lock. */
int wqe_cnt;
int wqe_size;
int max_gs;
struct ib_umem *umem;
struct pvrdma_ring_state *ring;
struct pvrdma_page_dir pdir;
u32 srq_handle;
int npages;
refcount_t refcnt;
wait_queue_head_t wait;
};

struct pvrdma_qp {
struct ib_qp ibqp;
u32 qp_handle;
Expand All @@ -171,6 +187,7 @@ struct pvrdma_qp {
struct ib_umem *rumem;
struct ib_umem *sumem;
struct pvrdma_page_dir pdir;
struct pvrdma_srq *srq;
int npages;
int npages_send;
int npages_recv;
Expand Down Expand Up @@ -210,6 +227,8 @@ struct pvrdma_dev {
struct pvrdma_page_dir cq_pdir;
struct pvrdma_cq **cq_tbl;
spinlock_t cq_tbl_lock;
struct pvrdma_srq **srq_tbl;
spinlock_t srq_tbl_lock;
struct pvrdma_qp **qp_tbl;
spinlock_t qp_tbl_lock;
struct pvrdma_uar_table uar_table;
Expand All @@ -221,6 +240,7 @@ struct pvrdma_dev {
bool ib_active;
atomic_t num_qps;
atomic_t num_cqs;
atomic_t num_srqs;
atomic_t num_pds;
atomic_t num_ahs;

Expand Down Expand Up @@ -256,6 +276,11 @@ static inline struct pvrdma_cq *to_vcq(struct ib_cq *ibcq)
return container_of(ibcq, struct pvrdma_cq, ibcq);
}

static inline struct pvrdma_srq *to_vsrq(struct ib_srq *ibsrq)
{
return container_of(ibsrq, struct pvrdma_srq, ibsrq);
}

static inline struct pvrdma_user_mr *to_vmr(struct ib_mr *ibmr)
{
return container_of(ibmr, struct pvrdma_user_mr, ibmr);
Expand Down
54 changes: 54 additions & 0 deletions drivers/infiniband/hw/vmw_pvrdma/pvrdma_dev_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,10 @@ enum {
PVRDMA_CMD_DESTROY_UC,
PVRDMA_CMD_CREATE_BIND,
PVRDMA_CMD_DESTROY_BIND,
PVRDMA_CMD_CREATE_SRQ,
PVRDMA_CMD_MODIFY_SRQ,
PVRDMA_CMD_QUERY_SRQ,
PVRDMA_CMD_DESTROY_SRQ,
PVRDMA_CMD_MAX,
};

Expand All @@ -361,6 +365,10 @@ enum {
PVRDMA_CMD_DESTROY_UC_RESP_NOOP,
PVRDMA_CMD_CREATE_BIND_RESP_NOOP,
PVRDMA_CMD_DESTROY_BIND_RESP_NOOP,
PVRDMA_CMD_CREATE_SRQ_RESP,
PVRDMA_CMD_MODIFY_SRQ_RESP,
PVRDMA_CMD_QUERY_SRQ_RESP,
PVRDMA_CMD_DESTROY_SRQ_RESP,
PVRDMA_CMD_MAX_RESP,
};

Expand Down Expand Up @@ -495,6 +503,46 @@ struct pvrdma_cmd_destroy_cq {
u8 reserved[4];
};

struct pvrdma_cmd_create_srq {
struct pvrdma_cmd_hdr hdr;
u64 pdir_dma;
u32 pd_handle;
u32 nchunks;
struct pvrdma_srq_attr attrs;
u8 srq_type;
u8 reserved[7];
};

struct pvrdma_cmd_create_srq_resp {
struct pvrdma_cmd_resp_hdr hdr;
u32 srqn;
u8 reserved[4];
};

struct pvrdma_cmd_modify_srq {
struct pvrdma_cmd_hdr hdr;
u32 srq_handle;
u32 attr_mask;
struct pvrdma_srq_attr attrs;
};

struct pvrdma_cmd_query_srq {
struct pvrdma_cmd_hdr hdr;
u32 srq_handle;
u8 reserved[4];
};

struct pvrdma_cmd_query_srq_resp {
struct pvrdma_cmd_resp_hdr hdr;
struct pvrdma_srq_attr attrs;
};

struct pvrdma_cmd_destroy_srq {
struct pvrdma_cmd_hdr hdr;
u32 srq_handle;
u8 reserved[4];
};

struct pvrdma_cmd_create_qp {
struct pvrdma_cmd_hdr hdr;
u64 pdir_dma;
Expand Down Expand Up @@ -594,6 +642,10 @@ union pvrdma_cmd_req {
struct pvrdma_cmd_destroy_qp destroy_qp;
struct pvrdma_cmd_create_bind create_bind;
struct pvrdma_cmd_destroy_bind destroy_bind;
struct pvrdma_cmd_create_srq create_srq;
struct pvrdma_cmd_modify_srq modify_srq;
struct pvrdma_cmd_query_srq query_srq;
struct pvrdma_cmd_destroy_srq destroy_srq;
};

union pvrdma_cmd_resp {
Expand All @@ -608,6 +660,8 @@ union pvrdma_cmd_resp {
struct pvrdma_cmd_create_qp_resp create_qp_resp;
struct pvrdma_cmd_query_qp_resp query_qp_resp;
struct pvrdma_cmd_destroy_qp_resp destroy_qp_resp;
struct pvrdma_cmd_create_srq_resp create_srq_resp;
struct pvrdma_cmd_query_srq_resp query_srq_resp;
};

#endif /* __PVRDMA_DEV_API_H__ */
59 changes: 58 additions & 1 deletion drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ static int pvrdma_init_device(struct pvrdma_dev *dev)
spin_lock_init(&dev->cmd_lock);
sema_init(&dev->cmd_sema, 1);
atomic_set(&dev->num_qps, 0);
atomic_set(&dev->num_srqs, 0);
atomic_set(&dev->num_cqs, 0);
atomic_set(&dev->num_pds, 0);
atomic_set(&dev->num_ahs, 0);
Expand Down Expand Up @@ -254,9 +255,32 @@ static int pvrdma_register_device(struct pvrdma_dev *dev)
goto err_cq_free;
spin_lock_init(&dev->qp_tbl_lock);

/* Check if SRQ is supported by backend */
if (dev->dsr->caps.max_srq) {
dev->ib_dev.uverbs_cmd_mask |=
(1ull << IB_USER_VERBS_CMD_CREATE_SRQ) |
(1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) |
(1ull << IB_USER_VERBS_CMD_QUERY_SRQ) |
(1ull << IB_USER_VERBS_CMD_DESTROY_SRQ) |
(1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV);

dev->ib_dev.create_srq = pvrdma_create_srq;
dev->ib_dev.modify_srq = pvrdma_modify_srq;
dev->ib_dev.query_srq = pvrdma_query_srq;
dev->ib_dev.destroy_srq = pvrdma_destroy_srq;
dev->ib_dev.post_srq_recv = pvrdma_post_srq_recv;

dev->srq_tbl = kcalloc(dev->dsr->caps.max_srq,
sizeof(struct pvrdma_srq *),
GFP_KERNEL);
if (!dev->srq_tbl)
goto err_qp_free;
}
spin_lock_init(&dev->srq_tbl_lock);

ret = ib_register_device(&dev->ib_dev, NULL);
if (ret)
goto err_qp_free;
goto err_srq_free;

for (i = 0; i < ARRAY_SIZE(pvrdma_class_attributes); ++i) {
ret = device_create_file(&dev->ib_dev.dev,
Expand All @@ -271,6 +295,8 @@ static int pvrdma_register_device(struct pvrdma_dev *dev)

err_class:
ib_unregister_device(&dev->ib_dev);
err_srq_free:
kfree(dev->srq_tbl);
err_qp_free:
kfree(dev->qp_tbl);
err_cq_free:
Expand Down Expand Up @@ -353,6 +379,35 @@ static void pvrdma_cq_event(struct pvrdma_dev *dev, u32 cqn, int type)
}
}

static void pvrdma_srq_event(struct pvrdma_dev *dev, u32 srqn, int type)
{
struct pvrdma_srq *srq;
unsigned long flags;

spin_lock_irqsave(&dev->srq_tbl_lock, flags);
if (dev->srq_tbl)
srq = dev->srq_tbl[srqn % dev->dsr->caps.max_srq];
else
srq = NULL;
if (srq)
refcount_inc(&srq->refcnt);
spin_unlock_irqrestore(&dev->srq_tbl_lock, flags);

if (srq && srq->ibsrq.event_handler) {
struct ib_srq *ibsrq = &srq->ibsrq;
struct ib_event e;

e.device = ibsrq->device;
e.element.srq = ibsrq;
e.event = type; /* 1:1 mapping for now. */
ibsrq->event_handler(&e, ibsrq->srq_context);
}
if (srq) {
if (refcount_dec_and_test(&srq->refcnt))
wake_up(&srq->wait);
}
}

static void pvrdma_dispatch_event(struct pvrdma_dev *dev, int port,
enum ib_event_type event)
{
Expand Down Expand Up @@ -423,6 +478,7 @@ static irqreturn_t pvrdma_intr1_handler(int irq, void *dev_id)

case PVRDMA_EVENT_SRQ_ERR:
case PVRDMA_EVENT_SRQ_LIMIT_REACHED:
pvrdma_srq_event(dev, eqe->info, eqe->type);
break;

case PVRDMA_EVENT_PORT_ACTIVE:
Expand Down Expand Up @@ -1059,6 +1115,7 @@ static void pvrdma_pci_remove(struct pci_dev *pdev)
iounmap(dev->regs);
kfree(dev->sgid_tbl);
kfree(dev->cq_tbl);
kfree(dev->srq_tbl);
kfree(dev->qp_tbl);
pvrdma_uar_table_cleanup(dev);
iounmap(dev->driver_uar.map);
Expand Down
55 changes: 43 additions & 12 deletions drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ struct ib_qp *pvrdma_create_qp(struct ib_pd *pd,
struct pvrdma_create_qp ucmd;
unsigned long flags;
int ret;
bool is_srq = !!init_attr->srq;

if (init_attr->create_flags) {
dev_warn(&dev->pdev->dev,
Expand All @@ -214,6 +215,12 @@ struct ib_qp *pvrdma_create_qp(struct ib_pd *pd,
return ERR_PTR(-EINVAL);
}

if (is_srq && !dev->dsr->caps.max_srq) {
dev_warn(&dev->pdev->dev,
"SRQs not supported by device\n");
return ERR_PTR(-EINVAL);
}

if (!atomic_add_unless(&dev->num_qps, 1, dev->dsr->caps.max_qp))
return ERR_PTR(-ENOMEM);

Expand Down Expand Up @@ -252,26 +259,36 @@ struct ib_qp *pvrdma_create_qp(struct ib_pd *pd,
goto err_qp;
}

/* set qp->sq.wqe_cnt, shift, buf_size.. */
qp->rumem = ib_umem_get(pd->uobject->context,
ucmd.rbuf_addr,
ucmd.rbuf_size, 0, 0);
if (IS_ERR(qp->rumem)) {
ret = PTR_ERR(qp->rumem);
goto err_qp;
if (!is_srq) {
/* set qp->sq.wqe_cnt, shift, buf_size.. */
qp->rumem = ib_umem_get(pd->uobject->context,
ucmd.rbuf_addr,
ucmd.rbuf_size, 0, 0);
if (IS_ERR(qp->rumem)) {
ret = PTR_ERR(qp->rumem);
goto err_qp;
}
qp->srq = NULL;
} else {
qp->rumem = NULL;
qp->srq = to_vsrq(init_attr->srq);
}

qp->sumem = ib_umem_get(pd->uobject->context,
ucmd.sbuf_addr,
ucmd.sbuf_size, 0, 0);
if (IS_ERR(qp->sumem)) {
ib_umem_release(qp->rumem);
if (!is_srq)
ib_umem_release(qp->rumem);
ret = PTR_ERR(qp->sumem);
goto err_qp;
}

qp->npages_send = ib_umem_page_count(qp->sumem);
qp->npages_recv = ib_umem_page_count(qp->rumem);
if (!is_srq)
qp->npages_recv = ib_umem_page_count(qp->rumem);
else
qp->npages_recv = 0;
qp->npages = qp->npages_send + qp->npages_recv;
} else {
qp->is_kernel = true;
Expand Down Expand Up @@ -312,12 +329,14 @@ struct ib_qp *pvrdma_create_qp(struct ib_pd *pd,

if (!qp->is_kernel) {
pvrdma_page_dir_insert_umem(&qp->pdir, qp->sumem, 0);
pvrdma_page_dir_insert_umem(&qp->pdir, qp->rumem,
qp->npages_send);
if (!is_srq)
pvrdma_page_dir_insert_umem(&qp->pdir,
qp->rumem,
qp->npages_send);
} else {
/* Ring state is always the first page. */
qp->sq.ring = qp->pdir.pages[0];
qp->rq.ring = &qp->sq.ring[1];
qp->rq.ring = is_srq ? NULL : &qp->sq.ring[1];
}
break;
default:
Expand All @@ -333,13 +352,19 @@ struct ib_qp *pvrdma_create_qp(struct ib_pd *pd,
cmd->pd_handle = to_vpd(pd)->pd_handle;
cmd->send_cq_handle = to_vcq(init_attr->send_cq)->cq_handle;
cmd->recv_cq_handle = to_vcq(init_attr->recv_cq)->cq_handle;
if (is_srq)
cmd->srq_handle = to_vsrq(init_attr->srq)->srq_handle;
else
cmd->srq_handle = 0;
cmd->max_send_wr = init_attr->cap.max_send_wr;
cmd->max_recv_wr = init_attr->cap.max_recv_wr;
cmd->max_send_sge = init_attr->cap.max_send_sge;
cmd->max_recv_sge = init_attr->cap.max_recv_sge;
cmd->max_inline_data = init_attr->cap.max_inline_data;
cmd->sq_sig_all = (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) ? 1 : 0;
cmd->qp_type = ib_qp_type_to_pvrdma(init_attr->qp_type);
cmd->is_srq = is_srq;
cmd->lkey = 0;
cmd->access_flags = IB_ACCESS_LOCAL_WRITE;
cmd->total_chunks = qp->npages;
cmd->send_chunks = qp->npages_send - PVRDMA_QP_NUM_HEADER_PAGES;
Expand Down Expand Up @@ -815,6 +840,12 @@ int pvrdma_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
return -EINVAL;
}

if (qp->srq) {
dev_warn(&dev->pdev->dev, "QP associated with SRQ\n");
*bad_wr = wr;
return -EINVAL;
}

spin_lock_irqsave(&qp->rq.lock, flags);

while (wr) {
Expand Down
Loading

0 comments on commit 8b10ba7

Please sign in to comment.