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

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.comSigned-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
......@@ -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,
......
......@@ -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
......@@ -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);
kfree(entry);
}
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;
}
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;
if (!qedr_search_mmap(ucontext, phys_addr, len)) {
DP_ERR(dev, "failed mmap, vm_pgoff=0x%lx is not authorized\n",
vma->vm_pgoff);
return -EINVAL;
}
ibdev_dbg(dev,
"start %#lx, end %#lx, length = %#zx, pgoff = %#lx\n",
vma->vm_start, vma->vm_end, length, vma->vm_pgoff);
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);
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 (vma->vm_flags & VM_READ) {
DP_ERR(dev, "failed mmap, cannot map doorbell bar for read\n");
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;
}
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);
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);
rdma_user_mmap_entry_put(rdma_entry);
return rc;
}
int qedr_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment