diff options
Diffstat (limited to 'drivers/infiniband/hw/ipath/ipath_mmap.c')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_mmap.c | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_mmap.c b/drivers/infiniband/hw/ipath/ipath_mmap.c new file mode 100644 index 000000000000..11b7378ff214 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_mmap.c | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2006 QLogic, Inc. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | */ | ||
32 | |||
33 | #include <linux/config.h> | ||
34 | #include <linux/module.h> | ||
35 | #include <linux/vmalloc.h> | ||
36 | #include <linux/mm.h> | ||
37 | #include <linux/errno.h> | ||
38 | #include <asm/pgtable.h> | ||
39 | |||
40 | #include "ipath_verbs.h" | ||
41 | |||
42 | /** | ||
43 | * ipath_release_mmap_info - free mmap info structure | ||
44 | * @ref: a pointer to the kref within struct ipath_mmap_info | ||
45 | */ | ||
46 | void ipath_release_mmap_info(struct kref *ref) | ||
47 | { | ||
48 | struct ipath_mmap_info *ip = | ||
49 | container_of(ref, struct ipath_mmap_info, ref); | ||
50 | |||
51 | vfree(ip->obj); | ||
52 | kfree(ip); | ||
53 | } | ||
54 | |||
55 | /* | ||
56 | * open and close keep track of how many times the CQ is mapped, | ||
57 | * to avoid releasing it. | ||
58 | */ | ||
59 | static void ipath_vma_open(struct vm_area_struct *vma) | ||
60 | { | ||
61 | struct ipath_mmap_info *ip = vma->vm_private_data; | ||
62 | |||
63 | kref_get(&ip->ref); | ||
64 | ip->mmap_cnt++; | ||
65 | } | ||
66 | |||
67 | static void ipath_vma_close(struct vm_area_struct *vma) | ||
68 | { | ||
69 | struct ipath_mmap_info *ip = vma->vm_private_data; | ||
70 | |||
71 | ip->mmap_cnt--; | ||
72 | kref_put(&ip->ref, ipath_release_mmap_info); | ||
73 | } | ||
74 | |||
75 | static struct vm_operations_struct ipath_vm_ops = { | ||
76 | .open = ipath_vma_open, | ||
77 | .close = ipath_vma_close, | ||
78 | }; | ||
79 | |||
80 | /** | ||
81 | * ipath_mmap - create a new mmap region | ||
82 | * @context: the IB user context of the process making the mmap() call | ||
83 | * @vma: the VMA to be initialized | ||
84 | * Return zero if the mmap is OK. Otherwise, return an errno. | ||
85 | */ | ||
86 | int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) | ||
87 | { | ||
88 | struct ipath_ibdev *dev = to_idev(context->device); | ||
89 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; | ||
90 | unsigned long size = vma->vm_end - vma->vm_start; | ||
91 | struct ipath_mmap_info *ip, **pp; | ||
92 | int ret = -EINVAL; | ||
93 | |||
94 | /* | ||
95 | * Search the device's list of objects waiting for a mmap call. | ||
96 | * Normally, this list is very short since a call to create a | ||
97 | * CQ, QP, or SRQ is soon followed by a call to mmap(). | ||
98 | */ | ||
99 | spin_lock_irq(&dev->pending_lock); | ||
100 | for (pp = &dev->pending_mmaps; (ip = *pp); pp = &ip->next) { | ||
101 | /* Only the creator is allowed to mmap the object */ | ||
102 | if (context != ip->context || (void *) offset != ip->obj) | ||
103 | continue; | ||
104 | /* Don't allow a mmap larger than the object. */ | ||
105 | if (size > ip->size) | ||
106 | break; | ||
107 | |||
108 | *pp = ip->next; | ||
109 | spin_unlock_irq(&dev->pending_lock); | ||
110 | |||
111 | ret = remap_vmalloc_range(vma, ip->obj, 0); | ||
112 | if (ret) | ||
113 | goto done; | ||
114 | vma->vm_ops = &ipath_vm_ops; | ||
115 | vma->vm_private_data = ip; | ||
116 | ipath_vma_open(vma); | ||
117 | goto done; | ||
118 | } | ||
119 | spin_unlock_irq(&dev->pending_lock); | ||
120 | done: | ||
121 | return ret; | ||
122 | } | ||