Path: blob/master/drivers/infiniband/hw/ehca/ehca_uverbs.c
15112 views
/*1* IBM eServer eHCA Infiniband device driver for Linux on POWER2*3* userspace support verbs4*5* Authors: Christoph Raisch <[email protected]>6* Hoang-Nam Nguyen <[email protected]>7* Heiko J Schick <[email protected]>8*9* Copyright (c) 2005 IBM Corporation10*11* All rights reserved.12*13* This source code is distributed under a dual license of GPL v2.0 and OpenIB14* BSD.15*16* OpenIB BSD License17*18* Redistribution and use in source and binary forms, with or without19* modification, are permitted provided that the following conditions are met:20*21* Redistributions of source code must retain the above copyright notice, this22* list of conditions and the following disclaimer.23*24* Redistributions in binary form must reproduce the above copyright notice,25* this list of conditions and the following disclaimer in the documentation26* and/or other materials27* provided with the distribution.28*29* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"30* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE31* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE32* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE33* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR34* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF35* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR36* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER37* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)38* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE39* POSSIBILITY OF SUCH DAMAGE.40*/4142#include <linux/slab.h>4344#include "ehca_classes.h"45#include "ehca_iverbs.h"46#include "ehca_mrmw.h"47#include "ehca_tools.h"48#include "hcp_if.h"4950struct ib_ucontext *ehca_alloc_ucontext(struct ib_device *device,51struct ib_udata *udata)52{53struct ehca_ucontext *my_context;5455my_context = kzalloc(sizeof *my_context, GFP_KERNEL);56if (!my_context) {57ehca_err(device, "Out of memory device=%p", device);58return ERR_PTR(-ENOMEM);59}6061return &my_context->ib_ucontext;62}6364int ehca_dealloc_ucontext(struct ib_ucontext *context)65{66kfree(container_of(context, struct ehca_ucontext, ib_ucontext));67return 0;68}6970static void ehca_mm_open(struct vm_area_struct *vma)71{72u32 *count = (u32 *)vma->vm_private_data;73if (!count) {74ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",75vma->vm_start, vma->vm_end);76return;77}78(*count)++;79if (!(*count))80ehca_gen_err("Use count overflow vm_start=%lx vm_end=%lx",81vma->vm_start, vma->vm_end);82ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x",83vma->vm_start, vma->vm_end, *count);84}8586static void ehca_mm_close(struct vm_area_struct *vma)87{88u32 *count = (u32 *)vma->vm_private_data;89if (!count) {90ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",91vma->vm_start, vma->vm_end);92return;93}94(*count)--;95ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x",96vma->vm_start, vma->vm_end, *count);97}9899static const struct vm_operations_struct vm_ops = {100.open = ehca_mm_open,101.close = ehca_mm_close,102};103104static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas,105u32 *mm_count)106{107int ret;108u64 vsize, physical;109110vsize = vma->vm_end - vma->vm_start;111if (vsize < EHCA_PAGESIZE) {112ehca_gen_err("invalid vsize=%lx", vma->vm_end - vma->vm_start);113return -EINVAL;114}115116physical = galpas->user.fw_handle;117vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);118ehca_gen_dbg("vsize=%llx physical=%llx", vsize, physical);119/* VM_IO | VM_RESERVED are set by remap_pfn_range() */120ret = remap_4k_pfn(vma, vma->vm_start, physical >> EHCA_PAGESHIFT,121vma->vm_page_prot);122if (unlikely(ret)) {123ehca_gen_err("remap_pfn_range() failed ret=%i", ret);124return -ENOMEM;125}126127vma->vm_private_data = mm_count;128(*mm_count)++;129vma->vm_ops = &vm_ops;130131return 0;132}133134static int ehca_mmap_queue(struct vm_area_struct *vma, struct ipz_queue *queue,135u32 *mm_count)136{137int ret;138u64 start, ofs;139struct page *page;140141vma->vm_flags |= VM_RESERVED;142start = vma->vm_start;143for (ofs = 0; ofs < queue->queue_length; ofs += PAGE_SIZE) {144u64 virt_addr = (u64)ipz_qeit_calc(queue, ofs);145page = virt_to_page(virt_addr);146ret = vm_insert_page(vma, start, page);147if (unlikely(ret)) {148ehca_gen_err("vm_insert_page() failed rc=%i", ret);149return ret;150}151start += PAGE_SIZE;152}153vma->vm_private_data = mm_count;154(*mm_count)++;155vma->vm_ops = &vm_ops;156157return 0;158}159160static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq,161u32 rsrc_type)162{163int ret;164165switch (rsrc_type) {166case 0: /* galpa fw handle */167ehca_dbg(cq->ib_cq.device, "cq_num=%x fw", cq->cq_number);168ret = ehca_mmap_fw(vma, &cq->galpas, &cq->mm_count_galpa);169if (unlikely(ret)) {170ehca_err(cq->ib_cq.device,171"ehca_mmap_fw() failed rc=%i cq_num=%x",172ret, cq->cq_number);173return ret;174}175break;176177case 1: /* cq queue_addr */178ehca_dbg(cq->ib_cq.device, "cq_num=%x queue", cq->cq_number);179ret = ehca_mmap_queue(vma, &cq->ipz_queue, &cq->mm_count_queue);180if (unlikely(ret)) {181ehca_err(cq->ib_cq.device,182"ehca_mmap_queue() failed rc=%i cq_num=%x",183ret, cq->cq_number);184return ret;185}186break;187188default:189ehca_err(cq->ib_cq.device, "bad resource type=%x cq_num=%x",190rsrc_type, cq->cq_number);191return -EINVAL;192}193194return 0;195}196197static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,198u32 rsrc_type)199{200int ret;201202switch (rsrc_type) {203case 0: /* galpa fw handle */204ehca_dbg(qp->ib_qp.device, "qp_num=%x fw", qp->ib_qp.qp_num);205ret = ehca_mmap_fw(vma, &qp->galpas, &qp->mm_count_galpa);206if (unlikely(ret)) {207ehca_err(qp->ib_qp.device,208"remap_pfn_range() failed ret=%i qp_num=%x",209ret, qp->ib_qp.qp_num);210return -ENOMEM;211}212break;213214case 1: /* qp rqueue_addr */215ehca_dbg(qp->ib_qp.device, "qp_num=%x rq", qp->ib_qp.qp_num);216ret = ehca_mmap_queue(vma, &qp->ipz_rqueue,217&qp->mm_count_rqueue);218if (unlikely(ret)) {219ehca_err(qp->ib_qp.device,220"ehca_mmap_queue(rq) failed rc=%i qp_num=%x",221ret, qp->ib_qp.qp_num);222return ret;223}224break;225226case 2: /* qp squeue_addr */227ehca_dbg(qp->ib_qp.device, "qp_num=%x sq", qp->ib_qp.qp_num);228ret = ehca_mmap_queue(vma, &qp->ipz_squeue,229&qp->mm_count_squeue);230if (unlikely(ret)) {231ehca_err(qp->ib_qp.device,232"ehca_mmap_queue(sq) failed rc=%i qp_num=%x",233ret, qp->ib_qp.qp_num);234return ret;235}236break;237238default:239ehca_err(qp->ib_qp.device, "bad resource type=%x qp=num=%x",240rsrc_type, qp->ib_qp.qp_num);241return -EINVAL;242}243244return 0;245}246247int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)248{249u64 fileoffset = vma->vm_pgoff;250u32 idr_handle = fileoffset & 0x1FFFFFF;251u32 q_type = (fileoffset >> 27) & 0x1; /* CQ, QP,... */252u32 rsrc_type = (fileoffset >> 25) & 0x3; /* sq,rq,cmnd_window */253u32 ret;254struct ehca_cq *cq;255struct ehca_qp *qp;256struct ib_uobject *uobject;257258switch (q_type) {259case 0: /* CQ */260read_lock(&ehca_cq_idr_lock);261cq = idr_find(&ehca_cq_idr, idr_handle);262read_unlock(&ehca_cq_idr_lock);263264/* make sure this mmap really belongs to the authorized user */265if (!cq)266return -EINVAL;267268if (!cq->ib_cq.uobject || cq->ib_cq.uobject->context != context)269return -EINVAL;270271ret = ehca_mmap_cq(vma, cq, rsrc_type);272if (unlikely(ret)) {273ehca_err(cq->ib_cq.device,274"ehca_mmap_cq() failed rc=%i cq_num=%x",275ret, cq->cq_number);276return ret;277}278break;279280case 1: /* QP */281read_lock(&ehca_qp_idr_lock);282qp = idr_find(&ehca_qp_idr, idr_handle);283read_unlock(&ehca_qp_idr_lock);284285/* make sure this mmap really belongs to the authorized user */286if (!qp)287return -EINVAL;288289uobject = IS_SRQ(qp) ? qp->ib_srq.uobject : qp->ib_qp.uobject;290if (!uobject || uobject->context != context)291return -EINVAL;292293ret = ehca_mmap_qp(vma, qp, rsrc_type);294if (unlikely(ret)) {295ehca_err(qp->ib_qp.device,296"ehca_mmap_qp() failed rc=%i qp_num=%x",297ret, qp->ib_qp.qp_num);298return ret;299}300break;301302default:303ehca_gen_err("bad queue type %x", q_type);304return -EINVAL;305}306307return 0;308}309310311