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. |
4885bf64 | 4 | * Copyright (c) 2005, 2006 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. | |
1da177e4 LT |
35 | */ |
36 | ||
a4d61e84 | 37 | #include <rdma/ib_smi.h> |
f7c6a7b5 | 38 | #include <rdma/ib_umem.h> |
883a99c7 | 39 | #include <rdma/ib_user_verbs.h> |
89944450 | 40 | #include <rdma/uverbs_ioctl.h> |
baaad380 RD |
41 | |
42 | #include <linux/sched.h> | |
5a0e3ad6 | 43 | #include <linux/slab.h> |
fc87af74 | 44 | #include <linux/stat.h> |
53b8b3ff | 45 | #include <linux/mm.h> |
b108d976 | 46 | #include <linux/export.h> |
1da177e4 LT |
47 | |
48 | #include "mthca_dev.h" | |
49 | #include "mthca_cmd.h" | |
486f6095 | 50 | #include <rdma/mthca-abi.h> |
5e0b537c | 51 | #include "mthca_memfree.h" |
1da177e4 | 52 | |
2528e33e MB |
53 | static int mthca_query_device(struct ib_device *ibdev, struct ib_device_attr *props, |
54 | struct ib_udata *uhw) | |
1da177e4 LT |
55 | { |
56 | struct ib_smp *in_mad = NULL; | |
57 | struct ib_smp *out_mad = NULL; | |
58 | int err = -ENOMEM; | |
b3999393 | 59 | struct mthca_dev *mdev = to_mdev(ibdev); |
1da177e4 | 60 | |
2528e33e MB |
61 | if (uhw->inlen || uhw->outlen) |
62 | return -EINVAL; | |
63 | ||
105e50a5 | 64 | in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); |
1da177e4 LT |
65 | out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); |
66 | if (!in_mad || !out_mad) | |
67 | goto out; | |
68 | ||
a852092e | 69 | memset(props, 0, sizeof *props); |
8cf2daf3 | 70 | |
1da177e4 LT |
71 | props->fw_ver = mdev->fw_ver; |
72 | ||
d82e2b27 | 73 | ib_init_query_mad(in_mad); |
87635b71 | 74 | in_mad->attr_id = IB_SMP_ATTR_NODE_INFO; |
1da177e4 LT |
75 | |
76 | err = mthca_MAD_IFC(mdev, 1, 1, | |
cdb73db0 | 77 | 1, NULL, NULL, in_mad, out_mad); |
1da177e4 LT |
78 | if (err) |
79 | goto out; | |
1da177e4 | 80 | |
8cf2daf3 | 81 | props->device_cap_flags = mdev->device_cap_flags; |
97f52eb4 | 82 | props->vendor_id = be32_to_cpup((__be32 *) (out_mad->data + 36)) & |
1da177e4 | 83 | 0xffffff; |
97f52eb4 | 84 | props->vendor_part_id = be16_to_cpup((__be16 *) (out_mad->data + 30)); |
a1c337af | 85 | props->hw_ver = be32_to_cpup((__be32 *) (out_mad->data + 32)); |
1da177e4 | 86 | memcpy(&props->sys_image_guid, out_mad->data + 4, 8); |
1da177e4 | 87 | |
8cf2daf3 | 88 | props->max_mr_size = ~0ull; |
0f69ce1e | 89 | props->page_size_cap = mdev->limits.page_size_cap; |
8cf2daf3 | 90 | props->max_qp = mdev->limits.num_qps - mdev->limits.reserved_qps; |
efaae8f7 | 91 | props->max_qp_wr = mdev->limits.max_wqes; |
33023fb8 SW |
92 | props->max_send_sge = mdev->limits.max_sg; |
93 | props->max_recv_sge = mdev->limits.max_sg; | |
94 | props->max_sge_rd = mdev->limits.max_sg; | |
8cf2daf3 | 95 | props->max_cq = mdev->limits.num_cqs - mdev->limits.reserved_cqs; |
efaae8f7 | 96 | props->max_cqe = mdev->limits.max_cqes; |
8cf2daf3 RD |
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; | |
efaae8f7 JM |
100 | props->max_qp_init_rd_atom = mdev->limits.max_qp_init_rdma; |
101 | props->max_res_rd_atom = props->max_qp_rd_atom * props->max_qp; | |
102 | props->max_srq = mdev->limits.num_srqs - mdev->limits.reserved_srqs; | |
103 | props->max_srq_wr = mdev->limits.max_srq_wqes; | |
59fef3b1 | 104 | props->max_srq_sge = mdev->limits.max_srq_sge; |
8cf2daf3 | 105 | props->local_ca_ack_delay = mdev->limits.local_ca_ack_delay; |
2fa5e2eb | 106 | props->atomic_cap = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ? |
33033b79 | 107 | IB_ATOMIC_HCA : IB_ATOMIC_NONE; |
efaae8f7 JM |
108 | props->max_pkeys = mdev->limits.pkey_table_len; |
109 | props->max_mcast_grp = mdev->limits.num_mgms + mdev->limits.num_amgms; | |
110 | props->max_mcast_qp_attach = MTHCA_QP_PER_MGM; | |
2fa5e2eb | 111 | props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * |
efaae8f7 | 112 | props->max_mcast_grp; |
8cf2daf3 | 113 | |
1da177e4 LT |
114 | err = 0; |
115 | out: | |
116 | kfree(in_mad); | |
117 | kfree(out_mad); | |
118 | return err; | |
119 | } | |
120 | ||
121 | static int mthca_query_port(struct ib_device *ibdev, | |
1fb7f897 | 122 | u32 port, struct ib_port_attr *props) |
1da177e4 LT |
123 | { |
124 | struct ib_smp *in_mad = NULL; | |
125 | struct ib_smp *out_mad = NULL; | |
126 | int err = -ENOMEM; | |
1da177e4 | 127 | |
105e50a5 | 128 | in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); |
1da177e4 LT |
129 | out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); |
130 | if (!in_mad || !out_mad) | |
131 | goto out; | |
132 | ||
c4550c63 | 133 | /* props being zeroed by the caller, avoid zeroing it here */ |
d1887ec2 | 134 | |
d82e2b27 | 135 | ib_init_query_mad(in_mad); |
87635b71 RD |
136 | in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; |
137 | in_mad->attr_mod = cpu_to_be32(port); | |
1da177e4 LT |
138 | |
139 | err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, | |
cdb73db0 | 140 | port, NULL, NULL, in_mad, out_mad); |
1da177e4 LT |
141 | if (err) |
142 | goto out; | |
1da177e4 | 143 | |
97f52eb4 | 144 | props->lid = be16_to_cpup((__be16 *) (out_mad->data + 16)); |
1da177e4 | 145 | props->lmc = out_mad->data[34] & 0x7; |
97f52eb4 | 146 | props->sm_lid = be16_to_cpup((__be16 *) (out_mad->data + 18)); |
1da177e4 LT |
147 | props->sm_sl = out_mad->data[36] & 0xf; |
148 | props->state = out_mad->data[32] & 0xf; | |
149 | props->phys_state = out_mad->data[33] >> 4; | |
97f52eb4 | 150 | props->port_cap_flags = be32_to_cpup((__be32 *) (out_mad->data + 20)); |
1da177e4 | 151 | props->gid_tbl_len = to_mdev(ibdev)->limits.gid_table_len; |
d1887ec2 | 152 | props->max_msg_sz = 0x80000000; |
1da177e4 | 153 | props->pkey_tbl_len = to_mdev(ibdev)->limits.pkey_table_len; |
9825051e | 154 | props->bad_pkey_cntr = be16_to_cpup((__be16 *) (out_mad->data + 46)); |
97f52eb4 | 155 | props->qkey_viol_cntr = be16_to_cpup((__be16 *) (out_mad->data + 48)); |
1da177e4 LT |
156 | props->active_width = out_mad->data[31] & 0xf; |
157 | props->active_speed = out_mad->data[35] >> 4; | |
9825051e JM |
158 | props->max_mtu = out_mad->data[41] & 0xf; |
159 | props->active_mtu = out_mad->data[36] >> 4; | |
160 | props->subnet_timeout = out_mad->data[51] & 0x1f; | |
a8bf4e77 JM |
161 | props->max_vl_num = out_mad->data[37] >> 4; |
162 | props->init_type_reply = out_mad->data[41] >> 4; | |
1da177e4 LT |
163 | |
164 | out: | |
165 | kfree(in_mad); | |
166 | kfree(out_mad); | |
167 | return err; | |
168 | } | |
169 | ||
6dfc3901 RD |
170 | static int mthca_modify_device(struct ib_device *ibdev, |
171 | int mask, | |
172 | struct ib_device_modify *props) | |
173 | { | |
174 | if (mask & ~IB_DEVICE_MODIFY_NODE_DESC) | |
175 | return -EOPNOTSUPP; | |
176 | ||
177 | if (mask & IB_DEVICE_MODIFY_NODE_DESC) { | |
178 | if (mutex_lock_interruptible(&to_mdev(ibdev)->cap_mask_mutex)) | |
179 | return -ERESTARTSYS; | |
bd99fdea YS |
180 | memcpy(ibdev->node_desc, props->node_desc, |
181 | IB_DEVICE_NODE_DESC_MAX); | |
6dfc3901 RD |
182 | mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex); |
183 | } | |
184 | ||
185 | return 0; | |
186 | } | |
187 | ||
1da177e4 | 188 | static int mthca_modify_port(struct ib_device *ibdev, |
1fb7f897 | 189 | u32 port, int port_modify_mask, |
1da177e4 LT |
190 | struct ib_port_modify *props) |
191 | { | |
192 | struct mthca_set_ib_param set_ib; | |
193 | struct ib_port_attr attr; | |
194 | int err; | |
1da177e4 | 195 | |
fd9cfdd1 | 196 | if (mutex_lock_interruptible(&to_mdev(ibdev)->cap_mask_mutex)) |
1da177e4 LT |
197 | return -ERESTARTSYS; |
198 | ||
c4550c63 | 199 | err = ib_query_port(ibdev, port, &attr); |
1da177e4 LT |
200 | if (err) |
201 | goto out; | |
202 | ||
203 | set_ib.set_si_guid = 0; | |
204 | set_ib.reset_qkey_viol = !!(port_modify_mask & IB_PORT_RESET_QKEY_CNTR); | |
205 | ||
206 | set_ib.cap_mask = (attr.port_cap_flags | props->set_port_cap_mask) & | |
207 | ~props->clr_port_cap_mask; | |
208 | ||
cdb73db0 | 209 | err = mthca_SET_IB(to_mdev(ibdev), &set_ib, port); |
1da177e4 LT |
210 | if (err) |
211 | goto out; | |
1da177e4 | 212 | out: |
fd9cfdd1 | 213 | mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex); |
1da177e4 LT |
214 | return err; |
215 | } | |
216 | ||
217 | static int mthca_query_pkey(struct ib_device *ibdev, | |
1fb7f897 | 218 | u32 port, u16 index, u16 *pkey) |
1da177e4 LT |
219 | { |
220 | struct ib_smp *in_mad = NULL; | |
221 | struct ib_smp *out_mad = NULL; | |
222 | int err = -ENOMEM; | |
1da177e4 | 223 | |
105e50a5 | 224 | in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); |
1da177e4 LT |
225 | out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); |
226 | if (!in_mad || !out_mad) | |
227 | goto out; | |
228 | ||
d82e2b27 | 229 | ib_init_query_mad(in_mad); |
87635b71 RD |
230 | in_mad->attr_id = IB_SMP_ATTR_PKEY_TABLE; |
231 | in_mad->attr_mod = cpu_to_be32(index / 32); | |
1da177e4 LT |
232 | |
233 | err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, | |
cdb73db0 | 234 | port, NULL, NULL, in_mad, out_mad); |
1da177e4 LT |
235 | if (err) |
236 | goto out; | |
1da177e4 | 237 | |
97f52eb4 | 238 | *pkey = be16_to_cpu(((__be16 *) out_mad->data)[index % 32]); |
1da177e4 LT |
239 | |
240 | out: | |
241 | kfree(in_mad); | |
242 | kfree(out_mad); | |
243 | return err; | |
244 | } | |
245 | ||
1fb7f897 | 246 | static int mthca_query_gid(struct ib_device *ibdev, u32 port, |
1da177e4 LT |
247 | int index, union ib_gid *gid) |
248 | { | |
249 | struct ib_smp *in_mad = NULL; | |
250 | struct ib_smp *out_mad = NULL; | |
251 | int err = -ENOMEM; | |
1da177e4 | 252 | |
105e50a5 | 253 | in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); |
1da177e4 LT |
254 | out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); |
255 | if (!in_mad || !out_mad) | |
256 | goto out; | |
257 | ||
d82e2b27 | 258 | ib_init_query_mad(in_mad); |
87635b71 RD |
259 | in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; |
260 | in_mad->attr_mod = cpu_to_be32(port); | |
1da177e4 LT |
261 | |
262 | err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, | |
cdb73db0 | 263 | port, NULL, NULL, in_mad, out_mad); |
1da177e4 LT |
264 | if (err) |
265 | goto out; | |
1da177e4 LT |
266 | |
267 | memcpy(gid->raw, out_mad->data + 8, 8); | |
268 | ||
d82e2b27 | 269 | ib_init_query_mad(in_mad); |
87635b71 RD |
270 | in_mad->attr_id = IB_SMP_ATTR_GUID_INFO; |
271 | in_mad->attr_mod = cpu_to_be32(index / 8); | |
1da177e4 LT |
272 | |
273 | err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, | |
cdb73db0 | 274 | port, NULL, NULL, in_mad, out_mad); |
1da177e4 LT |
275 | if (err) |
276 | goto out; | |
1da177e4 | 277 | |
254abfd3 | 278 | memcpy(gid->raw + 8, out_mad->data + (index % 8) * 8, 8); |
1da177e4 LT |
279 | |
280 | out: | |
281 | kfree(in_mad); | |
282 | kfree(out_mad); | |
283 | return err; | |
284 | } | |
285 | ||
a2a074ef LR |
286 | static int mthca_alloc_ucontext(struct ib_ucontext *uctx, |
287 | struct ib_udata *udata) | |
5e0b537c | 288 | { |
a2a074ef LR |
289 | struct ib_device *ibdev = uctx->device; |
290 | struct mthca_alloc_ucontext_resp uresp = {}; | |
291 | struct mthca_ucontext *context = to_mucontext(uctx); | |
5e0b537c RD |
292 | int err; |
293 | ||
d8410647 | 294 | if (!(to_mdev(ibdev)->active)) |
a2a074ef | 295 | return -EAGAIN; |
5e0b537c RD |
296 | |
297 | uresp.qp_tab_size = to_mdev(ibdev)->limits.num_qps; | |
298 | if (mthca_is_memfree(to_mdev(ibdev))) | |
299 | uresp.uarc_size = to_mdev(ibdev)->uar_table.uarc_size; | |
300 | else | |
301 | uresp.uarc_size = 0; | |
302 | ||
5e0b537c | 303 | err = mthca_uar_alloc(to_mdev(ibdev), &context->uar); |
a2a074ef LR |
304 | if (err) |
305 | return err; | |
5e0b537c RD |
306 | |
307 | context->db_tab = mthca_init_user_db_tab(to_mdev(ibdev)); | |
308 | if (IS_ERR(context->db_tab)) { | |
309 | err = PTR_ERR(context->db_tab); | |
310 | mthca_uar_free(to_mdev(ibdev), &context->uar); | |
a2a074ef | 311 | return err; |
5e0b537c RD |
312 | } |
313 | ||
a2a074ef | 314 | if (ib_copy_to_udata(udata, &uresp, sizeof(uresp))) { |
5e0b537c RD |
315 | mthca_cleanup_user_db_tab(to_mdev(ibdev), &context->uar, context->db_tab); |
316 | mthca_uar_free(to_mdev(ibdev), &context->uar); | |
a2a074ef | 317 | return -EFAULT; |
5e0b537c RD |
318 | } |
319 | ||
baaad380 RD |
320 | context->reg_mr_warned = 0; |
321 | ||
a2a074ef | 322 | return 0; |
5e0b537c RD |
323 | } |
324 | ||
a2a074ef | 325 | static void mthca_dealloc_ucontext(struct ib_ucontext *context) |
5e0b537c RD |
326 | { |
327 | mthca_cleanup_user_db_tab(to_mdev(context->device), &to_mucontext(context)->uar, | |
328 | to_mucontext(context)->db_tab); | |
329 | mthca_uar_free(to_mdev(context->device), &to_mucontext(context)->uar); | |
5e0b537c RD |
330 | } |
331 | ||
53b8b3ff RD |
332 | static int mthca_mmap_uar(struct ib_ucontext *context, |
333 | struct vm_area_struct *vma) | |
334 | { | |
335 | if (vma->vm_end - vma->vm_start != PAGE_SIZE) | |
336 | return -EINVAL; | |
337 | ||
338 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | |
339 | ||
6d376756 MT |
340 | if (io_remap_pfn_range(vma, vma->vm_start, |
341 | to_mucontext(context)->uar.pfn, | |
342 | PAGE_SIZE, vma->vm_page_prot)) | |
53b8b3ff RD |
343 | return -EAGAIN; |
344 | ||
345 | return 0; | |
346 | } | |
347 | ||
ff23dfa1 | 348 | static int mthca_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata) |
1da177e4 | 349 | { |
21a428a0 LR |
350 | struct ib_device *ibdev = ibpd->device; |
351 | struct mthca_pd *pd = to_mpd(ibpd); | |
1da177e4 LT |
352 | int err; |
353 | ||
ff23dfa1 | 354 | err = mthca_pd_alloc(to_mdev(ibdev), !udata, pd); |
21a428a0 LR |
355 | if (err) |
356 | return err; | |
1da177e4 | 357 | |
ff23dfa1 | 358 | if (udata) { |
99264c1e RD |
359 | if (ib_copy_to_udata(udata, &pd->pd_num, sizeof (__u32))) { |
360 | mthca_pd_free(to_mdev(ibdev), pd); | |
21a428a0 | 361 | return -EFAULT; |
99264c1e RD |
362 | } |
363 | } | |
364 | ||
21a428a0 | 365 | return 0; |
1da177e4 LT |
366 | } |
367 | ||
91a7c58f | 368 | static int mthca_dealloc_pd(struct ib_pd *pd, struct ib_udata *udata) |
1da177e4 LT |
369 | { |
370 | mthca_pd_free(to_mdev(pd->device), to_mpd(pd)); | |
91a7c58f | 371 | return 0; |
1da177e4 LT |
372 | } |
373 | ||
fa5d010c MG |
374 | static int mthca_ah_create(struct ib_ah *ibah, |
375 | struct rdma_ah_init_attr *init_attr, | |
376 | struct ib_udata *udata) | |
477864c8 | 377 | |
1da177e4 | 378 | { |
d3456914 | 379 | struct mthca_ah *ah = to_mah(ibah); |
1da177e4 | 380 | |
fa5d010c MG |
381 | return mthca_create_ah(to_mdev(ibah->device), to_mpd(ibah->pd), |
382 | init_attr->ah_attr, ah); | |
1da177e4 LT |
383 | } |
384 | ||
9a9ebf8c | 385 | static int mthca_ah_destroy(struct ib_ah *ah, u32 flags) |
1da177e4 LT |
386 | { |
387 | mthca_destroy_ah(to_mdev(ah->device), to_mah(ah)); | |
9a9ebf8c | 388 | return 0; |
1da177e4 LT |
389 | } |
390 | ||
68e326de LR |
391 | static int mthca_create_srq(struct ib_srq *ibsrq, |
392 | struct ib_srq_init_attr *init_attr, | |
393 | struct ib_udata *udata) | |
ec34a922 RD |
394 | { |
395 | struct mthca_create_srq ucmd; | |
89944450 SR |
396 | struct mthca_ucontext *context = rdma_udata_to_drv_context( |
397 | udata, struct mthca_ucontext, ibucontext); | |
68e326de | 398 | struct mthca_srq *srq = to_msrq(ibsrq); |
ec34a922 RD |
399 | int err; |
400 | ||
96104eda | 401 | if (init_attr->srq_type != IB_SRQT_BASIC) |
68e326de | 402 | return -EOPNOTSUPP; |
ec34a922 | 403 | |
e00b64f7 | 404 | if (udata) { |
68e326de LR |
405 | if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) |
406 | return -EFAULT; | |
ec34a922 | 407 | |
68e326de | 408 | err = mthca_map_user_db(to_mdev(ibsrq->device), &context->uar, |
ec34a922 RD |
409 | context->db_tab, ucmd.db_index, |
410 | ucmd.db_page); | |
411 | ||
412 | if (err) | |
68e326de | 413 | return err; |
ec34a922 RD |
414 | |
415 | srq->mr.ibmr.lkey = ucmd.lkey; | |
416 | srq->db_index = ucmd.db_index; | |
417 | } | |
418 | ||
68e326de | 419 | err = mthca_alloc_srq(to_mdev(ibsrq->device), to_mpd(ibsrq->pd), |
e00b64f7 | 420 | &init_attr->attr, srq, udata); |
ec34a922 | 421 | |
e00b64f7 | 422 | if (err && udata) |
68e326de | 423 | mthca_unmap_user_db(to_mdev(ibsrq->device), &context->uar, |
ec34a922 RD |
424 | context->db_tab, ucmd.db_index); |
425 | ||
426 | if (err) | |
68e326de | 427 | return err; |
ec34a922 | 428 | |
68e326de LR |
429 | if (context && ib_copy_to_udata(udata, &srq->srqn, sizeof(__u32))) { |
430 | mthca_free_srq(to_mdev(ibsrq->device), srq); | |
431 | return -EFAULT; | |
ec34a922 RD |
432 | } |
433 | ||
68e326de | 434 | return 0; |
ec34a922 RD |
435 | } |
436 | ||
119181d1 | 437 | static int mthca_destroy_srq(struct ib_srq *srq, struct ib_udata *udata) |
ec34a922 | 438 | { |
bdeacabd SR |
439 | if (udata) { |
440 | struct mthca_ucontext *context = | |
441 | rdma_udata_to_drv_context( | |
442 | udata, | |
443 | struct mthca_ucontext, | |
444 | ibucontext); | |
ec34a922 RD |
445 | |
446 | mthca_unmap_user_db(to_mdev(srq->device), &context->uar, | |
447 | context->db_tab, to_msrq(srq)->db_index); | |
448 | } | |
449 | ||
450 | mthca_free_srq(to_mdev(srq->device), to_msrq(srq)); | |
119181d1 | 451 | return 0; |
ec34a922 RD |
452 | } |
453 | ||
514aee66 LR |
454 | static int mthca_create_qp(struct ib_qp *ibqp, |
455 | struct ib_qp_init_attr *init_attr, | |
456 | struct ib_udata *udata) | |
1da177e4 | 457 | { |
89944450 SR |
458 | struct mthca_ucontext *context = rdma_udata_to_drv_context( |
459 | udata, struct mthca_ucontext, ibucontext); | |
80c8ec2c | 460 | struct mthca_create_qp ucmd; |
514aee66 LR |
461 | struct mthca_qp *qp = to_mqp(ibqp); |
462 | struct mthca_dev *dev = to_mdev(ibqp->device); | |
1da177e4 LT |
463 | int err; |
464 | ||
b846f25a | 465 | if (init_attr->create_flags) |
514aee66 | 466 | return -EOPNOTSUPP; |
b846f25a | 467 | |
1da177e4 LT |
468 | switch (init_attr->qp_type) { |
469 | case IB_QPT_RC: | |
470 | case IB_QPT_UC: | |
471 | case IB_QPT_UD: | |
472 | { | |
e00b64f7 | 473 | if (udata) { |
514aee66 LR |
474 | if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) |
475 | return -EFAULT; | |
80c8ec2c | 476 | |
514aee66 | 477 | err = mthca_map_user_db(dev, &context->uar, |
80c8ec2c | 478 | context->db_tab, |
514aee66 LR |
479 | ucmd.sq_db_index, |
480 | ucmd.sq_db_page); | |
481 | if (err) | |
482 | return err; | |
80c8ec2c | 483 | |
514aee66 | 484 | err = mthca_map_user_db(dev, &context->uar, |
80c8ec2c | 485 | context->db_tab, |
514aee66 LR |
486 | ucmd.rq_db_index, |
487 | ucmd.rq_db_page); | |
80c8ec2c | 488 | if (err) { |
514aee66 | 489 | mthca_unmap_user_db(dev, &context->uar, |
80c8ec2c RD |
490 | context->db_tab, |
491 | ucmd.sq_db_index); | |
514aee66 | 492 | return err; |
80c8ec2c RD |
493 | } |
494 | ||
495 | qp->mr.ibmr.lkey = ucmd.lkey; | |
496 | qp->sq.db_index = ucmd.sq_db_index; | |
497 | qp->rq.db_index = ucmd.rq_db_index; | |
498 | } | |
1da177e4 | 499 | |
514aee66 | 500 | err = mthca_alloc_qp(dev, to_mpd(ibqp->pd), |
1da177e4 LT |
501 | to_mcq(init_attr->send_cq), |
502 | to_mcq(init_attr->recv_cq), | |
503 | init_attr->qp_type, init_attr->sq_sig_type, | |
e00b64f7 | 504 | &init_attr->cap, qp, udata); |
80c8ec2c | 505 | |
e00b64f7 | 506 | if (err && udata) { |
514aee66 | 507 | mthca_unmap_user_db(dev, &context->uar, context->db_tab, |
80c8ec2c | 508 | ucmd.sq_db_index); |
514aee66 | 509 | mthca_unmap_user_db(dev, &context->uar, context->db_tab, |
80c8ec2c RD |
510 | ucmd.rq_db_index); |
511 | } | |
512 | ||
1da177e4 LT |
513 | qp->ibqp.qp_num = qp->qpn; |
514 | break; | |
515 | } | |
516 | case IB_QPT_SMI: | |
517 | case IB_QPT_GSI: | |
518 | { | |
21c2fe94 | 519 | qp->sqp = kzalloc(sizeof(struct mthca_sqp), GFP_KERNEL); |
514aee66 LR |
520 | if (!qp->sqp) |
521 | return -ENOMEM; | |
1da177e4 | 522 | |
1da177e4 LT |
523 | qp->ibqp.qp_num = init_attr->qp_type == IB_QPT_SMI ? 0 : 1; |
524 | ||
514aee66 | 525 | err = mthca_alloc_sqp(dev, to_mpd(ibqp->pd), |
1da177e4 LT |
526 | to_mcq(init_attr->send_cq), |
527 | to_mcq(init_attr->recv_cq), | |
80c8ec2c | 528 | init_attr->sq_sig_type, &init_attr->cap, |
514aee66 LR |
529 | qp->ibqp.qp_num, init_attr->port_num, qp, |
530 | udata); | |
1da177e4 LT |
531 | break; |
532 | } | |
533 | default: | |
534 | /* Don't support raw QPs */ | |
514aee66 | 535 | return -EOPNOTSUPP; |
1da177e4 LT |
536 | } |
537 | ||
538 | if (err) { | |
21c2fe94 | 539 | kfree(qp->sqp); |
514aee66 | 540 | return err; |
1da177e4 LT |
541 | } |
542 | ||
80c8ec2c RD |
543 | init_attr->cap.max_send_wr = qp->sq.max; |
544 | init_attr->cap.max_recv_wr = qp->rq.max; | |
545 | init_attr->cap.max_send_sge = qp->sq.max_gs; | |
546 | init_attr->cap.max_recv_sge = qp->rq.max_gs; | |
77369ed3 | 547 | init_attr->cap.max_inline_data = qp->max_inline_data; |
1da177e4 | 548 | |
514aee66 | 549 | return 0; |
1da177e4 LT |
550 | } |
551 | ||
c4367a26 | 552 | static int mthca_destroy_qp(struct ib_qp *qp, struct ib_udata *udata) |
1da177e4 | 553 | { |
bdeacabd SR |
554 | if (udata) { |
555 | struct mthca_ucontext *context = | |
556 | rdma_udata_to_drv_context( | |
557 | udata, | |
558 | struct mthca_ucontext, | |
559 | ibucontext); | |
560 | ||
80c8ec2c | 561 | mthca_unmap_user_db(to_mdev(qp->device), |
bdeacabd SR |
562 | &context->uar, |
563 | context->db_tab, | |
80c8ec2c RD |
564 | to_mqp(qp)->sq.db_index); |
565 | mthca_unmap_user_db(to_mdev(qp->device), | |
bdeacabd SR |
566 | &context->uar, |
567 | context->db_tab, | |
80c8ec2c RD |
568 | to_mqp(qp)->rq.db_index); |
569 | } | |
1da177e4 | 570 | mthca_free_qp(to_mdev(qp->device), to_mqp(qp)); |
21c2fe94 | 571 | kfree(to_mqp(qp)->sqp); |
1da177e4 LT |
572 | return 0; |
573 | } | |
574 | ||
e39afe3d LR |
575 | static int mthca_create_cq(struct ib_cq *ibcq, |
576 | const struct ib_cq_init_attr *attr, | |
577 | struct ib_udata *udata) | |
1da177e4 | 578 | { |
e39afe3d | 579 | struct ib_device *ibdev = ibcq->device; |
bcf4c1ea | 580 | int entries = attr->cqe; |
74c2174e | 581 | struct mthca_create_cq ucmd; |
1da177e4 LT |
582 | struct mthca_cq *cq; |
583 | int nent; | |
584 | int err; | |
ff23dfa1 SR |
585 | struct mthca_ucontext *context = rdma_udata_to_drv_context( |
586 | udata, struct mthca_ucontext, ibucontext); | |
1da177e4 | 587 | |
bcf4c1ea | 588 | if (attr->flags) |
1c407cb5 | 589 | return -EOPNOTSUPP; |
bcf4c1ea | 590 | |
efaae8f7 | 591 | if (entries < 1 || entries > to_mdev(ibdev)->limits.max_cqes) |
e39afe3d | 592 | return -EINVAL; |
efaae8f7 | 593 | |
ff23dfa1 | 594 | if (udata) { |
e39afe3d LR |
595 | if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) |
596 | return -EFAULT; | |
74c2174e | 597 | |
ff23dfa1 SR |
598 | err = mthca_map_user_db(to_mdev(ibdev), &context->uar, |
599 | context->db_tab, ucmd.set_db_index, | |
600 | ucmd.set_db_page); | |
74c2174e | 601 | if (err) |
e39afe3d | 602 | return err; |
74c2174e | 603 | |
ff23dfa1 SR |
604 | err = mthca_map_user_db(to_mdev(ibdev), &context->uar, |
605 | context->db_tab, ucmd.arm_db_index, | |
606 | ucmd.arm_db_page); | |
74c2174e RD |
607 | if (err) |
608 | goto err_unmap_set; | |
609 | } | |
610 | ||
e39afe3d | 611 | cq = to_mcq(ibcq); |
74c2174e | 612 | |
ff23dfa1 | 613 | if (udata) { |
4885bf64 RD |
614 | cq->buf.mr.ibmr.lkey = ucmd.lkey; |
615 | cq->set_ci_db_index = ucmd.set_db_index; | |
616 | cq->arm_db_index = ucmd.arm_db_index; | |
74c2174e | 617 | } |
1da177e4 LT |
618 | |
619 | for (nent = 1; nent <= entries; nent <<= 1) | |
620 | ; /* nothing */ | |
621 | ||
ff23dfa1 SR |
622 | err = mthca_init_cq(to_mdev(ibdev), nent, context, |
623 | udata ? ucmd.pdn : to_mdev(ibdev)->driver_pd.pd_num, | |
74c2174e RD |
624 | cq); |
625 | if (err) | |
e39afe3d | 626 | goto err_unmap_arm; |
74c2174e | 627 | |
ff23dfa1 | 628 | if (udata && ib_copy_to_udata(udata, &cq->cqn, sizeof(__u32))) { |
74c2174e | 629 | mthca_free_cq(to_mdev(ibdev), cq); |
08e74c4b | 630 | err = -EFAULT; |
e39afe3d | 631 | goto err_unmap_arm; |
1da177e4 LT |
632 | } |
633 | ||
4885bf64 RD |
634 | cq->resize_buf = NULL; |
635 | ||
e39afe3d | 636 | return 0; |
74c2174e RD |
637 | |
638 | err_unmap_arm: | |
ff23dfa1 SR |
639 | if (udata) |
640 | mthca_unmap_user_db(to_mdev(ibdev), &context->uar, | |
641 | context->db_tab, ucmd.arm_db_index); | |
74c2174e RD |
642 | |
643 | err_unmap_set: | |
ff23dfa1 SR |
644 | if (udata) |
645 | mthca_unmap_user_db(to_mdev(ibdev), &context->uar, | |
646 | context->db_tab, ucmd.set_db_index); | |
74c2174e | 647 | |
e39afe3d | 648 | return err; |
1da177e4 LT |
649 | } |
650 | ||
4885bf64 RD |
651 | static int mthca_alloc_resize_buf(struct mthca_dev *dev, struct mthca_cq *cq, |
652 | int entries) | |
653 | { | |
654 | int ret; | |
655 | ||
656 | spin_lock_irq(&cq->lock); | |
657 | if (cq->resize_buf) { | |
658 | ret = -EBUSY; | |
659 | goto unlock; | |
660 | } | |
661 | ||
662 | cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_ATOMIC); | |
663 | if (!cq->resize_buf) { | |
664 | ret = -ENOMEM; | |
665 | goto unlock; | |
666 | } | |
667 | ||
668 | cq->resize_buf->state = CQ_RESIZE_ALLOC; | |
669 | ||
670 | ret = 0; | |
671 | ||
672 | unlock: | |
673 | spin_unlock_irq(&cq->lock); | |
674 | ||
675 | if (ret) | |
676 | return ret; | |
677 | ||
678 | ret = mthca_alloc_cq_buf(dev, &cq->resize_buf->buf, entries); | |
679 | if (ret) { | |
680 | spin_lock_irq(&cq->lock); | |
681 | kfree(cq->resize_buf); | |
682 | cq->resize_buf = NULL; | |
683 | spin_unlock_irq(&cq->lock); | |
684 | return ret; | |
685 | } | |
686 | ||
687 | cq->resize_buf->cqe = entries - 1; | |
688 | ||
689 | spin_lock_irq(&cq->lock); | |
690 | cq->resize_buf->state = CQ_RESIZE_READY; | |
691 | spin_unlock_irq(&cq->lock); | |
692 | ||
693 | return 0; | |
694 | } | |
695 | ||
696 | static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) | |
697 | { | |
698 | struct mthca_dev *dev = to_mdev(ibcq->device); | |
699 | struct mthca_cq *cq = to_mcq(ibcq); | |
700 | struct mthca_resize_cq ucmd; | |
701 | u32 lkey; | |
4885bf64 RD |
702 | int ret; |
703 | ||
704 | if (entries < 1 || entries > dev->limits.max_cqes) | |
705 | return -EINVAL; | |
706 | ||
c93b6fba RD |
707 | mutex_lock(&cq->mutex); |
708 | ||
4885bf64 | 709 | entries = roundup_pow_of_two(entries + 1); |
c93b6fba RD |
710 | if (entries == ibcq->cqe + 1) { |
711 | ret = 0; | |
712 | goto out; | |
713 | } | |
4885bf64 RD |
714 | |
715 | if (cq->is_kernel) { | |
716 | ret = mthca_alloc_resize_buf(dev, cq, entries); | |
717 | if (ret) | |
c93b6fba | 718 | goto out; |
4885bf64 RD |
719 | lkey = cq->resize_buf->buf.mr.ibmr.lkey; |
720 | } else { | |
c93b6fba RD |
721 | if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) { |
722 | ret = -EFAULT; | |
723 | goto out; | |
724 | } | |
4885bf64 RD |
725 | lkey = ucmd.lkey; |
726 | } | |
727 | ||
cdb73db0 | 728 | ret = mthca_RESIZE_CQ(dev, cq->cqn, lkey, ilog2(entries)); |
4885bf64 RD |
729 | |
730 | if (ret) { | |
731 | if (cq->resize_buf) { | |
732 | mthca_free_cq_buf(dev, &cq->resize_buf->buf, | |
733 | cq->resize_buf->cqe); | |
734 | kfree(cq->resize_buf); | |
735 | spin_lock_irq(&cq->lock); | |
736 | cq->resize_buf = NULL; | |
737 | spin_unlock_irq(&cq->lock); | |
738 | } | |
c93b6fba | 739 | goto out; |
4885bf64 RD |
740 | } |
741 | ||
742 | if (cq->is_kernel) { | |
743 | struct mthca_cq_buf tbuf; | |
744 | int tcqe; | |
745 | ||
746 | spin_lock_irq(&cq->lock); | |
747 | if (cq->resize_buf->state == CQ_RESIZE_READY) { | |
748 | mthca_cq_resize_copy_cqes(cq); | |
749 | tbuf = cq->buf; | |
750 | tcqe = cq->ibcq.cqe; | |
751 | cq->buf = cq->resize_buf->buf; | |
752 | cq->ibcq.cqe = cq->resize_buf->cqe; | |
753 | } else { | |
754 | tbuf = cq->resize_buf->buf; | |
755 | tcqe = cq->resize_buf->cqe; | |
756 | } | |
757 | ||
758 | kfree(cq->resize_buf); | |
759 | cq->resize_buf = NULL; | |
760 | spin_unlock_irq(&cq->lock); | |
761 | ||
762 | mthca_free_cq_buf(dev, &tbuf, tcqe); | |
763 | } else | |
764 | ibcq->cqe = entries - 1; | |
765 | ||
c93b6fba RD |
766 | out: |
767 | mutex_unlock(&cq->mutex); | |
768 | ||
769 | return ret; | |
4885bf64 RD |
770 | } |
771 | ||
43d781b9 | 772 | static int mthca_destroy_cq(struct ib_cq *cq, struct ib_udata *udata) |
1da177e4 | 773 | { |
bdeacabd SR |
774 | if (udata) { |
775 | struct mthca_ucontext *context = | |
776 | rdma_udata_to_drv_context( | |
777 | udata, | |
778 | struct mthca_ucontext, | |
779 | ibucontext); | |
780 | ||
74c2174e | 781 | mthca_unmap_user_db(to_mdev(cq->device), |
bdeacabd SR |
782 | &context->uar, |
783 | context->db_tab, | |
74c2174e RD |
784 | to_mcq(cq)->arm_db_index); |
785 | mthca_unmap_user_db(to_mdev(cq->device), | |
bdeacabd SR |
786 | &context->uar, |
787 | context->db_tab, | |
74c2174e RD |
788 | to_mcq(cq)->set_ci_db_index); |
789 | } | |
1da177e4 | 790 | mthca_free_cq(to_mdev(cq->device), to_mcq(cq)); |
43d781b9 | 791 | return 0; |
1da177e4 LT |
792 | } |
793 | ||
794 | static inline u32 convert_access(int acc) | |
795 | { | |
796 | return (acc & IB_ACCESS_REMOTE_ATOMIC ? MTHCA_MPT_FLAG_ATOMIC : 0) | | |
797 | (acc & IB_ACCESS_REMOTE_WRITE ? MTHCA_MPT_FLAG_REMOTE_WRITE : 0) | | |
798 | (acc & IB_ACCESS_REMOTE_READ ? MTHCA_MPT_FLAG_REMOTE_READ : 0) | | |
799 | (acc & IB_ACCESS_LOCAL_WRITE ? MTHCA_MPT_FLAG_LOCAL_WRITE : 0) | | |
800 | MTHCA_MPT_FLAG_LOCAL_READ; | |
801 | } | |
802 | ||
803 | static struct ib_mr *mthca_get_dma_mr(struct ib_pd *pd, int acc) | |
804 | { | |
805 | struct mthca_mr *mr; | |
806 | int err; | |
807 | ||
808 | mr = kmalloc(sizeof *mr, GFP_KERNEL); | |
809 | if (!mr) | |
810 | return ERR_PTR(-ENOMEM); | |
811 | ||
812 | err = mthca_mr_alloc_notrans(to_mdev(pd->device), | |
813 | to_mpd(pd)->pd_num, | |
814 | convert_access(acc), mr); | |
815 | ||
816 | if (err) { | |
817 | kfree(mr); | |
818 | return ERR_PTR(err); | |
819 | } | |
820 | ||
f7c6a7b5 RD |
821 | mr->umem = NULL; |
822 | ||
1da177e4 LT |
823 | return &mr->ibmr; |
824 | } | |
825 | ||
f7c6a7b5 RD |
826 | static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, |
827 | u64 virt, int acc, struct ib_udata *udata) | |
24d4281b RD |
828 | { |
829 | struct mthca_dev *dev = to_mdev(pd->device); | |
89603f7e | 830 | struct ib_block_iter biter; |
89944450 SR |
831 | struct mthca_ucontext *context = rdma_udata_to_drv_context( |
832 | udata, struct mthca_ucontext, ibucontext); | |
24d4281b | 833 | struct mthca_mr *mr; |
cb9fbc5c | 834 | struct mthca_reg_mr ucmd; |
24d4281b | 835 | u64 *pages; |
8d249af3 | 836 | int n, i; |
24d4281b | 837 | int err = 0; |
b2875d4c | 838 | int write_mtt_size; |
24d4281b | 839 | |
e093111d | 840 | if (udata->inlen < sizeof ucmd) { |
89944450 | 841 | if (!context->reg_mr_warned) { |
baaad380 RD |
842 | mthca_warn(dev, "Process '%s' did not pass in MR attrs.\n", |
843 | current->comm); | |
844 | mthca_warn(dev, " Update libmthca to fix this.\n"); | |
845 | } | |
89944450 | 846 | ++context->reg_mr_warned; |
baaad380 RD |
847 | ucmd.mr_attrs = 0; |
848 | } else if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) | |
cb9fbc5c AK |
849 | return ERR_PTR(-EFAULT); |
850 | ||
24d4281b RD |
851 | mr = kmalloc(sizeof *mr, GFP_KERNEL); |
852 | if (!mr) | |
853 | return ERR_PTR(-ENOMEM); | |
854 | ||
c320e527 | 855 | mr->umem = ib_umem_get(pd->device, start, length, acc); |
f7c6a7b5 RD |
856 | if (IS_ERR(mr->umem)) { |
857 | err = PTR_ERR(mr->umem); | |
858 | goto err; | |
859 | } | |
860 | ||
a665aca8 | 861 | n = ib_umem_num_dma_blocks(mr->umem, PAGE_SIZE); |
24d4281b RD |
862 | |
863 | mr->mtt = mthca_alloc_mtt(dev, n); | |
864 | if (IS_ERR(mr->mtt)) { | |
865 | err = PTR_ERR(mr->mtt); | |
f7c6a7b5 | 866 | goto err_umem; |
24d4281b RD |
867 | } |
868 | ||
869 | pages = (u64 *) __get_free_page(GFP_KERNEL); | |
870 | if (!pages) { | |
871 | err = -ENOMEM; | |
872 | goto err_mtt; | |
873 | } | |
874 | ||
875 | i = n = 0; | |
876 | ||
b2875d4c MT |
877 | write_mtt_size = min(mthca_write_mtt_size(dev), (int) (PAGE_SIZE / sizeof *pages)); |
878 | ||
89603f7e JG |
879 | rdma_umem_for_each_dma_block(mr->umem, &biter, PAGE_SIZE) { |
880 | pages[i++] = rdma_block_iter_dma_address(&biter); | |
8d249af3 SS |
881 | |
882 | /* | |
883 | * Be friendly to write_mtt and pass it chunks | |
884 | * of appropriate size. | |
885 | */ | |
886 | if (i == write_mtt_size) { | |
887 | err = mthca_write_mtt(dev, mr->mtt, n, pages, i); | |
888 | if (err) | |
889 | goto mtt_done; | |
890 | n += i; | |
891 | i = 0; | |
24d4281b | 892 | } |
eeb8461e | 893 | } |
24d4281b RD |
894 | |
895 | if (i) | |
896 | err = mthca_write_mtt(dev, mr->mtt, n, pages, i); | |
897 | mtt_done: | |
898 | free_page((unsigned long) pages); | |
899 | if (err) | |
900 | goto err_mtt; | |
901 | ||
8d249af3 | 902 | err = mthca_mr_alloc(dev, to_mpd(pd)->pd_num, PAGE_SHIFT, virt, length, |
f7c6a7b5 | 903 | convert_access(acc), mr); |
24d4281b RD |
904 | |
905 | if (err) | |
906 | goto err_mtt; | |
907 | ||
908 | return &mr->ibmr; | |
909 | ||
910 | err_mtt: | |
911 | mthca_free_mtt(dev, mr->mtt); | |
912 | ||
f7c6a7b5 RD |
913 | err_umem: |
914 | ib_umem_release(mr->umem); | |
915 | ||
24d4281b RD |
916 | err: |
917 | kfree(mr); | |
918 | return ERR_PTR(err); | |
919 | } | |
920 | ||
c4367a26 | 921 | static int mthca_dereg_mr(struct ib_mr *mr, struct ib_udata *udata) |
1da177e4 | 922 | { |
e464b2a6 | 923 | struct mthca_mr *mmr = to_mmr(mr); |
f7c6a7b5 | 924 | |
e464b2a6 | 925 | mthca_free_mr(to_mdev(mr->device), mmr); |
836a0fbb | 926 | ib_umem_release(mmr->umem); |
e464b2a6 | 927 | kfree(mmr); |
f7c6a7b5 | 928 | |
1da177e4 LT |
929 | return 0; |
930 | } | |
931 | ||
508a523f PP |
932 | static ssize_t hw_rev_show(struct device *device, |
933 | struct device_attribute *attr, char *buf) | |
1da177e4 | 934 | { |
f4e91eb4 | 935 | struct mthca_dev *dev = |
54747231 PP |
936 | rdma_device_to_drv_device(device, struct mthca_dev, ib_dev); |
937 | ||
1c7fd726 | 938 | return sysfs_emit(buf, "%x\n", dev->rev_id); |
1da177e4 | 939 | } |
508a523f | 940 | static DEVICE_ATTR_RO(hw_rev); |
1da177e4 | 941 | |
45808361 | 942 | static const char *hca_type_string(int hca_type) |
1da177e4 | 943 | { |
45808361 | 944 | switch (hca_type) { |
68a3c212 | 945 | case PCI_DEVICE_ID_MELLANOX_TAVOR: |
45808361 | 946 | return "MT23108"; |
68a3c212 | 947 | case PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT: |
45808361 | 948 | return "MT25208 (MT23108 compat mode)"; |
68a3c212 | 949 | case PCI_DEVICE_ID_MELLANOX_ARBEL: |
45808361 | 950 | return "MT25208"; |
68a3c212 RD |
951 | case PCI_DEVICE_ID_MELLANOX_SINAI: |
952 | case PCI_DEVICE_ID_MELLANOX_SINAI_OLD: | |
45808361 | 953 | return "MT25204"; |
1da177e4 | 954 | } |
45808361 JP |
955 | |
956 | return "unknown"; | |
957 | } | |
958 | ||
959 | static ssize_t hca_type_show(struct device *device, | |
960 | struct device_attribute *attr, char *buf) | |
961 | { | |
962 | struct mthca_dev *dev = | |
963 | rdma_device_to_drv_device(device, struct mthca_dev, ib_dev); | |
964 | ||
965 | return sysfs_emit(buf, "%s\n", hca_type_string(dev->pdev->device)); | |
1da177e4 | 966 | } |
508a523f | 967 | static DEVICE_ATTR_RO(hca_type); |
1da177e4 | 968 | |
508a523f PP |
969 | static ssize_t board_id_show(struct device *device, |
970 | struct device_attribute *attr, char *buf) | |
2e8b981c | 971 | { |
f4e91eb4 | 972 | struct mthca_dev *dev = |
54747231 PP |
973 | rdma_device_to_drv_device(device, struct mthca_dev, ib_dev); |
974 | ||
1c7fd726 | 975 | return sysfs_emit(buf, "%.*s\n", MTHCA_BOARD_ID_LEN, dev->board_id); |
2e8b981c | 976 | } |
508a523f | 977 | static DEVICE_ATTR_RO(board_id); |
2e8b981c | 978 | |
508a523f PP |
979 | static struct attribute *mthca_dev_attributes[] = { |
980 | &dev_attr_hw_rev.attr, | |
981 | &dev_attr_hca_type.attr, | |
982 | &dev_attr_board_id.attr, | |
983 | NULL | |
984 | }; | |
1da177e4 | 985 | |
508a523f PP |
986 | static const struct attribute_group mthca_attr_group = { |
987 | .attrs = mthca_dev_attributes, | |
1da177e4 LT |
988 | }; |
989 | ||
cf311cd4 SH |
990 | static int mthca_init_node_data(struct mthca_dev *dev) |
991 | { | |
992 | struct ib_smp *in_mad = NULL; | |
993 | struct ib_smp *out_mad = NULL; | |
994 | int err = -ENOMEM; | |
cf311cd4 SH |
995 | |
996 | in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); | |
997 | out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); | |
998 | if (!in_mad || !out_mad) | |
999 | goto out; | |
1000 | ||
d82e2b27 | 1001 | ib_init_query_mad(in_mad); |
6dfc3901 RD |
1002 | in_mad->attr_id = IB_SMP_ATTR_NODE_DESC; |
1003 | ||
1004 | err = mthca_MAD_IFC(dev, 1, 1, | |
cdb73db0 | 1005 | 1, NULL, NULL, in_mad, out_mad); |
6dfc3901 RD |
1006 | if (err) |
1007 | goto out; | |
6dfc3901 | 1008 | |
bd99fdea | 1009 | memcpy(dev->ib_dev.node_desc, out_mad->data, IB_DEVICE_NODE_DESC_MAX); |
6dfc3901 | 1010 | |
cf311cd4 SH |
1011 | in_mad->attr_id = IB_SMP_ATTR_NODE_INFO; |
1012 | ||
1013 | err = mthca_MAD_IFC(dev, 1, 1, | |
cdb73db0 | 1014 | 1, NULL, NULL, in_mad, out_mad); |
cf311cd4 SH |
1015 | if (err) |
1016 | goto out; | |
cf311cd4 | 1017 | |
6ccef1de JM |
1018 | if (mthca_is_memfree(dev)) |
1019 | dev->rev_id = be32_to_cpup((__be32 *) (out_mad->data + 32)); | |
cf311cd4 SH |
1020 | memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8); |
1021 | ||
1022 | out: | |
1023 | kfree(in_mad); | |
1024 | kfree(out_mad); | |
1025 | return err; | |
1026 | } | |
1027 | ||
1fb7f897 | 1028 | static int mthca_port_immutable(struct ib_device *ibdev, u32 port_num, |
7738613e IW |
1029 | struct ib_port_immutable *immutable) |
1030 | { | |
1031 | struct ib_port_attr attr; | |
1032 | int err; | |
1033 | ||
c4550c63 OG |
1034 | immutable->core_cap_flags = RDMA_CORE_PORT_IBA_IB; |
1035 | ||
1036 | err = ib_query_port(ibdev, port_num, &attr); | |
7738613e IW |
1037 | if (err) |
1038 | return err; | |
1039 | ||
1040 | immutable->pkey_tbl_len = attr.pkey_tbl_len; | |
1041 | immutable->gid_tbl_len = attr.gid_tbl_len; | |
337877a4 | 1042 | immutable->max_mad_size = IB_MGMT_MAD_SIZE; |
7738613e IW |
1043 | |
1044 | return 0; | |
1045 | } | |
1046 | ||
9abb0d1b | 1047 | static void get_dev_fw_str(struct ib_device *device, char *str) |
51ed0397 IW |
1048 | { |
1049 | struct mthca_dev *dev = | |
1050 | container_of(device, struct mthca_dev, ib_dev); | |
9abb0d1b | 1051 | snprintf(str, IB_FW_VERSION_NAME_MAX, "%d.%d.%d", |
51ed0397 IW |
1052 | (int) (dev->fw_ver >> 32), |
1053 | (int) (dev->fw_ver >> 16) & 0xffff, | |
1054 | (int) dev->fw_ver & 0xffff); | |
1055 | } | |
1056 | ||
56e2a431 | 1057 | static const struct ib_device_ops mthca_dev_ops = { |
7a154142 | 1058 | .owner = THIS_MODULE, |
b9560a41 | 1059 | .driver_id = RDMA_DRIVER_MTHCA, |
72c6ec18 | 1060 | .uverbs_abi_ver = MTHCA_UVERBS_ABI_VERSION, |
8f71bb00 | 1061 | .uverbs_no_driver_id_binding = 1, |
b9560a41 | 1062 | |
56e2a431 KH |
1063 | .alloc_pd = mthca_alloc_pd, |
1064 | .alloc_ucontext = mthca_alloc_ucontext, | |
1065 | .attach_mcast = mthca_multicast_attach, | |
1066 | .create_ah = mthca_ah_create, | |
1067 | .create_cq = mthca_create_cq, | |
1068 | .create_qp = mthca_create_qp, | |
1069 | .dealloc_pd = mthca_dealloc_pd, | |
1070 | .dealloc_ucontext = mthca_dealloc_ucontext, | |
1071 | .dereg_mr = mthca_dereg_mr, | |
1072 | .destroy_ah = mthca_ah_destroy, | |
1073 | .destroy_cq = mthca_destroy_cq, | |
1074 | .destroy_qp = mthca_destroy_qp, | |
1075 | .detach_mcast = mthca_multicast_detach, | |
915e4af5 | 1076 | .device_group = &mthca_attr_group, |
56e2a431 KH |
1077 | .get_dev_fw_str = get_dev_fw_str, |
1078 | .get_dma_mr = mthca_get_dma_mr, | |
1079 | .get_port_immutable = mthca_port_immutable, | |
1080 | .mmap = mthca_mmap_uar, | |
1081 | .modify_device = mthca_modify_device, | |
1082 | .modify_port = mthca_modify_port, | |
1083 | .modify_qp = mthca_modify_qp, | |
1084 | .poll_cq = mthca_poll_cq, | |
1085 | .process_mad = mthca_process_mad, | |
1086 | .query_ah = mthca_ah_query, | |
1087 | .query_device = mthca_query_device, | |
1088 | .query_gid = mthca_query_gid, | |
1089 | .query_pkey = mthca_query_pkey, | |
1090 | .query_port = mthca_query_port, | |
1091 | .query_qp = mthca_query_qp, | |
1092 | .reg_user_mr = mthca_reg_user_mr, | |
1093 | .resize_cq = mthca_resize_cq, | |
d3456914 LR |
1094 | |
1095 | INIT_RDMA_OBJ_SIZE(ib_ah, mthca_ah, ibah), | |
e39afe3d | 1096 | INIT_RDMA_OBJ_SIZE(ib_cq, mthca_cq, ibcq), |
21a428a0 | 1097 | INIT_RDMA_OBJ_SIZE(ib_pd, mthca_pd, ibpd), |
514aee66 | 1098 | INIT_RDMA_OBJ_SIZE(ib_qp, mthca_qp, ibqp), |
a2a074ef | 1099 | INIT_RDMA_OBJ_SIZE(ib_ucontext, mthca_ucontext, ibucontext), |
56e2a431 KH |
1100 | }; |
1101 | ||
1102 | static const struct ib_device_ops mthca_dev_arbel_srq_ops = { | |
1103 | .create_srq = mthca_create_srq, | |
1104 | .destroy_srq = mthca_destroy_srq, | |
1105 | .modify_srq = mthca_modify_srq, | |
1106 | .post_srq_recv = mthca_arbel_post_srq_recv, | |
1107 | .query_srq = mthca_query_srq, | |
68e326de LR |
1108 | |
1109 | INIT_RDMA_OBJ_SIZE(ib_srq, mthca_srq, ibsrq), | |
56e2a431 KH |
1110 | }; |
1111 | ||
1112 | static const struct ib_device_ops mthca_dev_tavor_srq_ops = { | |
1113 | .create_srq = mthca_create_srq, | |
1114 | .destroy_srq = mthca_destroy_srq, | |
1115 | .modify_srq = mthca_modify_srq, | |
1116 | .post_srq_recv = mthca_tavor_post_srq_recv, | |
1117 | .query_srq = mthca_query_srq, | |
68e326de LR |
1118 | |
1119 | INIT_RDMA_OBJ_SIZE(ib_srq, mthca_srq, ibsrq), | |
56e2a431 KH |
1120 | }; |
1121 | ||
56e2a431 KH |
1122 | static const struct ib_device_ops mthca_dev_arbel_ops = { |
1123 | .post_recv = mthca_arbel_post_receive, | |
1124 | .post_send = mthca_arbel_post_send, | |
1125 | .req_notify_cq = mthca_arbel_arm_cq, | |
1126 | }; | |
1127 | ||
1128 | static const struct ib_device_ops mthca_dev_tavor_ops = { | |
1129 | .post_recv = mthca_tavor_post_receive, | |
1130 | .post_send = mthca_tavor_post_send, | |
1131 | .req_notify_cq = mthca_tavor_arm_cq, | |
1132 | }; | |
1133 | ||
1da177e4 LT |
1134 | int mthca_register_device(struct mthca_dev *dev) |
1135 | { | |
1136 | int ret; | |
1da177e4 | 1137 | |
cf311cd4 SH |
1138 | ret = mthca_init_node_data(dev); |
1139 | if (ret) | |
1140 | return ret; | |
1141 | ||
07ebafba | 1142 | dev->ib_dev.node_type = RDMA_NODE_IB_CA; |
1da177e4 | 1143 | dev->ib_dev.phys_port_cnt = dev->limits.num_ports; |
f4fd0b22 | 1144 | dev->ib_dev.num_comp_vectors = 1; |
26e37270 | 1145 | dev->ib_dev.dev.parent = &dev->pdev->dev; |
ec34a922 RD |
1146 | |
1147 | if (dev->mthca_flags & MTHCA_FLAG_SRQ) { | |
ec34a922 | 1148 | if (mthca_is_memfree(dev)) |
56e2a431 KH |
1149 | ib_set_device_ops(&dev->ib_dev, |
1150 | &mthca_dev_arbel_srq_ops); | |
ec34a922 | 1151 | else |
56e2a431 KH |
1152 | ib_set_device_ops(&dev->ib_dev, |
1153 | &mthca_dev_tavor_srq_ops); | |
ec34a922 RD |
1154 | } |
1155 | ||
56e2a431 | 1156 | ib_set_device_ops(&dev->ib_dev, &mthca_dev_ops); |
1da177e4 | 1157 | |
56e2a431 KH |
1158 | if (mthca_is_memfree(dev)) |
1159 | ib_set_device_ops(&dev->ib_dev, &mthca_dev_arbel_ops); | |
1160 | else | |
1161 | ib_set_device_ops(&dev->ib_dev, &mthca_dev_tavor_ops); | |
1da177e4 | 1162 | |
fd9cfdd1 | 1163 | mutex_init(&dev->cap_mask_mutex); |
1da177e4 | 1164 | |
e0477b34 | 1165 | ret = ib_register_device(&dev->ib_dev, "mthca%d", &dev->pdev->dev); |
1da177e4 LT |
1166 | if (ret) |
1167 | return ret; | |
1168 | ||
3d155f8c RD |
1169 | mthca_start_catas_poll(dev); |
1170 | ||
1da177e4 LT |
1171 | return 0; |
1172 | } | |
1173 | ||
1174 | void mthca_unregister_device(struct mthca_dev *dev) | |
1175 | { | |
3d155f8c | 1176 | mthca_stop_catas_poll(dev); |
1da177e4 LT |
1177 | ib_unregister_device(&dev->ib_dev); |
1178 | } |