• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  IBM eServer eHCA Infiniband device driver for Linux on POWER
3  *
4  *  userspace support verbs
5  *
6  *  Authors: Christoph Raisch <raisch@de.ibm.com>
7  *           Hoang-Nam Nguyen <hnguyen@de.ibm.com>
8  *           Heiko J Schick <schickhj@de.ibm.com>
9  *
10  *  Copyright (c) 2005 IBM Corporation
11  *
12  *  All rights reserved.
13  *
14  *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
15  *  BSD.
16  *
17  * OpenIB BSD License
18  *
19  * Redistribution and use in source and binary forms, with or without
20  * modification, are permitted provided that the following conditions are met:
21  *
22  * Redistributions of source code must retain the above copyright notice, this
23  * list of conditions and the following disclaimer.
24  *
25  * Redistributions in binary form must reproduce the above copyright notice,
26  * this list of conditions and the following disclaimer in the documentation
27  * and/or other materials
28  * provided with the distribution.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
31  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
34  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
37  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
38  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40  * POSSIBILITY OF SUCH DAMAGE.
41  */
42 
43 #include <linux/slab.h>
44 
45 #include "ehca_classes.h"
46 #include "ehca_iverbs.h"
47 #include "ehca_mrmw.h"
48 #include "ehca_tools.h"
49 #include "hcp_if.h"
50 
ehca_alloc_ucontext(struct ib_device * device,struct ib_udata * udata)51 struct ib_ucontext *ehca_alloc_ucontext(struct ib_device *device,
52 					struct ib_udata *udata)
53 {
54 	struct ehca_ucontext *my_context;
55 
56 	my_context = kzalloc(sizeof *my_context, GFP_KERNEL);
57 	if (!my_context) {
58 		ehca_err(device, "Out of memory device=%p", device);
59 		return ERR_PTR(-ENOMEM);
60 	}
61 
62 	return &my_context->ib_ucontext;
63 }
64 
ehca_dealloc_ucontext(struct ib_ucontext * context)65 int ehca_dealloc_ucontext(struct ib_ucontext *context)
66 {
67 	kfree(container_of(context, struct ehca_ucontext, ib_ucontext));
68 	return 0;
69 }
70 
ehca_mm_open(struct vm_area_struct * vma)71 static void ehca_mm_open(struct vm_area_struct *vma)
72 {
73 	u32 *count = (u32 *)vma->vm_private_data;
74 	if (!count) {
75 		ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
76 			     vma->vm_start, vma->vm_end);
77 		return;
78 	}
79 	(*count)++;
80 	if (!(*count))
81 		ehca_gen_err("Use count overflow vm_start=%lx vm_end=%lx",
82 			     vma->vm_start, vma->vm_end);
83 	ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x",
84 		     vma->vm_start, vma->vm_end, *count);
85 }
86 
ehca_mm_close(struct vm_area_struct * vma)87 static void ehca_mm_close(struct vm_area_struct *vma)
88 {
89 	u32 *count = (u32 *)vma->vm_private_data;
90 	if (!count) {
91 		ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
92 			     vma->vm_start, vma->vm_end);
93 		return;
94 	}
95 	(*count)--;
96 	ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x",
97 		     vma->vm_start, vma->vm_end, *count);
98 }
99 
100 static const struct vm_operations_struct vm_ops = {
101 	.open =	ehca_mm_open,
102 	.close = ehca_mm_close,
103 };
104 
ehca_mmap_fw(struct vm_area_struct * vma,struct h_galpas * galpas,u32 * mm_count)105 static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas,
106 			u32 *mm_count)
107 {
108 	int ret;
109 	u64 vsize, physical;
110 
111 	vsize = vma->vm_end - vma->vm_start;
112 	if (vsize < EHCA_PAGESIZE) {
113 		ehca_gen_err("invalid vsize=%lx", vma->vm_end - vma->vm_start);
114 		return -EINVAL;
115 	}
116 
117 	physical = galpas->user.fw_handle;
118 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
119 	ehca_gen_dbg("vsize=%llx physical=%llx", vsize, physical);
120 	/* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */
121 	ret = remap_4k_pfn(vma, vma->vm_start, physical >> EHCA_PAGESHIFT,
122 			   vma->vm_page_prot);
123 	if (unlikely(ret)) {
124 		ehca_gen_err("remap_pfn_range() failed ret=%i", ret);
125 		return -ENOMEM;
126 	}
127 
128 	vma->vm_private_data = mm_count;
129 	(*mm_count)++;
130 	vma->vm_ops = &vm_ops;
131 
132 	return 0;
133 }
134 
ehca_mmap_queue(struct vm_area_struct * vma,struct ipz_queue * queue,u32 * mm_count)135 static int ehca_mmap_queue(struct vm_area_struct *vma, struct ipz_queue *queue,
136 			   u32 *mm_count)
137 {
138 	int ret;
139 	u64 start, ofs;
140 	struct page *page;
141 
142 	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
143 	start = vma->vm_start;
144 	for (ofs = 0; ofs < queue->queue_length; ofs += PAGE_SIZE) {
145 		u64 virt_addr = (u64)ipz_qeit_calc(queue, ofs);
146 		page = virt_to_page(virt_addr);
147 		ret = vm_insert_page(vma, start, page);
148 		if (unlikely(ret)) {
149 			ehca_gen_err("vm_insert_page() failed rc=%i", ret);
150 			return ret;
151 		}
152 		start += PAGE_SIZE;
153 	}
154 	vma->vm_private_data = mm_count;
155 	(*mm_count)++;
156 	vma->vm_ops = &vm_ops;
157 
158 	return 0;
159 }
160 
ehca_mmap_cq(struct vm_area_struct * vma,struct ehca_cq * cq,u32 rsrc_type)161 static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq,
162 			u32 rsrc_type)
163 {
164 	int ret;
165 
166 	switch (rsrc_type) {
167 	case 0: /* galpa fw handle */
168 		ehca_dbg(cq->ib_cq.device, "cq_num=%x fw", cq->cq_number);
169 		ret = ehca_mmap_fw(vma, &cq->galpas, &cq->mm_count_galpa);
170 		if (unlikely(ret)) {
171 			ehca_err(cq->ib_cq.device,
172 				 "ehca_mmap_fw() failed rc=%i cq_num=%x",
173 				 ret, cq->cq_number);
174 			return ret;
175 		}
176 		break;
177 
178 	case 1: /* cq queue_addr */
179 		ehca_dbg(cq->ib_cq.device, "cq_num=%x queue", cq->cq_number);
180 		ret = ehca_mmap_queue(vma, &cq->ipz_queue, &cq->mm_count_queue);
181 		if (unlikely(ret)) {
182 			ehca_err(cq->ib_cq.device,
183 				 "ehca_mmap_queue() failed rc=%i cq_num=%x",
184 				 ret, cq->cq_number);
185 			return ret;
186 		}
187 		break;
188 
189 	default:
190 		ehca_err(cq->ib_cq.device, "bad resource type=%x cq_num=%x",
191 			 rsrc_type, cq->cq_number);
192 		return -EINVAL;
193 	}
194 
195 	return 0;
196 }
197 
ehca_mmap_qp(struct vm_area_struct * vma,struct ehca_qp * qp,u32 rsrc_type)198 static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,
199 			u32 rsrc_type)
200 {
201 	int ret;
202 
203 	switch (rsrc_type) {
204 	case 0: /* galpa fw handle */
205 		ehca_dbg(qp->ib_qp.device, "qp_num=%x fw", qp->ib_qp.qp_num);
206 		ret = ehca_mmap_fw(vma, &qp->galpas, &qp->mm_count_galpa);
207 		if (unlikely(ret)) {
208 			ehca_err(qp->ib_qp.device,
209 				 "remap_pfn_range() failed ret=%i qp_num=%x",
210 				 ret, qp->ib_qp.qp_num);
211 			return -ENOMEM;
212 		}
213 		break;
214 
215 	case 1: /* qp rqueue_addr */
216 		ehca_dbg(qp->ib_qp.device, "qp_num=%x rq", qp->ib_qp.qp_num);
217 		ret = ehca_mmap_queue(vma, &qp->ipz_rqueue,
218 				      &qp->mm_count_rqueue);
219 		if (unlikely(ret)) {
220 			ehca_err(qp->ib_qp.device,
221 				 "ehca_mmap_queue(rq) failed rc=%i qp_num=%x",
222 				 ret, qp->ib_qp.qp_num);
223 			return ret;
224 		}
225 		break;
226 
227 	case 2: /* qp squeue_addr */
228 		ehca_dbg(qp->ib_qp.device, "qp_num=%x sq", qp->ib_qp.qp_num);
229 		ret = ehca_mmap_queue(vma, &qp->ipz_squeue,
230 				      &qp->mm_count_squeue);
231 		if (unlikely(ret)) {
232 			ehca_err(qp->ib_qp.device,
233 				 "ehca_mmap_queue(sq) failed rc=%i qp_num=%x",
234 				 ret, qp->ib_qp.qp_num);
235 			return ret;
236 		}
237 		break;
238 
239 	default:
240 		ehca_err(qp->ib_qp.device, "bad resource type=%x qp=num=%x",
241 			 rsrc_type, qp->ib_qp.qp_num);
242 		return -EINVAL;
243 	}
244 
245 	return 0;
246 }
247 
ehca_mmap(struct ib_ucontext * context,struct vm_area_struct * vma)248 int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
249 {
250 	u64 fileoffset = vma->vm_pgoff;
251 	u32 idr_handle = fileoffset & 0x1FFFFFF;
252 	u32 q_type = (fileoffset >> 27) & 0x1;	  /* CQ, QP,...        */
253 	u32 rsrc_type = (fileoffset >> 25) & 0x3; /* sq,rq,cmnd_window */
254 	u32 ret;
255 	struct ehca_cq *cq;
256 	struct ehca_qp *qp;
257 	struct ib_uobject *uobject;
258 
259 	switch (q_type) {
260 	case  0: /* CQ */
261 		read_lock(&ehca_cq_idr_lock);
262 		cq = idr_find(&ehca_cq_idr, idr_handle);
263 		read_unlock(&ehca_cq_idr_lock);
264 
265 		/* make sure this mmap really belongs to the authorized user */
266 		if (!cq)
267 			return -EINVAL;
268 
269 		if (!cq->ib_cq.uobject || cq->ib_cq.uobject->context != context)
270 			return -EINVAL;
271 
272 		ret = ehca_mmap_cq(vma, cq, rsrc_type);
273 		if (unlikely(ret)) {
274 			ehca_err(cq->ib_cq.device,
275 				 "ehca_mmap_cq() failed rc=%i cq_num=%x",
276 				 ret, cq->cq_number);
277 			return ret;
278 		}
279 		break;
280 
281 	case 1: /* QP */
282 		read_lock(&ehca_qp_idr_lock);
283 		qp = idr_find(&ehca_qp_idr, idr_handle);
284 		read_unlock(&ehca_qp_idr_lock);
285 
286 		/* make sure this mmap really belongs to the authorized user */
287 		if (!qp)
288 			return -EINVAL;
289 
290 		uobject = IS_SRQ(qp) ? qp->ib_srq.uobject : qp->ib_qp.uobject;
291 		if (!uobject || uobject->context != context)
292 			return -EINVAL;
293 
294 		ret = ehca_mmap_qp(vma, qp, rsrc_type);
295 		if (unlikely(ret)) {
296 			ehca_err(qp->ib_qp.device,
297 				 "ehca_mmap_qp() failed rc=%i qp_num=%x",
298 				 ret, qp->ib_qp.qp_num);
299 			return ret;
300 		}
301 		break;
302 
303 	default:
304 		ehca_gen_err("bad queue type %x", q_type);
305 		return -EINVAL;
306 	}
307 
308 	return 0;
309 }
310