mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-10-30 15:48:52 +01:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
309
drivers/infiniband/hw/ehca/ehca_uverbs.c
Normal file
309
drivers/infiniband/hw/ehca/ehca_uverbs.c
Normal file
|
|
@ -0,0 +1,309 @@
|
|||
/*
|
||||
* 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 <linux/slab.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 const 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=%llx physical=%llx", vsize, physical);
|
||||
/* VM_IO | VM_DONTEXPAND | VM_DONTDUMP 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_DONTEXPAND | VM_DONTDUMP;
|
||||
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 rq", 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 sq", 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 ret;
|
||||
struct ehca_cq *cq;
|
||||
struct ehca_qp *qp;
|
||||
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->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;
|
||||
|
||||
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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue