Commit 4c6bb02d authored by Michal Kalderon's avatar Michal Kalderon Committed by Jason Gunthorpe
Browse files

RDMA/qedr: Use the common mmap API

Remove all functions related to mmap from qedr and use the common API.

Link: https://lore.kernel.org/r/20191030094417.16866-7-michal.kalderon@marvell.com


Signed-off-by: default avatarAriel Elior <ariel.elior@marvell.com>
Signed-off-by: default avatarMichal Kalderon <michal.kalderon@marvell.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@mellanox.com>
parent 11f1a755
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -212,6 +212,7 @@ static const struct ib_device_ops qedr_dev_ops = {
	.get_link_layer = qedr_link_layer,
	.map_mr_sg = qedr_map_mr_sg,
	.mmap = qedr_mmap,
	.mmap_free = qedr_mmap_free,
	.modify_port = qedr_modify_port,
	.modify_qp = qedr_modify_qp,
	.modify_srq = qedr_modify_srq,
+17 −13
Original line number Diff line number Diff line
@@ -231,14 +231,10 @@ struct qedr_ucontext {
	struct qedr_dev *dev;
	struct qedr_pd *pd;
	void __iomem *dpi_addr;
	struct rdma_user_mmap_entry *db_mmap_entry;
	u64 dpi_phys_addr;
	u32 dpi_size;
	u16 dpi;

	struct list_head mm_head;

	/* Lock to protect mm list */
	struct mutex mm_list_lock;
};

union db_prod64 {
@@ -301,14 +297,6 @@ struct qedr_pd {
	struct qedr_ucontext *uctx;
};

struct qedr_mm {
	struct {
		u64 phy_addr;
		unsigned long len;
	} key;
	struct list_head entry;
};

union db_prod32 {
	struct rdma_pwm_val16_data data;
	u32 raw;
@@ -491,6 +479,15 @@ struct qedr_mr {
	u32 npages;
};

struct qedr_user_mmap_entry {
	struct rdma_user_mmap_entry rdma_entry;
	struct qedr_dev *dev;
	u64 io_address;
	size_t length;
	u16 dpi;
	u8 mmap_flag;
};

#define SET_FIELD2(value, name, flag) ((value) |= ((flag) << (name ## _SHIFT)))

#define QEDR_RESP_IMM	(RDMA_CQE_RESPONDER_IMM_FLG_MASK << \
@@ -589,4 +586,11 @@ static inline struct qedr_srq *get_qedr_srq(struct ib_srq *ibsrq)
{
	return container_of(ibsrq, struct qedr_srq, ibsrq);
}

static inline struct qedr_user_mmap_entry *
get_qedr_mmap_entry(struct rdma_user_mmap_entry *rdma_entry)
{
	return container_of(rdma_entry, struct qedr_user_mmap_entry,
			    rdma_entry);
}
#endif
+78 −107
Original line number Diff line number Diff line
@@ -59,6 +59,10 @@

#define DB_ADDR_SHIFT(addr)		((addr) << DB_PWM_ADDR_OFFSET_SHIFT)

enum {
	QEDR_USER_MMAP_IO_WC = 0,
};

static inline int qedr_ib_copy_to_udata(struct ib_udata *udata, void *src,
					size_t len)
{
@@ -257,60 +261,6 @@ int qedr_modify_port(struct ib_device *ibdev, u8 port, int mask,
	return 0;
}

static int qedr_add_mmap(struct qedr_ucontext *uctx, u64 phy_addr,
			 unsigned long len)
{
	struct qedr_mm *mm;

	mm = kzalloc(sizeof(*mm), GFP_KERNEL);
	if (!mm)
		return -ENOMEM;

	mm->key.phy_addr = phy_addr;
	/* This function might be called with a length which is not a multiple
	 * of PAGE_SIZE, while the mapping is PAGE_SIZE grained and the kernel
	 * forces this granularity by increasing the requested size if needed.
	 * When qedr_mmap is called, it will search the list with the updated
	 * length as a key. To prevent search failures, the length is rounded up
	 * in advance to PAGE_SIZE.
	 */
	mm->key.len = roundup(len, PAGE_SIZE);
	INIT_LIST_HEAD(&mm->entry);

	mutex_lock(&uctx->mm_list_lock);
	list_add(&mm->entry, &uctx->mm_head);
	mutex_unlock(&uctx->mm_list_lock);

	DP_DEBUG(uctx->dev, QEDR_MSG_MISC,
		 "added (addr=0x%llx,len=0x%lx) for ctx=%p\n",
		 (unsigned long long)mm->key.phy_addr,
		 (unsigned long)mm->key.len, uctx);

	return 0;
}

static bool qedr_search_mmap(struct qedr_ucontext *uctx, u64 phy_addr,
			     unsigned long len)
{
	bool found = false;
	struct qedr_mm *mm;

	mutex_lock(&uctx->mm_list_lock);
	list_for_each_entry(mm, &uctx->mm_head, entry) {
		if (len != mm->key.len || phy_addr != mm->key.phy_addr)
			continue;

		found = true;
		break;
	}
	mutex_unlock(&uctx->mm_list_lock);
	DP_DEBUG(uctx->dev, QEDR_MSG_MISC,
		 "searched for (addr=0x%llx,len=0x%lx) for ctx=%p, result=%d\n",
		 mm->key.phy_addr, mm->key.len, uctx, found);

	return found;
}

int qedr_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata)
{
	struct ib_device *ibdev = uctx->device;
@@ -319,6 +269,7 @@ int qedr_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata)
	struct qedr_alloc_ucontext_resp uresp = {};
	struct qedr_dev *dev = get_qedr_dev(ibdev);
	struct qed_rdma_add_user_out_params oparams;
	struct qedr_user_mmap_entry *entry;

	if (!udata)
		return -EFAULT;
@@ -335,13 +286,29 @@ int qedr_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata)
	ctx->dpi_addr = oparams.dpi_addr;
	ctx->dpi_phys_addr = oparams.dpi_phys_addr;
	ctx->dpi_size = oparams.dpi_size;
	INIT_LIST_HEAD(&ctx->mm_head);
	mutex_init(&ctx->mm_list_lock);
	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
	if (!entry) {
		rc = -ENOMEM;
		goto err;
	}

	entry->io_address = ctx->dpi_phys_addr;
	entry->length = ctx->dpi_size;
	entry->mmap_flag = QEDR_USER_MMAP_IO_WC;
	entry->dpi = ctx->dpi;
	entry->dev = dev;
	rc = rdma_user_mmap_entry_insert(uctx, &entry->rdma_entry,
					 ctx->dpi_size);
	if (rc) {
		kfree(entry);
		goto err;
	}
	ctx->db_mmap_entry = &entry->rdma_entry;

	uresp.dpm_enabled = dev->user_dpm_enabled;
	uresp.wids_enabled = 1;
	uresp.wid_count = oparams.wid_count;
	uresp.db_pa = ctx->dpi_phys_addr;
	uresp.db_pa = rdma_user_mmap_get_offset(ctx->db_mmap_entry);
	uresp.db_size = ctx->dpi_size;
	uresp.max_send_wr = dev->attr.max_sqe;
	uresp.max_recv_wr = dev->attr.max_rqe;
@@ -353,82 +320,86 @@ int qedr_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata)

	rc = qedr_ib_copy_to_udata(udata, &uresp, sizeof(uresp));
	if (rc)
		return rc;
		goto err;

	ctx->dev = dev;

	rc = qedr_add_mmap(ctx, ctx->dpi_phys_addr, ctx->dpi_size);
	if (rc)
		return rc;

	DP_DEBUG(dev, QEDR_MSG_INIT, "Allocating user context %p\n",
		 &ctx->ibucontext);
	return 0;

err:
	if (!ctx->db_mmap_entry)
		dev->ops->rdma_remove_user(dev->rdma_ctx, ctx->dpi);
	else
		rdma_user_mmap_entry_remove(ctx->db_mmap_entry);

	return rc;
}

