e0ca2b413f2b39594a5b9f8dfd67ba471af5b4cb
[mirror/winof/.git] / hw / mlx4 / kernel / hca / verbs.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 2004-2005 Mellanox Technologies, Inc. All rights reserved. \r
4  *\r
5  * This software is available to you under the OpenIB.org BSD license\r
6  * below:\r
7  *\r
8  *     Redistribution and use in source and binary forms, with or\r
9  *     without modification, are permitted provided that the following\r
10  *     conditions are met:\r
11  *\r
12  *      - Redistributions of source code must retain the above\r
13  *        copyright notice, this list of conditions and the following\r
14  *        disclaimer.\r
15  *\r
16  *      - Redistributions in binary form must reproduce the above\r
17  *        copyright notice, this list of conditions and the following\r
18  *        disclaimer in the documentation and/or other materials\r
19  *        provided with the distribution.\r
20  *\r
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
24  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
25  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
26  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
27  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
28  * SOFTWARE.\r
29  *\r
30  * $Id: hca_verbs.c 2073 2007-11-13 11:38:40Z leonid $\r
31  */\r
32 \r
33 \r
34 #include "precomp.h"\r
35 \r
36 #if defined(EVENT_TRACING)\r
37 #ifdef offsetof\r
38 #undef offsetof\r
39 #endif\r
40 #include "verbs.tmh"\r
41 #endif\r
42 \r
43 \r
44 /* Memory regions */\r
45 \r
46 struct ib_mr *ib_get_dma_mr(struct ib_pd *pd, enum ib_access_flags mr_access_flags)\r
47 {\r
48         struct ib_mr *mr;\r
49 \r
50         mr = pd->device->get_dma_mr(pd, mr_access_flags);\r
51  \r
52         if (!IS_ERR(mr)) {\r
53                 mr->device  = pd->device;\r
54                 mr->pd      = pd;\r
55                 mr->p_uctx = pd->p_uctx;\r
56                 atomic_inc(&pd->usecnt);\r
57                 atomic_set(&mr->usecnt, 0);\r
58                 HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("pdn %d, usecnt %d \n", \r
59                         ((struct mlx4_ib_pd*)pd)->pdn, pd->usecnt));\r
60         }\r
61 \r
62         return mr;\r
63 }\r
64 \r
65 struct ib_mr *ib_reg_phys_mr(struct ib_pd *pd,\r
66                                   struct ib_phys_buf *phys_buf_array,\r
67                                   int num_phys_buf,\r
68                                   enum ib_access_flags mr_access_flags,\r
69                                   u64 *iova_start)\r
70 {\r
71         struct ib_mr *mr;\r
72 \r
73         if ( pd->device->reg_phys_mr )\r
74                 mr = pd->device->reg_phys_mr(pd, phys_buf_array, num_phys_buf,\r
75                         mr_access_flags, iova_start);\r
76         else\r
77                 mr = ERR_PTR(-ENOSYS);\r
78 \r
79         if (!IS_ERR(mr)) {\r
80                 mr->device  = pd->device;\r
81                 mr->pd   = pd;\r
82                 mr->p_uctx = pd->p_uctx;\r
83                 atomic_inc(&pd->usecnt);\r
84                 atomic_set(&mr->usecnt, 0);\r
85                 HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("PD%d use cnt %d \n", \r
86                         ((struct mlx4_ib_pd*)pd)->pdn, pd->usecnt));\r
87         }\r
88 \r
89         return mr;\r
90 }\r
91 \r
92 \r
93  struct ib_mr *ibv_reg_mr(struct ib_pd *pd, \r
94         u64 start, u64 length,\r
95         u64 virt_addr,\r
96         int mr_access_flags,\r
97         ci_umv_buf_t* const p_umv_buf )\r
98 {\r
99         struct ib_mr *ib_mr;\r
100         int err;\r
101         HCA_ENTER(HCA_DBG_MEMORY);\r
102 \r
103         if (p_umv_buf  && p_umv_buf->command) {\r
104                 err = -ENOSYS;\r
105                 goto err_not_supported;\r
106         }\r
107 \r
108         ib_mr = pd->device->reg_user_mr(pd, start, length, virt_addr, mr_access_flags, NULL);\r
109         if (IS_ERR(ib_mr)) {\r
110                 err = PTR_ERR(ib_mr);\r
111                 HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_MEMORY ,("mthca_reg_user_mr failed (%d)\n", err));\r
112                 goto err_reg_user_mr;\r
113         }\r
114 \r
115         ib_mr->device  = pd->device;\r
116         ib_mr->pd      = pd;\r
117         atomic_inc(&pd->usecnt);\r
118         atomic_set(&ib_mr->usecnt, 0);\r
119         HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_MEMORY ,("PD%d use cnt %d, pd_handle %p, ctx %p \n", \r
120                 ((struct mlx4_ib_pd*)pd)->pdn, pd->usecnt, pd, pd->p_uctx));\r
121         HCA_EXIT(HCA_DBG_MEMORY);\r
122         return ib_mr;\r
123 \r
124 err_reg_user_mr:\r
125 err_not_supported:\r
126         HCA_EXIT(HCA_DBG_MEMORY);\r
127         return ERR_PTR(err);\r
128 }\r
129 \r
130 int ib_dereg_mr(struct ib_mr *mr)\r
131 {\r
132         int ret;\r
133         struct ib_pd *pd;\r
134         struct ib_device *p_ibdev;\r
135 \r
136         if (atomic_read(&mr->usecnt))\r
137                 return -EBUSY;\r
138 \r
139         p_ibdev = mr->device;\r
140         pd = mr->pd;\r
141         ret = p_ibdev->dereg_mr(mr);\r
142         if (!ret) {\r
143                 atomic_dec(&pd->usecnt);\r
144                 HCA_PRINT(TRACE_LEVEL_INFORMATION  ,HCA_DBG_MEMORY ,("pdn %d, usecnt %d, pd_handle %p, ctx %p \n", \r
145                         ((struct mlx4_ib_pd*)pd)->pdn, pd->usecnt, pd, pd->p_uctx));\r
146         }\r
147 \r
148         return ret;\r
149 }\r
150 \r
151 static void release_user_cq_qp_resources(\r
152         struct ib_ucontext      *p_uctx)\r
153 {\r
154         if (p_uctx) {\r
155                 atomic_dec(&p_uctx->x.usecnt);\r
156                 if (!atomic_read(&p_uctx->x.usecnt) && p_uctx->closing) {\r
157                         HCA_PRINT(TRACE_LEVEL_ERROR  ,HCA_DBG_SHIM      ,("User resources are released. Removing context\n"));\r
158                         ibv_um_close(p_uctx);\r
159                 }\r
160         }\r
161 }\r
162 \r
163 //\r
164 // Completion queues\r
165 //\r
166 \r
167 struct ib_cq *ibv_create_cq(struct ib_device *p_ibdev,\r
168                            ib_comp_handler comp_handler,\r
169                            void (*event_handler)(struct ib_event *, void *),\r
170                            void *cq_context, int cqe, \r
171                            struct ib_ucontext *p_uctx, ci_umv_buf_t* const p_umv_buf)\r
172 {\r
173         int err;\r
174         struct ib_cq *cq;\r
175         struct ib_udata udata, *p_udata = &udata;\r
176         struct ibv_create_cq *p_req;\r
177         struct ibv_create_cq_resp *p_resp = NULL;\r
178 \r
179         if ( p_uctx && p_umv_buf && p_umv_buf->p_inout_buf ) {\r
180                 // prepare user parameters\r
181                 p_req = (struct ibv_create_cq*)(void*)p_umv_buf->p_inout_buf;\r
182                 p_resp = (struct ibv_create_cq_resp*)(void*)\r
183                         p_umv_buf->p_inout_buf;\r
184                 INIT_UDATA(&udata, &p_req->buf_addr, &p_resp->cqn, \r
185                         sizeof(struct mlx4_ib_create_cq), sizeof(struct mlx4_ib_create_cq_resp));\r
186         }\r
187         else \r
188                 p_udata = NULL;\r
189 \r
190         // create cq\r
191         cq = p_ibdev->create_cq(p_ibdev, cqe, 0, p_uctx, p_udata);\r
192         if (IS_ERR(cq)) {\r
193                 err = PTR_ERR(cq);\r
194                 HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_CQ ,("create_cq failed (%d)\n", err));\r
195                 goto err_create_cq;\r
196         }\r
197 \r
198         cq->device        = p_ibdev;\r
199         cq->p_uctx        = p_uctx;\r
200         cq->comp_handler  = comp_handler;\r
201         cq->event_handler = event_handler;\r
202         cq->cq_context    = cq_context;\r
203         atomic_set(&cq->usecnt, 0);\r
204         if (p_uctx)\r
205                 atomic_inc(&p_uctx->x.usecnt);\r
206 \r
207         HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_CQ ,\r
208                 ("created CQ: cqn %#x:%#x \n", ((struct mlx4_ib_cq*)cq)->mcq.cqn, cq->cqe ));\r
209 \r
210         // fill results\r
211         if (p_umv_buf) {\r
212                 p_resp->cq_handle = (u64)(ULONG_PTR)cq;\r
213                 p_resp->cqe = cq->cqe;\r
214                 p_umv_buf->output_size = sizeof(struct ibv_create_cq_resp);\r
215         }\r
216         \r
217         return cq;\r
218 \r
219 err_create_cq:\r
220         if( p_umv_buf && p_umv_buf->command ) \r
221                 p_umv_buf->status = IB_ERROR;\r
222         return ERR_PTR(err);\r
223 }\r
224 \r
225 int ib_destroy_cq(struct ib_cq *cq)\r
226 {\r
227         int ret;\r
228         struct ib_ucontext      *p_uctx = cq->p_uctx;\r
229         \r
230         if (atomic_read(&cq->usecnt))\r
231                 return -EBUSY;\r
232 \r
233         HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_CQ ,\r
234                 ("destroying CQ: cqn %#x:%#x \n", ((struct mlx4_ib_cq*)cq)->mcq.cqn, cq->cqe ));\r
235 \r
236         ret = cq->device->destroy_cq(cq);\r
237         release_user_cq_qp_resources(p_uctx);\r
238         return ret;\r
239 }\r
240 \r
241 //\r
242 // Queue pairs \r
243 //\r
244 \r
245 static char *__print_qtype(enum ib_qp_type qtype)\r
246 {\r
247         char *str = NULL;\r
248         switch (qtype) {\r
249                 case IB_QPT_SMI: str = "SMI"; break;\r
250                 case IB_QPT_GSI: str = "GSI"; break;\r
251                 case IB_QPT_RC: str = "RC"; break;\r
252                 case IB_QPT_UC: str = "UC"; break;\r
253                 case IB_QPT_UD: str = "UD"; break;\r
254                 case IB_QPT_RAW_IP_V6: str = "IP_V6"; break;\r
255                 case IB_QPT_RAW_ETY: str = "ETY"; break;\r
256                 default: str = "UKNWN"; break;\r
257         }\r
258         return str;\r
259 }\r
260 \r
261 struct ib_qp *ibv_create_qp(struct ib_pd *pd,\r
262         struct ib_qp_init_attr *qp_init_attr,\r
263         struct ib_ucontext *p_uctx, ci_umv_buf_t* const p_umv_buf)\r
264 {\r
265         int err;\r
266         struct ib_qp *p_ib_qp;\r
267         struct ib_udata udata, *p_udata = &udata;\r
268         struct ibv_create_qp *p_req = NULL;\r
269         struct ibv_create_qp_resp *p_resp= NULL;\r
270 \r
271         HCA_ENTER(HCA_DBG_QP);\r
272 \r
273         if ( p_uctx && p_umv_buf && p_umv_buf->command ) {\r
274                 // prepare user parameters\r
275                 p_req = (struct ibv_create_qp*)(void*)p_umv_buf->p_inout_buf;\r
276                 p_resp = (struct ibv_create_qp_resp*)(void*)p_umv_buf->p_inout_buf;\r
277                 INIT_UDATA(&udata, &p_req->buf_addr, NULL, \r
278                         sizeof(struct mlx4_ib_create_qp), 0);\r
279         }\r
280         else \r
281                 p_udata = NULL;\r
282 \r
283         p_ib_qp = pd->device->create_qp( pd, qp_init_attr, p_udata );\r
284 \r
285         if (IS_ERR(p_ib_qp)) {\r
286                 err = PTR_ERR(p_ib_qp);\r
287                 HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP ,("create_qp failed (%d)\n", err));\r
288                 goto err_create_qp;\r
289         }\r
290 \r
291         // fill results\r
292         p_ib_qp->device                         = pd->device;\r
293         p_ib_qp->pd                             = pd;\r
294         p_ib_qp->send_cq                        = qp_init_attr->send_cq;\r
295         p_ib_qp->recv_cq                        = qp_init_attr->recv_cq;\r
296         p_ib_qp->srq                            = qp_init_attr->srq;\r
297         p_ib_qp->p_uctx                                 = p_uctx;\r
298         p_ib_qp->event_handler                  = qp_init_attr->event_handler;\r
299         p_ib_qp->qp_context                     = qp_init_attr->qp_context;\r
300         p_ib_qp->qp_type                                = qp_init_attr->qp_type;\r
301         atomic_inc(&pd->usecnt);\r
302         atomic_inc(&qp_init_attr->send_cq->usecnt);\r
303         atomic_inc(&qp_init_attr->recv_cq->usecnt);\r
304         if (qp_init_attr->srq)\r
305                 atomic_inc(&qp_init_attr->srq->usecnt);\r
306         if (p_uctx)\r
307                 atomic_inc(&p_uctx->x.usecnt);\r
308                 HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_QP ,("pdn %d, usecnt %d, pd_handle %p, ctx %p \n", \r
309                         ((struct mlx4_ib_pd*)pd)->pdn, pd->usecnt, pd, pd->p_uctx));\r
310 \r
311         HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_QP ,\r
312                 ("qtype %s (%d), qnum %#x, q_num  %#x, ssz %d, rsz %d, scq %#x:%#x, rcq %#x:%#x, port_num %d \n",\r
313                 __print_qtype(p_ib_qp->qp_type), p_ib_qp->qp_type,\r
314                 ((struct mlx4_ib_qp*)p_ib_qp)->mqp.qpn, p_ib_qp->qp_num, \r
315                 qp_init_attr->cap.max_send_wr, qp_init_attr->cap.max_recv_wr,\r
316                 ((struct mlx4_ib_cq*)p_ib_qp->send_cq)->mcq.cqn, p_ib_qp->send_cq->cqe,\r
317                 ((struct mlx4_ib_cq*)p_ib_qp->recv_cq)->mcq.cqn, p_ib_qp->recv_cq->cqe,\r
318                 qp_init_attr->port_num\r
319                 ) );\r
320 \r
321         // fill results for user\r
322         if (p_uctx && p_umv_buf && p_umv_buf->p_inout_buf) {\r
323                 struct mlx4_ib_qp *p_mib_qp = (struct mlx4_ib_qp *)p_ib_qp;\r
324                 p_resp->qp_handle = (__u64)(ULONG_PTR)p_ib_qp;\r
325                 p_resp->qpn = p_mib_qp->mqp.qpn;\r
326                 p_resp->max_send_wr = p_mib_qp->sq.max_post;\r
327                 p_resp->max_recv_wr = p_mib_qp->rq.max_post;\r
328                 p_resp->max_send_sge = p_mib_qp->sq.max_gs;\r
329                 p_resp->max_recv_sge = p_mib_qp->rq.max_gs;\r
330                 /*\r
331                  * We don't support inline sends for kernel QPs (yet), and we\r
332                  * don't know what userspace's value should be.\r
333                  */\r
334                 p_resp->max_inline_data = 0;\r
335                 p_umv_buf->output_size = sizeof(struct ibv_create_qp_resp);\r
336         }\r
337 \r
338         return p_ib_qp;\r
339 \r
340 err_create_qp:\r
341         if( p_umv_buf && p_umv_buf->command ) \r
342                 p_umv_buf->status = IB_ERROR;\r
343         HCA_EXIT(HCA_DBG_QP);\r
344         return ERR_PTR(err);\r
345 }\r
346 \r
347 int ib_destroy_qp(struct ib_qp *qp)\r
348 {\r
349         struct ib_pd *p_ib_pd;\r
350         struct ib_cq *scq, *rcq;\r
351         struct ib_srq *srq;\r
352         struct ib_ucontext      *p_uctx;\r
353         int ret;\r
354 \r
355         p_ib_pd  = qp->pd;\r
356         scq = qp->send_cq;\r
357         rcq = qp->recv_cq;\r
358         srq = qp->srq;\r
359         p_uctx = p_ib_pd->p_uctx;\r
360 \r
361         ret = qp->device->destroy_qp(qp);\r
362         if (!ret) {\r
363                 atomic_dec(&p_ib_pd->usecnt);\r
364                 atomic_dec(&scq->usecnt);\r
365                 atomic_dec(&rcq->usecnt);\r
366                 HCA_PRINT(TRACE_LEVEL_INFORMATION  ,HCA_DBG_QP ,("PD%d use cnt %d, pd_handle %p, ctx %p \n", \r
367                         ((struct mlx4_ib_pd*)p_ib_pd)->pdn, p_ib_pd->usecnt, p_ib_pd, p_ib_pd->p_uctx));\r
368                 if (srq)\r
369                         atomic_dec(&srq->usecnt);\r
370                 release_user_cq_qp_resources(p_uctx);\r
371         }\r
372 \r
373         return ret;\r
374 }\r
375 \r
376 //\r
377 // Shared receive queues\r
378 //\r
379 \r
380 \r
381 /* Shared receive queues */\r
382 \r
383 struct ib_srq *ibv_create_srq(struct ib_pd *pd,\r
384         struct ib_srq_init_attr *srq_init_attr,\r
385         struct ib_ucontext *p_uctx, ci_umv_buf_t* const p_umv_buf)\r
386 {\r
387         int err;\r
388         struct ib_srq *p_ib_srq;\r
389         struct ib_udata udata, *p_udata = &udata;\r
390         struct ibv_create_srq *p_req = NULL;\r
391         struct ibv_create_srq_resp *p_resp= NULL;\r
392 \r
393         if ( p_uctx && p_umv_buf && p_umv_buf->p_inout_buf) {\r
394                 // prepare user parameters\r
395                 p_req = (struct ibv_create_srq*)(void*)p_umv_buf->p_inout_buf;\r
396                 p_resp = (struct ibv_create_srq_resp*)(void*)p_umv_buf->p_inout_buf;\r
397                 INIT_UDATA(&udata, &p_req->buf_addr, &p_resp->srqn, \r
398                         sizeof(struct ibv_create_srq), sizeof(struct ibv_create_srq_resp));\r
399         }\r
400         else \r
401                 p_udata = NULL;\r
402 \r
403         p_ib_srq = pd->device->create_srq( pd, srq_init_attr, p_udata );\r
404         if (IS_ERR(p_ib_srq)) {\r
405                 err = PTR_ERR(p_ib_srq);\r
406                 HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_QP ,("create_srq failed (%d)\n", err));\r
407                 goto err_create_srq;\r
408         }\r
409 \r
410         // fill results\r
411         p_ib_srq->device                        = pd->device;\r
412         p_ib_srq->pd                            = pd;\r
413         p_ib_srq->p_uctx                                = p_uctx;\r
414         p_ib_srq->event_handler                 = srq_init_attr->event_handler;\r
415         p_ib_srq->srq_context                   = srq_init_attr->srq_context;\r
416         atomic_inc(&pd->usecnt);\r
417         atomic_set(&p_ib_srq->usecnt, 0);\r
418         if (p_uctx)\r
419                 atomic_inc(&p_uctx->x.usecnt);\r
420                 HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_QP ,("PD%d use cnt %d, pd_handle %p, ctx %p \n", \r
421                         ((struct mlx4_ib_pd*)pd)->pdn, pd->usecnt, pd, pd->p_uctx));\r
422 \r
423         HCA_PRINT(TRACE_LEVEL_INFORMATION, HCA_DBG_SRQ ,\r
424                 ("uctx %p, qhndl %p, qnum %#x \n", \r
425                 pd->p_uctx, p_ib_srq, ((struct mlx4_ib_srq*)p_ib_srq)->msrq.srqn ) );\r
426 \r
427         // fill results for user\r
428         if (p_uctx && p_umv_buf && p_umv_buf->p_inout_buf) {\r
429                 struct mlx4_ib_srq* p_mib_srq = (struct mlx4_ib_srq*)p_ib_srq;\r
430                 p_resp->srq_handle = (__u64)(ULONG_PTR)p_ib_srq;\r
431                 p_resp->max_wr = p_mib_srq->msrq.max - 1;\r
432                 p_resp->max_sge = p_mib_srq->msrq.max_gs;\r
433                 p_umv_buf->output_size = sizeof(struct ibv_create_srq_resp);\r
434                 HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_QP ,("PD%d use cnt %d \n", \r
435                         ((struct mlx4_ib_pd*)pd)->pdn, pd->usecnt));\r
436         }\r
437 \r
438         return p_ib_srq;\r
439         \r
440 err_create_srq:\r
441         if( p_umv_buf && p_umv_buf->command ) \r
442                 p_umv_buf->status = IB_ERROR;\r
443         HCA_EXIT(HCA_DBG_QP);\r
444         return ERR_PTR(err);\r
445 }\r
446 \r
447 int ib_destroy_srq(struct ib_srq *srq)\r
448 {\r
449         int ret;\r
450         struct ib_pd *p_ib_pd = srq->pd;\r
451         struct ib_ucontext      *p_uctx = p_ib_pd->p_uctx;\r
452 \r
453         ret = srq->device->destroy_srq(srq);\r
454         if (!ret) {\r
455                 atomic_dec(&p_ib_pd->usecnt);\r
456                 HCA_PRINT(TRACE_LEVEL_INFORMATION  ,HCA_DBG_SRQ ,("PD%d use cnt %d, pd_handle %p, ctx %p \n", \r
457                         ((struct mlx4_ib_pd*)p_ib_pd)->pdn, p_ib_pd->usecnt, p_ib_pd, p_ib_pd->p_uctx));\r
458                 release_user_cq_qp_resources(p_uctx);\r
459         }\r
460 \r
461         return ret;\r
462 }\r
463 \r
464 //\r
465 // User context\r
466 //\r
467 static NTSTATUS __map_memory_for_user(\r
468         IN              io_addr_t       addr,\r
469         IN              SIZE_T          size,\r
470         IN              MEMORY_CACHING_TYPE mem_type,\r
471         OUT             umap_t  *       p_map\r
472         )\r
473 {\r
474         NTSTATUS status;\r
475 \r
476         HCA_ENTER(HCA_DBG_SHIM);\r
477 \r
478         p_map->mapped = 0;\r
479         \r
480         // map UAR to kernel \r
481         p_map->kva = ioremap(addr, size);\r
482         if (!p_map->kva) {\r
483                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_LOW ,\r
484                         ("Couldn't map kernel access region, aborting.\n") );\r
485                 status = IB_INSUFFICIENT_MEMORY;\r
486                 goto err_ioremap;\r
487         }\r
488 \r
489         // build MDL \r
490         p_map->mdl = IoAllocateMdl( p_map->kva, (ULONG)size,\r
491                 FALSE, TRUE, NULL );\r
492         if( !p_map->mdl ) {\r
493                 status = IB_INSUFFICIENT_MEMORY;\r
494                 goto err_alloc_mdl;\r
495         }\r
496         MmBuildMdlForNonPagedPool( p_map->mdl );\r
497 \r
498         /* Map the memory into the calling process's address space. */\r
499         __try   {\r
500                 p_map->uva = MmMapLockedPagesSpecifyCache( p_map->mdl,\r
501                         UserMode, mem_type, NULL, FALSE, NormalPagePriority );\r
502         }\r
503         __except(EXCEPTION_EXECUTE_HANDLER) {\r
504                 status = IB_INVALID_PERMISSION;\r
505                 goto err_map;\r
506         }\r
507 \r
508         p_map->mapped = 1;\r
509         status = STATUS_SUCCESS;\r
510         goto done;\r
511 \r
512 err_map:\r
513         IoFreeMdl(p_map->mdl);\r
514 \r
515 err_alloc_mdl:  \r
516         iounmap(p_map->kva, PAGE_SIZE);\r
517 \r
518 err_ioremap:\r
519 done:   \r
520         HCA_EXIT(HCA_DBG_SHIM);\r
521         return status;\r
522 }\r
523 \r
524 static void __unmap_memory_for_user(\r
525         IN              umap_t  *       p_map\r
526         )\r
527 {\r
528         if (p_map->mapped) {\r
529                 p_map->mapped = 0;\r
530                 MmUnmapLockedPages( p_map->uva, p_map->mdl );\r
531                 IoFreeMdl(p_map->mdl);\r
532                 iounmap(p_map->kva, PAGE_SIZE);\r
533         }\r
534 }\r
535 \r
536 ib_api_status_t ibv_um_open(    \r
537         IN                      struct ib_device                *       p_ibdev,\r
538         IN      OUT             ci_umv_buf_t* const                     p_umv_buf,\r
539         OUT                     struct ib_ucontext              **      pp_uctx )\r
540 {\r
541         int err;\r
542         ib_api_status_t         status;\r
543         struct mlx4_ib_ucontext *p_muctx;\r
544         struct ibv_get_context_resp *p_uresp;\r
545         struct mlx4_ib_alloc_ucontext_resp ib_alloc_ucontext_resp;\r
546         struct ib_ucontext              *p_uctx;\r
547         struct ib_udata udata;\r
548 \r
549         HCA_ENTER(HCA_DBG_SHIM);\r
550 \r
551         // create user context in kernel\r
552         INIT_UDATA(&udata, NULL, &ib_alloc_ucontext_resp, \r
553                 0, sizeof(struct mlx4_ib_alloc_ucontext_resp));\r
554 \r
555         p_uctx = p_ibdev->alloc_ucontext(p_ibdev, &udata);\r
556         if (IS_ERR(p_uctx)) {\r
557                 err = PTR_ERR(p_uctx);\r
558                 HCA_PRINT(TRACE_LEVEL_ERROR  ,HCA_DBG_SHIM,\r
559                         ("mthca_alloc_ucontext failed (%d)\n", err));\r
560                 status = errno_to_iberr(err);\r
561                 goto err_alloc_ucontext;\r
562         }\r
563         p_muctx = to_mucontext(p_uctx);\r
564         p_uresp = (struct ibv_get_context_resp *)(void*)p_umv_buf->p_inout_buf;\r
565 \r
566         // fill the rest of ib_ucontext fields \r
567         p_uctx->device = p_ibdev;\r
568         p_uctx->closing = 0;\r
569 \r
570         // livefish\r
571         if (hca_is_livefish(p_ibdev->x.p_fdo))\r
572                 goto done;\r
573         \r
574         // map uar to user space\r
575         status = __map_memory_for_user( \r
576                 (io_addr_t)p_muctx->uar.pfn << PAGE_SHIFT, \r
577                 PAGE_SIZE, MmNonCached, &p_uctx->x.uar );\r
578         if( !NT_SUCCESS(status) ) {\r
579                 goto err_map_uar;\r
580         }\r
581         p_uresp->uar_addr        = (u64)(ULONG_PTR)p_uctx->x.uar.uva;\r
582 \r
583         // map BF to user space\r
584         if (ib_alloc_ucontext_resp.bf_reg_size) {\r
585                 status = __map_memory_for_user( \r
586                         (io_addr_t)(p_muctx->uar.pfn + \r
587                         to_mdev(p_ibdev)->dev->caps.num_uars) << PAGE_SHIFT, \r
588                         PAGE_SIZE, MmWriteCombined, &p_uctx->x.bf );\r
589                 if( !NT_SUCCESS(status) ) {\r
590                         HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_SHIM,\r
591                                 ("BlueFlame available, but failed to be mapped (%#x)\n", status));\r
592                         p_uresp->bf_page         = 0;\r
593                         p_uresp->bf_buf_size = 0;\r
594                 } \r
595                 else {\r
596                         p_uresp->bf_page         = (u64)(ULONG_PTR)p_uctx->x.bf.uva;\r
597                         p_uresp->bf_buf_size = ib_alloc_ucontext_resp.bf_reg_size / 2;\r
598                         p_uresp->bf_offset       = 0;\r
599                 }\r
600         }\r
601         else {\r
602                         p_uresp->bf_page         = 0;\r
603                         p_uresp->bf_buf_size = 0;\r
604         }\r
605 \r
606 done:\r
607         // fill the response\r
608         p_uresp->bf_reg_size             = ib_alloc_ucontext_resp.bf_reg_size;\r
609         p_uresp->bf_regs_per_page        = ib_alloc_ucontext_resp.bf_regs_per_page;\r
610         p_uresp->qp_tab_size             = ib_alloc_ucontext_resp.qp_tab_size;\r
611 \r
612         *pp_uctx = p_uctx;\r
613         status = IB_SUCCESS;\r
614         goto end;\r
615 \r
616 err_map_uar:\r
617         p_ibdev->dealloc_ucontext(p_uctx);\r
618 err_alloc_ucontext: \r
619 end:\r
620         HCA_EXIT(HCA_DBG_SHIM);\r
621         return status;\r
622 }\r
623 \r
624 \r
625 void ibv_um_close(      struct ib_ucontext * h_um_ca )\r
626 {\r
627         int err;\r
628         ib_api_status_t         status;\r
629         struct ib_ucontext *p_uctx = (struct ib_ucontext *)h_um_ca;\r
630         PFDO_DEVICE_DATA p_fdo = p_uctx->device->x.p_fdo;\r
631 \r
632         HCA_ENTER(HCA_DBG_SHIM);\r
633 \r
634         p_uctx->closing = 1;\r
635 \r
636         if (atomic_read(&p_uctx->x.usecnt)) {\r
637                 HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM,\r
638                         ("resources are not released (cnt %d)\n", p_uctx->x.usecnt));\r
639                 status = IB_RESOURCE_BUSY;\r
640                 goto err_usage;\r
641         }\r
642         \r
643         if ( !hca_is_livefish(p_fdo)) {\r
644                 __unmap_memory_for_user( &p_uctx->x.bf );\r
645                 __unmap_memory_for_user( &p_uctx->x.uar );\r
646         }\r
647 \r
648         err = p_fdo->bus_ib_ifc.p_ibdev->dealloc_ucontext(p_uctx);\r
649         if (err) {\r
650                 HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM,\r
651                         ("mthca_dealloc_ucontext failed (%d)\n", err));\r
652                 status = errno_to_iberr(err);\r
653                 goto err_dealloc_ucontext;\r
654         }\r
655 \r
656         HCA_PRINT(TRACE_LEVEL_INFORMATION,HCA_DBG_SHIM,\r
657                 ("pcs %p\n", PsGetCurrentProcess()) );\r
658         status = IB_SUCCESS;\r
659         goto end;\r
660         \r
661 err_dealloc_ucontext: \r
662 err_usage:\r
663 end:\r
664         if (status != IB_SUCCESS)\r
665         {\r
666                 HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM,\r
667                         ("completes with ERROR status %x\n", status));\r
668         }\r
669         HCA_EXIT(HCA_DBG_SHIM);\r
670         return;\r
671 }\r
672 \r