817ccecefc9e83486e937eed0d61be0c6dfdc803
[mirror/winof/.git] / hw / mthca / kernel / mthca_provider.c
1 /* \r
2  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.\r
3  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.\r
4  * Copyright (c) 2005 Cisco Systems. All rights reserved.\r
5  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.\r
6  * Copyright (c) 2004 Voltaire, Inc. All rights reserved.\r
7  * Portions Copyright (c) 2008 Microsoft Corporation.  All rights reserved.\r
8  *\r
9  * This software is available to you under the OpenIB.org BSD license\r
10  * below:\r
11  *\r
12  *     Redistribution and use in source and binary forms, with or\r
13  *     without modification, are permitted provided that the following\r
14  *     conditions are met:\r
15  *\r
16  *      - Redistributions of source code must retain the above\r
17  *        copyright notice, this list of conditions and the following\r
18  *        disclaimer.\r
19  *\r
20  *      - Redistributions in binary form must reproduce the above\r
21  *        copyright notice, this list of conditions and the following\r
22  *        disclaimer in the documentation and/or other materials\r
23  *        provided with the distribution.\r
24  *\r
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
32  * SOFTWARE.\r
33  *\r
34  * $Id$\r
35  */\r
36 \r
37 #include <ib_smi.h>\r
38 \r
39 #include "mx_abi.h"\r
40 #include "mthca_dev.h"\r
41 #include "mt_pa_cash.h"\r
42 \r
43 #if defined(EVENT_TRACING)\r
44 #ifdef offsetof\r
45 #undef offsetof\r
46 #endif\r
47 #include "mthca_provider.tmh"\r
48 #endif\r
49 #include "mthca_cmd.h"\r
50 #include "mthca_memfree.h"\r
51 \r
52 static void init_query_mad(struct ib_smp *mad)\r
53 {\r
54          mad->base_version      = 1;\r
55          mad->mgmt_class                = IB_MGMT_CLASS_SUBN_LID_ROUTED;\r
56          mad->class_version = 1;\r
57          mad->method                            = IB_MGMT_METHOD_GET;\r
58 }\r
59 \r
60 int mthca_query_device(struct ib_device *ibdev,\r
61                               struct ib_device_attr *props)\r
62 {\r
63         struct ib_smp *in_mad  = NULL;\r
64         struct ib_smp *out_mad = NULL;\r
65         int err = -ENOMEM;\r
66         struct mthca_dev* mdev = to_mdev(ibdev);\r
67 \r
68         u8 status;\r
69 \r
70         RtlZeroMemory(props, sizeof *props);\r
71 \r
72         if (mthca_is_livefish(mdev)) {\r
73                 props->max_pd = 1;\r
74                 props->vendor_id = mdev->ext->hcaConfig.VendorID;\r
75                 props->vendor_part_id = mdev->ext->hcaConfig.DeviceID;\r
76                 return 0;\r
77         }\r
78 \r
79         in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);\r
80         out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);\r
81         if (!in_mad || !out_mad)\r
82                 goto out;\r
83 \r
84         init_query_mad(in_mad);\r
85         in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;\r
86 \r
87         err = mthca_MAD_IFC(mdev, 1, 1,\r
88             1, NULL, NULL, in_mad, out_mad, &status);\r
89         if (err)\r
90                 goto out;\r
91         if (status) {\r
92                 err = -EINVAL;\r
93                 goto out;\r
94         }\r
95 \r
96         props->fw_ver              = mdev->fw_ver;\r
97         props->device_cap_flags    = mdev->device_cap_flags;\r
98         props->vendor_id           = cl_ntoh32(*(__be32 *) (out_mad->data + 36)) &\r
99                 0xffffff;\r
100         props->vendor_part_id      = cl_ntoh16(*(__be16 *) (out_mad->data + 30));\r
101         props->hw_ver              = cl_ntoh32(*(__be32 *) (out_mad->data + 32));\r
102         memcpy(&props->sys_image_guid, out_mad->data +  4, 8);\r
103         props->max_mr_size         = ~0Ui64;\r
104         props->page_size_cap       = mdev->limits.page_size_cap;\r
105         props->max_qp              = mdev->limits.num_qps - mdev->limits.reserved_qps;\r
106         props->max_qp_wr           = mdev->limits.max_wqes;\r
107         props->max_sge             = mdev->limits.max_sg;\r
108         props->max_cq              = mdev->limits.num_cqs - mdev->limits.reserved_cqs;\r
109         props->max_cqe             = mdev->limits.max_cqes;\r
110         props->max_mr              = mdev->limits.num_mpts - mdev->limits.reserved_mrws;\r
111         props->max_pd              = mdev->limits.num_pds - mdev->limits.reserved_pds;\r
112         props->max_qp_rd_atom      = 1 << mdev->qp_table.rdb_shift;\r
113         props->max_qp_init_rd_atom = mdev->limits.max_qp_init_rdma;\r
114         props->max_res_rd_atom     = props->max_qp_rd_atom * props->max_qp;\r
115         props->max_srq             = mdev->limits.num_srqs - mdev->limits.reserved_srqs;\r
116         props->max_srq_wr          = mdev->limits.max_srq_wqes;\r
117         if (mthca_is_memfree(mdev))\r
118                 --props->max_srq_wr;\r
119         props->max_srq_sge         = mdev->limits.max_srq_sge;\r
120         props->local_ca_ack_delay  = (u8)mdev->limits.local_ca_ack_delay;\r
121         props->atomic_cap          = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ? \r
122                                         IB_ATOMIC_LOCAL : IB_ATOMIC_NONE;\r
123         props->max_pkeys           = (u16)mdev->limits.pkey_table_len;\r
124         props->max_mcast_grp       = mdev->limits.num_mgms + mdev->limits.num_amgms;\r
125         props->max_mcast_qp_attach = MTHCA_QP_PER_MGM;\r
126         props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * \r
127                                            props->max_mcast_grp;\r
128         props->max_ah              = mdev->limits.num_avs;\r
129 \r
130         /*\r
131          * If Sinai memory key optimization is being used, then only\r
132          * the 8-bit key portion will change.  For other HCAs, the\r
133          * unused index bits will also be used for FMR remapping.\r
134          */\r
135         if (mdev->mthca_flags & MTHCA_FLAG_SINAI_OPT)\r
136                 props->max_map_per_fmr = 255;\r
137         else\r
138                 props->max_map_per_fmr =\r
139                         (1 << (32 - long_log2(mdev->limits.num_mpts))) - 1;\r
140 \r
141         err = 0;\r
142  out:\r
143         kfree(in_mad);\r
144         kfree(out_mad);\r
145         return err;\r
146 }\r
147 \r
148 int mthca_query_port(struct ib_device *ibdev,\r
149                             u8 port, struct ib_port_attr *props)\r
150 {\r
151         struct ib_smp *in_mad  = NULL;\r
152         struct ib_smp *out_mad = NULL;\r
153         int err = -ENOMEM;\r
154         u8 status;\r
155 \r
156         in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);\r
157         out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);\r
158         if (!in_mad || !out_mad)\r
159                 goto out;\r
160 \r
161         init_query_mad(in_mad);\r
162         in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;\r
163         in_mad->attr_mod = cl_hton32(port);\r
164 \r
165         err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,\r
166                             port, NULL, NULL, in_mad, out_mad,\r
167                             &status);\r
168         if (err)\r
169                 goto out;\r
170         if (status) {\r
171                 err = -EINVAL;\r
172                 goto out;\r
173         }\r
174 \r
175         RtlZeroMemory(props, sizeof *props);\r
176         props->lid               = cl_ntoh16(*(__be16 *) (out_mad->data + 16));\r
177         props->lmc               = out_mad->data[34] & 0x7;\r
178         props->sm_lid            = cl_ntoh16(*(__be16 *) (out_mad->data + 18));\r
179         props->sm_sl             = out_mad->data[36] & 0xf;\r
180         props->state             = out_mad->data[32] & 0xf;\r
181         props->phys_state        = out_mad->data[33] >> 4;\r
182         props->port_cap_flags    = cl_ntoh32(*(__be32 *) (out_mad->data + 20));\r
183         props->gid_tbl_len       = to_mdev(ibdev)->limits.gid_table_len;\r
184         props->max_msg_sz        = 0x80000000;\r
185         props->pkey_tbl_len      = (u16)to_mdev(ibdev)->limits.pkey_table_len;\r
186         props->bad_pkey_cntr     = cl_ntoh16(*(__be16 *) (out_mad->data + 46));\r
187         props->qkey_viol_cntr    = cl_ntoh16(*(__be16 *) (out_mad->data + 48));\r
188         props->active_width      = out_mad->data[31] & 0xf;\r
189         props->active_speed      = out_mad->data[35] >> 4;\r
190         props->max_mtu           = out_mad->data[41] & 0xf;\r
191         props->active_mtu        = out_mad->data[36] >> 4;\r
192         props->subnet_timeout    = out_mad->data[51] & 0x1f;\r
193 \r
194  out:\r
195         kfree(in_mad);\r
196         kfree(out_mad);\r
197         return err;\r
198 }\r
199 \r
200 int mthca_modify_port(struct ib_device *ibdev,\r
201                              u8 port, int port_modify_mask,\r
202                              struct ib_port_modify *props)\r
203 {\r
204         struct mthca_set_ib_param set_ib;\r
205         struct ib_port_attr attr;\r
206         int err;\r
207         u8 status;\r
208 \r
209         if (down_interruptible(&to_mdev(ibdev)->cap_mask_mutex))\r
210                 return -EFAULT;\r
211 \r
212         err = mthca_query_port(ibdev, port, &attr);\r
213         if (err)\r
214                 goto out;\r
215 \r
216         set_ib.set_si_guid     = 0;\r
217         set_ib.reset_qkey_viol = !!(port_modify_mask & IB_PORT_RESET_QKEY_CNTR);\r
218 \r
219         set_ib.cap_mask = (attr.port_cap_flags | props->set_port_cap_mask) &\r
220                 ~props->clr_port_cap_mask;\r
221 \r
222         err = mthca_SET_IB(to_mdev(ibdev), &set_ib, port, &status);\r
223         if (err)\r
224                 goto out;\r
225         if (status) {\r
226                 err = -EINVAL;\r
227                 goto out;\r
228         }\r
229 \r
230 out:\r
231         up(&to_mdev(ibdev)->cap_mask_mutex);\r
232         return err;\r
233 }\r
234 \r
235 static int mthca_query_pkey_chunk(struct ib_device *ibdev,\r
236                             u8 port, u16 index, __be16 pkey[32])\r
237 {\r
238         struct ib_smp *in_mad  = NULL;\r
239         struct ib_smp *out_mad = NULL;\r
240         int err = -ENOMEM;\r
241         u8 status;\r
242 \r
243         in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);\r
244         out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);\r
245         if (!in_mad || !out_mad)\r
246                 goto out;\r
247 \r
248         init_query_mad(in_mad);\r
249         in_mad->attr_id  = IB_SMP_ATTR_PKEY_TABLE;\r
250         in_mad->attr_mod = cl_hton32(index / 32);\r
251 \r
252         err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,\r
253                             port, NULL, NULL, in_mad, out_mad,\r
254                             &status);\r
255         if (err)\r
256                 goto out;\r
257         if (status) {\r
258                 err = -EINVAL;\r
259                 goto out;\r
260         }\r
261 \r
262         { // copy the results\r
263                 int i;\r
264                 __be16 *pkey_chunk = (__be16 *)out_mad->data;\r
265                 for (i=0; i<32; ++i) \r
266                         pkey[i] = pkey_chunk[i];\r
267         }\r
268 \r
269  out:\r
270         kfree(in_mad);\r
271         kfree(out_mad);\r
272         return err;\r
273 }\r
274 \r
275 static int mthca_query_gid_chunk(struct ib_device *ibdev, u8 port,\r
276                            int index, union ib_gid gid[8])\r
277 {\r
278         struct ib_smp *in_mad  = NULL;\r
279         struct ib_smp *out_mad = NULL;\r
280         int err = -ENOMEM;\r
281         u8 status;\r
282         __be64  subnet_prefix;\r
283 \r
284         in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);\r
285         out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);\r
286         if (!in_mad || !out_mad)\r
287                 goto out;\r
288 \r
289         init_query_mad(in_mad);\r
290         in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;\r
291         in_mad->attr_mod = cl_hton32(port);\r
292 \r
293         err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,\r
294                             port, NULL, NULL, in_mad, out_mad,\r
295                             &status);\r
296         if (err)\r
297                 goto out;\r
298         if (status) {\r
299                 err = -EINVAL;\r
300                 goto out;\r
301         }\r
302 \r
303         memcpy(&subnet_prefix, out_mad->data + 8, 8);\r
304 \r
305         init_query_mad(in_mad);\r
306         in_mad->attr_id  = IB_SMP_ATTR_GUID_INFO;\r
307         in_mad->attr_mod = cl_hton32(index / 8);\r
308 \r
309         err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,\r
310                             port, NULL, NULL, in_mad, out_mad,\r
311                             &status);\r
312         if (err)\r
313                 goto out;\r
314         if (status) {\r
315                 err = -EINVAL;\r
316                 goto out;\r
317         }\r
318 \r
319         { // copy the results\r
320                 int i;\r
321                 __be64 *guid = (__be64 *)out_mad->data;\r
322                 for (i=0; i<8; ++i) {\r
323                         gid[i].global.subnet_prefix = subnet_prefix;\r
324                         gid[i].global.interface_id = guid[i];\r
325                 }\r
326         }\r
327 \r
328  out:\r
329         kfree(in_mad);\r
330         kfree(out_mad);\r
331         return err;\r
332 }\r
333 \r
334 struct ib_ucontext *mthca_alloc_ucontext(struct ib_device *ibdev,\r
335                                                 ci_umv_buf_t* const     p_umv_buf)\r
336 {\r
337         struct ibv_get_context_resp uresp;\r
338         struct mthca_ucontext           *context;\r
339         int                              err;\r
340 \r
341         RtlZeroMemory(&uresp, sizeof uresp);\r
342 \r
343         uresp.qp_tab_size = to_mdev(ibdev)->limits.num_qps;\r
344         if (mthca_is_memfree(to_mdev(ibdev)))\r
345                 uresp.uarc_size = to_mdev(ibdev)->uar_table.uarc_size;\r
346         else\r
347                 uresp.uarc_size = 0;\r
348 \r
349         context = kzalloc(sizeof *context, GFP_KERNEL);\r
350         if (!context) {\r
351                 err = -ENOMEM;\r
352                 goto err_nomem;\r
353         }\r
354 \r
355         if (mthca_is_livefish(to_mdev(ibdev)))\r
356                 goto done;\r
357         \r
358         err = mthca_uar_alloc(to_mdev(ibdev), &context->uar);\r
359         if (err) \r
360                 goto err_uar_alloc;\r
361 \r
362         /*\r
363         * map uar to user space\r
364         */\r
365 \r
366         /* map UAR to kernel */\r
367         context->kva = ioremap((io_addr_t)context->uar.pfn << PAGE_SHIFT, PAGE_SIZE,&context->uar_size);\r
368         if (!context->kva) {\r
369                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_LOW ,("Couldn't map kernel access region, aborting.\n") );\r
370                 err = -ENOMEM;\r
371                 goto err_ioremap;\r
372         }\r
373 \r
374         /* build MDL */\r
375         context->mdl = IoAllocateMdl( context->kva, (ULONG)context->uar_size,\r
376                 FALSE, TRUE, NULL );\r
377         if( !context->mdl ) {\r
378                 err = -ENOMEM;\r
379                 goto err_alloc_mdl;\r
380         }\r
381         MmBuildMdlForNonPagedPool( context->mdl );\r
382 \r
383         /* Map the memory into the calling process's address space. */\r
384         __try   {\r
385                 context->ibucontext.user_uar = MmMapLockedPagesSpecifyCache( context->mdl,\r
386                         UserMode, MmNonCached, NULL, FALSE, NormalPagePriority );\r
387         }\r
388         __except(EXCEPTION_EXECUTE_HANDLER) {\r
389                 err = -EACCES;\r
390                 goto err_map;\r
391         }\r
392 \r
393         /* user_db_tab */\r
394         context->db_tab = mthca_init_user_db_tab(to_mdev(ibdev));\r
395         if (IS_ERR(context->db_tab)) {\r
396                 err = PTR_ERR(context->db_tab);\r
397                 goto err_init_user;\r
398         }\r
399 \r
400 done:\r
401         err = ib_copy_to_umv_buf(p_umv_buf, &uresp, sizeof uresp);\r
402         if (err) \r
403                 goto err_copy_to_umv_buf;\r
404 \r
405         context->ibucontext.device = ibdev;\r
406         \r
407         atomic_set(&context->ibucontext.usecnt, 0);\r
408         return &context->ibucontext;\r
409 \r
410 err_copy_to_umv_buf:\r
411         mthca_cleanup_user_db_tab(to_mdev(ibdev), &context->uar,\r
412                 context->db_tab);\r
413 err_init_user:  \r
414         MmUnmapLockedPages( context->ibucontext.user_uar, context->mdl );\r
415 err_map:\r
416         IoFreeMdl(context->mdl);\r
417 err_alloc_mdl:  \r
418         iounmap(context->kva, PAGE_SIZE);\r
419 err_ioremap:    \r
420         mthca_uar_free(to_mdev(ibdev), &context->uar);\r
421 err_uar_alloc:\r
422         kfree(context);\r
423 err_nomem:      \r
424         return ERR_PTR(err);\r
425 }\r
426 \r
427  int mthca_dealloc_ucontext(struct ib_ucontext *context)\r
428 {\r
429          struct mthca_ucontext          *mucontext = to_mucontext(context);\r
430 \r
431         if (mthca_is_livefish(to_mdev(context->device)))\r
432                 goto done;\r
433         mthca_cleanup_user_db_tab(to_mdev(context->device), &mucontext->uar,\r
434                                   mucontext->db_tab);\r
435         MmUnmapLockedPages( mucontext->ibucontext.user_uar, mucontext->mdl );\r
436         IoFreeMdl(mucontext->mdl);\r
437         iounmap(mucontext->kva, PAGE_SIZE);\r
438         mthca_uar_free(to_mdev(context->device), &mucontext->uar);\r
439 done:   \r
440         kfree(mucontext);\r
441         \r
442         return 0;\r
443 }\r
444 \r
445 struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev,\r
446                                     struct ib_ucontext *context,\r
447                                     ci_umv_buf_t* const                 p_umv_buf)\r
448 {\r
449         int err;\r
450         struct mthca_pd *pd;\r
451         struct ibv_alloc_pd_resp resp;\r
452 \r
453         /* sanity check */\r
454         if (p_umv_buf && p_umv_buf->command) {\r
455                 if (p_umv_buf->output_size < sizeof(struct ibv_alloc_pd_resp)) {\r
456                         err = -EINVAL;\r
457                         goto err_param;\r
458                 }\r
459         }\r
460         \r
461         pd = kmalloc(sizeof *pd, GFP_KERNEL);\r
462         if (!pd) {\r
463                 err = -ENOMEM;\r
464                 goto err_mem;\r
465         }\r
466 \r
467         if (mthca_is_livefish(to_mdev(ibdev))) \r
468                 goto done;\r
469 \r
470         err = mthca_pd_alloc(to_mdev(ibdev), !context, pd);\r
471         if (err) {\r
472                 goto err_pd_alloc;\r
473         }\r
474 \r
475 done:\r
476         if (p_umv_buf && p_umv_buf->command) {\r
477                 resp.pd_handle = (u64)(UINT_PTR)pd;\r
478                 resp.pdn = pd->pd_num;\r
479                 if (ib_copy_to_umv_buf(p_umv_buf, &resp, sizeof(struct ibv_alloc_pd_resp))) {\r
480                         err = -EFAULT;\r
481                         goto err_copy;\r
482                 }\r
483         }\r
484 \r
485         return &pd->ibpd;\r
486 \r
487 err_copy:       \r
488         mthca_pd_free(to_mdev(ibdev), pd);\r
489 err_pd_alloc:\r
490         kfree(pd);\r
491 err_mem:\r
492 err_param:\r
493         return ERR_PTR(err);\r
494 }\r
495 \r
496 int mthca_dealloc_pd(struct ib_pd *pd)\r
497 {\r
498         if (mthca_is_livefish(to_mdev(pd->device))) \r
499                 goto done;\r
500 \r
501         mthca_pd_free(to_mdev(pd->device), to_mpd(pd));\r
502 \r
503 done:   \r
504         kfree(pd);\r
505         return 0;\r
506 }\r
507 \r
508 static struct ib_ah *mthca_ah_create(struct ib_pd *pd,\r
509                                      struct ib_ah_attr *ah_attr)\r
510 {\r
511         int err;\r
512         struct mthca_ah *ah;\r
513 \r
514         ah = kzalloc(sizeof *ah, GFP_ATOMIC);\r
515         if (!ah)\r
516                 return ERR_PTR(-ENOMEM);\r
517 \r
518         err = mthca_create_ah(to_mdev(pd->device), to_mpd(pd), ah_attr, ah);\r
519         if (err) {\r
520                 kfree(ah);\r
521                 return ERR_PTR(err);\r
522         }\r
523 \r
524         return &ah->ibah;\r
525 }\r
526 \r
527 static int mthca_ah_destroy(struct ib_ah *ah)\r
528 {\r
529         mthca_destroy_ah(to_mdev(ah->device), to_mah(ah));\r
530         kfree(ah);\r
531 \r
532         return 0;\r
533 }\r
534 \r
535 static struct ib_srq *mthca_create_srq(struct ib_pd *pd,\r
536                                 struct ib_srq_init_attr *init_attr,\r
537                                 ci_umv_buf_t* const p_umv_buf)\r
538 {\r
539         struct ibv_create_srq ucmd = { 0 };\r
540         struct mthca_ucontext *context = NULL;\r
541         struct mthca_srq *srq;\r
542         int err;\r
543 \r
544         srq = kzalloc(sizeof *srq, GFP_KERNEL);\r
545         if (!srq)\r
546                 return ERR_PTR(-ENOMEM);\r
547 \r
548         if (pd->ucontext) {\r
549                 context = to_mucontext(pd->ucontext);\r
550 \r
551                 if (ib_copy_from_umv_buf(&ucmd, p_umv_buf, sizeof ucmd)) {\r
552                         err = -EFAULT;\r
553                         goto err_free;\r
554                 }\r
555                 err = mthca_map_user_db(to_mdev(pd->device), &context->uar,\r
556                                         context->db_tab, ucmd.db_index,\r
557                                         ucmd.db_page, NULL);\r
558 \r
559                 if (err)\r
560                         goto err_free;\r
561 \r
562                 srq->mr.ibmr.lkey = ucmd.lkey;\r
563                 srq->db_index     = ucmd.db_index;\r
564         }\r
565 \r
566         err = mthca_alloc_srq(to_mdev(pd->device), to_mpd(pd),\r
567                 &init_attr->attr, srq);\r
568 \r
569         if (err && pd->ucontext)\r
570                 mthca_unmap_user_db(to_mdev(pd->device), &context->uar,\r
571                         context->db_tab, ucmd.db_index);\r
572 \r
573         if (err)\r
574                 goto err_free;\r
575 \r
576         if (context && ib_copy_to_umv_buf(p_umv_buf, &srq->srqn, sizeof (u32))) {\r
577                 mthca_free_srq(to_mdev(pd->device), srq);\r
578                 err = -EFAULT;\r
579                 goto err_free;\r
580         }\r
581 \r
582         return &srq->ibsrq;\r
583 \r
584 err_free:\r
585         kfree(srq);\r
586 \r
587         return ERR_PTR(err);\r
588 }\r
589 \r
590 static int mthca_destroy_srq(struct ib_srq *srq)\r
591 {\r
592         struct mthca_ucontext *context;\r
593 \r
594         if (srq->ucontext) {\r
595                 context = to_mucontext(srq->ucontext);\r
596 \r
597                 mthca_unmap_user_db(to_mdev(srq->device), &context->uar,\r
598                         context->db_tab, to_msrq(srq)->db_index);\r
599         }\r
600 \r
601         mthca_free_srq(to_mdev(srq->device), to_msrq(srq));\r
602         kfree(srq);\r
603 \r
604         return 0;\r
605 }\r
606 \r
607 static struct ib_qp *mthca_create_qp(struct ib_pd *pd,\r
608                                      struct ib_qp_init_attr *init_attr,\r
609                                       ci_umv_buf_t* const                       p_umv_buf)\r
610 {\r
611         struct ibv_create_qp ucmd = {0};\r
612         struct mthca_qp *qp = NULL;\r
613         struct mthca_ucontext *context = NULL;\r
614         int err;\r
615 \r
616         switch (init_attr->qp_type) {\r
617         case IB_QPT_RELIABLE_CONN:\r
618         case IB_QPT_UNRELIABLE_CONN:\r
619         case IB_QPT_UNRELIABLE_DGRM:\r
620         {\r
621 \r
622                 qp = kmalloc(sizeof *qp, GFP_KERNEL);\r
623                 if (!qp) {\r
624                         err = -ENOMEM;\r
625                         goto err_mem;\r
626                 }\r
627 \r
628                 if (pd->ucontext) {\r
629                         context = to_mucontext(pd->ucontext);\r
630 \r
631                         if (ib_copy_from_umv_buf(&ucmd, p_umv_buf, sizeof ucmd)) {\r
632                                 err = -EFAULT;\r
633                                 goto err_copy;\r
634                         }\r
635 \r
636                         err = mthca_map_user_db(to_mdev(pd->device), &context->uar,\r
637                                                 context->db_tab,\r
638                                                 ucmd.sq_db_index, ucmd.sq_db_page, NULL);\r
639                         if (err) \r
640                                 goto err_map1;\r
641 \r
642                         err = mthca_map_user_db(to_mdev(pd->device), &context->uar,\r
643                                                 context->db_tab,\r
644                                                 ucmd.rq_db_index, ucmd.rq_db_page, NULL);\r
645                         if (err) \r
646                                 goto err_map2;\r
647 \r
648                         qp->mr.ibmr.lkey = ucmd.lkey;\r
649                         qp->sq.db_index  = ucmd.sq_db_index;\r
650                         qp->rq.db_index  = ucmd.rq_db_index;\r
651                 }\r
652 \r
653                 err = mthca_alloc_qp(to_mdev(pd->device), to_mpd(pd),\r
654                                      to_mcq(init_attr->send_cq),\r
655                                      to_mcq(init_attr->recv_cq),\r
656                                      init_attr->qp_type, init_attr->sq_sig_type,\r
657                                      &init_attr->cap, qp);\r
658 \r
659                 if (err)\r
660                         if (pd->ucontext) \r
661                                 goto err_alloc_qp_user;\r
662                         else \r
663                                 goto err_copy;\r
664 \r
665                 qp->ibqp.qp_num = qp->qpn;\r
666                 break;\r
667         }\r
668         case IB_QPT_QP0:\r
669         case IB_QPT_QP1:\r
670         {\r
671                 /* Don't allow userspace to create special QPs */\r
672                 if (pd->ucontext) {\r
673                         err = -EINVAL;\r
674                         goto err_inval;\r
675                 }\r
676 \r
677                 qp = kmalloc(sizeof (struct mthca_sqp), GFP_KERNEL);\r
678                 if (!qp) {\r
679                         err = -ENOMEM;\r
680                         goto err_mem;\r
681                 }\r
682 \r
683                 qp->ibqp.qp_num = init_attr->qp_type == IB_QPT_QP0 ? 0 : 1;\r
684 \r
685                 err = mthca_alloc_sqp(to_mdev(pd->device), to_mpd(pd),\r
686                                       to_mcq(init_attr->send_cq),\r
687                                       to_mcq(init_attr->recv_cq),\r
688                                       init_attr->sq_sig_type, &init_attr->cap,\r
689                                       qp->ibqp.qp_num, init_attr->port_num,\r
690                                       to_msqp(qp));\r
691                 if (err)\r
692                         goto err_alloc_sqp;\r
693                 \r
694                 break;\r
695         }\r
696         default:\r
697                 /* Don't support raw QPs */\r
698                 err = -ENOSYS;\r
699                 goto err_unsupported;\r
700         }\r
701 \r
702         init_attr->cap.max_send_wr     = qp->sq.max;\r
703         init_attr->cap.max_recv_wr     = qp->rq.max;\r
704         init_attr->cap.max_send_sge    = qp->sq.max_gs;\r
705         init_attr->cap.max_recv_sge    = qp->rq.max_gs;\r
706         init_attr->cap.max_inline_data    = qp->max_inline_data;\r
707 \r
708         return &qp->ibqp;\r
709 \r
710                 \r
711 err_alloc_qp_user:\r
712         if (pd->ucontext) \r
713                 mthca_unmap_user_db(to_mdev(pd->device),\r
714                         &context->uar, context->db_tab, ucmd.rq_db_index);\r
715 err_map2:\r
716         if (pd->ucontext) \r
717                 mthca_unmap_user_db(to_mdev(pd->device),\r
718                         &context->uar, context->db_tab, ucmd.sq_db_index);\r
719 err_map1: err_copy: err_alloc_sqp:\r
720         if (qp)\r
721                 kfree(qp);\r
722 err_mem: err_inval:     err_unsupported:\r
723         return ERR_PTR(err);\r
724 }\r
725 \r
726 static int mthca_destroy_qp(struct ib_qp *qp)\r
727 {\r
728         if (qp->ucontext) {\r
729                 mthca_unmap_user_db(to_mdev(qp->device),\r
730                                     &to_mucontext(qp->ucontext)->uar,\r
731                                     to_mucontext(qp->ucontext)->db_tab,\r
732                                     to_mqp(qp)->sq.db_index);\r
733                 mthca_unmap_user_db(to_mdev(qp->device),\r
734                                     &to_mucontext(qp->ucontext)->uar,\r
735                                     to_mucontext(qp->ucontext)->db_tab,\r
736                                     to_mqp(qp)->rq.db_index);\r
737         }\r
738         mthca_free_qp(to_mdev(qp->device), to_mqp(qp));\r
739         kfree(qp);\r
740         return 0;\r
741 }\r
742 \r
743 static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries,\r
744                                      struct ib_ucontext *context,\r
745                                      ci_umv_buf_t* const                        p_umv_buf)\r
746 {\r
747         struct ibv_create_cq ucmd = {0};\r
748         struct mthca_cq *cq;\r
749         int nent;\r
750         int err;\r
751         void *u_arm_db_page = 0;\r
752 \r
753         if (entries < 1 || entries > to_mdev(ibdev)->limits.max_cqes)   \r
754                 return ERR_PTR(-EINVAL);\r
755 \r
756         if (context) {\r
757                 if (ib_copy_from_umv_buf(&ucmd, p_umv_buf, sizeof ucmd))\r
758                         return ERR_PTR(-EFAULT);\r
759 \r
760                 err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,\r
761                                         to_mucontext(context)->db_tab,\r
762                                         ucmd.set_db_index, ucmd.set_db_page, NULL);\r
763                 if (err)\r
764                         return ERR_PTR(err);\r
765 \r
766                 err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,\r
767                                         to_mucontext(context)->db_tab,\r
768                                         ucmd.arm_db_index, ucmd.arm_db_page, NULL);\r
769                 if (err)\r
770                         goto err_unmap_set;\r
771 \r
772                 err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,\r
773                                         to_mucontext(context)->db_tab,\r
774                                         ucmd.u_arm_db_index, \r
775                                         (u64)(ULONG_PTR)PAGE_ALIGN(ucmd.u_arm_db_page), \r
776                                         &u_arm_db_page);\r
777                 if (err)\r
778                         goto err_unmap_arm;\r
779         }\r
780 \r
781         cq = kmalloc(sizeof *cq, GFP_KERNEL);\r
782         if (!cq) {\r
783                 err = -ENOMEM;\r
784                 goto err_unmap_ev;\r
785         }\r
786 \r
787         if (context) {\r
788                 cq->mr.ibmr.lkey = ucmd.lkey;\r
789                 cq->set_ci_db_index = ucmd.set_db_index;\r
790                 cq->arm_db_index    = ucmd.arm_db_index;\r
791                 cq->u_arm_db_index    = ucmd.u_arm_db_index;\r
792                 cq->p_u_arm_sn = (int*)((char*)u_arm_db_page + BYTE_OFFSET(ucmd.u_arm_db_page));\r
793         }\r
794 \r
795         for (nent = 1; nent <= entries; nent <<= 1)\r
796                 ; /* nothing */\r
797 \r
798         err = mthca_init_cq(to_mdev(ibdev), nent, \r
799                             context ? to_mucontext(context) : NULL,\r
800                             context ? ucmd.mr.pdn : to_mdev(ibdev)->driver_pd.pd_num,\r
801                             cq);\r
802         if (err)\r
803                 goto err_free;\r
804 \r
805         if (context) {\r
806                 struct ibv_create_cq_resp *create_cq_resp = (struct ibv_create_cq_resp *)(ULONG_PTR)p_umv_buf->p_inout_buf;\r
807                 create_cq_resp->cqn = cq->cqn;\r
808         }\r
809 \r
810         HCA_PRINT( TRACE_LEVEL_INFORMATION, HCA_DBG_LOW ,\r
811                 ("uctx %p, cq_hndl %p, cq_num %#x, cqe  %#x\n",\r
812                 context, &cq->ibcq, cq->cqn, cq->ibcq.cqe ) );\r
813         \r
814         return &cq->ibcq;\r
815 \r
816 err_free:\r
817         kfree(cq);\r
818 \r
819 err_unmap_ev:\r
820         if (context)\r
821                 mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,\r
822                                     to_mucontext(context)->db_tab, ucmd.u_arm_db_index);\r
823 \r
824 err_unmap_arm:\r
825         if (context)\r
826                 mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,\r
827                                     to_mucontext(context)->db_tab, ucmd.arm_db_index);\r
828 \r
829 err_unmap_set:\r
830         if (context)\r
831                 mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,\r
832                                     to_mucontext(context)->db_tab, ucmd.set_db_index);\r
833 \r
834         return ERR_PTR(err);\r
835 }\r
836 \r
837 static int mthca_destroy_cq(struct ib_cq *cq)\r
838 {\r
839         if (cq->ucontext) {\r
840                 mthca_unmap_user_db(to_mdev(cq->device),\r
841                                     &to_mucontext(cq->ucontext)->uar,\r
842                                     to_mucontext(cq->ucontext)->db_tab,\r
843                                     to_mcq(cq)->u_arm_db_index);\r
844                 mthca_unmap_user_db(to_mdev(cq->device),\r
845                                     &to_mucontext(cq->ucontext)->uar,\r
846                                     to_mucontext(cq->ucontext)->db_tab,\r
847                                     to_mcq(cq)->arm_db_index);\r
848                 mthca_unmap_user_db(to_mdev(cq->device),\r
849                                     &to_mucontext(cq->ucontext)->uar,\r
850                                     to_mucontext(cq->ucontext)->db_tab,\r
851                                     to_mcq(cq)->set_ci_db_index);\r
852         }\r
853         mthca_free_cq(to_mdev(cq->device), to_mcq(cq));\r
854         kfree(cq);\r
855 \r
856         return 0;\r
857 }\r
858 \r
859 static\r
860 mthca_mpt_access_t\r
861 map_qp_mpt(\r
862         IN                              mthca_qp_access_t                               qp_acl)\r
863 {\r
864 #define ACL_MTHCA(mfl,ifl) if (qp_acl & mfl)   mpt_acl |= ifl\r
865         mthca_mpt_access_t mpt_acl = 0;\r
866 \r
867         ACL_MTHCA(MTHCA_ACCESS_REMOTE_READ,MTHCA_MPT_FLAG_REMOTE_READ);\r
868         ACL_MTHCA(MTHCA_ACCESS_REMOTE_WRITE,MTHCA_MPT_FLAG_REMOTE_WRITE);\r
869         ACL_MTHCA(MTHCA_ACCESS_REMOTE_ATOMIC,MTHCA_MPT_FLAG_ATOMIC);\r
870         ACL_MTHCA(MTHCA_ACCESS_LOCAL_WRITE,MTHCA_MPT_FLAG_LOCAL_WRITE);\r
871 \r
872         return (mpt_acl | MTHCA_MPT_FLAG_LOCAL_READ);\r
873 }\r
874 \r
875 struct ib_mr *mthca_get_dma_mr(struct ib_pd *pd, mthca_qp_access_t acc)\r
876 {\r
877         struct mthca_mr *mr;\r
878         int err;\r
879 \r
880         mr = kzalloc(sizeof *mr, GFP_KERNEL);\r
881         if (!mr)\r
882                 return ERR_PTR(-ENOMEM);\r
883 \r
884         err = mthca_mr_alloc_notrans(to_mdev(pd->device),\r
885                                      to_mpd(pd)->pd_num,\r
886                                      map_qp_mpt(acc), mr);\r
887 \r
888         if (err) {\r
889                 kfree(mr);\r
890                 return ERR_PTR(err);\r
891         }\r
892 \r
893         return &mr->ibmr;\r
894 }\r
895 \r
896 static struct ib_mr *mthca_reg_phys_mr(struct ib_pd       *pd,\r
897                                        struct ib_phys_buf *buffer_list,\r
898                                        int                 num_phys_buf,\r
899                                        mthca_qp_access_t                 acc,\r
900                                        u64                *iova_start)\r
901 {\r
902         struct mthca_mr *mr;\r
903         u64 *page_list;\r
904         u64 total_size;\r
905         u64 mask;\r
906         int shift;\r
907         int npages;\r
908         int err;\r
909         int i, j, n;\r
910 \r
911         /* First check that we have enough alignment */\r
912         if ((*iova_start & ~PAGE_MASK) != (buffer_list[0].addr & ~PAGE_MASK))\r
913                 return ERR_PTR(-EINVAL);\r
914 \r
915         if (num_phys_buf > 1 &&\r
916             ((buffer_list[0].addr + buffer_list[0].size) & ~PAGE_MASK))\r
917                 return ERR_PTR(-EINVAL);\r
918 \r
919         mask = 0;\r
920         total_size = 0;\r
921         for (i = 0; i < num_phys_buf; ++i) {\r
922                 if (i != 0)\r
923                         mask |= buffer_list[i].addr;\r
924                 if (i != num_phys_buf - 1)\r
925                         mask |= buffer_list[i].addr + buffer_list[i].size;\r
926 \r
927                 total_size += buffer_list[i].size;\r
928         }\r
929 \r
930         if (mask & ~PAGE_MASK)\r
931                 return ERR_PTR(-EINVAL);\r
932 \r
933         /* Find largest page shift we can use to cover buffers */\r
934         for (shift = PAGE_SHIFT; shift < 31; ++shift)\r
935                 if (num_phys_buf > 1) {\r
936                         if ((1Ui64 << shift) & mask)\r
937                                 break;\r
938                 } else {\r
939                         if (1Ui64 << shift >=\r
940                             buffer_list[0].size +\r
941                             (buffer_list[0].addr & ((1Ui64 << shift) - 1)))\r
942                                 break;\r
943                 }\r
944 \r
945         buffer_list[0].size += buffer_list[0].addr & ((1Ui64 << shift) - 1);\r
946         buffer_list[0].addr &= ~0Ui64 << shift;\r
947 \r
948         mr = kzalloc(sizeof *mr, GFP_KERNEL);\r
949         if (!mr)\r
950                 return ERR_PTR(-ENOMEM);\r
951 \r
952         npages = 0;\r
953         for (i = 0; i < num_phys_buf; ++i)\r
954                 npages += (int)((buffer_list[i].size + (1Ui64 << shift) - 1) >> shift);\r
955 \r
956         if (!npages)\r
957                 return &mr->ibmr;\r
958 \r
959         page_list = kmalloc(npages * sizeof *page_list, GFP_KERNEL);\r
960         if (!page_list) {\r
961                 kfree(mr);\r
962                 return ERR_PTR(-ENOMEM);\r
963         }\r
964 \r
965         n = 0;\r
966         for (i = 0; i < num_phys_buf; ++i)\r
967                 for (j = 0;\r
968                      j < (buffer_list[i].size + (1Ui64 << shift) - 1) >> shift;\r
969                      ++j)\r
970                         page_list[n++] = buffer_list[i].addr + ((u64) j << shift);\r
971 \r
972         HCA_PRINT( TRACE_LEVEL_VERBOSE ,HCA_DBG_LOW ,("Registering memory at %I64x (iova %I64x) "\r
973                   "in PD %x; shift %d, npages %d.\n",\r
974                   (u64) buffer_list[0].addr,\r
975                   (u64) *iova_start,\r
976                   to_mpd(pd)->pd_num,\r
977                   shift, npages));\r
978 \r
979         err = mthca_mr_alloc_phys(to_mdev(pd->device),\r
980                                   to_mpd(pd)->pd_num,\r
981                                   page_list, shift, npages,\r
982                                   *iova_start, total_size,\r
983                                   map_qp_mpt(acc), mr);\r
984 \r
985         if (err) {\r
986                 kfree(page_list);\r
987                 kfree(mr);\r
988                 return ERR_PTR(err);\r
989         }\r
990 \r
991         kfree(page_list);\r
992         return &mr->ibmr;\r
993 }\r
994 \r
995 static struct ib_mr *mthca_reg_virt_mr(struct ib_pd *pd, \r
996         void* vaddr, uint64_t length, uint64_t hca_va,\r
997         mthca_qp_access_t acc, boolean_t um_call, boolean_t secure)\r
998 {\r
999         struct mthca_dev *dev = to_mdev(pd->device);\r
1000         struct mthca_mr *mr;\r
1001         u64 *pages;\r
1002         int err = 0;\r
1003         uint32_t i, n;\r
1004         mt_iobuf_t *iobuf_p;\r
1005         mt_iobuf_iter_t iobuf_iter;\r
1006         ib_access_t ib_acc;\r
1007 \r
1008         /*\r
1009          * Be friendly to WRITE_MTT command and leave two \r
1010          * empty slots for the  index and reserved fields of the mailbox.\r
1011          */\r
1012         int max_buf_list_size = PAGE_SIZE / sizeof (u64) - 2;\r
1013 \r
1014         HCA_ENTER(HCA_DBG_MEMORY);\r
1015 \r
1016         mr = kzalloc(sizeof *mr, GFP_KERNEL);\r
1017         if (!mr) {\r
1018                 err = -ENOMEM;\r
1019                 goto err_nomem;\r
1020         }\r
1021 \r
1022         /*\r
1023          * We ask for writable memory if any access flags other than\r
1024          * "remote read" are set.  "Local write" and "remote write"\r
1025          * obviously require write access.  "Remote atomic" can do\r
1026          * things like fetch and add, which will modify memory, and\r
1027          * "MW bind" can change permissions by binding a window.\r
1028          */\r
1029 \r
1030         // try register the buffer\r
1031         iobuf_p = &mr->iobuf;\r
1032         iobuf_init( (ULONG_PTR)vaddr, length, um_call, iobuf_p);\r
1033         ib_acc = (acc & ~MTHCA_ACCESS_REMOTE_READ) ? IB_AC_LOCAL_WRITE : 0;\r
1034         err =  iobuf_register_with_cash( (ULONG_PTR)vaddr, length, um_call, \r
1035                 &ib_acc, iobuf_p );\r
1036         if (err)\r
1037                 goto err_reg_mem;\r
1038         mr->iobuf_used = TRUE;\r
1039 \r
1040         // allocate MTT's\r
1041         mr->mtt = mthca_alloc_mtt(dev, iobuf_p->nr_pages);\r
1042         if (IS_ERR(mr->mtt)) {\r
1043                 err = PTR_ERR(mr->mtt);\r
1044                 goto err_alloc_mtt;\r
1045         }\r
1046 \r
1047         // allocate buffer_list for writing MTT's\r
1048         pages = (u64 *) kmalloc(PAGE_SIZE,GFP_KERNEL);\r
1049         if (!pages) {\r
1050                 err = -ENOMEM;\r
1051                 goto err_pages;\r
1052         }\r
1053 \r
1054         // write MTT's\r
1055         iobuf_iter_init( iobuf_p, &iobuf_iter );\r
1056         n = 0;\r
1057         for (;;) {\r
1058                 // get up to  max_buf_list_size page physical addresses\r
1059                 i = iobuf_get_tpt_seg( iobuf_p, &iobuf_iter, max_buf_list_size, pages );\r
1060                 if (!i)\r
1061                         break;\r
1062 \r
1063                 //TODO: convert physical adresses to dma one's\r
1064 \r
1065                 // write 'i' dma addresses\r
1066                 err = mthca_write_mtt(dev, mr->mtt, n, pages, i);\r
1067                 if (err)\r
1068                         goto err_write_mtt;\r
1069                 n += i;\r
1070                 if (n >= iobuf_p->nr_pages)\r
1071                         break;\r
1072         }\r
1073 \r
1074         CL_ASSERT(n == iobuf_p->nr_pages);\r
1075         \r
1076         // write MPT\r
1077         err = mthca_mr_alloc(dev, to_mpd(pd)->pd_num, PAGE_SHIFT, hca_va,\r
1078                 length, map_qp_mpt(acc), mr);\r
1079         if (err)\r
1080                 goto err_mt_alloc;\r
1081 \r
1082         // secure memory\r
1083         if (!pd->ucontext || !secure)\r
1084                 goto done;\r
1085         __try {\r
1086                 mr->secure_handle = MmSecureVirtualMemory ( vaddr, (SIZE_T)length,\r
1087                         (ib_acc & IB_AC_LOCAL_WRITE) ? PAGE_READWRITE : PAGE_READONLY );\r
1088                 if (mr->secure_handle == NULL) {\r
1089                         err = -EFAULT;\r
1090                         goto err_secure;\r
1091                 }\r
1092         }\r
1093         __except (EXCEPTION_EXECUTE_HANDLER) {\r
1094                 NTSTATUS Status = GetExceptionCode();\r
1095                 UNUSED_PARAM_WOWPP(Status);\r
1096                 HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY ,\r
1097                         ("Exception 0x%x on MmSecureVirtualMemory(), addr %p, size %I64d, access %#x\n", \r
1098                         Status, vaddr, length, acc ));\r
1099                 err = -EFAULT;\r
1100                 goto err_secure;\r
1101         }\r
1102 \r
1103 done:   \r
1104         free_page((void*) pages);\r
1105 \r
1106         HCA_EXIT(HCA_DBG_MEMORY);\r
1107         return &mr->ibmr;\r
1108 \r
1109 err_secure:\r
1110 err_mt_alloc:\r
1111 err_write_mtt:\r
1112         free_page((void*) pages);\r
1113 err_pages:\r
1114         mthca_free_mtt(dev, mr->mtt);\r
1115 err_alloc_mtt:\r
1116         iobuf_deregister(iobuf_p);\r
1117 err_reg_mem:    \r
1118         kfree(mr);\r
1119 err_nomem:      \r
1120 \r
1121         HCA_EXIT(HCA_DBG_MEMORY);\r
1122         return ERR_PTR(err);\r
1123 }\r
1124 \r
1125 int mthca_dereg_mr(struct ib_mr *mr)\r
1126 {\r
1127         struct mthca_mr *mmr = to_mmr(mr);\r
1128         struct mthca_dev* dev = to_mdev(mr->device);\r
1129 \r
1130         if (mmr->secure_handle) {\r
1131                 __try {\r
1132                         MmUnsecureVirtualMemory( mmr->secure_handle );\r
1133                         mmr->secure_handle = NULL;\r
1134                 }\r
1135                 __except (EXCEPTION_EXECUTE_HANDLER) {\r
1136                         NTSTATUS Status = GetExceptionCode();\r
1137                         UNUSED_PARAM_WOWPP(Status);\r
1138                         HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_MEMORY ,\r
1139                                 ("Exception 0x%x on MmUnsecureVirtualMemory(), addr %I64x, size %I64x, seg_num %d, nr_pages %d\n", \r
1140                                 Status, mmr->iobuf.va, (u64)mmr->iobuf.size, mmr->iobuf.seg_num, mmr->iobuf.nr_pages ));\r
1141                 }\r
1142         }\r
1143         mthca_free_mr(dev, mmr);\r
1144         if (mmr->iobuf_used)\r
1145                 iobuf_deregister_with_cash(&mmr->iobuf);\r
1146         kfree(mmr);\r
1147         return 0;\r
1148 }\r
1149 \r
1150 static struct ib_fmr *mthca_alloc_fmr(struct ib_pd *pd, mthca_qp_access_t acc,\r
1151                                       struct ib_fmr_attr *fmr_attr)\r
1152 {\r
1153         struct mthca_fmr *fmr;\r
1154         int err;\r
1155 \r
1156         fmr = kzalloc(sizeof *fmr, GFP_KERNEL);\r
1157         if (!fmr)\r
1158                 return ERR_PTR(-ENOMEM);\r
1159 \r
1160         RtlCopyMemory(&fmr->attr, fmr_attr, sizeof *fmr_attr);\r
1161         err = mthca_fmr_alloc(to_mdev(pd->device), to_mpd(pd)->pd_num,\r
1162                              map_qp_mpt(acc), fmr);\r
1163 \r
1164         if (err) {\r
1165                 kfree(fmr);\r
1166                 return ERR_PTR(err);\r
1167         }\r
1168 \r
1169         return &fmr->ibfmr;\r
1170 }\r
1171 \r
1172 static int mthca_dealloc_fmr(struct ib_fmr *fmr)\r
1173 {\r
1174         struct mthca_fmr *mfmr = to_mfmr(fmr);\r
1175         int err;\r
1176 \r
1177         err = mthca_free_fmr(to_mdev(fmr->device), mfmr);\r
1178         if (err)\r
1179                 return err;\r
1180 \r
1181         kfree(mfmr);\r
1182         return 0;\r
1183 }\r
1184 \r
1185 static int mthca_unmap_fmr(struct list_head *fmr_list)\r
1186 {\r
1187         struct ib_fmr *fmr;\r
1188         int err;\r
1189         u8 status;\r
1190         struct mthca_dev *mdev = NULL;\r
1191 \r
1192         list_for_each_entry(fmr, fmr_list, list,struct ib_fmr) {\r
1193                 if (mdev && to_mdev(fmr->device) != mdev)\r
1194                         return -EINVAL;\r
1195                 mdev = to_mdev(fmr->device);\r
1196         }\r
1197 \r
1198         if (!mdev)\r
1199                 return 0;\r
1200 \r
1201         if (mthca_is_memfree(mdev)) {\r
1202                 list_for_each_entry(fmr, fmr_list, list,struct ib_fmr)\r
1203                         mthca_arbel_fmr_unmap(mdev, to_mfmr(fmr));\r
1204 \r
1205                 wmb();\r
1206         } else\r
1207                 list_for_each_entry(fmr, fmr_list, list,struct ib_fmr)\r
1208                         mthca_tavor_fmr_unmap(mdev, to_mfmr(fmr));\r
1209 \r
1210         err = mthca_SYNC_TPT(mdev, &status);\r
1211         if (err)\r
1212                 return err;\r
1213         if (status)\r
1214                 return -EINVAL;\r
1215         return 0;\r
1216 }\r
1217 \r
1218 static int mthca_init_node_data(struct mthca_dev *dev)\r
1219 {\r
1220         struct ib_smp *in_mad  = NULL;\r
1221         struct ib_smp *out_mad = NULL;\r
1222         int err = -ENOMEM;\r
1223         u8 status;\r
1224 \r
1225         in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);\r
1226         out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);\r
1227         if (!in_mad || !out_mad)\r
1228                 goto out;\r
1229 \r
1230         init_query_mad(in_mad);\r
1231         in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;\r
1232 \r
1233         err = mthca_MAD_IFC(dev, 1, 1,\r
1234                             1, NULL, NULL, in_mad, out_mad,\r
1235                             &status);\r
1236         if (err)\r
1237                 goto out;\r
1238         if (status) {\r
1239                 err = -EINVAL;\r
1240                 goto out;\r
1241         }\r
1242 \r
1243         memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8);\r
1244 \r
1245 out:\r
1246         kfree(in_mad);\r
1247         kfree(out_mad);\r
1248         return err;\r
1249 }\r
1250 \r
1251 int mthca_register_device(struct mthca_dev *dev)\r
1252 {\r
1253         int ret;\r
1254 \r
1255         ret = mthca_init_node_data(dev);        \r
1256         if (ret)\r
1257                 return ret;\r
1258 \r
1259         strlcpy(dev->ib_dev.name, "mthca%d", IB_DEVICE_NAME_MAX);\r
1260         dev->ib_dev.node_type            = IB_NODE_CA;\r
1261         dev->ib_dev.phys_port_cnt        = (u8)dev->limits.num_ports;\r
1262         dev->ib_dev.mdev                                = dev;\r
1263         dev->ib_dev.query_device         = mthca_query_device;\r
1264         dev->ib_dev.query_port           = mthca_query_port;\r
1265         dev->ib_dev.modify_port          = mthca_modify_port;\r
1266         dev->ib_dev.query_pkey_chunk           = mthca_query_pkey_chunk;\r
1267         dev->ib_dev.query_gid_chunk            = mthca_query_gid_chunk;\r
1268         dev->ib_dev.alloc_ucontext       = mthca_alloc_ucontext;\r
1269         dev->ib_dev.dealloc_ucontext     = mthca_dealloc_ucontext;\r
1270         dev->ib_dev.alloc_pd             = mthca_alloc_pd;\r
1271         dev->ib_dev.dealloc_pd           = mthca_dealloc_pd;\r
1272         dev->ib_dev.create_ah            = mthca_ah_create;\r
1273         dev->ib_dev.destroy_ah           = mthca_ah_destroy;\r
1274 \r
1275         if (dev->mthca_flags & MTHCA_FLAG_SRQ) {\r
1276                 dev->ib_dev.create_srq           = mthca_create_srq;\r
1277                 dev->ib_dev.modify_srq           = mthca_modify_srq;\r
1278                 dev->ib_dev.query_srq            = mthca_query_srq;\r
1279                 dev->ib_dev.destroy_srq          = mthca_destroy_srq;\r
1280 \r
1281                 if (mthca_is_memfree(dev))\r
1282                         dev->ib_dev.post_srq_recv = mthca_arbel_post_srq_recv;\r
1283                 else\r
1284                         dev->ib_dev.post_srq_recv = mthca_tavor_post_srq_recv;\r
1285         }\r
1286 \r
1287         dev->ib_dev.create_qp            = mthca_create_qp;\r
1288         dev->ib_dev.modify_qp            = mthca_modify_qp;\r
1289         dev->ib_dev.query_qp             = mthca_query_qp;\r
1290         dev->ib_dev.destroy_qp           = mthca_destroy_qp;\r
1291         dev->ib_dev.create_cq            = mthca_create_cq;\r
1292         dev->ib_dev.destroy_cq           = mthca_destroy_cq;\r
1293         dev->ib_dev.poll_cq              = mthca_poll_cq;\r
1294         dev->ib_dev.get_dma_mr           = mthca_get_dma_mr;\r
1295         dev->ib_dev.reg_phys_mr          = mthca_reg_phys_mr;\r
1296         dev->ib_dev.reg_virt_mr                  = mthca_reg_virt_mr;\r
1297         dev->ib_dev.dereg_mr             = mthca_dereg_mr;\r
1298 \r
1299         if (dev->mthca_flags & MTHCA_FLAG_FMR) {\r
1300                 dev->ib_dev.alloc_fmr            = mthca_alloc_fmr;\r
1301                 dev->ib_dev.unmap_fmr            = mthca_unmap_fmr;\r
1302                 dev->ib_dev.dealloc_fmr          = mthca_dealloc_fmr;\r
1303                 if (mthca_is_memfree(dev))\r
1304                         dev->ib_dev.map_phys_fmr = mthca_arbel_map_phys_fmr;\r
1305                 else\r
1306                         dev->ib_dev.map_phys_fmr = mthca_tavor_map_phys_fmr;\r
1307         }\r
1308 \r
1309         dev->ib_dev.attach_mcast         = mthca_multicast_attach;\r
1310         dev->ib_dev.detach_mcast         = mthca_multicast_detach;\r
1311         dev->ib_dev.process_mad          = mthca_process_mad;\r
1312 \r
1313         if (mthca_is_memfree(dev)) {\r
1314                 dev->ib_dev.req_notify_cq = mthca_arbel_arm_cq;\r
1315                 dev->ib_dev.post_send = mthca_arbel_post_send;\r
1316                 dev->ib_dev.post_recv = mthca_arbel_post_recv;\r
1317         } else {\r
1318                 dev->ib_dev.req_notify_cq = mthca_tavor_arm_cq;\r
1319                 dev->ib_dev.post_send = mthca_tavor_post_send;\r
1320                 dev->ib_dev.post_recv = mthca_tavor_post_recv;\r
1321         }\r
1322 \r
1323         KeInitializeMutex(&dev->cap_mask_mutex, 0);\r
1324 \r
1325         ret = ib_register_device(&dev->ib_dev);\r
1326         if (ret)\r
1327                 return ret;\r
1328 \r
1329         mthca_start_catas_poll(dev);\r
1330 \r
1331         return 0;\r
1332 }\r
1333 \r
1334 void mthca_unregister_device(struct mthca_dev *dev)\r
1335 {\r
1336         mthca_stop_catas_poll(dev);\r
1337         ib_unregister_device(&dev->ib_dev);\r
1338 }\r