Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8b10ba78 authored by Bryan Tan's avatar Bryan Tan Committed by Doug Ledford
Browse files

RDMA/vmw_pvrdma: Add shared receive queue support



Add the required functions needed to support SRQs. Currently, kernel
clients are not supported. SRQs will only be available in userspace.

Reviewed-by: default avatarAdit Ranadive <aditr@vmware.com>
Reviewed-by: default avatarAditya Sarwade <asarwade@vmware.com>
Reviewed-by: default avatarJorgen Hansen <jhansen@vmware.com>
Reviewed-by: default avatarNitish Bhat <bnitish@vmware.com>
Signed-off-by: default avatarBryan Tan <bryantan@vmware.com>
Reviewed-by: default avatarYuval Shaia <yuval.shaia@oracle.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent cb9fd89f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
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 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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;

@@ -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);
+54 −0
Original line number Diff line number Diff line
@@ -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,
};

@@ -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,
};

@@ -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;
@@ -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 {
@@ -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__ */
+58 −1
Original line number Diff line number Diff line
@@ -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);
@@ -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,
@@ -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:
@@ -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)
{
@@ -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:
@@ -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);
+43 −12
Original line number Diff line number Diff line
@@ -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,
@@ -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);

@@ -252,6 +259,7 @@ struct ib_qp *pvrdma_create_qp(struct ib_pd *pd,
				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,
@@ -260,18 +268,27 @@ struct ib_qp *pvrdma_create_qp(struct ib_pd *pd,
					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)) {
				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);
			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;
@@ -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,
			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:
@@ -333,6 +352,10 @@ 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;
@@ -340,6 +363,8 @@ struct ib_qp *pvrdma_create_qp(struct ib_pd *pd,
	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;
@@ -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) {
Loading