// SPDX-License-Identifier: GPL-2.0/* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */ #include <linux/module.h>#include <linux/printk.h>#include <rdma/ib_addr.h>#include <rdma/ib_cache.h>#include <rdma/ib_user_verbs.h>#include <ionic_api.h> #include "ionic_fw.h"#include "ionic_ibdev.h" #define ionic_set_ecn(tos) (((tos) | 2u) & ~1u)#define ionic_clear_ecn(tos) ((tos) & ~3u) static int ionic_validate_qdesc(struct ionic_qdesc *q){ if (!q->addr || !q->size || !q->mask || !q->depth_log2 || !q->stride_log2) return -EINVAL; if (q->addr & (PAGE_SIZE - 1)) return -EINVAL; if (q->mask != BIT(q->depth_log2) - 1) return -EINVAL; if (q->size < BIT_ULL(q->depth_log2 + q->stride_log2)) return -EINVAL; return 0;} static u32 ionic_get_eqid(struct ionic_ibdev *dev, u32 comp_vector, u8 udma_idx){ /* EQ per vector per udma, and the first eqs reserved for async events. * The rest of the vectors can be requested for completions. */ u32 comp_vec_count = dev->lif_cfg.eq_count / dev->lif_cfg.udma_count - 1; return (comp_vector % comp_vec_count + 1) * dev->lif_cfg.udma_count + udma_idx;} static int ionic_get_cqid(struct ionic_ibdev *dev, u32 *cqid, u8 udma_idx){ unsigned int size, base, bound; int rc; size = dev->lif_cfg.cq_count / dev->lif_cfg.udma_count; base = size * udma_idx; bound = base + size; rc = ionic_resid_get_shared(&dev->inuse_cqid, base, bound); if (rc >= 0) { /* cq_base is zero or a multiple of two queue groups */ *cqid = dev->lif_cfg.cq_base + ionic_bitid_to_qid(rc, dev->lif_cfg.udma_qgrp_shift, dev->half_cqid_udma_shift); rc = 0; } return rc;} static void ionic_put_cqid(struct ionic_ibdev *dev, u32 cqid){ u32 bitid = ionic_qid_to_bitid(cqid - dev->lif_cfg.cq_base, dev->lif_cfg.udma_qgrp_shift, dev->half_cqid_udma_shift); ionic_resid_put(&dev->inuse_cqid, bitid);} int ionic_create_cq_common(struct ionic_vcq *vcq, struct ionic_tbl_buf *buf, const struct ib_cq_init_attr *attr, struct ionic_ctx *ctx, struct ib_udata *udata, struct ionic_qdesc *req_cq, __u32 *resp_cqid, int udma_idx){ struct ionic_ibdev *dev = to_ionic_ibdev(vcq->ibcq.device); struct ionic_cq *cq = &vcq->cq[udma_idx]; void *entry; int rc; cq->vcq = vcq; if (attr->cqe < 1 || attr->cqe + IONIC_CQ_GRACE > 0xffff) { rc = -EINVAL; goto err_args; } rc = ionic_get_cqid(dev, &cq->cqid, udma_idx); if (rc) goto err_args; cq->eqid = ionic_get_eqid(dev, attr->comp_vector, udma_idx); spin_lock_init(&cq->lock); INIT_LIST_HEAD(&cq->poll_sq); INIT_LIST_HEAD(&cq->flush_sq); INIT_LIST_HEAD(&cq->flush_rq); if (udata) { rc = ionic_validate_qdesc(req_cq); if (rc) goto err_qdesc; cq->umem = ib_umem_get_va(&dev->ibdev, req_cq->addr, req_cq->size, IB_ACCESS_LOCAL_WRITE); if (IS_ERR(cq->umem)) { rc = PTR_ERR(cq->umem); goto err_qdesc; } cq->q.ptr = NULL; cq->q.size = req_cq->size; cq->q.mask = req_cq->mask; cq->q.depth_log2 = req_cq->depth_log2; cq->q.stride_log2 = req_cq->stride_log2; *resp_cqid = cq->cqid; } else { rc = ionic_queue_init(&cq->q, dev->lif_cfg.hwdev, attr->cqe + IONIC_CQ_GRACE, sizeof(struct ionic_v1_cqe)); if (rc) goto err_q_init; ionic_queue_dbell_init(&cq->q, cq->cqid); cq->color = true; cq->credit = cq->q.mask; } rc = ionic_pgtbl_init(dev, buf, cq->umem, cq->q.dma, 1, PAGE_SIZE); if (rc) goto err_pgtbl_init; init_completion(&cq->cq_rel_comp); kref_init(&cq->cq_kref); entry = xa_store_irq(&dev->cq_tbl, cq->cqid, cq, GFP_KERNEL); if (entry) { if (!xa_is_err(entry)) rc = -EINVAL; else rc = xa_err(entry); goto err_xa; } return 0; err_xa: ionic_pgtbl_unbuf(dev, buf);err_pgtbl_init: if (!udata) ionic_queue_destroy(&cq->q, dev->lif_cfg.hwdev);err_q_init: if (cq->umem) ib_umem_release(cq->umem);err_qdesc: ionic_put_cqid(dev, cq->cqid);err_args: cq->vcq = NULL; return rc;} void ionic_destroy_cq_common(struct ionic_ibdev *dev, struct ionic_cq *cq){ if (!cq->vcq) return; xa_erase_irq(&dev->cq_tbl, cq->cqid); kref_put(&cq->cq_kref, ionic_cq_complete); wait_for_completion(&cq->cq_rel_comp); if (cq->umem) ib_umem_release(cq->umem); else ionic_queue_destroy(&cq->q, dev->lif_cfg.hwdev); ionic_put_cqid(dev, cq->cqid); cq->vcq = NULL;} static int ionic_validate_qdesc_zero(struct ionic_qdesc *q){ if (q->addr || q->size || q->mask || q->depth_log2 || q->stride_log2) return -EINVAL; return 0;} static int ionic_get_pdid(struct ionic_ibdev *dev, u32 *pdid){ int rc; rc = ionic_resid_get(&dev->inuse_pdid); if (rc < 0) return rc; *pdid = rc; return 0;} static int ionic_get_ahid(struct ionic_ibdev *dev, u32 *ahid){ int rc; rc = ionic_resid_get(&dev->inuse_ahid); if (rc < 0) return rc; *ahid = rc; return 0;} static int ionic_get_mrid(struct ionic_ibdev *dev, u32 *mrid){ int rc; /* wrap to 1, skip reserved lkey */ rc = ionic_resid_get_shared(&dev->inuse_mrid, 1, dev->inuse_mrid.inuse_size); if (rc < 0) return rc; *mrid = ionic_mrid(rc, dev->next_mrkey++); return 0;} static int ionic_get_gsi_qpid(struct ionic_ibdev *dev, u32 *qpid){ int rc = 0; rc = ionic_resid_get_shared(&dev->inuse_qpid, IB_QPT_GSI, IB_QPT_GSI + 1); if (rc < 0) return rc; *qpid = IB_QPT_GSI; return 0;} static int ionic_get_qpid(struct ionic_ibdev *dev, u32 *qpid, u8 *udma_idx, u8 udma_mask){ unsigned int size, base, bound; int udma_i, udma_x, udma_ix; int rc = -EINVAL; udma_x = dev->next_qpid_udma_idx; dev->next_qpid_udma_idx ^= dev->lif_cfg.udma_count - 1; for (udma_i = 0; udma_i < dev->lif_cfg.udma_count; ++udma_i) { udma_ix = udma_i ^ udma_x; if (!(udma_mask & BIT(udma_ix))) continue; size = dev->lif_cfg.qp_count / dev->lif_cfg.udma_count; base = size * udma_ix; bound = base + size; /* skip reserved SMI and GSI qpids in group zero */ if (!base) base = 2; rc = ionic_resid_get_shared(&dev->inuse_qpid, base, bound); if (rc >= 0) { *qpid = ionic_bitid_to_qid(rc, dev->lif_cfg.udma_qgrp_shift, dev->half_qpid_udma_shift); *udma_idx = udma_ix; rc = 0; break; } } return rc;} static int ionic_get_dbid(struct ionic_ibdev *dev, u32 *dbid, phys_addr_t *addr){ int rc, dbpage_num; /* wrap to 1, skip kernel reserved */ rc = ionic_resid_get_shared(&dev->inuse_dbid, 1, dev->inuse_dbid.inuse_size); if (rc < 0) return rc; dbpage_num = (dev->lif_cfg.lif_hw_index * dev->lif_cfg.dbid_count) + rc; *addr = dev->lif_cfg.db_phys + ((phys_addr_t)dbpage_num << PAGE_SHIFT); *dbid = rc; return 0;} static void ionic_put_pdid(struct ionic_ibdev *dev, u32 pdid){ ionic_resid_put(&dev->inuse_pdid, pdid);} static void ionic_put_ahid(struct ionic_ibdev *dev, u32 ahid){ ionic_resid_put(&dev->inuse_ahid, ahid);} static void ionic_put_mrid(struct ionic_ibdev *dev, u32 mrid){ ionic_resid_put(&dev->inuse_mrid, ionic_mrid_index(mrid));} static void ionic_put_qpid(struct ionic_ibdev *dev, u32 qpid){ u32 bitid = ionic_qid_to_bitid(qpid, dev->lif_cfg.udma_qgrp_shift, dev->half_qpid_udma_shift); ionic_resid_put(&dev->inuse_qpid, bitid);} static void ionic_put_dbid(struct ionic_ibdev *dev, u32 dbid){ ionic_resid_put(&dev->inuse_dbid, dbid);} static struct rdma_user_mmap_entry*ionic_mmap_entry_insert(struct ionic_ctx *ctx, unsigned long size, unsigned long pfn, u8 mmap_flags, u64 *offset){ struct ionic_mmap_entry *entry; int rc; entry = kzalloc_obj(*entry); if (!entry) return NULL; entry->size = size; entry->pfn = pfn; entry->mmap_flags = mmap_flags; rc = rdma_user_mmap_entry_insert(&ctx->ibctx, &entry->rdma_entry, entry->size); if (rc) { kfree(entry); return NULL; } if (offset) *offset = rdma_user_mmap_get_offset(&entry->rdma_entry); return &entry->rdma_entry;} int ionic_alloc_ucontext(struct ib_ucontext *ibctx, struct ib_udata *udata){ struct ionic_ibdev *dev = to_ionic_ibdev(ibctx->device); struct ionic_ctx *ctx = to_ionic_ctx(ibctx); struct ionic_ctx_resp resp = {}; struct ionic_ctx_req req; phys_addr_t db_phys = 0; int rc; rc = ib_copy_validate_udata_in(udata, req, rsvd); if (rc) return rc; /* try to allocate dbid for user ctx */ rc = ionic_get_dbid(dev, &ctx->dbid, &db_phys); if (rc < 0) return rc; ibdev_dbg(&dev->ibdev, "user space dbid %u\n", ctx->dbid); ctx->mmap_dbell = ionic_mmap_entry_insert(ctx, PAGE_SIZE, PHYS_PFN(db_phys), 0, NULL); if (!ctx->mmap_dbell) { rc = -ENOMEM; goto err_mmap_dbell; } if (dev->lif_cfg.phc_state) { ctx->mmap_phc = ionic_mmap_entry_insert(ctx, PAGE_SIZE, 0, IONIC_MMAP_PHC, &resp.phc_offset); if (!ctx->mmap_phc) { rc = -ENOMEM; goto err_mmap_phc; } } resp.page_shift = PAGE_SHIFT; resp.dbell_offset = db_phys & ~PAGE_MASK; resp.version = dev->lif_cfg.rdma_version; resp.qp_opcodes = dev->lif_cfg.qp_opcodes; resp.admin_opcodes = dev->lif_cfg.admin_opcodes; resp.sq_qtype = dev->lif_cfg.sq_qtype; resp.rq_qtype = dev->lif_cfg.rq_qtype; resp.cq_qtype = dev->lif_cfg.cq_qtype; resp.admin_qtype = dev->lif_cfg.aq_qtype; resp.max_stride = dev->lif_cfg.max_stride; resp.max_spec = IONIC_SPEC_HIGH; resp.udma_count = dev->lif_cfg.udma_count; resp.expdb_mask = dev->lif_cfg.expdb_mask; if (dev->lif_cfg.sq_expdb) resp.expdb_qtypes |= IONIC_EXPDB_SQ; if (dev->lif_cfg.rq_expdb) resp.expdb_qtypes |= IONIC_EXPDB_RQ; rc = ib_respond_udata(udata, resp); if (rc) goto err_resp; return 0; err_resp: rdma_user_mmap_entry_remove(ctx->mmap_phc);err_mmap_phc: rdma_user_mmap_entry_remove(ctx->mmap_dbell);err_mmap_dbell: ionic_put_dbid(dev, ctx->dbid); return rc;} void ionic_dealloc_ucontext(struct ib_ucontext *ibctx){ struct ionic_ibdev *dev = to_ionic_ibdev(ibctx->device); struct ionic_ctx *ctx = to_ionic_ctx(ibctx); rdma_user_mmap_entry_remove(ctx->mmap_phc); rdma_user_mmap_entry_remove(ctx->mmap_dbell); ionic_put_dbid(dev, ctx->dbid);} static int ionic_mmap_phc_state(struct ionic_ibdev *dev, struct vm_area_struct *vma){ if (!(vma->vm_flags & VM_SHARED)) return -EINVAL; if (vma->vm_flags & (VM_WRITE | VM_EXEC)) return -EPERM; vm_flags_clear(vma, VM_MAYWRITE); return vm_insert_page(vma, vma->vm_start, virt_to_page(dev->lif_cfg.phc_state));} int ionic_mmap(struct ib_ucontext *ibctx, struct vm_area_struct *vma){ struct ionic_ibdev *dev = to_ionic_ibdev(ibctx->device); struct ionic_ctx *ctx = to_ionic_ctx(ibctx); struct rdma_user_mmap_entry *rdma_entry; struct ionic_mmap_entry *ionic_entry; int rc = 0; rdma_entry = rdma_user_mmap_entry_get(&ctx->ibctx, vma); if (!rdma_entry) { ibdev_dbg(&dev->ibdev, "not found %#lx\n", vma->vm_pgoff << PAGE_SHIFT); return -EINVAL; } ionic_entry = container_of(rdma_entry, struct ionic_mmap_entry, rdma_entry); if (ionic_entry->mmap_flags & IONIC_MMAP_PHC) { rc = ionic_mmap_phc_state(dev, vma); rdma_user_mmap_entry_put(rdma_entry); return rc; } ibdev_dbg(&dev->ibdev, "writecombine? %d\n", ionic_entry->mmap_flags & IONIC_MMAP_WC); if (ionic_entry->mmap_flags & IONIC_MMAP_WC) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); else vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ibdev_dbg(&dev->ibdev, "remap st %#lx pf %#lx sz %#lx\n", vma->vm_start, ionic_entry->pfn, ionic_entry->size);Lines 1–500 of 2768. Load more
// SPDX-License-Identifier: GPL-2.0 /* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */ #include <linux/module.h> #include <linux/printk.h> #include <rdma/ib_addr.h> #include <rdma/ib_cache.h> #include <rdma/ib_user_verbs.h> #include <ionic_api.h> #include "ionic_fw.h" #include "ionic_ibdev.h" #define ionic_set_ecn(tos) (((tos) | 2u) & ~1u) #define ionic_clear_ecn(tos) ((tos) & ~3u) static int ionic_validate_qdesc(struct ionic_qdesc *q) { if (!q->addr || !q->size || !q->mask || !q->depth_log2 || !q->stride_log2) return -EINVAL; if (q->addr & (PAGE_SIZE - 1)) return -EINVAL; if (q->mask != BIT(q->depth_log2) - 1) return -EINVAL; if (q->size < BIT_ULL(q->depth_log2 + q->stride_log2)) return -EINVAL; return 0; } static u32 ionic_get_eqid(struct ionic_ibdev *dev, u32 comp_vector, u8 udma_idx) { /* EQ per vector per udma, and the first eqs reserved for async events. * The rest of the vectors can be requested for completions. */ u32 comp_vec_count = dev->lif_cfg.eq_count / dev->lif_cfg.udma_count - 1; return (comp_vector % comp_vec_count + 1) * dev->lif_cfg.udma_count + udma_idx; } static int ionic_get_cqid(struct ionic_ibdev *dev, u32 *cqid, u8 udma_idx) { unsigned int size, base, bound; int rc; size = dev->lif_cfg.cq_count / dev->lif_cfg.udma_count; base = size * udma_idx; bound = base + size; rc = ionic_resid_get_shared(&dev->inuse_cqid, base, bound); if (rc >= 0) { /* cq_base is zero or a multiple of two queue groups */ *cqid = dev->lif_cfg.cq_base + ionic_bitid_to_qid(rc, dev->lif_cfg.udma_qgrp_shift, dev->half_cqid_udma_shift); rc = 0; } return rc; } static void ionic_put_cqid(struct ionic_ibdev *dev, u32 cqid) { u32 bitid = ionic_qid_to_bitid(cqid - dev->lif_cfg.cq_base, dev->lif_cfg.udma_qgrp_shift, dev->half_cqid_udma_shift); ionic_resid_put(&dev->inuse_cqid, bitid); } int ionic_create_cq_common(struct ionic_vcq *vcq, struct ionic_tbl_buf *buf, const struct ib_cq_init_attr *attr, struct ionic_ctx *ctx, struct ib_udata *udata, struct ionic_qdesc *req_cq, __u32 *resp_cqid, int udma_idx) { struct ionic_ibdev *dev = to_ionic_ibdev(vcq->ibcq.device); struct ionic_cq *cq = &vcq->cq[udma_idx]; void *entry; int rc; cq->vcq = vcq; if (attr->cqe < 1 || attr->cqe + IONIC_CQ_GRACE > 0xffff) { rc = -EINVAL; goto err_args; } rc = ionic_get_cqid(dev, &cq->cqid, udma_idx); if (rc) goto err_args; cq->eqid = ionic_get_eqid(dev, attr->comp_vector, udma_idx); spin_lock_init(&cq->lock); INIT_LIST_HEAD(&cq->poll_sq); INIT_LIST_HEAD(&cq->flush_sq); INIT_LIST_HEAD(&cq->flush_rq); if (udata) { rc = ionic_validate_qdesc(req_cq); if (rc) goto err_qdesc; cq->umem = ib_umem_get_va(&dev->ibdev, req_cq->addr, req_cq->size, IB_ACCESS_LOCAL_WRITE); if (IS_ERR(cq->umem)) { rc = PTR_ERR(cq->umem); goto err_qdesc; } cq->q.ptr = NULL; cq->q.size = req_cq->size; cq->q.mask = req_cq->mask; cq->q.depth_log2 = req_cq->depth_log2; cq->q.stride_log2 = req_cq->stride_log2; *resp_cqid = cq->cqid; } else { rc = ionic_queue_init(&cq->q, dev->lif_cfg.hwdev, attr->cqe + IONIC_CQ_GRACE, sizeof(struct ionic_v1_cqe)); if (rc) goto err_q_init; ionic_queue_dbell_init(&cq->q, cq->cqid); cq->color = true; cq->credit = cq->q.mask; } rc = ionic_pgtbl_init(dev, buf, cq->umem, cq->q.dma, 1, PAGE_SIZE); if (rc) goto err_pgtbl_init; init_completion(&cq->cq_rel_comp); kref_init(&cq->cq_kref); entry = xa_store_irq(&dev->cq_tbl, cq->cqid, cq, GFP_KERNEL); if (entry) { if (!xa_is_err(entry)) rc = -EINVAL; else rc = xa_err(entry); goto err_xa; } return 0; err_xa: ionic_pgtbl_unbuf(dev, buf); err_pgtbl_init: if (!udata) ionic_queue_destroy(&cq->q, dev->lif_cfg.hwdev); err_q_init: if (cq->umem) ib_umem_release(cq->umem); err_qdesc: ionic_put_cqid(dev, cq->cqid); err_args: cq->vcq = NULL; return rc; } void ionic_destroy_cq_common(struct ionic_ibdev *dev, struct ionic_cq *cq) { if (!cq->vcq) return; xa_erase_irq(&dev->cq_tbl, cq->cqid); kref_put(&cq->cq_kref, ionic_cq_complete); wait_for_completion(&cq->cq_rel_comp); if (cq->umem) ib_umem_release(cq->umem); else ionic_queue_destroy(&cq->q, dev->lif_cfg.hwdev); ionic_put_cqid(dev, cq->cqid); cq->vcq = NULL; } static int ionic_validate_qdesc_zero(struct ionic_qdesc *q) { if (q->addr || q->size || q->mask || q->depth_log2 || q->stride_log2) return -EINVAL; return 0; } static int ionic_get_pdid(struct ionic_ibdev *dev, u32 *pdid) { int rc; rc = ionic_resid_get(&dev->inuse_pdid); if (rc < 0) return rc; *pdid = rc; return 0; } static int ionic_get_ahid(struct ionic_ibdev *dev, u32 *ahid) { int rc; rc = ionic_resid_get(&dev->inuse_ahid); if (rc < 0) return rc; *ahid = rc; return 0; } static int ionic_get_mrid(struct ionic_ibdev *dev, u32 *mrid) { int rc; /* wrap to 1, skip reserved lkey */ rc = ionic_resid_get_shared(&dev->inuse_mrid, 1, dev->inuse_mrid.inuse_size); if (rc < 0) return rc; *mrid = ionic_mrid(rc, dev->next_mrkey++); return 0; } static int ionic_get_gsi_qpid(struct ionic_ibdev *dev, u32 *qpid) { int rc = 0; rc = ionic_resid_get_shared(&dev->inuse_qpid, IB_QPT_GSI, IB_QPT_GSI + 1); if (rc < 0) return rc; *qpid = IB_QPT_GSI; return 0; } static int ionic_get_qpid(struct ionic_ibdev *dev, u32 *qpid, u8 *udma_idx, u8 udma_mask) { unsigned int size, base, bound; int udma_i, udma_x, udma_ix; int rc = -EINVAL; udma_x = dev->next_qpid_udma_idx; dev->next_qpid_udma_idx ^= dev->lif_cfg.udma_count - 1; for (udma_i = 0; udma_i < dev->lif_cfg.udma_count; ++udma_i) { udma_ix = udma_i ^ udma_x; if (!(udma_mask & BIT(udma_ix))) continue; size = dev->lif_cfg.qp_count / dev->lif_cfg.udma_count; base = size * udma_ix; bound = base + size; /* skip reserved SMI and GSI qpids in group zero */ if (!base) base = 2; rc = ionic_resid_get_shared(&dev->inuse_qpid, base, bound); if (rc >= 0) { *qpid = ionic_bitid_to_qid(rc, dev->lif_cfg.udma_qgrp_shift, dev->half_qpid_udma_shift); *udma_idx = udma_ix; rc = 0; break; } } return rc; } static int ionic_get_dbid(struct ionic_ibdev *dev, u32 *dbid, phys_addr_t *addr) { int rc, dbpage_num; /* wrap to 1, skip kernel reserved */ rc = ionic_resid_get_shared(&dev->inuse_dbid, 1, dev->inuse_dbid.inuse_size); if (rc < 0) return rc; dbpage_num = (dev->lif_cfg.lif_hw_index * dev->lif_cfg.dbid_count) + rc; *addr = dev->lif_cfg.db_phys + ((phys_addr_t)dbpage_num << PAGE_SHIFT); *dbid = rc; return 0; } static void ionic_put_pdid(struct ionic_ibdev *dev, u32 pdid) { ionic_resid_put(&dev->inuse_pdid, pdid); } static void ionic_put_ahid(struct ionic_ibdev *dev, u32 ahid) { ionic_resid_put(&dev->inuse_ahid, ahid); } static void ionic_put_mrid(struct ionic_ibdev *dev, u32 mrid) { ionic_resid_put(&dev->inuse_mrid, ionic_mrid_index(mrid)); } static void ionic_put_qpid(struct ionic_ibdev *dev, u32 qpid) { u32 bitid = ionic_qid_to_bitid(qpid, dev->lif_cfg.udma_qgrp_shift, dev->half_qpid_udma_shift); ionic_resid_put(&dev->inuse_qpid, bitid); } static void ionic_put_dbid(struct ionic_ibdev *dev, u32 dbid) { ionic_resid_put(&dev->inuse_dbid, dbid); } static struct rdma_user_mmap_entry* ionic_mmap_entry_insert(struct ionic_ctx *ctx, unsigned long size, unsigned long pfn, u8 mmap_flags, u64 *offset) { struct ionic_mmap_entry *entry; int rc; entry = kzalloc_obj(*entry); if (!entry) return NULL; entry->size = size; entry->pfn = pfn; entry->mmap_flags = mmap_flags; rc = rdma_user_mmap_entry_insert(&ctx->ibctx, &entry->rdma_entry, entry->size); if (rc) { kfree(entry); return NULL; } if (offset) *offset = rdma_user_mmap_get_offset(&entry->rdma_entry); return &entry->rdma_entry; } int ionic_alloc_ucontext(struct ib_ucontext *ibctx, struct ib_udata *udata) { struct ionic_ibdev *dev = to_ionic_ibdev(ibctx->device); struct ionic_ctx *ctx = to_ionic_ctx(ibctx); struct ionic_ctx_resp resp = {}; struct ionic_ctx_req req; phys_addr_t db_phys = 0; int rc; rc = ib_copy_validate_udata_in(udata, req, rsvd); if (rc) return rc; /* try to allocate dbid for user ctx */ rc = ionic_get_dbid(dev, &ctx->dbid, &db_phys); if (rc < 0) return rc; ibdev_dbg(&dev->ibdev, "user space dbid %u\n", ctx->dbid); ctx->mmap_dbell = ionic_mmap_entry_insert(ctx, PAGE_SIZE, PHYS_PFN(db_phys), 0, NULL); if (!ctx->mmap_dbell) { rc = -ENOMEM; goto err_mmap_dbell; } if (dev->lif_cfg.phc_state) { ctx->mmap_phc = ionic_mmap_entry_insert(ctx, PAGE_SIZE, 0, IONIC_MMAP_PHC, &resp.phc_offset); if (!ctx->mmap_phc) { rc = -ENOMEM; goto err_mmap_phc; } } resp.page_shift = PAGE_SHIFT; resp.dbell_offset = db_phys & ~PAGE_MASK; resp.version = dev->lif_cfg.rdma_version; resp.qp_opcodes = dev->lif_cfg.qp_opcodes; resp.admin_opcodes = dev->lif_cfg.admin_opcodes; resp.sq_qtype = dev->lif_cfg.sq_qtype; resp.rq_qtype = dev->lif_cfg.rq_qtype; resp.cq_qtype = dev->lif_cfg.cq_qtype; resp.admin_qtype = dev->lif_cfg.aq_qtype; resp.max_stride = dev->lif_cfg.max_stride; resp.max_spec = IONIC_SPEC_HIGH; resp.udma_count = dev->lif_cfg.udma_count; resp.expdb_mask = dev->lif_cfg.expdb_mask; if (dev->lif_cfg.sq_expdb) resp.expdb_qtypes |= IONIC_EXPDB_SQ; if (dev->lif_cfg.rq_expdb) resp.expdb_qtypes |= IONIC_EXPDB_RQ; rc = ib_respond_udata(udata, resp); if (rc) goto err_resp; return 0; err_resp: rdma_user_mmap_entry_remove(ctx->mmap_phc); err_mmap_phc: rdma_user_mmap_entry_remove(ctx->mmap_dbell); err_mmap_dbell: ionic_put_dbid(dev, ctx->dbid); return rc; } void ionic_dealloc_ucontext(struct ib_ucontext *ibctx) { struct ionic_ibdev *dev = to_ionic_ibdev(ibctx->device); struct ionic_ctx *ctx = to_ionic_ctx(ibctx); rdma_user_mmap_entry_remove(ctx->mmap_phc); rdma_user_mmap_entry_remove(ctx->mmap_dbell); ionic_put_dbid(dev, ctx->dbid); } static int ionic_mmap_phc_state(struct ionic_ibdev *dev, struct vm_area_struct *vma) { if (!(vma->vm_flags & VM_SHARED)) return -EINVAL; if (vma->vm_flags & (VM_WRITE | VM_EXEC)) return -EPERM; vm_flags_clear(vma, VM_MAYWRITE); return vm_insert_page(vma, vma->vm_start, virt_to_page(dev->lif_cfg.phc_state)); } int ionic_mmap(struct ib_ucontext *ibctx, struct vm_area_struct *vma) { struct ionic_ibdev *dev = to_ionic_ibdev(ibctx->device); struct ionic_ctx *ctx = to_ionic_ctx(ibctx); struct rdma_user_mmap_entry *rdma_entry; struct ionic_mmap_entry *ionic_entry; int rc = 0; rdma_entry = rdma_user_mmap_entry_get(&ctx->ibctx, vma); if (!rdma_entry) { ibdev_dbg(&dev->ibdev, "not found %#lx\n", vma->vm_pgoff << PAGE_SHIFT); return -EINVAL; } ionic_entry = container_of(rdma_entry, struct ionic_mmap_entry, rdma_entry); if (ionic_entry->mmap_flags & IONIC_MMAP_PHC) { rc = ionic_mmap_phc_state(dev, vma); rdma_user_mmap_entry_put(rdma_entry); return rc; } ibdev_dbg(&dev->ibdev, "writecombine? %d\n", ionic_entry->mmap_flags & IONIC_MMAP_WC); if (ionic_entry->mmap_flags & IONIC_MMAP_WC) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); else vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ibdev_dbg(&dev->ibdev, "remap st %#lx pf %#lx sz %#lx\n", vma->vm_start, ionic_entry->pfn, ionic_entry->size);