void qedr_dealloc_ucontext(struct ib_ucontext *ibctx)
{
	struct qedr_ucontext *uctx = get_qedr_ucontext(ibctx);
	struct qedr_mm *mm, *tmp;

	DP_DEBUG(uctx->dev, QEDR_MSG_INIT, "Deallocating user context %p\n",
		 uctx);
	uctx->dev->ops->rdma_remove_user(uctx->dev->rdma_ctx, uctx->dpi);

	list_for_each_entry_safe(mm, tmp, &uctx->mm_head, entry) {
		DP_DEBUG(uctx->dev, QEDR_MSG_MISC,
			 "deleted (addr=0x%llx,len=0x%lx) for ctx=%p\n",
			 mm->key.phy_addr, mm->key.len, uctx);
		list_del(&mm->entry);
		kfree(mm);
	}
	rdma_user_mmap_entry_remove(uctx->db_mmap_entry);
}

int qedr_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
void qedr_mmap_free(struct rdma_user_mmap_entry *rdma_entry)
{
	struct qedr_ucontext *ucontext = get_qedr_ucontext(context);
	struct qedr_dev *dev = get_qedr_dev(context->device);
	unsigned long phys_addr = vma->vm_pgoff << PAGE_SHIFT;
	unsigned long len = (vma->vm_end - vma->vm_start);
	unsigned long dpi_start;
	struct qedr_user_mmap_entry *entry = get_qedr_mmap_entry(rdma_entry);
	struct qedr_dev *dev = entry->dev;

	dpi_start = dev->db_phys_addr + (ucontext->dpi * ucontext->dpi_size);
	if (entry->mmap_flag == QEDR_USER_MMAP_IO_WC)
		dev->ops->rdma_remove_user(dev->rdma_ctx, entry->dpi);

	DP_DEBUG(dev, QEDR_MSG_INIT,
		 "mmap invoked with vm_start=0x%pK, vm_end=0x%pK,vm_pgoff=0x%pK; dpi_start=0x%pK dpi_size=0x%x\n",
		 (void *)vma->vm_start, (void *)vma->vm_end,
		 (void *)vma->vm_pgoff, (void *)dpi_start, ucontext->dpi_size);

	if ((vma->vm_start & (PAGE_SIZE - 1)) || (len & (PAGE_SIZE - 1))) {
		DP_ERR(dev,
		       "failed mmap, addresses must be page aligned: start=0x%pK, end=0x%pK\n",
		       (void *)vma->vm_start, (void *)vma->vm_end);
		return -EINVAL;
	kfree(entry);
}

	if (!qedr_search_mmap(ucontext, phys_addr, len)) {
		DP_ERR(dev, "failed mmap, vm_pgoff=0x%lx is not authorized\n",
int qedr_mmap(struct ib_ucontext *ucontext, struct vm_area_struct *vma)
{
	struct ib_device *dev = ucontext->device;
	size_t length = vma->vm_end - vma->vm_start;
	struct rdma_user_mmap_entry *rdma_entry;
	struct qedr_user_mmap_entry *entry;
	int rc = 0;
	u64 pfn;

	ibdev_dbg(dev,
		  "start %#lx, end %#lx, length = %#zx, pgoff = %#lx\n",
		  vma->vm_start, vma->vm_end, length, vma->vm_pgoff);

	rdma_entry = rdma_user_mmap_entry_get(ucontext, vma);
	if (!rdma_entry) {
		ibdev_dbg(dev, "pgoff[%#lx] does not have valid entry\n",
			  vma->vm_pgoff);
		return -EINVAL;
	}

	if (phys_addr < dpi_start ||
	    ((phys_addr + len) > (dpi_start + ucontext->dpi_size))) {
		DP_ERR(dev,
		       "failed mmap, pages are outside of dpi; page address=0x%pK, dpi_start=0x%pK, dpi_size=0x%x\n",
		       (void *)phys_addr, (void *)dpi_start,
		       ucontext->dpi_size);
		return -EINVAL;
	entry = get_qedr_mmap_entry(rdma_entry);
	ibdev_dbg(dev,
		  "Mapping address[%#llx], length[%#zx], mmap_flag[%d]\n",
		  entry->io_address, length, entry->mmap_flag);

	switch (entry->mmap_flag) {
	case QEDR_USER_MMAP_IO_WC:
		pfn = entry->io_address >> PAGE_SHIFT;
		rc = rdma_user_mmap_io(ucontext, vma, pfn, length,
				       pgprot_writecombine(vma->vm_page_prot),
				       rdma_entry);
		break;
	default:
		rc = -EINVAL;
	}

	if (vma->vm_flags & VM_READ) {
		DP_ERR(dev, "failed mmap, cannot map doorbell bar for read\n");
		return -EINVAL;
	}
	if (rc)
		ibdev_dbg(dev,
			  "Couldn't mmap address[%#llx] length[%#zx] mmap_flag[%d] err[%d]\n",
			  entry->io_address, length, entry->mmap_flag, rc);

	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
	return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, len,
				  vma->vm_page_prot);
	rdma_user_mmap_entry_put(rdma_entry);
	return rc;
}

int qedr_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
+2 −1
Original line number Diff line number Diff line
@@ -46,7 +46,8 @@ int qedr_query_pkey(struct ib_device *, u8 port, u16 index, u16 *pkey);
int qedr_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata);
void qedr_dealloc_ucontext(struct ib_ucontext *uctx);

int qedr_mmap(struct ib_ucontext *, struct vm_area_struct *vma);
int qedr_mmap(struct ib_ucontext *ucontext, struct vm_area_struct *vma);
void qedr_mmap_free(struct rdma_user_mmap_entry *rdma_entry);
int qedr_alloc_pd(struct ib_pd *pd, struct ib_udata *udata);
void qedr_dealloc_pd(struct ib_pd *pd, struct ib_udata *udata);