forked from Minki/linux
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: Ariel Elior <ariel.elior@marvell.com> Signed-off-by: Michal Kalderon <michal.kalderon@marvell.com> Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
This commit is contained in:
parent
11f1a75567
commit
4c6bb02d59
@ -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);
|
||||
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;
|
||||
}
|
||||
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);
|
||||
|
||||
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;
|
||||
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 (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;
|
||||
}
|
||||
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);
|
||||
|
||||
if (vma->vm_flags & VM_READ) {
|
||||
DP_ERR(dev, "failed mmap, cannot map doorbell bar for read\n");
|
||||
return -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);
|
||||
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user