diff options
Diffstat (limited to 'drivers/infiniband/hw/ipath/ipath_mmap.c')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_mmap.c | 64 |
1 files changed, 58 insertions, 6 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_mmap.c b/drivers/infiniband/hw/ipath/ipath_mmap.c index a82157db4689..937bc3396b53 100644 --- a/drivers/infiniband/hw/ipath/ipath_mmap.c +++ b/drivers/infiniband/hw/ipath/ipath_mmap.c | |||
@@ -46,6 +46,11 @@ void ipath_release_mmap_info(struct kref *ref) | |||
46 | { | 46 | { |
47 | struct ipath_mmap_info *ip = | 47 | struct ipath_mmap_info *ip = |
48 | container_of(ref, struct ipath_mmap_info, ref); | 48 | container_of(ref, struct ipath_mmap_info, ref); |
49 | struct ipath_ibdev *dev = to_idev(ip->context->device); | ||
50 | |||
51 | spin_lock_irq(&dev->pending_lock); | ||
52 | list_del(&ip->pending_mmaps); | ||
53 | spin_unlock_irq(&dev->pending_lock); | ||
49 | 54 | ||
50 | vfree(ip->obj); | 55 | vfree(ip->obj); |
51 | kfree(ip); | 56 | kfree(ip); |
@@ -60,14 +65,12 @@ static void ipath_vma_open(struct vm_area_struct *vma) | |||
60 | struct ipath_mmap_info *ip = vma->vm_private_data; | 65 | struct ipath_mmap_info *ip = vma->vm_private_data; |
61 | 66 | ||
62 | kref_get(&ip->ref); | 67 | kref_get(&ip->ref); |
63 | ip->mmap_cnt++; | ||
64 | } | 68 | } |
65 | 69 | ||
66 | static void ipath_vma_close(struct vm_area_struct *vma) | 70 | static void ipath_vma_close(struct vm_area_struct *vma) |
67 | { | 71 | { |
68 | struct ipath_mmap_info *ip = vma->vm_private_data; | 72 | struct ipath_mmap_info *ip = vma->vm_private_data; |
69 | 73 | ||
70 | ip->mmap_cnt--; | ||
71 | kref_put(&ip->ref, ipath_release_mmap_info); | 74 | kref_put(&ip->ref, ipath_release_mmap_info); |
72 | } | 75 | } |
73 | 76 | ||
@@ -87,7 +90,7 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) | |||
87 | struct ipath_ibdev *dev = to_idev(context->device); | 90 | struct ipath_ibdev *dev = to_idev(context->device); |
88 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; | 91 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; |
89 | unsigned long size = vma->vm_end - vma->vm_start; | 92 | unsigned long size = vma->vm_end - vma->vm_start; |
90 | struct ipath_mmap_info *ip, **pp; | 93 | struct ipath_mmap_info *ip, *pp; |
91 | int ret = -EINVAL; | 94 | int ret = -EINVAL; |
92 | 95 | ||
93 | /* | 96 | /* |
@@ -96,15 +99,16 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) | |||
96 | * CQ, QP, or SRQ is soon followed by a call to mmap(). | 99 | * CQ, QP, or SRQ is soon followed by a call to mmap(). |
97 | */ | 100 | */ |
98 | spin_lock_irq(&dev->pending_lock); | 101 | spin_lock_irq(&dev->pending_lock); |
99 | for (pp = &dev->pending_mmaps; (ip = *pp); pp = &ip->next) { | 102 | list_for_each_entry_safe(ip, pp, &dev->pending_mmaps, |
103 | pending_mmaps) { | ||
100 | /* Only the creator is allowed to mmap the object */ | 104 | /* Only the creator is allowed to mmap the object */ |
101 | if (context != ip->context || (void *) offset != ip->obj) | 105 | if (context != ip->context || (__u64) offset != ip->offset) |
102 | continue; | 106 | continue; |
103 | /* Don't allow a mmap larger than the object. */ | 107 | /* Don't allow a mmap larger than the object. */ |
104 | if (size > ip->size) | 108 | if (size > ip->size) |
105 | break; | 109 | break; |
106 | 110 | ||
107 | *pp = ip->next; | 111 | list_del_init(&ip->pending_mmaps); |
108 | spin_unlock_irq(&dev->pending_lock); | 112 | spin_unlock_irq(&dev->pending_lock); |
109 | 113 | ||
110 | ret = remap_vmalloc_range(vma, ip->obj, 0); | 114 | ret = remap_vmalloc_range(vma, ip->obj, 0); |
@@ -119,3 +123,51 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) | |||
119 | done: | 123 | done: |
120 | return ret; | 124 | return ret; |
121 | } | 125 | } |
126 | |||
127 | /* | ||
128 | * Allocate information for ipath_mmap | ||
129 | */ | ||
130 | struct ipath_mmap_info *ipath_create_mmap_info(struct ipath_ibdev *dev, | ||
131 | u32 size, | ||
132 | struct ib_ucontext *context, | ||
133 | void *obj) { | ||
134 | struct ipath_mmap_info *ip; | ||
135 | |||
136 | ip = kmalloc(sizeof *ip, GFP_KERNEL); | ||
137 | if (!ip) | ||
138 | goto bail; | ||
139 | |||
140 | size = PAGE_ALIGN(size); | ||
141 | |||
142 | spin_lock_irq(&dev->mmap_offset_lock); | ||
143 | if (dev->mmap_offset == 0) | ||
144 | dev->mmap_offset = PAGE_SIZE; | ||
145 | ip->offset = dev->mmap_offset; | ||
146 | dev->mmap_offset += size; | ||
147 | spin_unlock_irq(&dev->mmap_offset_lock); | ||
148 | |||
149 | INIT_LIST_HEAD(&ip->pending_mmaps); | ||
150 | ip->size = size; | ||
151 | ip->context = context; | ||
152 | ip->obj = obj; | ||
153 | kref_init(&ip->ref); | ||
154 | |||
155 | bail: | ||
156 | return ip; | ||
157 | } | ||
158 | |||
159 | void ipath_update_mmap_info(struct ipath_ibdev *dev, | ||
160 | struct ipath_mmap_info *ip, | ||
161 | u32 size, void *obj) { | ||
162 | size = PAGE_ALIGN(size); | ||
163 | |||
164 | spin_lock_irq(&dev->mmap_offset_lock); | ||
165 | if (dev->mmap_offset == 0) | ||
166 | dev->mmap_offset = PAGE_SIZE; | ||
167 | ip->offset = dev->mmap_offset; | ||
168 | dev->mmap_offset += size; | ||
169 | spin_unlock_irq(&dev->mmap_offset_lock); | ||
170 | |||
171 | ip->size = size; | ||
172 | ip->obj = obj; | ||
173 | } | ||