Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. | |
cd4e8fb4 | 3 | * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. |
5e0b537c | 4 | * Copyright (c) 2005 Cisco Systems. All rights reserved. |
2a1d9b7f RD |
5 | * Copyright (c) 2005 Mellanox Technologies. All rights reserved. |
6 | * Copyright (c) 2004 Voltaire, Inc. All rights reserved. | |
1da177e4 LT |
7 | * |
8 | * This software is available to you under a choice of one of two | |
9 | * licenses. You may choose to be licensed under the terms of the GNU | |
10 | * General Public License (GPL) Version 2, available from the file | |
11 | * COPYING in the main directory of this source tree, or the | |
12 | * OpenIB.org BSD license below: | |
13 | * | |
14 | * Redistribution and use in source and binary forms, with or | |
15 | * without modification, are permitted provided that the following | |
16 | * conditions are met: | |
17 | * | |
18 | * - Redistributions of source code must retain the above | |
19 | * copyright notice, this list of conditions and the following | |
20 | * disclaimer. | |
21 | * | |
22 | * - Redistributions in binary form must reproduce the above | |
23 | * copyright notice, this list of conditions and the following | |
24 | * disclaimer in the documentation and/or other materials | |
25 | * provided with the distribution. | |
26 | * | |
27 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
28 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
29 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
30 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
31 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
32 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
33 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
34 | * SOFTWARE. | |
35 | * | |
36 | * $Id: mthca_provider.c 1397 2004-12-28 05:09:00Z roland $ | |
37 | */ | |
38 | ||
39 | #include <ib_smi.h> | |
53b8b3ff | 40 | #include <linux/mm.h> |
1da177e4 LT |
41 | |
42 | #include "mthca_dev.h" | |
43 | #include "mthca_cmd.h" | |
5e0b537c RD |
44 | #include "mthca_user.h" |
45 | #include "mthca_memfree.h" | |
1da177e4 LT |
46 | |
47 | static int mthca_query_device(struct ib_device *ibdev, | |
48 | struct ib_device_attr *props) | |
49 | { | |
50 | struct ib_smp *in_mad = NULL; | |
51 | struct ib_smp *out_mad = NULL; | |
52 | int err = -ENOMEM; | |
53 | struct mthca_dev* mdev = to_mdev(ibdev); | |
54 | ||
55 | u8 status; | |
56 | ||
57 | in_mad = kmalloc(sizeof *in_mad, GFP_KERNEL); | |
58 | out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); | |
59 | if (!in_mad || !out_mad) | |
60 | goto out; | |
61 | ||
a852092e | 62 | memset(props, 0, sizeof *props); |
8cf2daf3 | 63 | |
1da177e4 LT |
64 | props->fw_ver = mdev->fw_ver; |
65 | ||
66 | memset(in_mad, 0, sizeof *in_mad); | |
67 | in_mad->base_version = 1; | |
68 | in_mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; | |
69 | in_mad->class_version = 1; | |
70 | in_mad->method = IB_MGMT_METHOD_GET; | |
71 | in_mad->attr_id = IB_SMP_ATTR_NODE_INFO; | |
72 | ||
73 | err = mthca_MAD_IFC(mdev, 1, 1, | |
74 | 1, NULL, NULL, in_mad, out_mad, | |
75 | &status); | |
76 | if (err) | |
77 | goto out; | |
78 | if (status) { | |
79 | err = -EINVAL; | |
80 | goto out; | |
81 | } | |
82 | ||
8cf2daf3 | 83 | props->device_cap_flags = mdev->device_cap_flags; |
97f52eb4 | 84 | props->vendor_id = be32_to_cpup((__be32 *) (out_mad->data + 36)) & |
1da177e4 | 85 | 0xffffff; |
97f52eb4 SH |
86 | props->vendor_part_id = be16_to_cpup((__be16 *) (out_mad->data + 30)); |
87 | props->hw_ver = be16_to_cpup((__be16 *) (out_mad->data + 32)); | |
1da177e4 LT |
88 | memcpy(&props->sys_image_guid, out_mad->data + 4, 8); |
89 | memcpy(&props->node_guid, out_mad->data + 12, 8); | |
90 | ||
8cf2daf3 RD |
91 | props->max_mr_size = ~0ull; |
92 | props->max_qp = mdev->limits.num_qps - mdev->limits.reserved_qps; | |
93 | props->max_qp_wr = 0xffff; | |
94 | props->max_sge = mdev->limits.max_sg; | |
95 | props->max_cq = mdev->limits.num_cqs - mdev->limits.reserved_cqs; | |
96 | props->max_cqe = 0xffff; | |
97 | props->max_mr = mdev->limits.num_mpts - mdev->limits.reserved_mrws; | |
98 | props->max_pd = mdev->limits.num_pds - mdev->limits.reserved_pds; | |
99 | props->max_qp_rd_atom = 1 << mdev->qp_table.rdb_shift; | |
100 | props->max_qp_init_rd_atom = 1 << mdev->qp_table.rdb_shift; | |
101 | props->local_ca_ack_delay = mdev->limits.local_ca_ack_delay; | |
102 | ||
1da177e4 LT |
103 | err = 0; |
104 | out: | |
105 | kfree(in_mad); | |
106 | kfree(out_mad); | |
107 | return err; | |
108 | } | |
109 | ||
110 | static int mthca_query_port(struct ib_device *ibdev, | |
111 | u8 port, struct ib_port_attr *props) | |
112 | { | |
113 | struct ib_smp *in_mad = NULL; | |
114 | struct ib_smp *out_mad = NULL; | |
115 | int err = -ENOMEM; | |
116 | u8 status; | |
117 | ||
118 | in_mad = kmalloc(sizeof *in_mad, GFP_KERNEL); | |
119 | out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); | |
120 | if (!in_mad || !out_mad) | |
121 | goto out; | |
122 | ||
123 | memset(in_mad, 0, sizeof *in_mad); | |
124 | in_mad->base_version = 1; | |
125 | in_mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; | |
126 | in_mad->class_version = 1; | |
127 | in_mad->method = IB_MGMT_METHOD_GET; | |
128 | in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; | |
129 | in_mad->attr_mod = cpu_to_be32(port); | |
130 | ||
131 | err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, | |
132 | port, NULL, NULL, in_mad, out_mad, | |
133 | &status); | |
134 | if (err) | |
135 | goto out; | |
136 | if (status) { | |
137 | err = -EINVAL; | |
138 | goto out; | |
139 | } | |
140 | ||
97f52eb4 | 141 | props->lid = be16_to_cpup((__be16 *) (out_mad->data + 16)); |
1da177e4 | 142 | props->lmc = out_mad->data[34] & 0x7; |
97f52eb4 | 143 | props->sm_lid = be16_to_cpup((__be16 *) (out_mad->data + 18)); |
1da177e4 LT |
144 | props->sm_sl = out_mad->data[36] & 0xf; |
145 | props->state = out_mad->data[32] & 0xf; | |
146 | props->phys_state = out_mad->data[33] >> 4; | |
97f52eb4 | 147 | props->port_cap_flags = be32_to_cpup((__be32 *) (out_mad->data + 20)); |
1da177e4 LT |
148 | props->gid_tbl_len = to_mdev(ibdev)->limits.gid_table_len; |
149 | props->pkey_tbl_len = to_mdev(ibdev)->limits.pkey_table_len; | |
97f52eb4 | 150 | props->qkey_viol_cntr = be16_to_cpup((__be16 *) (out_mad->data + 48)); |
1da177e4 LT |
151 | props->active_width = out_mad->data[31] & 0xf; |
152 | props->active_speed = out_mad->data[35] >> 4; | |
153 | ||
154 | out: | |
155 | kfree(in_mad); | |
156 | kfree(out_mad); | |
157 | return err; | |
158 | } | |
159 | ||
160 | static int mthca_modify_port(struct ib_device *ibdev, | |
161 | u8 port, int port_modify_mask, | |
162 | struct ib_port_modify *props) | |
163 | { | |
164 | struct mthca_set_ib_param set_ib; | |
165 | struct ib_port_attr attr; | |
166 | int err; | |
167 | u8 status; | |
168 | ||
169 | if (down_interruptible(&to_mdev(ibdev)->cap_mask_mutex)) | |
170 | return -ERESTARTSYS; | |
171 | ||
172 | err = mthca_query_port(ibdev, port, &attr); | |
173 | if (err) | |
174 | goto out; | |
175 | ||
176 | set_ib.set_si_guid = 0; | |
177 | set_ib.reset_qkey_viol = !!(port_modify_mask & IB_PORT_RESET_QKEY_CNTR); | |
178 | ||
179 | set_ib.cap_mask = (attr.port_cap_flags | props->set_port_cap_mask) & | |
180 | ~props->clr_port_cap_mask; | |
181 | ||
182 | err = mthca_SET_IB(to_mdev(ibdev), &set_ib, port, &status); | |
183 | if (err) | |
184 | goto out; | |
185 | if (status) { | |
186 | err = -EINVAL; | |
187 | goto out; | |
188 | } | |
189 | ||
190 | out: | |
191 | up(&to_mdev(ibdev)->cap_mask_mutex); | |
192 | return err; | |
193 | } | |
194 | ||
195 | static int mthca_query_pkey(struct ib_device *ibdev, | |
196 | u8 port, u16 index, u16 *pkey) | |
197 | { | |
198 | struct ib_smp *in_mad = NULL; | |
199 | struct ib_smp *out_mad = NULL; | |
200 | int err = -ENOMEM; | |
201 | u8 status; | |
202 | ||
203 | in_mad = kmalloc(sizeof *in_mad, GFP_KERNEL); | |
204 | out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); | |
205 | if (!in_mad || !out_mad) | |
206 | goto out; | |
207 | ||
208 | memset(in_mad, 0, sizeof *in_mad); | |
209 | in_mad->base_version = 1; | |
210 | in_mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; | |
211 | in_mad->class_version = 1; | |
212 | in_mad->method = IB_MGMT_METHOD_GET; | |
213 | in_mad->attr_id = IB_SMP_ATTR_PKEY_TABLE; | |
214 | in_mad->attr_mod = cpu_to_be32(index / 32); | |
215 | ||
216 | err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, | |
217 | port, NULL, NULL, in_mad, out_mad, | |
218 | &status); | |
219 | if (err) | |
220 | goto out; | |
221 | if (status) { | |
222 | err = -EINVAL; | |
223 | goto out; | |
224 | } | |
225 | ||
97f52eb4 | 226 | *pkey = be16_to_cpu(((__be16 *) out_mad->data)[index % 32]); |
1da177e4 LT |
227 | |
228 | out: | |
229 | kfree(in_mad); | |
230 | kfree(out_mad); | |
231 | return err; | |
232 | } | |
233 | ||
234 | static int mthca_query_gid(struct ib_device *ibdev, u8 port, | |
235 | int index, union ib_gid *gid) | |
236 | { | |
237 | struct ib_smp *in_mad = NULL; | |
238 | struct ib_smp *out_mad = NULL; | |
239 | int err = -ENOMEM; | |
240 | u8 status; | |
241 | ||
242 | in_mad = kmalloc(sizeof *in_mad, GFP_KERNEL); | |
243 | out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); | |
244 | if (!in_mad || !out_mad) | |
245 | goto out; | |
246 | ||
247 | memset(in_mad, 0, sizeof *in_mad); | |
248 | in_mad->base_version = 1; | |
249 | in_mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; | |
250 | in_mad->class_version = 1; | |
251 | in_mad->method = IB_MGMT_METHOD_GET; | |
252 | in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; | |
253 | in_mad->attr_mod = cpu_to_be32(port); | |
254 | ||
255 | err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, | |
256 | port, NULL, NULL, in_mad, out_mad, | |
257 | &status); | |
258 | if (err) | |
259 | goto out; | |
260 | if (status) { | |
261 | err = -EINVAL; | |
262 | goto out; | |
263 | } | |
264 | ||
265 | memcpy(gid->raw, out_mad->data + 8, 8); | |
266 | ||
267 | memset(in_mad, 0, sizeof *in_mad); | |
268 | in_mad->base_version = 1; | |
269 | in_mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; | |
270 | in_mad->class_version = 1; | |
271 | in_mad->method = IB_MGMT_METHOD_GET; | |
272 | in_mad->attr_id = IB_SMP_ATTR_GUID_INFO; | |
273 | in_mad->attr_mod = cpu_to_be32(index / 8); | |
274 | ||
275 | err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, | |
276 | port, NULL, NULL, in_mad, out_mad, | |
277 | &status); | |
278 | if (err) | |
279 | goto out; | |
280 | if (status) { | |
281 | err = -EINVAL; | |
282 | goto out; | |
283 | } | |
284 | ||
285 | memcpy(gid->raw + 8, out_mad->data + (index % 8) * 16, 8); | |
286 | ||
287 | out: | |
288 | kfree(in_mad); | |
289 | kfree(out_mad); | |
290 | return err; | |
291 | } | |
292 | ||
5e0b537c RD |
293 | static struct ib_ucontext *mthca_alloc_ucontext(struct ib_device *ibdev, |
294 | struct ib_udata *udata) | |
295 | { | |
296 | struct mthca_alloc_ucontext_resp uresp; | |
297 | struct mthca_ucontext *context; | |
298 | int err; | |
299 | ||
300 | memset(&uresp, 0, sizeof uresp); | |
301 | ||
302 | uresp.qp_tab_size = to_mdev(ibdev)->limits.num_qps; | |
303 | if (mthca_is_memfree(to_mdev(ibdev))) | |
304 | uresp.uarc_size = to_mdev(ibdev)->uar_table.uarc_size; | |
305 | else | |
306 | uresp.uarc_size = 0; | |
307 | ||
308 | context = kmalloc(sizeof *context, GFP_KERNEL); | |
309 | if (!context) | |
310 | return ERR_PTR(-ENOMEM); | |
311 | ||
312 | err = mthca_uar_alloc(to_mdev(ibdev), &context->uar); | |
313 | if (err) { | |
314 | kfree(context); | |
315 | return ERR_PTR(err); | |
316 | } | |
317 | ||
318 | context->db_tab = mthca_init_user_db_tab(to_mdev(ibdev)); | |
319 | if (IS_ERR(context->db_tab)) { | |
320 | err = PTR_ERR(context->db_tab); | |
321 | mthca_uar_free(to_mdev(ibdev), &context->uar); | |
322 | kfree(context); | |
323 | return ERR_PTR(err); | |
324 | } | |
325 | ||
326 | if (ib_copy_to_udata(udata, &uresp, sizeof uresp)) { | |
327 | mthca_cleanup_user_db_tab(to_mdev(ibdev), &context->uar, context->db_tab); | |
328 | mthca_uar_free(to_mdev(ibdev), &context->uar); | |
329 | kfree(context); | |
330 | return ERR_PTR(-EFAULT); | |
331 | } | |
332 | ||
333 | return &context->ibucontext; | |
334 | } | |
335 | ||
336 | static int mthca_dealloc_ucontext(struct ib_ucontext *context) | |
337 | { | |
338 | mthca_cleanup_user_db_tab(to_mdev(context->device), &to_mucontext(context)->uar, | |
339 | to_mucontext(context)->db_tab); | |
340 | mthca_uar_free(to_mdev(context->device), &to_mucontext(context)->uar); | |
341 | kfree(to_mucontext(context)); | |
342 | ||
343 | return 0; | |
344 | } | |
345 | ||
53b8b3ff RD |
346 | static int mthca_mmap_uar(struct ib_ucontext *context, |
347 | struct vm_area_struct *vma) | |
348 | { | |
349 | if (vma->vm_end - vma->vm_start != PAGE_SIZE) | |
350 | return -EINVAL; | |
351 | ||
352 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | |
353 | ||
6d376756 MT |
354 | if (io_remap_pfn_range(vma, vma->vm_start, |
355 | to_mucontext(context)->uar.pfn, | |
356 | PAGE_SIZE, vma->vm_page_prot)) | |
53b8b3ff RD |
357 | return -EAGAIN; |
358 | ||
359 | return 0; | |
360 | } | |
361 | ||
1cf296b6 RD |
362 | static struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev, |
363 | struct ib_ucontext *context, | |
364 | struct ib_udata *udata) | |
1da177e4 LT |
365 | { |
366 | struct mthca_pd *pd; | |
367 | int err; | |
368 | ||
369 | pd = kmalloc(sizeof *pd, GFP_KERNEL); | |
370 | if (!pd) | |
371 | return ERR_PTR(-ENOMEM); | |
372 | ||
99264c1e | 373 | err = mthca_pd_alloc(to_mdev(ibdev), !context, pd); |
1da177e4 LT |
374 | if (err) { |
375 | kfree(pd); | |
376 | return ERR_PTR(err); | |
377 | } | |
378 | ||
99264c1e RD |
379 | if (context) { |
380 | if (ib_copy_to_udata(udata, &pd->pd_num, sizeof (__u32))) { | |
381 | mthca_pd_free(to_mdev(ibdev), pd); | |
382 | kfree(pd); | |
383 | return ERR_PTR(-EFAULT); | |
384 | } | |
385 | } | |
386 | ||
1da177e4 LT |
387 | return &pd->ibpd; |
388 | } | |
389 | ||
390 | static int mthca_dealloc_pd(struct ib_pd *pd) | |
391 | { | |
392 | mthca_pd_free(to_mdev(pd->device), to_mpd(pd)); | |
393 | kfree(pd); | |
394 | ||
395 | return 0; | |
396 | } | |
397 | ||
398 | static struct ib_ah *mthca_ah_create(struct ib_pd *pd, | |
399 | struct ib_ah_attr *ah_attr) | |
400 | { | |
401 | int err; | |
402 | struct mthca_ah *ah; | |
403 | ||
8df8a34d | 404 | ah = kmalloc(sizeof *ah, GFP_ATOMIC); |
1da177e4 LT |
405 | if (!ah) |
406 | return ERR_PTR(-ENOMEM); | |
407 | ||
408 | err = mthca_create_ah(to_mdev(pd->device), to_mpd(pd), ah_attr, ah); | |
409 | if (err) { | |
410 | kfree(ah); | |
411 | return ERR_PTR(err); | |
412 | } | |
413 | ||
414 | return &ah->ibah; | |
415 | } | |
416 | ||
417 | static int mthca_ah_destroy(struct ib_ah *ah) | |
418 | { | |
419 | mthca_destroy_ah(to_mdev(ah->device), to_mah(ah)); | |
420 | kfree(ah); | |
421 | ||
422 | return 0; | |
423 | } | |
424 | ||
425 | static struct ib_qp *mthca_create_qp(struct ib_pd *pd, | |
1cf296b6 RD |
426 | struct ib_qp_init_attr *init_attr, |
427 | struct ib_udata *udata) | |
1da177e4 | 428 | { |
80c8ec2c | 429 | struct mthca_create_qp ucmd; |
1da177e4 LT |
430 | struct mthca_qp *qp; |
431 | int err; | |
432 | ||
433 | switch (init_attr->qp_type) { | |
434 | case IB_QPT_RC: | |
435 | case IB_QPT_UC: | |
436 | case IB_QPT_UD: | |
437 | { | |
80c8ec2c RD |
438 | struct mthca_ucontext *context; |
439 | ||
1da177e4 LT |
440 | qp = kmalloc(sizeof *qp, GFP_KERNEL); |
441 | if (!qp) | |
442 | return ERR_PTR(-ENOMEM); | |
443 | ||
80c8ec2c RD |
444 | if (pd->uobject) { |
445 | context = to_mucontext(pd->uobject->context); | |
446 | ||
447 | if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) | |
448 | return ERR_PTR(-EFAULT); | |
449 | ||
450 | err = mthca_map_user_db(to_mdev(pd->device), &context->uar, | |
451 | context->db_tab, | |
452 | ucmd.sq_db_index, ucmd.sq_db_page); | |
453 | if (err) { | |
454 | kfree(qp); | |
455 | return ERR_PTR(err); | |
456 | } | |
457 | ||
458 | err = mthca_map_user_db(to_mdev(pd->device), &context->uar, | |
459 | context->db_tab, | |
460 | ucmd.rq_db_index, ucmd.rq_db_page); | |
461 | if (err) { | |
462 | mthca_unmap_user_db(to_mdev(pd->device), | |
463 | &context->uar, | |
464 | context->db_tab, | |
465 | ucmd.sq_db_index); | |
466 | kfree(qp); | |
467 | return ERR_PTR(err); | |
468 | } | |
469 | ||
470 | qp->mr.ibmr.lkey = ucmd.lkey; | |
471 | qp->sq.db_index = ucmd.sq_db_index; | |
472 | qp->rq.db_index = ucmd.rq_db_index; | |
473 | } | |
1da177e4 LT |
474 | |
475 | err = mthca_alloc_qp(to_mdev(pd->device), to_mpd(pd), | |
476 | to_mcq(init_attr->send_cq), | |
477 | to_mcq(init_attr->recv_cq), | |
478 | init_attr->qp_type, init_attr->sq_sig_type, | |
80c8ec2c RD |
479 | &init_attr->cap, qp); |
480 | ||
481 | if (err && pd->uobject) { | |
482 | context = to_mucontext(pd->uobject->context); | |
483 | ||
484 | mthca_unmap_user_db(to_mdev(pd->device), | |
485 | &context->uar, | |
486 | context->db_tab, | |
487 | ucmd.sq_db_index); | |
488 | mthca_unmap_user_db(to_mdev(pd->device), | |
489 | &context->uar, | |
490 | context->db_tab, | |
491 | ucmd.rq_db_index); | |
492 | } | |
493 | ||
1da177e4 LT |
494 | qp->ibqp.qp_num = qp->qpn; |
495 | break; | |
496 | } | |
497 | case IB_QPT_SMI: | |
498 | case IB_QPT_GSI: | |
499 | { | |
80c8ec2c RD |
500 | /* Don't allow userspace to create special QPs */ |
501 | if (pd->uobject) | |
502 | return ERR_PTR(-EINVAL); | |
503 | ||
1da177e4 LT |
504 | qp = kmalloc(sizeof (struct mthca_sqp), GFP_KERNEL); |
505 | if (!qp) | |
506 | return ERR_PTR(-ENOMEM); | |
507 | ||
1da177e4 LT |
508 | qp->ibqp.qp_num = init_attr->qp_type == IB_QPT_SMI ? 0 : 1; |
509 | ||
510 | err = mthca_alloc_sqp(to_mdev(pd->device), to_mpd(pd), | |
511 | to_mcq(init_attr->send_cq), | |
512 | to_mcq(init_attr->recv_cq), | |
80c8ec2c | 513 | init_attr->sq_sig_type, &init_attr->cap, |
1da177e4 LT |
514 | qp->ibqp.qp_num, init_attr->port_num, |
515 | to_msqp(qp)); | |
516 | break; | |
517 | } | |
518 | default: | |
519 | /* Don't support raw QPs */ | |
520 | return ERR_PTR(-ENOSYS); | |
521 | } | |
522 | ||
523 | if (err) { | |
524 | kfree(qp); | |
525 | return ERR_PTR(err); | |
526 | } | |
527 | ||
80c8ec2c RD |
528 | init_attr->cap.max_inline_data = 0; |
529 | init_attr->cap.max_send_wr = qp->sq.max; | |
530 | init_attr->cap.max_recv_wr = qp->rq.max; | |
531 | init_attr->cap.max_send_sge = qp->sq.max_gs; | |
532 | init_attr->cap.max_recv_sge = qp->rq.max_gs; | |
1da177e4 LT |
533 | |
534 | return &qp->ibqp; | |
535 | } | |
536 | ||
537 | static int mthca_destroy_qp(struct ib_qp *qp) | |
538 | { | |
80c8ec2c RD |
539 | if (qp->uobject) { |
540 | mthca_unmap_user_db(to_mdev(qp->device), | |
541 | &to_mucontext(qp->uobject->context)->uar, | |
542 | to_mucontext(qp->uobject->context)->db_tab, | |
543 | to_mqp(qp)->sq.db_index); | |
544 | mthca_unmap_user_db(to_mdev(qp->device), | |
545 | &to_mucontext(qp->uobject->context)->uar, | |
546 | to_mucontext(qp->uobject->context)->db_tab, | |
547 | to_mqp(qp)->rq.db_index); | |
548 | } | |
1da177e4 LT |
549 | mthca_free_qp(to_mdev(qp->device), to_mqp(qp)); |
550 | kfree(qp); | |
551 | return 0; | |
552 | } | |
553 | ||
1cf296b6 RD |
554 | static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries, |
555 | struct ib_ucontext *context, | |
556 | struct ib_udata *udata) | |
1da177e4 | 557 | { |
74c2174e | 558 | struct mthca_create_cq ucmd; |
1da177e4 LT |
559 | struct mthca_cq *cq; |
560 | int nent; | |
561 | int err; | |
562 | ||
74c2174e RD |
563 | if (context) { |
564 | if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) | |
565 | return ERR_PTR(-EFAULT); | |
566 | ||
567 | err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar, | |
568 | to_mucontext(context)->db_tab, | |
569 | ucmd.set_db_index, ucmd.set_db_page); | |
570 | if (err) | |
571 | return ERR_PTR(err); | |
572 | ||
573 | err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar, | |
574 | to_mucontext(context)->db_tab, | |
575 | ucmd.arm_db_index, ucmd.arm_db_page); | |
576 | if (err) | |
577 | goto err_unmap_set; | |
578 | } | |
579 | ||
1da177e4 | 580 | cq = kmalloc(sizeof *cq, GFP_KERNEL); |
74c2174e RD |
581 | if (!cq) { |
582 | err = -ENOMEM; | |
583 | goto err_unmap_arm; | |
584 | } | |
585 | ||
586 | if (context) { | |
587 | cq->mr.ibmr.lkey = ucmd.lkey; | |
588 | cq->set_ci_db_index = ucmd.set_db_index; | |
589 | cq->arm_db_index = ucmd.arm_db_index; | |
590 | } | |
1da177e4 LT |
591 | |
592 | for (nent = 1; nent <= entries; nent <<= 1) | |
593 | ; /* nothing */ | |
594 | ||
74c2174e RD |
595 | err = mthca_init_cq(to_mdev(ibdev), nent, |
596 | context ? to_mucontext(context) : NULL, | |
597 | context ? ucmd.pdn : to_mdev(ibdev)->driver_pd.pd_num, | |
598 | cq); | |
599 | if (err) | |
600 | goto err_free; | |
601 | ||
602 | if (context && ib_copy_to_udata(udata, &cq->cqn, sizeof (__u32))) { | |
603 | mthca_free_cq(to_mdev(ibdev), cq); | |
604 | goto err_free; | |
1da177e4 LT |
605 | } |
606 | ||
607 | return &cq->ibcq; | |
74c2174e RD |
608 | |
609 | err_free: | |
610 | kfree(cq); | |
611 | ||
612 | err_unmap_arm: | |
613 | if (context) | |
614 | mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar, | |
615 | to_mucontext(context)->db_tab, ucmd.arm_db_index); | |
616 | ||
617 | err_unmap_set: | |
618 | if (context) | |
619 | mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar, | |
620 | to_mucontext(context)->db_tab, ucmd.set_db_index); | |
621 | ||
622 | return ERR_PTR(err); | |
1da177e4 LT |
623 | } |
624 | ||
625 | static int mthca_destroy_cq(struct ib_cq *cq) | |
626 | { | |
74c2174e RD |
627 | if (cq->uobject) { |
628 | mthca_unmap_user_db(to_mdev(cq->device), | |
629 | &to_mucontext(cq->uobject->context)->uar, | |
630 | to_mucontext(cq->uobject->context)->db_tab, | |
631 | to_mcq(cq)->arm_db_index); | |
632 | mthca_unmap_user_db(to_mdev(cq->device), | |
633 | &to_mucontext(cq->uobject->context)->uar, | |
634 | to_mucontext(cq->uobject->context)->db_tab, | |
635 | to_mcq(cq)->set_ci_db_index); | |
636 | } | |
1da177e4 LT |
637 | mthca_free_cq(to_mdev(cq->device), to_mcq(cq)); |
638 | kfree(cq); | |
639 | ||
640 | return 0; | |
641 | } | |
642 | ||
643 | static inline u32 convert_access(int acc) | |
644 | { | |
645 | return (acc & IB_ACCESS_REMOTE_ATOMIC ? MTHCA_MPT_FLAG_ATOMIC : 0) | | |
646 | (acc & IB_ACCESS_REMOTE_WRITE ? MTHCA_MPT_FLAG_REMOTE_WRITE : 0) | | |
647 | (acc & IB_ACCESS_REMOTE_READ ? MTHCA_MPT_FLAG_REMOTE_READ : 0) | | |
648 | (acc & IB_ACCESS_LOCAL_WRITE ? MTHCA_MPT_FLAG_LOCAL_WRITE : 0) | | |
649 | MTHCA_MPT_FLAG_LOCAL_READ; | |
650 | } | |
651 | ||
652 | static struct ib_mr *mthca_get_dma_mr(struct ib_pd *pd, int acc) | |
653 | { | |
654 | struct mthca_mr *mr; | |
655 | int err; | |
656 | ||
657 | mr = kmalloc(sizeof *mr, GFP_KERNEL); | |
658 | if (!mr) | |
659 | return ERR_PTR(-ENOMEM); | |
660 | ||
661 | err = mthca_mr_alloc_notrans(to_mdev(pd->device), | |
662 | to_mpd(pd)->pd_num, | |
663 | convert_access(acc), mr); | |
664 | ||
665 | if (err) { | |
666 | kfree(mr); | |
667 | return ERR_PTR(err); | |
668 | } | |
669 | ||
670 | return &mr->ibmr; | |
671 | } | |
672 | ||
673 | static struct ib_mr *mthca_reg_phys_mr(struct ib_pd *pd, | |
674 | struct ib_phys_buf *buffer_list, | |
675 | int num_phys_buf, | |
676 | int acc, | |
677 | u64 *iova_start) | |
678 | { | |
679 | struct mthca_mr *mr; | |
680 | u64 *page_list; | |
681 | u64 total_size; | |
682 | u64 mask; | |
683 | int shift; | |
684 | int npages; | |
685 | int err; | |
686 | int i, j, n; | |
687 | ||
688 | /* First check that we have enough alignment */ | |
689 | if ((*iova_start & ~PAGE_MASK) != (buffer_list[0].addr & ~PAGE_MASK)) | |
690 | return ERR_PTR(-EINVAL); | |
691 | ||
692 | if (num_phys_buf > 1 && | |
693 | ((buffer_list[0].addr + buffer_list[0].size) & ~PAGE_MASK)) | |
694 | return ERR_PTR(-EINVAL); | |
695 | ||
696 | mask = 0; | |
697 | total_size = 0; | |
698 | for (i = 0; i < num_phys_buf; ++i) { | |
72c30290 | 699 | if (i != 0 && buffer_list[i].addr & ~PAGE_MASK) |
1da177e4 LT |
700 | return ERR_PTR(-EINVAL); |
701 | if (i != 0 && i != num_phys_buf - 1 && | |
702 | (buffer_list[i].size & ~PAGE_MASK)) | |
703 | return ERR_PTR(-EINVAL); | |
704 | ||
705 | total_size += buffer_list[i].size; | |
706 | if (i > 0) | |
707 | mask |= buffer_list[i].addr; | |
708 | } | |
709 | ||
710 | /* Find largest page shift we can use to cover buffers */ | |
711 | for (shift = PAGE_SHIFT; shift < 31; ++shift) | |
712 | if (num_phys_buf > 1) { | |
713 | if ((1ULL << shift) & mask) | |
714 | break; | |
715 | } else { | |
716 | if (1ULL << shift >= | |
717 | buffer_list[0].size + | |
718 | (buffer_list[0].addr & ((1ULL << shift) - 1))) | |
719 | break; | |
720 | } | |
721 | ||
722 | buffer_list[0].size += buffer_list[0].addr & ((1ULL << shift) - 1); | |
723 | buffer_list[0].addr &= ~0ull << shift; | |
724 | ||
725 | mr = kmalloc(sizeof *mr, GFP_KERNEL); | |
726 | if (!mr) | |
727 | return ERR_PTR(-ENOMEM); | |
728 | ||
729 | npages = 0; | |
730 | for (i = 0; i < num_phys_buf; ++i) | |
731 | npages += (buffer_list[i].size + (1ULL << shift) - 1) >> shift; | |
732 | ||
733 | if (!npages) | |
734 | return &mr->ibmr; | |
735 | ||
736 | page_list = kmalloc(npages * sizeof *page_list, GFP_KERNEL); | |
737 | if (!page_list) { | |
738 | kfree(mr); | |
739 | return ERR_PTR(-ENOMEM); | |
740 | } | |
741 | ||
742 | n = 0; | |
743 | for (i = 0; i < num_phys_buf; ++i) | |
744 | for (j = 0; | |
745 | j < (buffer_list[i].size + (1ULL << shift) - 1) >> shift; | |
746 | ++j) | |
747 | page_list[n++] = buffer_list[i].addr + ((u64) j << shift); | |
748 | ||
749 | mthca_dbg(to_mdev(pd->device), "Registering memory at %llx (iova %llx) " | |
750 | "in PD %x; shift %d, npages %d.\n", | |
751 | (unsigned long long) buffer_list[0].addr, | |
752 | (unsigned long long) *iova_start, | |
753 | to_mpd(pd)->pd_num, | |
754 | shift, npages); | |
755 | ||
756 | err = mthca_mr_alloc_phys(to_mdev(pd->device), | |
757 | to_mpd(pd)->pd_num, | |
758 | page_list, shift, npages, | |
759 | *iova_start, total_size, | |
760 | convert_access(acc), mr); | |
761 | ||
762 | if (err) { | |
761f9eb8 | 763 | kfree(page_list); |
1da177e4 LT |
764 | kfree(mr); |
765 | return ERR_PTR(err); | |
766 | } | |
767 | ||
768 | kfree(page_list); | |
769 | return &mr->ibmr; | |
770 | } | |
771 | ||
24d4281b RD |
772 | static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, |
773 | int acc, struct ib_udata *udata) | |
774 | { | |
775 | struct mthca_dev *dev = to_mdev(pd->device); | |
776 | struct ib_umem_chunk *chunk; | |
777 | struct mthca_mr *mr; | |
778 | u64 *pages; | |
779 | int shift, n, len; | |
780 | int i, j, k; | |
781 | int err = 0; | |
782 | ||
783 | shift = ffs(region->page_size) - 1; | |
784 | ||
785 | mr = kmalloc(sizeof *mr, GFP_KERNEL); | |
786 | if (!mr) | |
787 | return ERR_PTR(-ENOMEM); | |
788 | ||
789 | n = 0; | |
790 | list_for_each_entry(chunk, ®ion->chunk_list, list) | |
791 | n += chunk->nents; | |
792 | ||
793 | mr->mtt = mthca_alloc_mtt(dev, n); | |
794 | if (IS_ERR(mr->mtt)) { | |
795 | err = PTR_ERR(mr->mtt); | |
796 | goto err; | |
797 | } | |
798 | ||
799 | pages = (u64 *) __get_free_page(GFP_KERNEL); | |
800 | if (!pages) { | |
801 | err = -ENOMEM; | |
802 | goto err_mtt; | |
803 | } | |
804 | ||
805 | i = n = 0; | |
806 | ||
807 | list_for_each_entry(chunk, ®ion->chunk_list, list) | |
808 | for (j = 0; j < chunk->nmap; ++j) { | |
809 | len = sg_dma_len(&chunk->page_list[j]) >> shift; | |
810 | for (k = 0; k < len; ++k) { | |
811 | pages[i++] = sg_dma_address(&chunk->page_list[j]) + | |
812 | region->page_size * k; | |
813 | /* | |
814 | * Be friendly to WRITE_MTT command | |
815 | * and leave two empty slots for the | |
816 | * index and reserved fields of the | |
817 | * mailbox. | |
818 | */ | |
819 | if (i == PAGE_SIZE / sizeof (u64) - 2) { | |
820 | err = mthca_write_mtt(dev, mr->mtt, | |
821 | n, pages, i); | |
822 | if (err) | |
823 | goto mtt_done; | |
824 | n += i; | |
825 | i = 0; | |
826 | } | |
827 | } | |
828 | } | |
829 | ||
830 | if (i) | |
831 | err = mthca_write_mtt(dev, mr->mtt, n, pages, i); | |
832 | mtt_done: | |
833 | free_page((unsigned long) pages); | |
834 | if (err) | |
835 | goto err_mtt; | |
836 | ||
837 | err = mthca_mr_alloc(dev, to_mpd(pd)->pd_num, shift, region->virt_base, | |
838 | region->length, convert_access(acc), mr); | |
839 | ||
840 | if (err) | |
841 | goto err_mtt; | |
842 | ||
843 | return &mr->ibmr; | |
844 | ||
845 | err_mtt: | |
846 | mthca_free_mtt(dev, mr->mtt); | |
847 | ||
848 | err: | |
849 | kfree(mr); | |
850 | return ERR_PTR(err); | |
851 | } | |
852 | ||
1da177e4 LT |
853 | static int mthca_dereg_mr(struct ib_mr *mr) |
854 | { | |
e464b2a6 RD |
855 | struct mthca_mr *mmr = to_mmr(mr); |
856 | mthca_free_mr(to_mdev(mr->device), mmr); | |
857 | kfree(mmr); | |
1da177e4 LT |
858 | return 0; |
859 | } | |
860 | ||
e0f5fdca MT |
861 | static struct ib_fmr *mthca_alloc_fmr(struct ib_pd *pd, int mr_access_flags, |
862 | struct ib_fmr_attr *fmr_attr) | |
863 | { | |
864 | struct mthca_fmr *fmr; | |
865 | int err; | |
866 | ||
867 | fmr = kmalloc(sizeof *fmr, GFP_KERNEL); | |
868 | if (!fmr) | |
869 | return ERR_PTR(-ENOMEM); | |
870 | ||
871 | memcpy(&fmr->attr, fmr_attr, sizeof *fmr_attr); | |
872 | err = mthca_fmr_alloc(to_mdev(pd->device), to_mpd(pd)->pd_num, | |
873 | convert_access(mr_access_flags), fmr); | |
874 | ||
875 | if (err) { | |
876 | kfree(fmr); | |
877 | return ERR_PTR(err); | |
878 | } | |
879 | ||
880 | return &fmr->ibmr; | |
881 | } | |
882 | ||
883 | static int mthca_dealloc_fmr(struct ib_fmr *fmr) | |
884 | { | |
885 | struct mthca_fmr *mfmr = to_mfmr(fmr); | |
886 | int err; | |
887 | ||
888 | err = mthca_free_fmr(to_mdev(fmr->device), mfmr); | |
889 | if (err) | |
890 | return err; | |
891 | ||
892 | kfree(mfmr); | |
893 | return 0; | |
894 | } | |
895 | ||
896 | static int mthca_unmap_fmr(struct list_head *fmr_list) | |
897 | { | |
898 | struct ib_fmr *fmr; | |
899 | int err; | |
900 | u8 status; | |
901 | struct mthca_dev *mdev = NULL; | |
902 | ||
903 | list_for_each_entry(fmr, fmr_list, list) { | |
904 | if (mdev && to_mdev(fmr->device) != mdev) | |
905 | return -EINVAL; | |
906 | mdev = to_mdev(fmr->device); | |
907 | } | |
908 | ||
909 | if (!mdev) | |
910 | return 0; | |
911 | ||
d10ddbf6 | 912 | if (mthca_is_memfree(mdev)) { |
e0f5fdca MT |
913 | list_for_each_entry(fmr, fmr_list, list) |
914 | mthca_arbel_fmr_unmap(mdev, to_mfmr(fmr)); | |
915 | ||
916 | wmb(); | |
917 | } else | |
918 | list_for_each_entry(fmr, fmr_list, list) | |
919 | mthca_tavor_fmr_unmap(mdev, to_mfmr(fmr)); | |
920 | ||
921 | err = mthca_SYNC_TPT(mdev, &status); | |
922 | if (err) | |
923 | return err; | |
924 | if (status) | |
925 | return -EINVAL; | |
926 | return 0; | |
927 | } | |
928 | ||
1da177e4 LT |
929 | static ssize_t show_rev(struct class_device *cdev, char *buf) |
930 | { | |
931 | struct mthca_dev *dev = container_of(cdev, struct mthca_dev, ib_dev.class_dev); | |
932 | return sprintf(buf, "%x\n", dev->rev_id); | |
933 | } | |
934 | ||
935 | static ssize_t show_fw_ver(struct class_device *cdev, char *buf) | |
936 | { | |
937 | struct mthca_dev *dev = container_of(cdev, struct mthca_dev, ib_dev.class_dev); | |
938 | return sprintf(buf, "%x.%x.%x\n", (int) (dev->fw_ver >> 32), | |
939 | (int) (dev->fw_ver >> 16) & 0xffff, | |
940 | (int) dev->fw_ver & 0xffff); | |
941 | } | |
942 | ||
943 | static ssize_t show_hca(struct class_device *cdev, char *buf) | |
944 | { | |
945 | struct mthca_dev *dev = container_of(cdev, struct mthca_dev, ib_dev.class_dev); | |
68a3c212 RD |
946 | switch (dev->pdev->device) { |
947 | case PCI_DEVICE_ID_MELLANOX_TAVOR: | |
948 | return sprintf(buf, "MT23108\n"); | |
949 | case PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT: | |
950 | return sprintf(buf, "MT25208 (MT23108 compat mode)\n"); | |
951 | case PCI_DEVICE_ID_MELLANOX_ARBEL: | |
952 | return sprintf(buf, "MT25208\n"); | |
953 | case PCI_DEVICE_ID_MELLANOX_SINAI: | |
954 | case PCI_DEVICE_ID_MELLANOX_SINAI_OLD: | |
955 | return sprintf(buf, "MT25204\n"); | |
956 | default: | |
957 | return sprintf(buf, "unknown\n"); | |
1da177e4 LT |
958 | } |
959 | } | |
960 | ||
2e8b981c MT |
961 | static ssize_t show_board(struct class_device *cdev, char *buf) |
962 | { | |
963 | struct mthca_dev *dev = container_of(cdev, struct mthca_dev, ib_dev.class_dev); | |
964 | return sprintf(buf, "%.*s\n", MTHCA_BOARD_ID_LEN, dev->board_id); | |
965 | } | |
966 | ||
1da177e4 LT |
967 | static CLASS_DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); |
968 | static CLASS_DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL); | |
969 | static CLASS_DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); | |
2e8b981c | 970 | static CLASS_DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL); |
1da177e4 LT |
971 | |
972 | static struct class_device_attribute *mthca_class_attributes[] = { | |
973 | &class_device_attr_hw_rev, | |
974 | &class_device_attr_fw_ver, | |
2e8b981c MT |
975 | &class_device_attr_hca_type, |
976 | &class_device_attr_board_id | |
1da177e4 LT |
977 | }; |
978 | ||
979 | int mthca_register_device(struct mthca_dev *dev) | |
980 | { | |
981 | int ret; | |
982 | int i; | |
983 | ||
984 | strlcpy(dev->ib_dev.name, "mthca%d", IB_DEVICE_NAME_MAX); | |
1cf296b6 RD |
985 | dev->ib_dev.owner = THIS_MODULE; |
986 | ||
1da177e4 LT |
987 | dev->ib_dev.node_type = IB_NODE_CA; |
988 | dev->ib_dev.phys_port_cnt = dev->limits.num_ports; | |
989 | dev->ib_dev.dma_device = &dev->pdev->dev; | |
990 | dev->ib_dev.class_dev.dev = &dev->pdev->dev; | |
991 | dev->ib_dev.query_device = mthca_query_device; | |
992 | dev->ib_dev.query_port = mthca_query_port; | |
993 | dev->ib_dev.modify_port = mthca_modify_port; | |
994 | dev->ib_dev.query_pkey = mthca_query_pkey; | |
995 | dev->ib_dev.query_gid = mthca_query_gid; | |
5e0b537c RD |
996 | dev->ib_dev.alloc_ucontext = mthca_alloc_ucontext; |
997 | dev->ib_dev.dealloc_ucontext = mthca_dealloc_ucontext; | |
53b8b3ff | 998 | dev->ib_dev.mmap = mthca_mmap_uar; |
1da177e4 LT |
999 | dev->ib_dev.alloc_pd = mthca_alloc_pd; |
1000 | dev->ib_dev.dealloc_pd = mthca_dealloc_pd; | |
1001 | dev->ib_dev.create_ah = mthca_ah_create; | |
1002 | dev->ib_dev.destroy_ah = mthca_ah_destroy; | |
1003 | dev->ib_dev.create_qp = mthca_create_qp; | |
1004 | dev->ib_dev.modify_qp = mthca_modify_qp; | |
1005 | dev->ib_dev.destroy_qp = mthca_destroy_qp; | |
1006 | dev->ib_dev.create_cq = mthca_create_cq; | |
1007 | dev->ib_dev.destroy_cq = mthca_destroy_cq; | |
1008 | dev->ib_dev.poll_cq = mthca_poll_cq; | |
1009 | dev->ib_dev.get_dma_mr = mthca_get_dma_mr; | |
1010 | dev->ib_dev.reg_phys_mr = mthca_reg_phys_mr; | |
24d4281b | 1011 | dev->ib_dev.reg_user_mr = mthca_reg_user_mr; |
1da177e4 | 1012 | dev->ib_dev.dereg_mr = mthca_dereg_mr; |
e0f5fdca MT |
1013 | |
1014 | if (dev->mthca_flags & MTHCA_FLAG_FMR) { | |
1015 | dev->ib_dev.alloc_fmr = mthca_alloc_fmr; | |
1016 | dev->ib_dev.unmap_fmr = mthca_unmap_fmr; | |
1017 | dev->ib_dev.dealloc_fmr = mthca_dealloc_fmr; | |
d10ddbf6 | 1018 | if (mthca_is_memfree(dev)) |
e0f5fdca MT |
1019 | dev->ib_dev.map_phys_fmr = mthca_arbel_map_phys_fmr; |
1020 | else | |
1021 | dev->ib_dev.map_phys_fmr = mthca_tavor_map_phys_fmr; | |
1022 | } | |
1023 | ||
1da177e4 LT |
1024 | dev->ib_dev.attach_mcast = mthca_multicast_attach; |
1025 | dev->ib_dev.detach_mcast = mthca_multicast_detach; | |
1026 | dev->ib_dev.process_mad = mthca_process_mad; | |
1027 | ||
d10ddbf6 | 1028 | if (mthca_is_memfree(dev)) { |
1da177e4 LT |
1029 | dev->ib_dev.req_notify_cq = mthca_arbel_arm_cq; |
1030 | dev->ib_dev.post_send = mthca_arbel_post_send; | |
1031 | dev->ib_dev.post_recv = mthca_arbel_post_receive; | |
1032 | } else { | |
1033 | dev->ib_dev.req_notify_cq = mthca_tavor_arm_cq; | |
1034 | dev->ib_dev.post_send = mthca_tavor_post_send; | |
1035 | dev->ib_dev.post_recv = mthca_tavor_post_receive; | |
1036 | } | |
1037 | ||
1038 | init_MUTEX(&dev->cap_mask_mutex); | |
1039 | ||
1040 | ret = ib_register_device(&dev->ib_dev); | |
1041 | if (ret) | |
1042 | return ret; | |
1043 | ||
1044 | for (i = 0; i < ARRAY_SIZE(mthca_class_attributes); ++i) { | |
1045 | ret = class_device_create_file(&dev->ib_dev.class_dev, | |
1046 | mthca_class_attributes[i]); | |
1047 | if (ret) { | |
1048 | ib_unregister_device(&dev->ib_dev); | |
1049 | return ret; | |
1050 | } | |
1051 | } | |
1052 | ||
1053 | return 0; | |
1054 | } | |
1055 | ||
1056 | void mthca_unregister_device(struct mthca_dev *dev) | |
1057 | { | |
1058 | ib_unregister_device(&dev->ib_dev); | |
1059 | } |