diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/infiniband/hw/mthca/mthca_provider.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/infiniband/hw/mthca/mthca_provider.c')
-rw-r--r-- | drivers/infiniband/hw/mthca/mthca_provider.c | 660 |
1 files changed, 660 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c new file mode 100644 index 000000000000..bbf74cf43343 --- /dev/null +++ b/drivers/infiniband/hw/mthca/mthca_provider.c | |||
@@ -0,0 +1,660 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | * | ||
32 | * $Id: mthca_provider.c 1397 2004-12-28 05:09:00Z roland $ | ||
33 | */ | ||
34 | |||
35 | #include <ib_smi.h> | ||
36 | |||
37 | #include "mthca_dev.h" | ||
38 | #include "mthca_cmd.h" | ||
39 | |||
40 | static int mthca_query_device(struct ib_device *ibdev, | ||
41 | struct ib_device_attr *props) | ||
42 | { | ||
43 | struct ib_smp *in_mad = NULL; | ||
44 | struct ib_smp *out_mad = NULL; | ||
45 | int err = -ENOMEM; | ||
46 | struct mthca_dev* mdev = to_mdev(ibdev); | ||
47 | |||
48 | u8 status; | ||
49 | |||
50 | in_mad = kmalloc(sizeof *in_mad, GFP_KERNEL); | ||
51 | out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); | ||
52 | if (!in_mad || !out_mad) | ||
53 | goto out; | ||
54 | |||
55 | props->fw_ver = mdev->fw_ver; | ||
56 | |||
57 | memset(in_mad, 0, sizeof *in_mad); | ||
58 | in_mad->base_version = 1; | ||
59 | in_mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; | ||
60 | in_mad->class_version = 1; | ||
61 | in_mad->method = IB_MGMT_METHOD_GET; | ||
62 | in_mad->attr_id = IB_SMP_ATTR_NODE_INFO; | ||
63 | |||
64 | err = mthca_MAD_IFC(mdev, 1, 1, | ||
65 | 1, NULL, NULL, in_mad, out_mad, | ||
66 | &status); | ||
67 | if (err) | ||
68 | goto out; | ||
69 | if (status) { | ||
70 | err = -EINVAL; | ||
71 | goto out; | ||
72 | } | ||
73 | |||
74 | props->device_cap_flags = mdev->device_cap_flags; | ||
75 | props->vendor_id = be32_to_cpup((u32 *) (out_mad->data + 36)) & | ||
76 | 0xffffff; | ||
77 | props->vendor_part_id = be16_to_cpup((u16 *) (out_mad->data + 30)); | ||
78 | props->hw_ver = be16_to_cpup((u16 *) (out_mad->data + 32)); | ||
79 | memcpy(&props->sys_image_guid, out_mad->data + 4, 8); | ||
80 | memcpy(&props->node_guid, out_mad->data + 12, 8); | ||
81 | |||
82 | err = 0; | ||
83 | out: | ||
84 | kfree(in_mad); | ||
85 | kfree(out_mad); | ||
86 | return err; | ||
87 | } | ||
88 | |||
89 | static int mthca_query_port(struct ib_device *ibdev, | ||
90 | u8 port, struct ib_port_attr *props) | ||
91 | { | ||
92 | struct ib_smp *in_mad = NULL; | ||
93 | struct ib_smp *out_mad = NULL; | ||
94 | int err = -ENOMEM; | ||
95 | u8 status; | ||
96 | |||
97 | in_mad = kmalloc(sizeof *in_mad, GFP_KERNEL); | ||
98 | out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); | ||
99 | if (!in_mad || !out_mad) | ||
100 | goto out; | ||
101 | |||
102 | memset(in_mad, 0, sizeof *in_mad); | ||
103 | in_mad->base_version = 1; | ||
104 | in_mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; | ||
105 | in_mad->class_version = 1; | ||
106 | in_mad->method = IB_MGMT_METHOD_GET; | ||
107 | in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; | ||
108 | in_mad->attr_mod = cpu_to_be32(port); | ||
109 | |||
110 | err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, | ||
111 | port, NULL, NULL, in_mad, out_mad, | ||
112 | &status); | ||
113 | if (err) | ||
114 | goto out; | ||
115 | if (status) { | ||
116 | err = -EINVAL; | ||
117 | goto out; | ||
118 | } | ||
119 | |||
120 | props->lid = be16_to_cpup((u16 *) (out_mad->data + 16)); | ||
121 | props->lmc = out_mad->data[34] & 0x7; | ||
122 | props->sm_lid = be16_to_cpup((u16 *) (out_mad->data + 18)); | ||
123 | props->sm_sl = out_mad->data[36] & 0xf; | ||
124 | props->state = out_mad->data[32] & 0xf; | ||
125 | props->phys_state = out_mad->data[33] >> 4; | ||
126 | props->port_cap_flags = be32_to_cpup((u32 *) (out_mad->data + 20)); | ||
127 | props->gid_tbl_len = to_mdev(ibdev)->limits.gid_table_len; | ||
128 | props->pkey_tbl_len = to_mdev(ibdev)->limits.pkey_table_len; | ||
129 | props->qkey_viol_cntr = be16_to_cpup((u16 *) (out_mad->data + 48)); | ||
130 | props->active_width = out_mad->data[31] & 0xf; | ||
131 | props->active_speed = out_mad->data[35] >> 4; | ||
132 | |||
133 | out: | ||
134 | kfree(in_mad); | ||
135 | kfree(out_mad); | ||
136 | return err; | ||
137 | } | ||
138 | |||
139 | static int mthca_modify_port(struct ib_device *ibdev, | ||
140 | u8 port, int port_modify_mask, | ||
141 | struct ib_port_modify *props) | ||
142 | { | ||
143 | struct mthca_set_ib_param set_ib; | ||
144 | struct ib_port_attr attr; | ||
145 | int err; | ||
146 | u8 status; | ||
147 | |||
148 | if (down_interruptible(&to_mdev(ibdev)->cap_mask_mutex)) | ||
149 | return -ERESTARTSYS; | ||
150 | |||
151 | err = mthca_query_port(ibdev, port, &attr); | ||
152 | if (err) | ||
153 | goto out; | ||
154 | |||
155 | set_ib.set_si_guid = 0; | ||
156 | set_ib.reset_qkey_viol = !!(port_modify_mask & IB_PORT_RESET_QKEY_CNTR); | ||
157 | |||
158 | set_ib.cap_mask = (attr.port_cap_flags | props->set_port_cap_mask) & | ||
159 | ~props->clr_port_cap_mask; | ||
160 | |||
161 | err = mthca_SET_IB(to_mdev(ibdev), &set_ib, port, &status); | ||
162 | if (err) | ||
163 | goto out; | ||
164 | if (status) { | ||
165 | err = -EINVAL; | ||
166 | goto out; | ||
167 | } | ||
168 | |||
169 | out: | ||
170 | up(&to_mdev(ibdev)->cap_mask_mutex); | ||
171 | return err; | ||
172 | } | ||
173 | |||
174 | static int mthca_query_pkey(struct ib_device *ibdev, | ||
175 | u8 port, u16 index, u16 *pkey) | ||
176 | { | ||
177 | struct ib_smp *in_mad = NULL; | ||
178 | struct ib_smp *out_mad = NULL; | ||
179 | int err = -ENOMEM; | ||
180 | u8 status; | ||
181 | |||
182 | in_mad = kmalloc(sizeof *in_mad, GFP_KERNEL); | ||
183 | out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); | ||
184 | if (!in_mad || !out_mad) | ||
185 | goto out; | ||
186 | |||
187 | memset(in_mad, 0, sizeof *in_mad); | ||
188 | in_mad->base_version = 1; | ||
189 | in_mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; | ||
190 | in_mad->class_version = 1; | ||
191 | in_mad->method = IB_MGMT_METHOD_GET; | ||
192 | in_mad->attr_id = IB_SMP_ATTR_PKEY_TABLE; | ||
193 | in_mad->attr_mod = cpu_to_be32(index / 32); | ||
194 | |||
195 | err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, | ||
196 | port, NULL, NULL, in_mad, out_mad, | ||
197 | &status); | ||
198 | if (err) | ||
199 | goto out; | ||
200 | if (status) { | ||
201 | err = -EINVAL; | ||
202 | goto out; | ||
203 | } | ||
204 | |||
205 | *pkey = be16_to_cpu(((u16 *) out_mad->data)[index % 32]); | ||
206 | |||
207 | out: | ||
208 | kfree(in_mad); | ||
209 | kfree(out_mad); | ||
210 | return err; | ||
211 | } | ||
212 | |||
213 | static int mthca_query_gid(struct ib_device *ibdev, u8 port, | ||
214 | int index, union ib_gid *gid) | ||
215 | { | ||
216 | struct ib_smp *in_mad = NULL; | ||
217 | struct ib_smp *out_mad = NULL; | ||
218 | int err = -ENOMEM; | ||
219 | u8 status; | ||
220 | |||
221 | in_mad = kmalloc(sizeof *in_mad, GFP_KERNEL); | ||
222 | out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); | ||
223 | if (!in_mad || !out_mad) | ||
224 | goto out; | ||
225 | |||
226 | memset(in_mad, 0, sizeof *in_mad); | ||
227 | in_mad->base_version = 1; | ||
228 | in_mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; | ||
229 | in_mad->class_version = 1; | ||
230 | in_mad->method = IB_MGMT_METHOD_GET; | ||
231 | in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; | ||
232 | in_mad->attr_mod = cpu_to_be32(port); | ||
233 | |||
234 | err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, | ||
235 | port, NULL, NULL, in_mad, out_mad, | ||
236 | &status); | ||
237 | if (err) | ||
238 | goto out; | ||
239 | if (status) { | ||
240 | err = -EINVAL; | ||
241 | goto out; | ||
242 | } | ||
243 | |||
244 | memcpy(gid->raw, out_mad->data + 8, 8); | ||
245 | |||
246 | memset(in_mad, 0, sizeof *in_mad); | ||
247 | in_mad->base_version = 1; | ||
248 | in_mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; | ||
249 | in_mad->class_version = 1; | ||
250 | in_mad->method = IB_MGMT_METHOD_GET; | ||
251 | in_mad->attr_id = IB_SMP_ATTR_GUID_INFO; | ||
252 | in_mad->attr_mod = cpu_to_be32(index / 8); | ||
253 | |||
254 | err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, | ||
255 | port, NULL, NULL, in_mad, out_mad, | ||
256 | &status); | ||
257 | if (err) | ||
258 | goto out; | ||
259 | if (status) { | ||
260 | err = -EINVAL; | ||
261 | goto out; | ||
262 | } | ||
263 | |||
264 | memcpy(gid->raw + 8, out_mad->data + (index % 8) * 16, 8); | ||
265 | |||
266 | out: | ||
267 | kfree(in_mad); | ||
268 | kfree(out_mad); | ||
269 | return err; | ||
270 | } | ||
271 | |||
272 | static struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev) | ||
273 | { | ||
274 | struct mthca_pd *pd; | ||
275 | int err; | ||
276 | |||
277 | pd = kmalloc(sizeof *pd, GFP_KERNEL); | ||
278 | if (!pd) | ||
279 | return ERR_PTR(-ENOMEM); | ||
280 | |||
281 | err = mthca_pd_alloc(to_mdev(ibdev), pd); | ||
282 | if (err) { | ||
283 | kfree(pd); | ||
284 | return ERR_PTR(err); | ||
285 | } | ||
286 | |||
287 | return &pd->ibpd; | ||
288 | } | ||
289 | |||
290 | static int mthca_dealloc_pd(struct ib_pd *pd) | ||
291 | { | ||
292 | mthca_pd_free(to_mdev(pd->device), to_mpd(pd)); | ||
293 | kfree(pd); | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static struct ib_ah *mthca_ah_create(struct ib_pd *pd, | ||
299 | struct ib_ah_attr *ah_attr) | ||
300 | { | ||
301 | int err; | ||
302 | struct mthca_ah *ah; | ||
303 | |||
304 | ah = kmalloc(sizeof *ah, GFP_KERNEL); | ||
305 | if (!ah) | ||
306 | return ERR_PTR(-ENOMEM); | ||
307 | |||
308 | err = mthca_create_ah(to_mdev(pd->device), to_mpd(pd), ah_attr, ah); | ||
309 | if (err) { | ||
310 | kfree(ah); | ||
311 | return ERR_PTR(err); | ||
312 | } | ||
313 | |||
314 | return &ah->ibah; | ||
315 | } | ||
316 | |||
317 | static int mthca_ah_destroy(struct ib_ah *ah) | ||
318 | { | ||
319 | mthca_destroy_ah(to_mdev(ah->device), to_mah(ah)); | ||
320 | kfree(ah); | ||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static struct ib_qp *mthca_create_qp(struct ib_pd *pd, | ||
326 | struct ib_qp_init_attr *init_attr) | ||
327 | { | ||
328 | struct mthca_qp *qp; | ||
329 | int err; | ||
330 | |||
331 | switch (init_attr->qp_type) { | ||
332 | case IB_QPT_RC: | ||
333 | case IB_QPT_UC: | ||
334 | case IB_QPT_UD: | ||
335 | { | ||
336 | qp = kmalloc(sizeof *qp, GFP_KERNEL); | ||
337 | if (!qp) | ||
338 | return ERR_PTR(-ENOMEM); | ||
339 | |||
340 | qp->sq.max = init_attr->cap.max_send_wr; | ||
341 | qp->rq.max = init_attr->cap.max_recv_wr; | ||
342 | qp->sq.max_gs = init_attr->cap.max_send_sge; | ||
343 | qp->rq.max_gs = init_attr->cap.max_recv_sge; | ||
344 | |||
345 | err = mthca_alloc_qp(to_mdev(pd->device), to_mpd(pd), | ||
346 | to_mcq(init_attr->send_cq), | ||
347 | to_mcq(init_attr->recv_cq), | ||
348 | init_attr->qp_type, init_attr->sq_sig_type, | ||
349 | qp); | ||
350 | qp->ibqp.qp_num = qp->qpn; | ||
351 | break; | ||
352 | } | ||
353 | case IB_QPT_SMI: | ||
354 | case IB_QPT_GSI: | ||
355 | { | ||
356 | qp = kmalloc(sizeof (struct mthca_sqp), GFP_KERNEL); | ||
357 | if (!qp) | ||
358 | return ERR_PTR(-ENOMEM); | ||
359 | |||
360 | qp->sq.max = init_attr->cap.max_send_wr; | ||
361 | qp->rq.max = init_attr->cap.max_recv_wr; | ||
362 | qp->sq.max_gs = init_attr->cap.max_send_sge; | ||
363 | qp->rq.max_gs = init_attr->cap.max_recv_sge; | ||
364 | |||
365 | qp->ibqp.qp_num = init_attr->qp_type == IB_QPT_SMI ? 0 : 1; | ||
366 | |||
367 | err = mthca_alloc_sqp(to_mdev(pd->device), to_mpd(pd), | ||
368 | to_mcq(init_attr->send_cq), | ||
369 | to_mcq(init_attr->recv_cq), | ||
370 | init_attr->sq_sig_type, | ||
371 | qp->ibqp.qp_num, init_attr->port_num, | ||
372 | to_msqp(qp)); | ||
373 | break; | ||
374 | } | ||
375 | default: | ||
376 | /* Don't support raw QPs */ | ||
377 | return ERR_PTR(-ENOSYS); | ||
378 | } | ||
379 | |||
380 | if (err) { | ||
381 | kfree(qp); | ||
382 | return ERR_PTR(err); | ||
383 | } | ||
384 | |||
385 | init_attr->cap.max_inline_data = 0; | ||
386 | |||
387 | return &qp->ibqp; | ||
388 | } | ||
389 | |||
390 | static int mthca_destroy_qp(struct ib_qp *qp) | ||
391 | { | ||
392 | mthca_free_qp(to_mdev(qp->device), to_mqp(qp)); | ||
393 | kfree(qp); | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries) | ||
398 | { | ||
399 | struct mthca_cq *cq; | ||
400 | int nent; | ||
401 | int err; | ||
402 | |||
403 | cq = kmalloc(sizeof *cq, GFP_KERNEL); | ||
404 | if (!cq) | ||
405 | return ERR_PTR(-ENOMEM); | ||
406 | |||
407 | for (nent = 1; nent <= entries; nent <<= 1) | ||
408 | ; /* nothing */ | ||
409 | |||
410 | err = mthca_init_cq(to_mdev(ibdev), nent, cq); | ||
411 | if (err) { | ||
412 | kfree(cq); | ||
413 | cq = ERR_PTR(err); | ||
414 | } | ||
415 | |||
416 | return &cq->ibcq; | ||
417 | } | ||
418 | |||
419 | static int mthca_destroy_cq(struct ib_cq *cq) | ||
420 | { | ||
421 | mthca_free_cq(to_mdev(cq->device), to_mcq(cq)); | ||
422 | kfree(cq); | ||
423 | |||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | static inline u32 convert_access(int acc) | ||
428 | { | ||
429 | return (acc & IB_ACCESS_REMOTE_ATOMIC ? MTHCA_MPT_FLAG_ATOMIC : 0) | | ||
430 | (acc & IB_ACCESS_REMOTE_WRITE ? MTHCA_MPT_FLAG_REMOTE_WRITE : 0) | | ||
431 | (acc & IB_ACCESS_REMOTE_READ ? MTHCA_MPT_FLAG_REMOTE_READ : 0) | | ||
432 | (acc & IB_ACCESS_LOCAL_WRITE ? MTHCA_MPT_FLAG_LOCAL_WRITE : 0) | | ||
433 | MTHCA_MPT_FLAG_LOCAL_READ; | ||
434 | } | ||
435 | |||
436 | static struct ib_mr *mthca_get_dma_mr(struct ib_pd *pd, int acc) | ||
437 | { | ||
438 | struct mthca_mr *mr; | ||
439 | int err; | ||
440 | |||
441 | mr = kmalloc(sizeof *mr, GFP_KERNEL); | ||
442 | if (!mr) | ||
443 | return ERR_PTR(-ENOMEM); | ||
444 | |||
445 | err = mthca_mr_alloc_notrans(to_mdev(pd->device), | ||
446 | to_mpd(pd)->pd_num, | ||
447 | convert_access(acc), mr); | ||
448 | |||
449 | if (err) { | ||
450 | kfree(mr); | ||
451 | return ERR_PTR(err); | ||
452 | } | ||
453 | |||
454 | return &mr->ibmr; | ||
455 | } | ||
456 | |||
457 | static struct ib_mr *mthca_reg_phys_mr(struct ib_pd *pd, | ||
458 | struct ib_phys_buf *buffer_list, | ||
459 | int num_phys_buf, | ||
460 | int acc, | ||
461 | u64 *iova_start) | ||
462 | { | ||
463 | struct mthca_mr *mr; | ||
464 | u64 *page_list; | ||
465 | u64 total_size; | ||
466 | u64 mask; | ||
467 | int shift; | ||
468 | int npages; | ||
469 | int err; | ||
470 | int i, j, n; | ||
471 | |||
472 | /* First check that we have enough alignment */ | ||
473 | if ((*iova_start & ~PAGE_MASK) != (buffer_list[0].addr & ~PAGE_MASK)) | ||
474 | return ERR_PTR(-EINVAL); | ||
475 | |||
476 | if (num_phys_buf > 1 && | ||
477 | ((buffer_list[0].addr + buffer_list[0].size) & ~PAGE_MASK)) | ||
478 | return ERR_PTR(-EINVAL); | ||
479 | |||
480 | mask = 0; | ||
481 | total_size = 0; | ||
482 | for (i = 0; i < num_phys_buf; ++i) { | ||
483 | if (buffer_list[i].addr & ~PAGE_MASK) | ||
484 | return ERR_PTR(-EINVAL); | ||
485 | if (i != 0 && i != num_phys_buf - 1 && | ||
486 | (buffer_list[i].size & ~PAGE_MASK)) | ||
487 | return ERR_PTR(-EINVAL); | ||
488 | |||
489 | total_size += buffer_list[i].size; | ||
490 | if (i > 0) | ||
491 | mask |= buffer_list[i].addr; | ||
492 | } | ||
493 | |||
494 | /* Find largest page shift we can use to cover buffers */ | ||
495 | for (shift = PAGE_SHIFT; shift < 31; ++shift) | ||
496 | if (num_phys_buf > 1) { | ||
497 | if ((1ULL << shift) & mask) | ||
498 | break; | ||
499 | } else { | ||
500 | if (1ULL << shift >= | ||
501 | buffer_list[0].size + | ||
502 | (buffer_list[0].addr & ((1ULL << shift) - 1))) | ||
503 | break; | ||
504 | } | ||
505 | |||
506 | buffer_list[0].size += buffer_list[0].addr & ((1ULL << shift) - 1); | ||
507 | buffer_list[0].addr &= ~0ull << shift; | ||
508 | |||
509 | mr = kmalloc(sizeof *mr, GFP_KERNEL); | ||
510 | if (!mr) | ||
511 | return ERR_PTR(-ENOMEM); | ||
512 | |||
513 | npages = 0; | ||
514 | for (i = 0; i < num_phys_buf; ++i) | ||
515 | npages += (buffer_list[i].size + (1ULL << shift) - 1) >> shift; | ||
516 | |||
517 | if (!npages) | ||
518 | return &mr->ibmr; | ||
519 | |||
520 | page_list = kmalloc(npages * sizeof *page_list, GFP_KERNEL); | ||
521 | if (!page_list) { | ||
522 | kfree(mr); | ||
523 | return ERR_PTR(-ENOMEM); | ||
524 | } | ||
525 | |||
526 | n = 0; | ||
527 | for (i = 0; i < num_phys_buf; ++i) | ||
528 | for (j = 0; | ||
529 | j < (buffer_list[i].size + (1ULL << shift) - 1) >> shift; | ||
530 | ++j) | ||
531 | page_list[n++] = buffer_list[i].addr + ((u64) j << shift); | ||
532 | |||
533 | mthca_dbg(to_mdev(pd->device), "Registering memory at %llx (iova %llx) " | ||
534 | "in PD %x; shift %d, npages %d.\n", | ||
535 | (unsigned long long) buffer_list[0].addr, | ||
536 | (unsigned long long) *iova_start, | ||
537 | to_mpd(pd)->pd_num, | ||
538 | shift, npages); | ||
539 | |||
540 | err = mthca_mr_alloc_phys(to_mdev(pd->device), | ||
541 | to_mpd(pd)->pd_num, | ||
542 | page_list, shift, npages, | ||
543 | *iova_start, total_size, | ||
544 | convert_access(acc), mr); | ||
545 | |||
546 | if (err) { | ||
547 | kfree(mr); | ||
548 | return ERR_PTR(err); | ||
549 | } | ||
550 | |||
551 | kfree(page_list); | ||
552 | return &mr->ibmr; | ||
553 | } | ||
554 | |||
555 | static int mthca_dereg_mr(struct ib_mr *mr) | ||
556 | { | ||
557 | mthca_free_mr(to_mdev(mr->device), to_mmr(mr)); | ||
558 | kfree(mr); | ||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | static ssize_t show_rev(struct class_device *cdev, char *buf) | ||
563 | { | ||
564 | struct mthca_dev *dev = container_of(cdev, struct mthca_dev, ib_dev.class_dev); | ||
565 | return sprintf(buf, "%x\n", dev->rev_id); | ||
566 | } | ||
567 | |||
568 | static ssize_t show_fw_ver(struct class_device *cdev, char *buf) | ||
569 | { | ||
570 | struct mthca_dev *dev = container_of(cdev, struct mthca_dev, ib_dev.class_dev); | ||
571 | return sprintf(buf, "%x.%x.%x\n", (int) (dev->fw_ver >> 32), | ||
572 | (int) (dev->fw_ver >> 16) & 0xffff, | ||
573 | (int) dev->fw_ver & 0xffff); | ||
574 | } | ||
575 | |||
576 | static ssize_t show_hca(struct class_device *cdev, char *buf) | ||
577 | { | ||
578 | struct mthca_dev *dev = container_of(cdev, struct mthca_dev, ib_dev.class_dev); | ||
579 | switch (dev->hca_type) { | ||
580 | case TAVOR: return sprintf(buf, "MT23108\n"); | ||
581 | case ARBEL_COMPAT: return sprintf(buf, "MT25208 (MT23108 compat mode)\n"); | ||
582 | case ARBEL_NATIVE: return sprintf(buf, "MT25208\n"); | ||
583 | default: return sprintf(buf, "unknown\n"); | ||
584 | } | ||
585 | } | ||
586 | |||
587 | static CLASS_DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); | ||
588 | static CLASS_DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL); | ||
589 | static CLASS_DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); | ||
590 | |||
591 | static struct class_device_attribute *mthca_class_attributes[] = { | ||
592 | &class_device_attr_hw_rev, | ||
593 | &class_device_attr_fw_ver, | ||
594 | &class_device_attr_hca_type | ||
595 | }; | ||
596 | |||
597 | int mthca_register_device(struct mthca_dev *dev) | ||
598 | { | ||
599 | int ret; | ||
600 | int i; | ||
601 | |||
602 | strlcpy(dev->ib_dev.name, "mthca%d", IB_DEVICE_NAME_MAX); | ||
603 | dev->ib_dev.node_type = IB_NODE_CA; | ||
604 | dev->ib_dev.phys_port_cnt = dev->limits.num_ports; | ||
605 | dev->ib_dev.dma_device = &dev->pdev->dev; | ||
606 | dev->ib_dev.class_dev.dev = &dev->pdev->dev; | ||
607 | dev->ib_dev.query_device = mthca_query_device; | ||
608 | dev->ib_dev.query_port = mthca_query_port; | ||
609 | dev->ib_dev.modify_port = mthca_modify_port; | ||
610 | dev->ib_dev.query_pkey = mthca_query_pkey; | ||
611 | dev->ib_dev.query_gid = mthca_query_gid; | ||
612 | dev->ib_dev.alloc_pd = mthca_alloc_pd; | ||
613 | dev->ib_dev.dealloc_pd = mthca_dealloc_pd; | ||
614 | dev->ib_dev.create_ah = mthca_ah_create; | ||
615 | dev->ib_dev.destroy_ah = mthca_ah_destroy; | ||
616 | dev->ib_dev.create_qp = mthca_create_qp; | ||
617 | dev->ib_dev.modify_qp = mthca_modify_qp; | ||
618 | dev->ib_dev.destroy_qp = mthca_destroy_qp; | ||
619 | dev->ib_dev.create_cq = mthca_create_cq; | ||
620 | dev->ib_dev.destroy_cq = mthca_destroy_cq; | ||
621 | dev->ib_dev.poll_cq = mthca_poll_cq; | ||
622 | dev->ib_dev.get_dma_mr = mthca_get_dma_mr; | ||
623 | dev->ib_dev.reg_phys_mr = mthca_reg_phys_mr; | ||
624 | dev->ib_dev.dereg_mr = mthca_dereg_mr; | ||
625 | dev->ib_dev.attach_mcast = mthca_multicast_attach; | ||
626 | dev->ib_dev.detach_mcast = mthca_multicast_detach; | ||
627 | dev->ib_dev.process_mad = mthca_process_mad; | ||
628 | |||
629 | if (dev->hca_type == ARBEL_NATIVE) { | ||
630 | dev->ib_dev.req_notify_cq = mthca_arbel_arm_cq; | ||
631 | dev->ib_dev.post_send = mthca_arbel_post_send; | ||
632 | dev->ib_dev.post_recv = mthca_arbel_post_receive; | ||
633 | } else { | ||
634 | dev->ib_dev.req_notify_cq = mthca_tavor_arm_cq; | ||
635 | dev->ib_dev.post_send = mthca_tavor_post_send; | ||
636 | dev->ib_dev.post_recv = mthca_tavor_post_receive; | ||
637 | } | ||
638 | |||
639 | init_MUTEX(&dev->cap_mask_mutex); | ||
640 | |||
641 | ret = ib_register_device(&dev->ib_dev); | ||
642 | if (ret) | ||
643 | return ret; | ||
644 | |||
645 | for (i = 0; i < ARRAY_SIZE(mthca_class_attributes); ++i) { | ||
646 | ret = class_device_create_file(&dev->ib_dev.class_dev, | ||
647 | mthca_class_attributes[i]); | ||
648 | if (ret) { | ||
649 | ib_unregister_device(&dev->ib_dev); | ||
650 | return ret; | ||
651 | } | ||
652 | } | ||
653 | |||
654 | return 0; | ||
655 | } | ||
656 | |||
657 | void mthca_unregister_device(struct mthca_dev *dev) | ||
658 | { | ||
659 | ib_unregister_device(&dev->ib_dev); | ||
660 | } | ||