⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ehca_uverbs.c

📁 linux内核源码
💻 C
字号:
/* *  IBM eServer eHCA Infiniband device driver for Linux on POWER * *  userspace support verbs * *  Authors: Christoph Raisch <raisch@de.ibm.com> *           Hoang-Nam Nguyen <hnguyen@de.ibm.com> *           Heiko J Schick <schickhj@de.ibm.com> * *  Copyright (c) 2005 IBM Corporation * *  All rights reserved. * *  This source code is distributed under a dual license of GPL v2.0 and OpenIB *  BSD. * * OpenIB BSD License * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */#include <asm/current.h>#include "ehca_classes.h"#include "ehca_iverbs.h"#include "ehca_mrmw.h"#include "ehca_tools.h"#include "hcp_if.h"struct ib_ucontext *ehca_alloc_ucontext(struct ib_device *device,					struct ib_udata *udata){	struct ehca_ucontext *my_context;	my_context = kzalloc(sizeof *my_context, GFP_KERNEL);	if (!my_context) {		ehca_err(device, "Out of memory device=%p", device);		return ERR_PTR(-ENOMEM);	}	return &my_context->ib_ucontext;}int ehca_dealloc_ucontext(struct ib_ucontext *context){	kfree(container_of(context, struct ehca_ucontext, ib_ucontext));	return 0;}static void ehca_mm_open(struct vm_area_struct *vma){	u32 *count = (u32 *)vma->vm_private_data;	if (!count) {		ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",			     vma->vm_start, vma->vm_end);		return;	}	(*count)++;	if (!(*count))		ehca_gen_err("Use count overflow vm_start=%lx vm_end=%lx",			     vma->vm_start, vma->vm_end);	ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x",		     vma->vm_start, vma->vm_end, *count);}static void ehca_mm_close(struct vm_area_struct *vma){	u32 *count = (u32 *)vma->vm_private_data;	if (!count) {		ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",			     vma->vm_start, vma->vm_end);		return;	}	(*count)--;	ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x",		     vma->vm_start, vma->vm_end, *count);}static struct vm_operations_struct vm_ops = {	.open =	ehca_mm_open,	.close = ehca_mm_close,};static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas,			u32 *mm_count){	int ret;	u64 vsize, physical;	vsize = vma->vm_end - vma->vm_start;	if (vsize < EHCA_PAGESIZE) {		ehca_gen_err("invalid vsize=%lx", vma->vm_end - vma->vm_start);		return -EINVAL;	}	physical = galpas->user.fw_handle;	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);	ehca_gen_dbg("vsize=%lx physical=%lx", vsize, physical);	/* VM_IO | VM_RESERVED are set by remap_pfn_range() */	ret = remap_4k_pfn(vma, vma->vm_start, physical >> EHCA_PAGESHIFT,			   vma->vm_page_prot);	if (unlikely(ret)) {		ehca_gen_err("remap_pfn_range() failed ret=%i", ret);		return -ENOMEM;	}	vma->vm_private_data = mm_count;	(*mm_count)++;	vma->vm_ops = &vm_ops;	return 0;}static int ehca_mmap_queue(struct vm_area_struct *vma, struct ipz_queue *queue,			   u32 *mm_count){	int ret;	u64 start, ofs;	struct page *page;	vma->vm_flags |= VM_RESERVED;	start = vma->vm_start;	for (ofs = 0; ofs < queue->queue_length; ofs += PAGE_SIZE) {		u64 virt_addr = (u64)ipz_qeit_calc(queue, ofs);		page = virt_to_page(virt_addr);		ret = vm_insert_page(vma, start, page);		if (unlikely(ret)) {			ehca_gen_err("vm_insert_page() failed rc=%i", ret);			return ret;		}		start += PAGE_SIZE;	}	vma->vm_private_data = mm_count;	(*mm_count)++;	vma->vm_ops = &vm_ops;	return 0;}static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq,			u32 rsrc_type){	int ret;	switch (rsrc_type) {	case 0: /* galpa fw handle */		ehca_dbg(cq->ib_cq.device, "cq_num=%x fw", cq->cq_number);		ret = ehca_mmap_fw(vma, &cq->galpas, &cq->mm_count_galpa);		if (unlikely(ret)) {			ehca_err(cq->ib_cq.device,				 "ehca_mmap_fw() failed rc=%i cq_num=%x",				 ret, cq->cq_number);			return ret;		}		break;	case 1: /* cq queue_addr */		ehca_dbg(cq->ib_cq.device, "cq_num=%x queue", cq->cq_number);		ret = ehca_mmap_queue(vma, &cq->ipz_queue, &cq->mm_count_queue);		if (unlikely(ret)) {			ehca_err(cq->ib_cq.device,				 "ehca_mmap_queue() failed rc=%i cq_num=%x",				 ret, cq->cq_number);			return ret;		}		break;	default:		ehca_err(cq->ib_cq.device, "bad resource type=%x cq_num=%x",			 rsrc_type, cq->cq_number);		return -EINVAL;	}	return 0;}static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,			u32 rsrc_type){	int ret;	switch (rsrc_type) {	case 0: /* galpa fw handle */		ehca_dbg(qp->ib_qp.device, "qp_num=%x fw", qp->ib_qp.qp_num);		ret = ehca_mmap_fw(vma, &qp->galpas, &qp->mm_count_galpa);		if (unlikely(ret)) {			ehca_err(qp->ib_qp.device,				 "remap_pfn_range() failed ret=%i qp_num=%x",				 ret, qp->ib_qp.qp_num);			return -ENOMEM;		}		break;	case 1: /* qp rqueue_addr */		ehca_dbg(qp->ib_qp.device, "qp_num=%x rqueue",			 qp->ib_qp.qp_num);		ret = ehca_mmap_queue(vma, &qp->ipz_rqueue,				      &qp->mm_count_rqueue);		if (unlikely(ret)) {			ehca_err(qp->ib_qp.device,				 "ehca_mmap_queue(rq) failed rc=%i qp_num=%x",				 ret, qp->ib_qp.qp_num);			return ret;		}		break;	case 2: /* qp squeue_addr */		ehca_dbg(qp->ib_qp.device, "qp_num=%x squeue",			 qp->ib_qp.qp_num);		ret = ehca_mmap_queue(vma, &qp->ipz_squeue,				      &qp->mm_count_squeue);		if (unlikely(ret)) {			ehca_err(qp->ib_qp.device,				 "ehca_mmap_queue(sq) failed rc=%i qp_num=%x",				 ret, qp->ib_qp.qp_num);			return ret;		}		break;	default:		ehca_err(qp->ib_qp.device, "bad resource type=%x qp=num=%x",			 rsrc_type, qp->ib_qp.qp_num);		return -EINVAL;	}	return 0;}int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma){	u64 fileoffset = vma->vm_pgoff;	u32 idr_handle = fileoffset & 0x1FFFFFF;	u32 q_type = (fileoffset >> 27) & 0x1;	  /* CQ, QP,...        */	u32 rsrc_type = (fileoffset >> 25) & 0x3; /* sq,rq,cmnd_window */	u32 cur_pid = current->tgid;	u32 ret;	struct ehca_cq *cq;	struct ehca_qp *qp;	struct ehca_pd *pd;	struct ib_uobject *uobject;	switch (q_type) {	case  0: /* CQ */		read_lock(&ehca_cq_idr_lock);		cq = idr_find(&ehca_cq_idr, idr_handle);		read_unlock(&ehca_cq_idr_lock);		/* make sure this mmap really belongs to the authorized user */		if (!cq)			return -EINVAL;		if (cq->ownpid != cur_pid) {			ehca_err(cq->ib_cq.device,				 "Invalid caller pid=%x ownpid=%x",				 cur_pid, cq->ownpid);			return -ENOMEM;		}		if (!cq->ib_cq.uobject || cq->ib_cq.uobject->context != context)			return -EINVAL;		ret = ehca_mmap_cq(vma, cq, rsrc_type);		if (unlikely(ret)) {			ehca_err(cq->ib_cq.device,				 "ehca_mmap_cq() failed rc=%i cq_num=%x",				 ret, cq->cq_number);			return ret;		}		break;	case 1: /* QP */		read_lock(&ehca_qp_idr_lock);		qp = idr_find(&ehca_qp_idr, idr_handle);		read_unlock(&ehca_qp_idr_lock);		/* make sure this mmap really belongs to the authorized user */		if (!qp)			return -EINVAL;		pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd);		if (pd->ownpid != cur_pid) {			ehca_err(qp->ib_qp.device,				 "Invalid caller pid=%x ownpid=%x",				 cur_pid, pd->ownpid);			return -ENOMEM;		}		uobject = IS_SRQ(qp) ? qp->ib_srq.uobject : qp->ib_qp.uobject;		if (!uobject || uobject->context != context)			return -EINVAL;		ret = ehca_mmap_qp(vma, qp, rsrc_type);		if (unlikely(ret)) {			ehca_err(qp->ib_qp.device,				 "ehca_mmap_qp() failed rc=%i qp_num=%x",				 ret, qp->ib_qp.qp_num);			return ret;		}		break;	default:		ehca_gen_err("bad queue type %x", q_type);		return -EINVAL;	}	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -