xref: /openbmc/linux/drivers/infiniband/hw/mthca/mthca_provider.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
3cd4e8fb4STom Duffy  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
44885bf64SRoland Dreier  * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
52a1d9b7fSRoland Dreier  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
62a1d9b7fSRoland Dreier  * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * This software is available to you under a choice of one of two
91da177e4SLinus Torvalds  * licenses.  You may choose to be licensed under the terms of the GNU
101da177e4SLinus Torvalds  * General Public License (GPL) Version 2, available from the file
111da177e4SLinus Torvalds  * COPYING in the main directory of this source tree, or the
121da177e4SLinus Torvalds  * OpenIB.org BSD license below:
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  *     Redistribution and use in source and binary forms, with or
151da177e4SLinus Torvalds  *     without modification, are permitted provided that the following
161da177e4SLinus Torvalds  *     conditions are met:
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  *      - Redistributions of source code must retain the above
191da177e4SLinus Torvalds  *        copyright notice, this list of conditions and the following
201da177e4SLinus Torvalds  *        disclaimer.
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  *      - Redistributions in binary form must reproduce the above
231da177e4SLinus Torvalds  *        copyright notice, this list of conditions and the following
241da177e4SLinus Torvalds  *        disclaimer in the documentation and/or other materials
251da177e4SLinus Torvalds  *        provided with the distribution.
261da177e4SLinus Torvalds  *
271da177e4SLinus Torvalds  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
281da177e4SLinus Torvalds  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
291da177e4SLinus Torvalds  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
301da177e4SLinus Torvalds  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
311da177e4SLinus Torvalds  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
321da177e4SLinus Torvalds  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
331da177e4SLinus Torvalds  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
341da177e4SLinus Torvalds  * SOFTWARE.
351da177e4SLinus Torvalds  */
361da177e4SLinus Torvalds 
37a4d61e84SRoland Dreier #include <rdma/ib_smi.h>
38f7c6a7b5SRoland Dreier #include <rdma/ib_umem.h>
39883a99c7SRoland Dreier #include <rdma/ib_user_verbs.h>
4089944450SShamir Rabinovitch #include <rdma/uverbs_ioctl.h>
41baaad380SRoland Dreier 
42baaad380SRoland Dreier #include <linux/sched.h>
435a0e3ad6STejun Heo #include <linux/slab.h>
44fc87af74SPaul Gortmaker #include <linux/stat.h>
4553b8b3ffSRoland Dreier #include <linux/mm.h>
46b108d976SPaul Gortmaker #include <linux/export.h>
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds #include "mthca_dev.h"
491da177e4SLinus Torvalds #include "mthca_cmd.h"
50486f6095SLeon Romanovsky #include <rdma/mthca-abi.h>
515e0b537cSRoland Dreier #include "mthca_memfree.h"
521da177e4SLinus Torvalds 
mthca_query_device(struct ib_device * ibdev,struct ib_device_attr * props,struct ib_udata * uhw)532528e33eSMatan Barak static int mthca_query_device(struct ib_device *ibdev, struct ib_device_attr *props,
542528e33eSMatan Barak 			      struct ib_udata *uhw)
551da177e4SLinus Torvalds {
56*50f338cdSRuan Jinjie 	struct ib_smp *in_mad;
57*50f338cdSRuan Jinjie 	struct ib_smp *out_mad;
581da177e4SLinus Torvalds 	int err = -ENOMEM;
591da177e4SLinus Torvalds 	struct mthca_dev *mdev = to_mdev(ibdev);
601da177e4SLinus Torvalds 
612528e33eSMatan Barak 	if (uhw->inlen || uhw->outlen)
622528e33eSMatan Barak 		return -EINVAL;
632528e33eSMatan Barak 
64105e50a5SRoland Dreier 	in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
651da177e4SLinus Torvalds 	out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
661da177e4SLinus Torvalds 	if (!in_mad || !out_mad)
671da177e4SLinus Torvalds 		goto out;
681da177e4SLinus Torvalds 
69a852092eSRoland Dreier 	memset(props, 0, sizeof *props);
708cf2daf3SRoland Dreier 
711da177e4SLinus Torvalds 	props->fw_ver              = mdev->fw_ver;
721da177e4SLinus Torvalds 
73d82e2b27SLeon Romanovsky 	ib_init_query_mad(in_mad);
741da177e4SLinus Torvalds 	in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds 	err = mthca_MAD_IFC(mdev, 1, 1,
77cdb73db0SGoldwyn Rodrigues 			    1, NULL, NULL, in_mad, out_mad);
781da177e4SLinus Torvalds 	if (err)
791da177e4SLinus Torvalds 		goto out;
801da177e4SLinus Torvalds 
811da177e4SLinus Torvalds 	props->device_cap_flags    = mdev->device_cap_flags;
8297f52eb4SSean Hefty 	props->vendor_id           = be32_to_cpup((__be32 *) (out_mad->data + 36)) &
831da177e4SLinus Torvalds 		0xffffff;
8497f52eb4SSean Hefty 	props->vendor_part_id      = be16_to_cpup((__be16 *) (out_mad->data + 30));
85a1c337afSJack Morgenstein 	props->hw_ver              = be32_to_cpup((__be32 *) (out_mad->data + 32));
861da177e4SLinus Torvalds 	memcpy(&props->sys_image_guid, out_mad->data +  4, 8);
871da177e4SLinus Torvalds 
888cf2daf3SRoland Dreier 	props->max_mr_size         = ~0ull;
890f69ce1eSJack Morgenstein 	props->page_size_cap       = mdev->limits.page_size_cap;
908cf2daf3SRoland Dreier 	props->max_qp              = mdev->limits.num_qps - mdev->limits.reserved_qps;
91efaae8f7SJack Morgenstein 	props->max_qp_wr           = mdev->limits.max_wqes;
9233023fb8SSteve Wise 	props->max_send_sge        = mdev->limits.max_sg;
9333023fb8SSteve Wise 	props->max_recv_sge        = mdev->limits.max_sg;
9433023fb8SSteve Wise 	props->max_sge_rd          = mdev->limits.max_sg;
958cf2daf3SRoland Dreier 	props->max_cq              = mdev->limits.num_cqs - mdev->limits.reserved_cqs;
96efaae8f7SJack Morgenstein 	props->max_cqe             = mdev->limits.max_cqes;
978cf2daf3SRoland Dreier 	props->max_mr              = mdev->limits.num_mpts - mdev->limits.reserved_mrws;
988cf2daf3SRoland Dreier 	props->max_pd              = mdev->limits.num_pds - mdev->limits.reserved_pds;
998cf2daf3SRoland Dreier 	props->max_qp_rd_atom      = 1 << mdev->qp_table.rdb_shift;
100efaae8f7SJack Morgenstein 	props->max_qp_init_rd_atom = mdev->limits.max_qp_init_rdma;
101efaae8f7SJack Morgenstein 	props->max_res_rd_atom     = props->max_qp_rd_atom * props->max_qp;
102efaae8f7SJack Morgenstein 	props->max_srq             = mdev->limits.num_srqs - mdev->limits.reserved_srqs;
103efaae8f7SJack Morgenstein 	props->max_srq_wr          = mdev->limits.max_srq_wqes;
10459fef3b1SJack Morgenstein 	props->max_srq_sge         = mdev->limits.max_srq_sge;
1058cf2daf3SRoland Dreier 	props->local_ca_ack_delay  = mdev->limits.local_ca_ack_delay;
10633033b79SJack Morgenstein 	props->atomic_cap          = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ?
10733033b79SJack Morgenstein 					IB_ATOMIC_HCA : IB_ATOMIC_NONE;
108efaae8f7SJack Morgenstein 	props->max_pkeys           = mdev->limits.pkey_table_len;
109efaae8f7SJack Morgenstein 	props->max_mcast_grp       = mdev->limits.num_mgms + mdev->limits.num_amgms;
110efaae8f7SJack Morgenstein 	props->max_mcast_qp_attach = MTHCA_QP_PER_MGM;
111efaae8f7SJack Morgenstein 	props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
112efaae8f7SJack Morgenstein 					   props->max_mcast_grp;
1138cf2daf3SRoland Dreier 
1141da177e4SLinus Torvalds 	err = 0;
1151da177e4SLinus Torvalds  out:
1161da177e4SLinus Torvalds 	kfree(in_mad);
1171da177e4SLinus Torvalds 	kfree(out_mad);
1181da177e4SLinus Torvalds 	return err;
1191da177e4SLinus Torvalds }
1201da177e4SLinus Torvalds 
mthca_query_port(struct ib_device * ibdev,u32 port,struct ib_port_attr * props)1211da177e4SLinus Torvalds static int mthca_query_port(struct ib_device *ibdev,
1221fb7f897SMark Bloch 			    u32 port, struct ib_port_attr *props)
1231da177e4SLinus Torvalds {
124*50f338cdSRuan Jinjie 	struct ib_smp *in_mad;
125*50f338cdSRuan Jinjie 	struct ib_smp *out_mad;
1261da177e4SLinus Torvalds 	int err = -ENOMEM;
1271da177e4SLinus Torvalds 
128105e50a5SRoland Dreier 	in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
1291da177e4SLinus Torvalds 	out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
1301da177e4SLinus Torvalds 	if (!in_mad || !out_mad)
1311da177e4SLinus Torvalds 		goto out;
1321da177e4SLinus Torvalds 
133c4550c63SOr Gerlitz 	/* props being zeroed by the caller, avoid zeroing it here */
134d1887ec2SRoland Dreier 
135d82e2b27SLeon Romanovsky 	ib_init_query_mad(in_mad);
1361da177e4SLinus Torvalds 	in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;
1371da177e4SLinus Torvalds 	in_mad->attr_mod = cpu_to_be32(port);
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds 	err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,
140cdb73db0SGoldwyn Rodrigues 			    port, NULL, NULL, in_mad, out_mad);
1411da177e4SLinus Torvalds 	if (err)
1421da177e4SLinus Torvalds 		goto out;
1431da177e4SLinus Torvalds 
14497f52eb4SSean Hefty 	props->lid               = be16_to_cpup((__be16 *) (out_mad->data + 16));
1451da177e4SLinus Torvalds 	props->lmc               = out_mad->data[34] & 0x7;
14697f52eb4SSean Hefty 	props->sm_lid            = be16_to_cpup((__be16 *) (out_mad->data + 18));
1471da177e4SLinus Torvalds 	props->sm_sl             = out_mad->data[36] & 0xf;
1481da177e4SLinus Torvalds 	props->state             = out_mad->data[32] & 0xf;
1491da177e4SLinus Torvalds 	props->phys_state        = out_mad->data[33] >> 4;
15097f52eb4SSean Hefty 	props->port_cap_flags    = be32_to_cpup((__be32 *) (out_mad->data + 20));
1511da177e4SLinus Torvalds 	props->gid_tbl_len       = to_mdev(ibdev)->limits.gid_table_len;
152d1887ec2SRoland Dreier 	props->max_msg_sz        = 0x80000000;
1531da177e4SLinus Torvalds 	props->pkey_tbl_len      = to_mdev(ibdev)->limits.pkey_table_len;
1549825051eSJack Morgenstein 	props->bad_pkey_cntr     = be16_to_cpup((__be16 *) (out_mad->data + 46));
15597f52eb4SSean Hefty 	props->qkey_viol_cntr    = be16_to_cpup((__be16 *) (out_mad->data + 48));
1561da177e4SLinus Torvalds 	props->active_width      = out_mad->data[31] & 0xf;
1571da177e4SLinus Torvalds 	props->active_speed      = out_mad->data[35] >> 4;
1589825051eSJack Morgenstein 	props->max_mtu           = out_mad->data[41] & 0xf;
1599825051eSJack Morgenstein 	props->active_mtu        = out_mad->data[36] >> 4;
1609825051eSJack Morgenstein 	props->subnet_timeout    = out_mad->data[51] & 0x1f;
161a8bf4e77SJack Morgenstein 	props->max_vl_num        = out_mad->data[37] >> 4;
162a8bf4e77SJack Morgenstein 	props->init_type_reply   = out_mad->data[41] >> 4;
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds  out:
1651da177e4SLinus Torvalds 	kfree(in_mad);
1661da177e4SLinus Torvalds 	kfree(out_mad);
1671da177e4SLinus Torvalds 	return err;
1681da177e4SLinus Torvalds }
1691da177e4SLinus Torvalds 
mthca_modify_device(struct ib_device * ibdev,int mask,struct ib_device_modify * props)1706dfc3901SRoland Dreier static int mthca_modify_device(struct ib_device *ibdev,
1716dfc3901SRoland Dreier 			       int mask,
1726dfc3901SRoland Dreier 			       struct ib_device_modify *props)
1736dfc3901SRoland Dreier {
1746dfc3901SRoland Dreier 	if (mask & ~IB_DEVICE_MODIFY_NODE_DESC)
1756dfc3901SRoland Dreier 		return -EOPNOTSUPP;
1766dfc3901SRoland Dreier 
1776dfc3901SRoland Dreier 	if (mask & IB_DEVICE_MODIFY_NODE_DESC) {
1786dfc3901SRoland Dreier 		if (mutex_lock_interruptible(&to_mdev(ibdev)->cap_mask_mutex))
1796dfc3901SRoland Dreier 			return -ERESTARTSYS;
180bd99fdeaSYuval Shaia 		memcpy(ibdev->node_desc, props->node_desc,
181bd99fdeaSYuval Shaia 		       IB_DEVICE_NODE_DESC_MAX);
1826dfc3901SRoland Dreier 		mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex);
1836dfc3901SRoland Dreier 	}
1846dfc3901SRoland Dreier 
1856dfc3901SRoland Dreier 	return 0;
1866dfc3901SRoland Dreier }
1876dfc3901SRoland Dreier 
mthca_modify_port(struct ib_device * ibdev,u32 port,int port_modify_mask,struct ib_port_modify * props)1881da177e4SLinus Torvalds static int mthca_modify_port(struct ib_device *ibdev,
1891fb7f897SMark Bloch 			     u32 port, int port_modify_mask,
1901da177e4SLinus Torvalds 			     struct ib_port_modify *props)
1911da177e4SLinus Torvalds {
1921da177e4SLinus Torvalds 	struct mthca_set_ib_param set_ib;
1931da177e4SLinus Torvalds 	struct ib_port_attr attr;
1941da177e4SLinus Torvalds 	int err;
1951da177e4SLinus Torvalds 
196fd9cfdd1SRoland Dreier 	if (mutex_lock_interruptible(&to_mdev(ibdev)->cap_mask_mutex))
1971da177e4SLinus Torvalds 		return -ERESTARTSYS;
1981da177e4SLinus Torvalds 
199c4550c63SOr Gerlitz 	err = ib_query_port(ibdev, port, &attr);
2001da177e4SLinus Torvalds 	if (err)
2011da177e4SLinus Torvalds 		goto out;
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds 	set_ib.set_si_guid     = 0;
2041da177e4SLinus Torvalds 	set_ib.reset_qkey_viol = !!(port_modify_mask & IB_PORT_RESET_QKEY_CNTR);
2051da177e4SLinus Torvalds 
2061da177e4SLinus Torvalds 	set_ib.cap_mask = (attr.port_cap_flags | props->set_port_cap_mask) &
2071da177e4SLinus Torvalds 		~props->clr_port_cap_mask;
2081da177e4SLinus Torvalds 
209cdb73db0SGoldwyn Rodrigues 	err = mthca_SET_IB(to_mdev(ibdev), &set_ib, port);
2101da177e4SLinus Torvalds 	if (err)
2111da177e4SLinus Torvalds 		goto out;
2121da177e4SLinus Torvalds out:
213fd9cfdd1SRoland Dreier 	mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex);
2141da177e4SLinus Torvalds 	return err;
2151da177e4SLinus Torvalds }
2161da177e4SLinus Torvalds 
mthca_query_pkey(struct ib_device * ibdev,u32 port,u16 index,u16 * pkey)2171da177e4SLinus Torvalds static int mthca_query_pkey(struct ib_device *ibdev,
2181fb7f897SMark Bloch 			    u32 port, u16 index, u16 *pkey)
2191da177e4SLinus Torvalds {
220*50f338cdSRuan Jinjie 	struct ib_smp *in_mad;
221*50f338cdSRuan Jinjie 	struct ib_smp *out_mad;
2221da177e4SLinus Torvalds 	int err = -ENOMEM;
2231da177e4SLinus Torvalds 
224105e50a5SRoland Dreier 	in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
2251da177e4SLinus Torvalds 	out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
2261da177e4SLinus Torvalds 	if (!in_mad || !out_mad)
2271da177e4SLinus Torvalds 		goto out;
2281da177e4SLinus Torvalds 
229d82e2b27SLeon Romanovsky 	ib_init_query_mad(in_mad);
2301da177e4SLinus Torvalds 	in_mad->attr_id  = IB_SMP_ATTR_PKEY_TABLE;
2311da177e4SLinus Torvalds 	in_mad->attr_mod = cpu_to_be32(index / 32);
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds 	err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,
234cdb73db0SGoldwyn Rodrigues 			    port, NULL, NULL, in_mad, out_mad);
2351da177e4SLinus Torvalds 	if (err)
2361da177e4SLinus Torvalds 		goto out;
2371da177e4SLinus Torvalds 
23897f52eb4SSean Hefty 	*pkey = be16_to_cpu(((__be16 *) out_mad->data)[index % 32]);
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds  out:
2411da177e4SLinus Torvalds 	kfree(in_mad);
2421da177e4SLinus Torvalds 	kfree(out_mad);
2431da177e4SLinus Torvalds 	return err;
2441da177e4SLinus Torvalds }
2451da177e4SLinus Torvalds 
mthca_query_gid(struct ib_device * ibdev,u32 port,int index,union ib_gid * gid)2461fb7f897SMark Bloch static int mthca_query_gid(struct ib_device *ibdev, u32 port,
2471da177e4SLinus Torvalds 			   int index, union ib_gid *gid)
2481da177e4SLinus Torvalds {
249*50f338cdSRuan Jinjie 	struct ib_smp *in_mad;
250*50f338cdSRuan Jinjie 	struct ib_smp *out_mad;
2511da177e4SLinus Torvalds 	int err = -ENOMEM;
2521da177e4SLinus Torvalds 
253105e50a5SRoland Dreier 	in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
2541da177e4SLinus Torvalds 	out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
2551da177e4SLinus Torvalds 	if (!in_mad || !out_mad)
2561da177e4SLinus Torvalds 		goto out;
2571da177e4SLinus Torvalds 
258d82e2b27SLeon Romanovsky 	ib_init_query_mad(in_mad);
2591da177e4SLinus Torvalds 	in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;
2601da177e4SLinus Torvalds 	in_mad->attr_mod = cpu_to_be32(port);
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds 	err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,
263cdb73db0SGoldwyn Rodrigues 			    port, NULL, NULL, in_mad, out_mad);
2641da177e4SLinus Torvalds 	if (err)
2651da177e4SLinus Torvalds 		goto out;
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds 	memcpy(gid->raw, out_mad->data + 8, 8);
2681da177e4SLinus Torvalds 
269d82e2b27SLeon Romanovsky 	ib_init_query_mad(in_mad);
2701da177e4SLinus Torvalds 	in_mad->attr_id  = IB_SMP_ATTR_GUID_INFO;
2711da177e4SLinus Torvalds 	in_mad->attr_mod = cpu_to_be32(index / 8);
2721da177e4SLinus Torvalds 
2731da177e4SLinus Torvalds 	err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,
274cdb73db0SGoldwyn Rodrigues 			    port, NULL, NULL, in_mad, out_mad);
2751da177e4SLinus Torvalds 	if (err)
2761da177e4SLinus Torvalds 		goto out;
2771da177e4SLinus Torvalds 
278254abfd3SRoland Dreier 	memcpy(gid->raw + 8, out_mad->data + (index % 8) * 8, 8);
2791da177e4SLinus Torvalds 
2801da177e4SLinus Torvalds  out:
2811da177e4SLinus Torvalds 	kfree(in_mad);
2821da177e4SLinus Torvalds 	kfree(out_mad);
2831da177e4SLinus Torvalds 	return err;
2841da177e4SLinus Torvalds }
2851da177e4SLinus Torvalds 
mthca_alloc_ucontext(struct ib_ucontext * uctx,struct ib_udata * udata)286a2a074efSLeon Romanovsky static int mthca_alloc_ucontext(struct ib_ucontext *uctx,
2875e0b537cSRoland Dreier 				struct ib_udata *udata)
2885e0b537cSRoland Dreier {
289a2a074efSLeon Romanovsky 	struct ib_device *ibdev = uctx->device;
290a2a074efSLeon Romanovsky 	struct mthca_alloc_ucontext_resp uresp = {};
291a2a074efSLeon Romanovsky 	struct mthca_ucontext *context = to_mucontext(uctx);
2925e0b537cSRoland Dreier 	int                              err;
2935e0b537cSRoland Dreier 
294d8410647SJack Morgenstein 	if (!(to_mdev(ibdev)->active))
295a2a074efSLeon Romanovsky 		return -EAGAIN;
2965e0b537cSRoland Dreier 
2975e0b537cSRoland Dreier 	uresp.qp_tab_size = to_mdev(ibdev)->limits.num_qps;
2985e0b537cSRoland Dreier 	if (mthca_is_memfree(to_mdev(ibdev)))
2995e0b537cSRoland Dreier 		uresp.uarc_size = to_mdev(ibdev)->uar_table.uarc_size;
3005e0b537cSRoland Dreier 	else
3015e0b537cSRoland Dreier 		uresp.uarc_size = 0;
3025e0b537cSRoland Dreier 
3035e0b537cSRoland Dreier 	err = mthca_uar_alloc(to_mdev(ibdev), &context->uar);
304a2a074efSLeon Romanovsky 	if (err)
305a2a074efSLeon Romanovsky 		return err;
3065e0b537cSRoland Dreier 
3075e0b537cSRoland Dreier 	context->db_tab = mthca_init_user_db_tab(to_mdev(ibdev));
3085e0b537cSRoland Dreier 	if (IS_ERR(context->db_tab)) {
3095e0b537cSRoland Dreier 		err = PTR_ERR(context->db_tab);
3105e0b537cSRoland Dreier 		mthca_uar_free(to_mdev(ibdev), &context->uar);
311a2a074efSLeon Romanovsky 		return err;
3125e0b537cSRoland Dreier 	}
3135e0b537cSRoland Dreier 
314a2a074efSLeon Romanovsky 	if (ib_copy_to_udata(udata, &uresp, sizeof(uresp))) {
3155e0b537cSRoland Dreier 		mthca_cleanup_user_db_tab(to_mdev(ibdev), &context->uar, context->db_tab);
3165e0b537cSRoland Dreier 		mthca_uar_free(to_mdev(ibdev), &context->uar);
317a2a074efSLeon Romanovsky 		return -EFAULT;
3185e0b537cSRoland Dreier 	}
3195e0b537cSRoland Dreier 
320baaad380SRoland Dreier 	context->reg_mr_warned = 0;
321baaad380SRoland Dreier 
322a2a074efSLeon Romanovsky 	return 0;
3235e0b537cSRoland Dreier }
3245e0b537cSRoland Dreier 
mthca_dealloc_ucontext(struct ib_ucontext * context)325a2a074efSLeon Romanovsky static void mthca_dealloc_ucontext(struct ib_ucontext *context)
3265e0b537cSRoland Dreier {
3275e0b537cSRoland Dreier 	mthca_cleanup_user_db_tab(to_mdev(context->device), &to_mucontext(context)->uar,
3285e0b537cSRoland Dreier 				  to_mucontext(context)->db_tab);
3295e0b537cSRoland Dreier 	mthca_uar_free(to_mdev(context->device), &to_mucontext(context)->uar);
3305e0b537cSRoland Dreier }
3315e0b537cSRoland Dreier 
mthca_mmap_uar(struct ib_ucontext * context,struct vm_area_struct * vma)33253b8b3ffSRoland Dreier static int mthca_mmap_uar(struct ib_ucontext *context,
33353b8b3ffSRoland Dreier 			  struct vm_area_struct *vma)
33453b8b3ffSRoland Dreier {
33553b8b3ffSRoland Dreier 	if (vma->vm_end - vma->vm_start != PAGE_SIZE)
33653b8b3ffSRoland Dreier 		return -EINVAL;
33753b8b3ffSRoland Dreier 
33853b8b3ffSRoland Dreier 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
33953b8b3ffSRoland Dreier 
3406d376756SMichael S. Tsirkin 	if (io_remap_pfn_range(vma, vma->vm_start,
34153b8b3ffSRoland Dreier 			       to_mucontext(context)->uar.pfn,
34253b8b3ffSRoland Dreier 			       PAGE_SIZE, vma->vm_page_prot))
34353b8b3ffSRoland Dreier 		return -EAGAIN;
34453b8b3ffSRoland Dreier 
34553b8b3ffSRoland Dreier 	return 0;
34653b8b3ffSRoland Dreier }
34753b8b3ffSRoland Dreier 
mthca_alloc_pd(struct ib_pd * ibpd,struct ib_udata * udata)348ff23dfa1SShamir Rabinovitch static int mthca_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
3491da177e4SLinus Torvalds {
35021a428a0SLeon Romanovsky 	struct ib_device *ibdev = ibpd->device;
35121a428a0SLeon Romanovsky 	struct mthca_pd *pd = to_mpd(ibpd);
3521da177e4SLinus Torvalds 	int err;
3531da177e4SLinus Torvalds 
354ff23dfa1SShamir Rabinovitch 	err = mthca_pd_alloc(to_mdev(ibdev), !udata, pd);
35521a428a0SLeon Romanovsky 	if (err)
35621a428a0SLeon Romanovsky 		return err;
3571da177e4SLinus Torvalds 
358ff23dfa1SShamir Rabinovitch 	if (udata) {
35999264c1eSRoland Dreier 		if (ib_copy_to_udata(udata, &pd->pd_num, sizeof (__u32))) {
36099264c1eSRoland Dreier 			mthca_pd_free(to_mdev(ibdev), pd);
36121a428a0SLeon Romanovsky 			return -EFAULT;
36299264c1eSRoland Dreier 		}
36399264c1eSRoland Dreier 	}
36499264c1eSRoland Dreier 
3651da177e4SLinus Torvalds 	return 0;
3661da177e4SLinus Torvalds }
3671da177e4SLinus Torvalds 
mthca_dealloc_pd(struct ib_pd * pd,struct ib_udata * udata)36891a7c58fSLeon Romanovsky static int mthca_dealloc_pd(struct ib_pd *pd, struct ib_udata *udata)
36921a428a0SLeon Romanovsky {
37021a428a0SLeon Romanovsky 	mthca_pd_free(to_mdev(pd->device), to_mpd(pd));
37191a7c58fSLeon Romanovsky 	return 0;
37221a428a0SLeon Romanovsky }
37321a428a0SLeon Romanovsky 
mthca_ah_create(struct ib_ah * ibah,struct rdma_ah_init_attr * init_attr,struct ib_udata * udata)374fa5d010cSMaor Gottlieb static int mthca_ah_create(struct ib_ah *ibah,
375fa5d010cSMaor Gottlieb 			   struct rdma_ah_init_attr *init_attr,
376fa5d010cSMaor Gottlieb 			   struct ib_udata *udata)
377477864c8SMoni Shoua 
3781da177e4SLinus Torvalds {
379d3456914SLeon Romanovsky 	struct mthca_ah *ah = to_mah(ibah);
3801da177e4SLinus Torvalds 
381fa5d010cSMaor Gottlieb 	return mthca_create_ah(to_mdev(ibah->device), to_mpd(ibah->pd),
382fa5d010cSMaor Gottlieb 			       init_attr->ah_attr, ah);
3831da177e4SLinus Torvalds }
3841da177e4SLinus Torvalds 
mthca_ah_destroy(struct ib_ah * ah,u32 flags)3859a9ebf8cSLeon Romanovsky static int mthca_ah_destroy(struct ib_ah *ah, u32 flags)
3861da177e4SLinus Torvalds {
3871da177e4SLinus Torvalds 	mthca_destroy_ah(to_mdev(ah->device), to_mah(ah));
3889a9ebf8cSLeon Romanovsky 	return 0;
3891da177e4SLinus Torvalds }
3901da177e4SLinus Torvalds 
mthca_create_srq(struct ib_srq * ibsrq,struct ib_srq_init_attr * init_attr,struct ib_udata * udata)39168e326deSLeon Romanovsky static int mthca_create_srq(struct ib_srq *ibsrq,
392ec34a922SRoland Dreier 			    struct ib_srq_init_attr *init_attr,
393ec34a922SRoland Dreier 			    struct ib_udata *udata)
394ec34a922SRoland Dreier {
395ec34a922SRoland Dreier 	struct mthca_create_srq ucmd;
39689944450SShamir Rabinovitch 	struct mthca_ucontext *context = rdma_udata_to_drv_context(
39789944450SShamir Rabinovitch 		udata, struct mthca_ucontext, ibucontext);
39868e326deSLeon Romanovsky 	struct mthca_srq *srq = to_msrq(ibsrq);
399ec34a922SRoland Dreier 	int err;
400ec34a922SRoland Dreier 
40196104edaSSean Hefty 	if (init_attr->srq_type != IB_SRQT_BASIC)
40268e326deSLeon Romanovsky 		return -EOPNOTSUPP;
403ec34a922SRoland Dreier 
404e00b64f7SShamir Rabinovitch 	if (udata) {
40568e326deSLeon Romanovsky 		if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)))
40668e326deSLeon Romanovsky 			return -EFAULT;
407ec34a922SRoland Dreier 
40868e326deSLeon Romanovsky 		err = mthca_map_user_db(to_mdev(ibsrq->device), &context->uar,
409ec34a922SRoland Dreier 					context->db_tab, ucmd.db_index,
410ec34a922SRoland Dreier 					ucmd.db_page);
411ec34a922SRoland Dreier 
412ec34a922SRoland Dreier 		if (err)
41368e326deSLeon Romanovsky 			return err;
414ec34a922SRoland Dreier 
415ec34a922SRoland Dreier 		srq->mr.ibmr.lkey = ucmd.lkey;
416ec34a922SRoland Dreier 		srq->db_index     = ucmd.db_index;
417ec34a922SRoland Dreier 	}
418ec34a922SRoland Dreier 
41968e326deSLeon Romanovsky 	err = mthca_alloc_srq(to_mdev(ibsrq->device), to_mpd(ibsrq->pd),
420e00b64f7SShamir Rabinovitch 			      &init_attr->attr, srq, udata);
421ec34a922SRoland Dreier 
422e00b64f7SShamir Rabinovitch 	if (err && udata)
42368e326deSLeon Romanovsky 		mthca_unmap_user_db(to_mdev(ibsrq->device), &context->uar,
424ec34a922SRoland Dreier 				    context->db_tab, ucmd.db_index);
425ec34a922SRoland Dreier 
426ec34a922SRoland Dreier 	if (err)
42768e326deSLeon Romanovsky 		return err;
428ec34a922SRoland Dreier 
429ec34a922SRoland Dreier 	if (context && ib_copy_to_udata(udata, &srq->srqn, sizeof(__u32))) {
43068e326deSLeon Romanovsky 		mthca_free_srq(to_mdev(ibsrq->device), srq);
43168e326deSLeon Romanovsky 		return -EFAULT;
432ec34a922SRoland Dreier 	}
433ec34a922SRoland Dreier 
43468e326deSLeon Romanovsky 	return 0;
435ec34a922SRoland Dreier }
436ec34a922SRoland Dreier 
mthca_destroy_srq(struct ib_srq * srq,struct ib_udata * udata)437119181d1SLeon Romanovsky static int mthca_destroy_srq(struct ib_srq *srq, struct ib_udata *udata)
438ec34a922SRoland Dreier {
439bdeacabdSShamir Rabinovitch 	if (udata) {
440bdeacabdSShamir Rabinovitch 		struct mthca_ucontext *context =
441bdeacabdSShamir Rabinovitch 			rdma_udata_to_drv_context(
442bdeacabdSShamir Rabinovitch 				udata,
443bdeacabdSShamir Rabinovitch 				struct mthca_ucontext,
444bdeacabdSShamir Rabinovitch 				ibucontext);
445ec34a922SRoland Dreier 
446ec34a922SRoland Dreier 		mthca_unmap_user_db(to_mdev(srq->device), &context->uar,
447ec34a922SRoland Dreier 				    context->db_tab, to_msrq(srq)->db_index);
448ec34a922SRoland Dreier 	}
449ec34a922SRoland Dreier 
450ec34a922SRoland Dreier 	mthca_free_srq(to_mdev(srq->device), to_msrq(srq));
451119181d1SLeon Romanovsky 	return 0;
452ec34a922SRoland Dreier }
453ec34a922SRoland Dreier 
mthca_create_qp(struct ib_qp * ibqp,struct ib_qp_init_attr * init_attr,struct ib_udata * udata)454514aee66SLeon Romanovsky static int mthca_create_qp(struct ib_qp *ibqp,
4551cf296b6SRoland Dreier 			   struct ib_qp_init_attr *init_attr,
4561cf296b6SRoland Dreier 			   struct ib_udata *udata)
4571da177e4SLinus Torvalds {
45889944450SShamir Rabinovitch 	struct mthca_ucontext *context = rdma_udata_to_drv_context(
45989944450SShamir Rabinovitch 		udata, struct mthca_ucontext, ibucontext);
46080c8ec2cSRoland Dreier 	struct mthca_create_qp ucmd;
461514aee66SLeon Romanovsky 	struct mthca_qp *qp = to_mqp(ibqp);
462514aee66SLeon Romanovsky 	struct mthca_dev *dev = to_mdev(ibqp->device);
4631da177e4SLinus Torvalds 	int err;
4641da177e4SLinus Torvalds 
465b846f25aSEli Cohen 	if (init_attr->create_flags)
466514aee66SLeon Romanovsky 		return -EOPNOTSUPP;
467b846f25aSEli Cohen 
4681da177e4SLinus Torvalds 	switch (init_attr->qp_type) {
4691da177e4SLinus Torvalds 	case IB_QPT_RC:
4701da177e4SLinus Torvalds 	case IB_QPT_UC:
4711da177e4SLinus Torvalds 	case IB_QPT_UD:
4721da177e4SLinus Torvalds 	{
473e00b64f7SShamir Rabinovitch 		if (udata) {
474514aee66SLeon Romanovsky 			if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)))
475514aee66SLeon Romanovsky 				return -EFAULT;
47680c8ec2cSRoland Dreier 
477514aee66SLeon Romanovsky 			err = mthca_map_user_db(dev, &context->uar,
47880c8ec2cSRoland Dreier 						context->db_tab,
479514aee66SLeon Romanovsky 						ucmd.sq_db_index,
480514aee66SLeon Romanovsky 						ucmd.sq_db_page);
481514aee66SLeon Romanovsky 			if (err)
482514aee66SLeon Romanovsky 				return err;
48380c8ec2cSRoland Dreier 
484514aee66SLeon Romanovsky 			err = mthca_map_user_db(dev, &context->uar,
48580c8ec2cSRoland Dreier 						context->db_tab,
486514aee66SLeon Romanovsky 						ucmd.rq_db_index,
487514aee66SLeon Romanovsky 						ucmd.rq_db_page);
48880c8ec2cSRoland Dreier 			if (err) {
489514aee66SLeon Romanovsky 				mthca_unmap_user_db(dev, &context->uar,
49080c8ec2cSRoland Dreier 						    context->db_tab,
49180c8ec2cSRoland Dreier 						    ucmd.sq_db_index);
492514aee66SLeon Romanovsky 				return err;
49380c8ec2cSRoland Dreier 			}
49480c8ec2cSRoland Dreier 
49580c8ec2cSRoland Dreier 			qp->mr.ibmr.lkey = ucmd.lkey;
49680c8ec2cSRoland Dreier 			qp->sq.db_index  = ucmd.sq_db_index;
49780c8ec2cSRoland Dreier 			qp->rq.db_index  = ucmd.rq_db_index;
49880c8ec2cSRoland Dreier 		}
4991da177e4SLinus Torvalds 
500514aee66SLeon Romanovsky 		err = mthca_alloc_qp(dev, to_mpd(ibqp->pd),
5011da177e4SLinus Torvalds 				     to_mcq(init_attr->send_cq),
5021da177e4SLinus Torvalds 				     to_mcq(init_attr->recv_cq),
5031da177e4SLinus Torvalds 				     init_attr->qp_type, init_attr->sq_sig_type,
504e00b64f7SShamir Rabinovitch 				     &init_attr->cap, qp, udata);
50580c8ec2cSRoland Dreier 
506e00b64f7SShamir Rabinovitch 		if (err && udata) {
507514aee66SLeon Romanovsky 			mthca_unmap_user_db(dev, &context->uar, context->db_tab,
50880c8ec2cSRoland Dreier 					    ucmd.sq_db_index);
509514aee66SLeon Romanovsky 			mthca_unmap_user_db(dev, &context->uar, context->db_tab,
51080c8ec2cSRoland Dreier 					    ucmd.rq_db_index);
51180c8ec2cSRoland Dreier 		}
51280c8ec2cSRoland Dreier 
5131da177e4SLinus Torvalds 		qp->ibqp.qp_num = qp->qpn;
5141da177e4SLinus Torvalds 		break;
5151da177e4SLinus Torvalds 	}
5161da177e4SLinus Torvalds 	case IB_QPT_SMI:
5171da177e4SLinus Torvalds 	case IB_QPT_GSI:
5181da177e4SLinus Torvalds 	{
51921c2fe94SLeon Romanovsky 		qp->sqp = kzalloc(sizeof(struct mthca_sqp), GFP_KERNEL);
520514aee66SLeon Romanovsky 		if (!qp->sqp)
521514aee66SLeon Romanovsky 			return -ENOMEM;
5221da177e4SLinus Torvalds 
5231da177e4SLinus Torvalds 		qp->ibqp.qp_num = init_attr->qp_type == IB_QPT_SMI ? 0 : 1;
5241da177e4SLinus Torvalds 
525514aee66SLeon Romanovsky 		err = mthca_alloc_sqp(dev, to_mpd(ibqp->pd),
5261da177e4SLinus Torvalds 				      to_mcq(init_attr->send_cq),
5271da177e4SLinus Torvalds 				      to_mcq(init_attr->recv_cq),
52880c8ec2cSRoland Dreier 				      init_attr->sq_sig_type, &init_attr->cap,
529514aee66SLeon Romanovsky 				      qp->ibqp.qp_num, init_attr->port_num, qp,
530514aee66SLeon Romanovsky 				      udata);
5311da177e4SLinus Torvalds 		break;
5321da177e4SLinus Torvalds 	}
5331da177e4SLinus Torvalds 	default:
5341da177e4SLinus Torvalds 		/* Don't support raw QPs */
535514aee66SLeon Romanovsky 		return -EOPNOTSUPP;
5361da177e4SLinus Torvalds 	}
5371da177e4SLinus Torvalds 
5381da177e4SLinus Torvalds 	if (err) {
53921c2fe94SLeon Romanovsky 		kfree(qp->sqp);
540514aee66SLeon Romanovsky 		return err;
5411da177e4SLinus Torvalds 	}
5421da177e4SLinus Torvalds 
54380c8ec2cSRoland Dreier 	init_attr->cap.max_send_wr     = qp->sq.max;
54480c8ec2cSRoland Dreier 	init_attr->cap.max_recv_wr     = qp->rq.max;
54580c8ec2cSRoland Dreier 	init_attr->cap.max_send_sge    = qp->sq.max_gs;
54680c8ec2cSRoland Dreier 	init_attr->cap.max_recv_sge    = qp->rq.max_gs;
54777369ed3SJack Morgenstein 	init_attr->cap.max_inline_data = qp->max_inline_data;
5481da177e4SLinus Torvalds 
549514aee66SLeon Romanovsky 	return 0;
5501da177e4SLinus Torvalds }
5511da177e4SLinus Torvalds 
mthca_destroy_qp(struct ib_qp * qp,struct ib_udata * udata)552c4367a26SShamir Rabinovitch static int mthca_destroy_qp(struct ib_qp *qp, struct ib_udata *udata)
5531da177e4SLinus Torvalds {
554bdeacabdSShamir Rabinovitch 	if (udata) {
555bdeacabdSShamir Rabinovitch 		struct mthca_ucontext *context =
556bdeacabdSShamir Rabinovitch 			rdma_udata_to_drv_context(
557bdeacabdSShamir Rabinovitch 				udata,
558bdeacabdSShamir Rabinovitch 				struct mthca_ucontext,
559bdeacabdSShamir Rabinovitch 				ibucontext);
560bdeacabdSShamir Rabinovitch 
56180c8ec2cSRoland Dreier 		mthca_unmap_user_db(to_mdev(qp->device),
562bdeacabdSShamir Rabinovitch 				    &context->uar,
563bdeacabdSShamir Rabinovitch 				    context->db_tab,
56480c8ec2cSRoland Dreier 				    to_mqp(qp)->sq.db_index);
56580c8ec2cSRoland Dreier 		mthca_unmap_user_db(to_mdev(qp->device),
566bdeacabdSShamir Rabinovitch 				    &context->uar,
567bdeacabdSShamir Rabinovitch 				    context->db_tab,
56880c8ec2cSRoland Dreier 				    to_mqp(qp)->rq.db_index);
56980c8ec2cSRoland Dreier 	}
5701da177e4SLinus Torvalds 	mthca_free_qp(to_mdev(qp->device), to_mqp(qp));
57121c2fe94SLeon Romanovsky 	kfree(to_mqp(qp)->sqp);
5721da177e4SLinus Torvalds 	return 0;
5731da177e4SLinus Torvalds }
5741da177e4SLinus Torvalds 
mthca_create_cq(struct ib_cq * ibcq,const struct ib_cq_init_attr * attr,struct ib_udata * udata)575e39afe3dSLeon Romanovsky static int mthca_create_cq(struct ib_cq *ibcq,
576bcf4c1eaSMatan Barak 			   const struct ib_cq_init_attr *attr,
5771cf296b6SRoland Dreier 			   struct ib_udata *udata)
5781da177e4SLinus Torvalds {
579e39afe3dSLeon Romanovsky 	struct ib_device *ibdev = ibcq->device;
580bcf4c1eaSMatan Barak 	int entries = attr->cqe;
58174c2174eSRoland Dreier 	struct mthca_create_cq ucmd;
5821da177e4SLinus Torvalds 	struct mthca_cq *cq;
5831da177e4SLinus Torvalds 	int nent;
5841da177e4SLinus Torvalds 	int err;
585ff23dfa1SShamir Rabinovitch 	struct mthca_ucontext *context = rdma_udata_to_drv_context(
586ff23dfa1SShamir Rabinovitch 		udata, struct mthca_ucontext, ibucontext);
5871da177e4SLinus Torvalds 
588bcf4c1eaSMatan Barak 	if (attr->flags)
5891c407cb5SJason Gunthorpe 		return -EOPNOTSUPP;
590bcf4c1eaSMatan Barak 
591efaae8f7SJack Morgenstein 	if (entries < 1 || entries > to_mdev(ibdev)->limits.max_cqes)
592e39afe3dSLeon Romanovsky 		return -EINVAL;
593efaae8f7SJack Morgenstein 
594ff23dfa1SShamir Rabinovitch 	if (udata) {
595e39afe3dSLeon Romanovsky 		if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)))
596e39afe3dSLeon Romanovsky 			return -EFAULT;
59774c2174eSRoland Dreier 
598ff23dfa1SShamir Rabinovitch 		err = mthca_map_user_db(to_mdev(ibdev), &context->uar,
599ff23dfa1SShamir Rabinovitch 					context->db_tab, ucmd.set_db_index,
600ff23dfa1SShamir Rabinovitch 					ucmd.set_db_page);
60174c2174eSRoland Dreier 		if (err)
602e39afe3dSLeon Romanovsky 			return err;
60374c2174eSRoland Dreier 
604ff23dfa1SShamir Rabinovitch 		err = mthca_map_user_db(to_mdev(ibdev), &context->uar,
605ff23dfa1SShamir Rabinovitch 					context->db_tab, ucmd.arm_db_index,
606ff23dfa1SShamir Rabinovitch 					ucmd.arm_db_page);
60774c2174eSRoland Dreier 		if (err)
60874c2174eSRoland Dreier 			goto err_unmap_set;
60974c2174eSRoland Dreier 	}
61074c2174eSRoland Dreier 
611e39afe3dSLeon Romanovsky 	cq = to_mcq(ibcq);
61274c2174eSRoland Dreier 
613ff23dfa1SShamir Rabinovitch 	if (udata) {
6144885bf64SRoland Dreier 		cq->buf.mr.ibmr.lkey = ucmd.lkey;
61574c2174eSRoland Dreier 		cq->set_ci_db_index  = ucmd.set_db_index;
61674c2174eSRoland Dreier 		cq->arm_db_index     = ucmd.arm_db_index;
61774c2174eSRoland Dreier 	}
6181da177e4SLinus Torvalds 
6191da177e4SLinus Torvalds 	for (nent = 1; nent <= entries; nent <<= 1)
6201da177e4SLinus Torvalds 		; /* nothing */
6211da177e4SLinus Torvalds 
622ff23dfa1SShamir Rabinovitch 	err = mthca_init_cq(to_mdev(ibdev), nent, context,
623ff23dfa1SShamir Rabinovitch 			    udata ? ucmd.pdn : to_mdev(ibdev)->driver_pd.pd_num,
62474c2174eSRoland Dreier 			    cq);
62574c2174eSRoland Dreier 	if (err)
626e39afe3dSLeon Romanovsky 		goto err_unmap_arm;
62774c2174eSRoland Dreier 
628ff23dfa1SShamir Rabinovitch 	if (udata && ib_copy_to_udata(udata, &cq->cqn, sizeof(__u32))) {
62974c2174eSRoland Dreier 		mthca_free_cq(to_mdev(ibdev), cq);
63008e74c4bSYann Droneaud 		err = -EFAULT;
631e39afe3dSLeon Romanovsky 		goto err_unmap_arm;
6321da177e4SLinus Torvalds 	}
6331da177e4SLinus Torvalds 
6344885bf64SRoland Dreier 	cq->resize_buf = NULL;
6354885bf64SRoland Dreier 
636e39afe3dSLeon Romanovsky 	return 0;
63774c2174eSRoland Dreier 
63874c2174eSRoland Dreier err_unmap_arm:
639ff23dfa1SShamir Rabinovitch 	if (udata)
640ff23dfa1SShamir Rabinovitch 		mthca_unmap_user_db(to_mdev(ibdev), &context->uar,
641ff23dfa1SShamir Rabinovitch 				    context->db_tab, ucmd.arm_db_index);
64274c2174eSRoland Dreier 
64374c2174eSRoland Dreier err_unmap_set:
644ff23dfa1SShamir Rabinovitch 	if (udata)
645ff23dfa1SShamir Rabinovitch 		mthca_unmap_user_db(to_mdev(ibdev), &context->uar,
646ff23dfa1SShamir Rabinovitch 				    context->db_tab, ucmd.set_db_index);
64774c2174eSRoland Dreier 
648e39afe3dSLeon Romanovsky 	return err;
6491da177e4SLinus Torvalds }
6501da177e4SLinus Torvalds 
mthca_alloc_resize_buf(struct mthca_dev * dev,struct mthca_cq * cq,int entries)6514885bf64SRoland Dreier static int mthca_alloc_resize_buf(struct mthca_dev *dev, struct mthca_cq *cq,
6524885bf64SRoland Dreier 				  int entries)
6534885bf64SRoland Dreier {
6544885bf64SRoland Dreier 	int ret;
6554885bf64SRoland Dreier 
6564885bf64SRoland Dreier 	spin_lock_irq(&cq->lock);
6574885bf64SRoland Dreier 	if (cq->resize_buf) {
6584885bf64SRoland Dreier 		ret = -EBUSY;
6594885bf64SRoland Dreier 		goto unlock;
6604885bf64SRoland Dreier 	}
6614885bf64SRoland Dreier 
6624885bf64SRoland Dreier 	cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_ATOMIC);
6634885bf64SRoland Dreier 	if (!cq->resize_buf) {
6644885bf64SRoland Dreier 		ret = -ENOMEM;
6654885bf64SRoland Dreier 		goto unlock;
6664885bf64SRoland Dreier 	}
6674885bf64SRoland Dreier 
6684885bf64SRoland Dreier 	cq->resize_buf->state = CQ_RESIZE_ALLOC;
6694885bf64SRoland Dreier 
6704885bf64SRoland Dreier 	ret = 0;
6714885bf64SRoland Dreier 
6724885bf64SRoland Dreier unlock:
6734885bf64SRoland Dreier 	spin_unlock_irq(&cq->lock);
6744885bf64SRoland Dreier 
6754885bf64SRoland Dreier 	if (ret)
6764885bf64SRoland Dreier 		return ret;
6774885bf64SRoland Dreier 
6784885bf64SRoland Dreier 	ret = mthca_alloc_cq_buf(dev, &cq->resize_buf->buf, entries);
6794885bf64SRoland Dreier 	if (ret) {
6804885bf64SRoland Dreier 		spin_lock_irq(&cq->lock);
6814885bf64SRoland Dreier 		kfree(cq->resize_buf);
6824885bf64SRoland Dreier 		cq->resize_buf = NULL;
6834885bf64SRoland Dreier 		spin_unlock_irq(&cq->lock);
6844885bf64SRoland Dreier 		return ret;
6854885bf64SRoland Dreier 	}
6864885bf64SRoland Dreier 
6874885bf64SRoland Dreier 	cq->resize_buf->cqe = entries - 1;
6884885bf64SRoland Dreier 
6894885bf64SRoland Dreier 	spin_lock_irq(&cq->lock);
6904885bf64SRoland Dreier 	cq->resize_buf->state = CQ_RESIZE_READY;
6914885bf64SRoland Dreier 	spin_unlock_irq(&cq->lock);
6924885bf64SRoland Dreier 
6934885bf64SRoland Dreier 	return 0;
6944885bf64SRoland Dreier }
6954885bf64SRoland Dreier 
mthca_resize_cq(struct ib_cq * ibcq,int entries,struct ib_udata * udata)6964885bf64SRoland Dreier static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
6974885bf64SRoland Dreier {
6984885bf64SRoland Dreier 	struct mthca_dev *dev = to_mdev(ibcq->device);
6994885bf64SRoland Dreier 	struct mthca_cq *cq = to_mcq(ibcq);
7004885bf64SRoland Dreier 	struct mthca_resize_cq ucmd;
7014885bf64SRoland Dreier 	u32 lkey;
7024885bf64SRoland Dreier 	int ret;
7034885bf64SRoland Dreier 
7044885bf64SRoland Dreier 	if (entries < 1 || entries > dev->limits.max_cqes)
7054885bf64SRoland Dreier 		return -EINVAL;
7064885bf64SRoland Dreier 
707c93b6fbaSRoland Dreier 	mutex_lock(&cq->mutex);
708c93b6fbaSRoland Dreier 
7094885bf64SRoland Dreier 	entries = roundup_pow_of_two(entries + 1);
710c93b6fbaSRoland Dreier 	if (entries == ibcq->cqe + 1) {
711c93b6fbaSRoland Dreier 		ret = 0;
712c93b6fbaSRoland Dreier 		goto out;
713c93b6fbaSRoland Dreier 	}
7144885bf64SRoland Dreier 
7154885bf64SRoland Dreier 	if (cq->is_kernel) {
7164885bf64SRoland Dreier 		ret = mthca_alloc_resize_buf(dev, cq, entries);
7174885bf64SRoland Dreier 		if (ret)
718c93b6fbaSRoland Dreier 			goto out;
7194885bf64SRoland Dreier 		lkey = cq->resize_buf->buf.mr.ibmr.lkey;
7204885bf64SRoland Dreier 	} else {
721c93b6fbaSRoland Dreier 		if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) {
722c93b6fbaSRoland Dreier 			ret = -EFAULT;
723c93b6fbaSRoland Dreier 			goto out;
724c93b6fbaSRoland Dreier 		}
7254885bf64SRoland Dreier 		lkey = ucmd.lkey;
7264885bf64SRoland Dreier 	}
7274885bf64SRoland Dreier 
728cdb73db0SGoldwyn Rodrigues 	ret = mthca_RESIZE_CQ(dev, cq->cqn, lkey, ilog2(entries));
7294885bf64SRoland Dreier 
7304885bf64SRoland Dreier 	if (ret) {
7314885bf64SRoland Dreier 		if (cq->resize_buf) {
7324885bf64SRoland Dreier 			mthca_free_cq_buf(dev, &cq->resize_buf->buf,
7334885bf64SRoland Dreier 					  cq->resize_buf->cqe);
7344885bf64SRoland Dreier 			kfree(cq->resize_buf);
7354885bf64SRoland Dreier 			spin_lock_irq(&cq->lock);
7364885bf64SRoland Dreier 			cq->resize_buf = NULL;
7374885bf64SRoland Dreier 			spin_unlock_irq(&cq->lock);
7384885bf64SRoland Dreier 		}
739c93b6fbaSRoland Dreier 		goto out;
7404885bf64SRoland Dreier 	}
7414885bf64SRoland Dreier 
7424885bf64SRoland Dreier 	if (cq->is_kernel) {
7434885bf64SRoland Dreier 		struct mthca_cq_buf tbuf;
7444885bf64SRoland Dreier 		int tcqe;
7454885bf64SRoland Dreier 
7464885bf64SRoland Dreier 		spin_lock_irq(&cq->lock);
7474885bf64SRoland Dreier 		if (cq->resize_buf->state == CQ_RESIZE_READY) {
7484885bf64SRoland Dreier 			mthca_cq_resize_copy_cqes(cq);
7494885bf64SRoland Dreier 			tbuf         = cq->buf;
7504885bf64SRoland Dreier 			tcqe         = cq->ibcq.cqe;
7514885bf64SRoland Dreier 			cq->buf      = cq->resize_buf->buf;
7524885bf64SRoland Dreier 			cq->ibcq.cqe = cq->resize_buf->cqe;
7534885bf64SRoland Dreier 		} else {
7544885bf64SRoland Dreier 			tbuf = cq->resize_buf->buf;
7554885bf64SRoland Dreier 			tcqe = cq->resize_buf->cqe;
7564885bf64SRoland Dreier 		}
7574885bf64SRoland Dreier 
7584885bf64SRoland Dreier 		kfree(cq->resize_buf);
7594885bf64SRoland Dreier 		cq->resize_buf = NULL;
7604885bf64SRoland Dreier 		spin_unlock_irq(&cq->lock);
7614885bf64SRoland Dreier 
7624885bf64SRoland Dreier 		mthca_free_cq_buf(dev, &tbuf, tcqe);
7634885bf64SRoland Dreier 	} else
7644885bf64SRoland Dreier 		ibcq->cqe = entries - 1;
7654885bf64SRoland Dreier 
766c93b6fbaSRoland Dreier out:
767c93b6fbaSRoland Dreier 	mutex_unlock(&cq->mutex);
768c93b6fbaSRoland Dreier 
769c93b6fbaSRoland Dreier 	return ret;
7704885bf64SRoland Dreier }
7714885bf64SRoland Dreier 
mthca_destroy_cq(struct ib_cq * cq,struct ib_udata * udata)77243d781b9SLeon Romanovsky static int mthca_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)
7731da177e4SLinus Torvalds {
774bdeacabdSShamir Rabinovitch 	if (udata) {
775bdeacabdSShamir Rabinovitch 		struct mthca_ucontext *context =
776bdeacabdSShamir Rabinovitch 			rdma_udata_to_drv_context(
777bdeacabdSShamir Rabinovitch 				udata,
778bdeacabdSShamir Rabinovitch 				struct mthca_ucontext,
779bdeacabdSShamir Rabinovitch 				ibucontext);
780bdeacabdSShamir Rabinovitch 
78174c2174eSRoland Dreier 		mthca_unmap_user_db(to_mdev(cq->device),
782bdeacabdSShamir Rabinovitch 				    &context->uar,
783bdeacabdSShamir Rabinovitch 				    context->db_tab,
78474c2174eSRoland Dreier 				    to_mcq(cq)->arm_db_index);
78574c2174eSRoland Dreier 		mthca_unmap_user_db(to_mdev(cq->device),
786bdeacabdSShamir Rabinovitch 				    &context->uar,
787bdeacabdSShamir Rabinovitch 				    context->db_tab,
78874c2174eSRoland Dreier 				    to_mcq(cq)->set_ci_db_index);
78974c2174eSRoland Dreier 	}
7901da177e4SLinus Torvalds 	mthca_free_cq(to_mdev(cq->device), to_mcq(cq));
79143d781b9SLeon Romanovsky 	return 0;
7921da177e4SLinus Torvalds }
7931da177e4SLinus Torvalds 
convert_access(int acc)7941da177e4SLinus Torvalds static inline u32 convert_access(int acc)
7951da177e4SLinus Torvalds {
7961da177e4SLinus Torvalds 	return (acc & IB_ACCESS_REMOTE_ATOMIC ? MTHCA_MPT_FLAG_ATOMIC       : 0) |
7971da177e4SLinus Torvalds 	       (acc & IB_ACCESS_REMOTE_WRITE  ? MTHCA_MPT_FLAG_REMOTE_WRITE : 0) |
7981da177e4SLinus Torvalds 	       (acc & IB_ACCESS_REMOTE_READ   ? MTHCA_MPT_FLAG_REMOTE_READ  : 0) |
7991da177e4SLinus Torvalds 	       (acc & IB_ACCESS_LOCAL_WRITE   ? MTHCA_MPT_FLAG_LOCAL_WRITE  : 0) |
8001da177e4SLinus Torvalds 	       MTHCA_MPT_FLAG_LOCAL_READ;
8011da177e4SLinus Torvalds }
8021da177e4SLinus Torvalds 
mthca_get_dma_mr(struct ib_pd * pd,int acc)8031da177e4SLinus Torvalds static struct ib_mr *mthca_get_dma_mr(struct ib_pd *pd, int acc)
8041da177e4SLinus Torvalds {
8051da177e4SLinus Torvalds 	struct mthca_mr *mr;
8061da177e4SLinus Torvalds 	int err;
8071da177e4SLinus Torvalds 
8081da177e4SLinus Torvalds 	mr = kmalloc(sizeof *mr, GFP_KERNEL);
8091da177e4SLinus Torvalds 	if (!mr)
8101da177e4SLinus Torvalds 		return ERR_PTR(-ENOMEM);
8111da177e4SLinus Torvalds 
8121da177e4SLinus Torvalds 	err = mthca_mr_alloc_notrans(to_mdev(pd->device),
8131da177e4SLinus Torvalds 				     to_mpd(pd)->pd_num,
8141da177e4SLinus Torvalds 				     convert_access(acc), mr);
8151da177e4SLinus Torvalds 
8161da177e4SLinus Torvalds 	if (err) {
8171da177e4SLinus Torvalds 		kfree(mr);
8181da177e4SLinus Torvalds 		return ERR_PTR(err);
8191da177e4SLinus Torvalds 	}
8201da177e4SLinus Torvalds 
821f7c6a7b5SRoland Dreier 	mr->umem = NULL;
822f7c6a7b5SRoland Dreier 
8231da177e4SLinus Torvalds 	return &mr->ibmr;
8241da177e4SLinus Torvalds }
8251da177e4SLinus Torvalds 
mthca_reg_user_mr(struct ib_pd * pd,u64 start,u64 length,u64 virt,int acc,struct ib_udata * udata)826f7c6a7b5SRoland Dreier static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
827f7c6a7b5SRoland Dreier 				       u64 virt, int acc, struct ib_udata *udata)
82824d4281bSRoland Dreier {
82924d4281bSRoland Dreier 	struct mthca_dev *dev = to_mdev(pd->device);
83089603f7eSJason Gunthorpe 	struct ib_block_iter biter;
83189944450SShamir Rabinovitch 	struct mthca_ucontext *context = rdma_udata_to_drv_context(
83289944450SShamir Rabinovitch 		udata, struct mthca_ucontext, ibucontext);
83324d4281bSRoland Dreier 	struct mthca_mr *mr;
834cb9fbc5cSArthur Kepner 	struct mthca_reg_mr ucmd;
83524d4281bSRoland Dreier 	u64 *pages;
8368d249af3SShiraz, Saleem 	int n, i;
83724d4281bSRoland Dreier 	int err = 0;
838b2875d4cSMichael S. Tsirkin 	int write_mtt_size;
83924d4281bSRoland Dreier 
840e093111dSAmrani, Ram 	if (udata->inlen < sizeof ucmd) {
84189944450SShamir Rabinovitch 		if (!context->reg_mr_warned) {
842baaad380SRoland Dreier 			mthca_warn(dev, "Process '%s' did not pass in MR attrs.\n",
843baaad380SRoland Dreier 				   current->comm);
844baaad380SRoland Dreier 			mthca_warn(dev, "  Update libmthca to fix this.\n");
845baaad380SRoland Dreier 		}
84689944450SShamir Rabinovitch 		++context->reg_mr_warned;
847baaad380SRoland Dreier 		ucmd.mr_attrs = 0;
848baaad380SRoland Dreier 	} else if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
849cb9fbc5cSArthur Kepner 		return ERR_PTR(-EFAULT);
850cb9fbc5cSArthur Kepner 
85124d4281bSRoland Dreier 	mr = kmalloc(sizeof *mr, GFP_KERNEL);
85224d4281bSRoland Dreier 	if (!mr)
85324d4281bSRoland Dreier 		return ERR_PTR(-ENOMEM);
85424d4281bSRoland Dreier 
855c320e527SMoni Shoua 	mr->umem = ib_umem_get(pd->device, start, length, acc);
856f7c6a7b5SRoland Dreier 	if (IS_ERR(mr->umem)) {
857f7c6a7b5SRoland Dreier 		err = PTR_ERR(mr->umem);
858f7c6a7b5SRoland Dreier 		goto err;
859f7c6a7b5SRoland Dreier 	}
860f7c6a7b5SRoland Dreier 
861a665aca8SJason Gunthorpe 	n = ib_umem_num_dma_blocks(mr->umem, PAGE_SIZE);
86224d4281bSRoland Dreier 
86324d4281bSRoland Dreier 	mr->mtt = mthca_alloc_mtt(dev, n);
86424d4281bSRoland Dreier 	if (IS_ERR(mr->mtt)) {
86524d4281bSRoland Dreier 		err = PTR_ERR(mr->mtt);
866f7c6a7b5SRoland Dreier 		goto err_umem;
86724d4281bSRoland Dreier 	}
86824d4281bSRoland Dreier 
86924d4281bSRoland Dreier 	pages = (u64 *) __get_free_page(GFP_KERNEL);
87024d4281bSRoland Dreier 	if (!pages) {
87124d4281bSRoland Dreier 		err = -ENOMEM;
87224d4281bSRoland Dreier 		goto err_mtt;
87324d4281bSRoland Dreier 	}
87424d4281bSRoland Dreier 
87524d4281bSRoland Dreier 	i = n = 0;
87624d4281bSRoland Dreier 
877b2875d4cSMichael S. Tsirkin 	write_mtt_size = min(mthca_write_mtt_size(dev), (int) (PAGE_SIZE / sizeof *pages));
878b2875d4cSMichael S. Tsirkin 
87989603f7eSJason Gunthorpe 	rdma_umem_for_each_dma_block(mr->umem, &biter, PAGE_SIZE) {
88089603f7eSJason Gunthorpe 		pages[i++] = rdma_block_iter_dma_address(&biter);
8818d249af3SShiraz, Saleem 
88224d4281bSRoland Dreier 		/*
883b2875d4cSMichael S. Tsirkin 		 * Be friendly to write_mtt and pass it chunks
884b2875d4cSMichael S. Tsirkin 		 * of appropriate size.
88524d4281bSRoland Dreier 		 */
886b2875d4cSMichael S. Tsirkin 		if (i == write_mtt_size) {
887b2875d4cSMichael S. Tsirkin 			err = mthca_write_mtt(dev, mr->mtt, n, pages, i);
88824d4281bSRoland Dreier 			if (err)
88924d4281bSRoland Dreier 				goto mtt_done;
89024d4281bSRoland Dreier 			n += i;
89124d4281bSRoland Dreier 			i = 0;
89224d4281bSRoland Dreier 		}
89324d4281bSRoland Dreier 	}
89424d4281bSRoland Dreier 
89524d4281bSRoland Dreier 	if (i)
89624d4281bSRoland Dreier 		err = mthca_write_mtt(dev, mr->mtt, n, pages, i);
89724d4281bSRoland Dreier mtt_done:
89824d4281bSRoland Dreier 	free_page((unsigned long) pages);
89924d4281bSRoland Dreier 	if (err)
90024d4281bSRoland Dreier 		goto err_mtt;
90124d4281bSRoland Dreier 
9028d249af3SShiraz, Saleem 	err = mthca_mr_alloc(dev, to_mpd(pd)->pd_num, PAGE_SHIFT, virt, length,
903f7c6a7b5SRoland Dreier 			     convert_access(acc), mr);
90424d4281bSRoland Dreier 
90524d4281bSRoland Dreier 	if (err)
90624d4281bSRoland Dreier 		goto err_mtt;
90724d4281bSRoland Dreier 
90824d4281bSRoland Dreier 	return &mr->ibmr;
90924d4281bSRoland Dreier 
91024d4281bSRoland Dreier err_mtt:
91124d4281bSRoland Dreier 	mthca_free_mtt(dev, mr->mtt);
91224d4281bSRoland Dreier 
913f7c6a7b5SRoland Dreier err_umem:
914f7c6a7b5SRoland Dreier 	ib_umem_release(mr->umem);
915f7c6a7b5SRoland Dreier 
91624d4281bSRoland Dreier err:
91724d4281bSRoland Dreier 	kfree(mr);
91824d4281bSRoland Dreier 	return ERR_PTR(err);
91924d4281bSRoland Dreier }
92024d4281bSRoland Dreier 
mthca_dereg_mr(struct ib_mr * mr,struct ib_udata * udata)921c4367a26SShamir Rabinovitch static int mthca_dereg_mr(struct ib_mr *mr, struct ib_udata *udata)
9221da177e4SLinus Torvalds {
923e464b2a6SRoland Dreier 	struct mthca_mr *mmr = to_mmr(mr);
924f7c6a7b5SRoland Dreier 
925e464b2a6SRoland Dreier 	mthca_free_mr(to_mdev(mr->device), mmr);
926f7c6a7b5SRoland Dreier 	ib_umem_release(mmr->umem);
927e464b2a6SRoland Dreier 	kfree(mmr);
928f7c6a7b5SRoland Dreier 
9291da177e4SLinus Torvalds 	return 0;
9301da177e4SLinus Torvalds }
9311da177e4SLinus Torvalds 
hw_rev_show(struct device * device,struct device_attribute * attr,char * buf)932508a523fSParav Pandit static ssize_t hw_rev_show(struct device *device,
933508a523fSParav Pandit 			   struct device_attribute *attr, char *buf)
9341da177e4SLinus Torvalds {
935f4e91eb4STony Jones 	struct mthca_dev *dev =
93654747231SParav Pandit 		rdma_device_to_drv_device(device, struct mthca_dev, ib_dev);
93754747231SParav Pandit 
9381c7fd726SJoe Perches 	return sysfs_emit(buf, "%x\n", dev->rev_id);
9391da177e4SLinus Torvalds }
940508a523fSParav Pandit static DEVICE_ATTR_RO(hw_rev);
9411da177e4SLinus Torvalds 
hca_type_string(int hca_type)94245808361SJoe Perches static const char *hca_type_string(int hca_type)
94345808361SJoe Perches {
94445808361SJoe Perches 	switch (hca_type) {
94545808361SJoe Perches 	case PCI_DEVICE_ID_MELLANOX_TAVOR:
94645808361SJoe Perches 		return "MT23108";
94745808361SJoe Perches 	case PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT:
94845808361SJoe Perches 		return "MT25208 (MT23108 compat mode)";
94945808361SJoe Perches 	case PCI_DEVICE_ID_MELLANOX_ARBEL:
95045808361SJoe Perches 		return "MT25208";
95145808361SJoe Perches 	case PCI_DEVICE_ID_MELLANOX_SINAI:
95245808361SJoe Perches 	case PCI_DEVICE_ID_MELLANOX_SINAI_OLD:
95345808361SJoe Perches 		return "MT25204";
95445808361SJoe Perches 	}
95545808361SJoe Perches 
95645808361SJoe Perches 	return "unknown";
95745808361SJoe Perches }
95845808361SJoe Perches 
hca_type_show(struct device * device,struct device_attribute * attr,char * buf)959508a523fSParav Pandit static ssize_t hca_type_show(struct device *device,
960508a523fSParav Pandit 			     struct device_attribute *attr, char *buf)
9611da177e4SLinus Torvalds {
962f4e91eb4STony Jones 	struct mthca_dev *dev =
96354747231SParav Pandit 		rdma_device_to_drv_device(device, struct mthca_dev, ib_dev);
96454747231SParav Pandit 
96545808361SJoe Perches 	return sysfs_emit(buf, "%s\n", hca_type_string(dev->pdev->device));
9661da177e4SLinus Torvalds }
967508a523fSParav Pandit static DEVICE_ATTR_RO(hca_type);
9681da177e4SLinus Torvalds 
board_id_show(struct device * device,struct device_attribute * attr,char * buf)969508a523fSParav Pandit static ssize_t board_id_show(struct device *device,
970508a523fSParav Pandit 			     struct device_attribute *attr, char *buf)
9712e8b981cSMichael S. Tsirkin {
972f4e91eb4STony Jones 	struct mthca_dev *dev =
97354747231SParav Pandit 		rdma_device_to_drv_device(device, struct mthca_dev, ib_dev);
97454747231SParav Pandit 
9751c7fd726SJoe Perches 	return sysfs_emit(buf, "%.*s\n", MTHCA_BOARD_ID_LEN, dev->board_id);
9762e8b981cSMichael S. Tsirkin }
977508a523fSParav Pandit static DEVICE_ATTR_RO(board_id);
9782e8b981cSMichael S. Tsirkin 
979508a523fSParav Pandit static struct attribute *mthca_dev_attributes[] = {
980508a523fSParav Pandit 	&dev_attr_hw_rev.attr,
981508a523fSParav Pandit 	&dev_attr_hca_type.attr,
982508a523fSParav Pandit 	&dev_attr_board_id.attr,
983508a523fSParav Pandit 	NULL
984508a523fSParav Pandit };
9851da177e4SLinus Torvalds 
986508a523fSParav Pandit static const struct attribute_group mthca_attr_group = {
987508a523fSParav Pandit 	.attrs = mthca_dev_attributes,
9881da177e4SLinus Torvalds };
9891da177e4SLinus Torvalds 
mthca_init_node_data(struct mthca_dev * dev)990cf311cd4SSean Hefty static int mthca_init_node_data(struct mthca_dev *dev)
991cf311cd4SSean Hefty {
992*50f338cdSRuan Jinjie 	struct ib_smp *in_mad;
993*50f338cdSRuan Jinjie 	struct ib_smp *out_mad;
994cf311cd4SSean Hefty 	int err = -ENOMEM;
995cf311cd4SSean Hefty 
996cf311cd4SSean Hefty 	in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
997cf311cd4SSean Hefty 	out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
998cf311cd4SSean Hefty 	if (!in_mad || !out_mad)
999cf311cd4SSean Hefty 		goto out;
1000cf311cd4SSean Hefty 
1001d82e2b27SLeon Romanovsky 	ib_init_query_mad(in_mad);
10026dfc3901SRoland Dreier 	in_mad->attr_id = IB_SMP_ATTR_NODE_DESC;
10036dfc3901SRoland Dreier 
10046dfc3901SRoland Dreier 	err = mthca_MAD_IFC(dev, 1, 1,
1005cdb73db0SGoldwyn Rodrigues 			    1, NULL, NULL, in_mad, out_mad);
10066dfc3901SRoland Dreier 	if (err)
10076dfc3901SRoland Dreier 		goto out;
10086dfc3901SRoland Dreier 
1009bd99fdeaSYuval Shaia 	memcpy(dev->ib_dev.node_desc, out_mad->data, IB_DEVICE_NODE_DESC_MAX);
10106dfc3901SRoland Dreier 
1011cf311cd4SSean Hefty 	in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
1012cf311cd4SSean Hefty 
1013cf311cd4SSean Hefty 	err = mthca_MAD_IFC(dev, 1, 1,
1014cdb73db0SGoldwyn Rodrigues 			    1, NULL, NULL, in_mad, out_mad);
1015cf311cd4SSean Hefty 	if (err)
1016cf311cd4SSean Hefty 		goto out;
1017cf311cd4SSean Hefty 
10186ccef1deSJack Morgenstein 	if (mthca_is_memfree(dev))
10196ccef1deSJack Morgenstein 		dev->rev_id = be32_to_cpup((__be32 *) (out_mad->data + 32));
1020cf311cd4SSean Hefty 	memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8);
1021cf311cd4SSean Hefty 
1022cf311cd4SSean Hefty out:
1023cf311cd4SSean Hefty 	kfree(in_mad);
1024cf311cd4SSean Hefty 	kfree(out_mad);
1025cf311cd4SSean Hefty 	return err;
1026cf311cd4SSean Hefty }
1027cf311cd4SSean Hefty 
mthca_port_immutable(struct ib_device * ibdev,u32 port_num,struct ib_port_immutable * immutable)10281fb7f897SMark Bloch static int mthca_port_immutable(struct ib_device *ibdev, u32 port_num,
10297738613eSIra Weiny 			        struct ib_port_immutable *immutable)
10307738613eSIra Weiny {
10317738613eSIra Weiny 	struct ib_port_attr attr;
10327738613eSIra Weiny 	int err;
10337738613eSIra Weiny 
1034c4550c63SOr Gerlitz 	immutable->core_cap_flags = RDMA_CORE_PORT_IBA_IB;
1035c4550c63SOr Gerlitz 
1036c4550c63SOr Gerlitz 	err = ib_query_port(ibdev, port_num, &attr);
10377738613eSIra Weiny 	if (err)
10387738613eSIra Weiny 		return err;
10397738613eSIra Weiny 
10407738613eSIra Weiny 	immutable->pkey_tbl_len = attr.pkey_tbl_len;
10417738613eSIra Weiny 	immutable->gid_tbl_len = attr.gid_tbl_len;
1042337877a4SIra Weiny 	immutable->max_mad_size = IB_MGMT_MAD_SIZE;
10437738613eSIra Weiny 
10447738613eSIra Weiny 	return 0;
10457738613eSIra Weiny }
10467738613eSIra Weiny 
get_dev_fw_str(struct ib_device * device,char * str)10479abb0d1bSLeon Romanovsky static void get_dev_fw_str(struct ib_device *device, char *str)
104851ed0397SIra Weiny {
104951ed0397SIra Weiny 	struct mthca_dev *dev =
105051ed0397SIra Weiny 		container_of(device, struct mthca_dev, ib_dev);
10519abb0d1bSLeon Romanovsky 	snprintf(str, IB_FW_VERSION_NAME_MAX, "%d.%d.%d",
105251ed0397SIra Weiny 		 (int) (dev->fw_ver >> 32),
105351ed0397SIra Weiny 		 (int) (dev->fw_ver >> 16) & 0xffff,
105451ed0397SIra Weiny 		 (int) dev->fw_ver & 0xffff);
105551ed0397SIra Weiny }
105651ed0397SIra Weiny 
105756e2a431SKamal Heib static const struct ib_device_ops mthca_dev_ops = {
10587a154142SJason Gunthorpe 	.owner = THIS_MODULE,
1059b9560a41SJason Gunthorpe 	.driver_id = RDMA_DRIVER_MTHCA,
106072c6ec18SJason Gunthorpe 	.uverbs_abi_ver = MTHCA_UVERBS_ABI_VERSION,
10618f71bb00SJason Gunthorpe 	.uverbs_no_driver_id_binding = 1,
1062b9560a41SJason Gunthorpe 
106356e2a431SKamal Heib 	.alloc_pd = mthca_alloc_pd,
106456e2a431SKamal Heib 	.alloc_ucontext = mthca_alloc_ucontext,
106556e2a431SKamal Heib 	.attach_mcast = mthca_multicast_attach,
106656e2a431SKamal Heib 	.create_ah = mthca_ah_create,
106756e2a431SKamal Heib 	.create_cq = mthca_create_cq,
106856e2a431SKamal Heib 	.create_qp = mthca_create_qp,
106956e2a431SKamal Heib 	.dealloc_pd = mthca_dealloc_pd,
107056e2a431SKamal Heib 	.dealloc_ucontext = mthca_dealloc_ucontext,
107156e2a431SKamal Heib 	.dereg_mr = mthca_dereg_mr,
107256e2a431SKamal Heib 	.destroy_ah = mthca_ah_destroy,
107356e2a431SKamal Heib 	.destroy_cq = mthca_destroy_cq,
107456e2a431SKamal Heib 	.destroy_qp = mthca_destroy_qp,
107556e2a431SKamal Heib 	.detach_mcast = mthca_multicast_detach,
1076915e4af5SJason Gunthorpe 	.device_group = &mthca_attr_group,
107756e2a431SKamal Heib 	.get_dev_fw_str = get_dev_fw_str,
107856e2a431SKamal Heib 	.get_dma_mr = mthca_get_dma_mr,
107956e2a431SKamal Heib 	.get_port_immutable = mthca_port_immutable,
108056e2a431SKamal Heib 	.mmap = mthca_mmap_uar,
108156e2a431SKamal Heib 	.modify_device = mthca_modify_device,
108256e2a431SKamal Heib 	.modify_port = mthca_modify_port,
108356e2a431SKamal Heib 	.modify_qp = mthca_modify_qp,
108456e2a431SKamal Heib 	.poll_cq = mthca_poll_cq,
108556e2a431SKamal Heib 	.process_mad = mthca_process_mad,
108656e2a431SKamal Heib 	.query_ah = mthca_ah_query,
108756e2a431SKamal Heib 	.query_device = mthca_query_device,
108856e2a431SKamal Heib 	.query_gid = mthca_query_gid,
108956e2a431SKamal Heib 	.query_pkey = mthca_query_pkey,
109056e2a431SKamal Heib 	.query_port = mthca_query_port,
109156e2a431SKamal Heib 	.query_qp = mthca_query_qp,
109256e2a431SKamal Heib 	.reg_user_mr = mthca_reg_user_mr,
109356e2a431SKamal Heib 	.resize_cq = mthca_resize_cq,
1094d3456914SLeon Romanovsky 
1095d3456914SLeon Romanovsky 	INIT_RDMA_OBJ_SIZE(ib_ah, mthca_ah, ibah),
1096e39afe3dSLeon Romanovsky 	INIT_RDMA_OBJ_SIZE(ib_cq, mthca_cq, ibcq),
109721a428a0SLeon Romanovsky 	INIT_RDMA_OBJ_SIZE(ib_pd, mthca_pd, ibpd),
1098514aee66SLeon Romanovsky 	INIT_RDMA_OBJ_SIZE(ib_qp, mthca_qp, ibqp),
1099a2a074efSLeon Romanovsky 	INIT_RDMA_OBJ_SIZE(ib_ucontext, mthca_ucontext, ibucontext),
110056e2a431SKamal Heib };
110156e2a431SKamal Heib 
110256e2a431SKamal Heib static const struct ib_device_ops mthca_dev_arbel_srq_ops = {
110356e2a431SKamal Heib 	.create_srq = mthca_create_srq,
110456e2a431SKamal Heib 	.destroy_srq = mthca_destroy_srq,
110556e2a431SKamal Heib 	.modify_srq = mthca_modify_srq,
110656e2a431SKamal Heib 	.post_srq_recv = mthca_arbel_post_srq_recv,
110756e2a431SKamal Heib 	.query_srq = mthca_query_srq,
110868e326deSLeon Romanovsky 
110968e326deSLeon Romanovsky 	INIT_RDMA_OBJ_SIZE(ib_srq, mthca_srq, ibsrq),
111056e2a431SKamal Heib };
111156e2a431SKamal Heib 
111256e2a431SKamal Heib static const struct ib_device_ops mthca_dev_tavor_srq_ops = {
111356e2a431SKamal Heib 	.create_srq = mthca_create_srq,
111456e2a431SKamal Heib 	.destroy_srq = mthca_destroy_srq,
111556e2a431SKamal Heib 	.modify_srq = mthca_modify_srq,
111656e2a431SKamal Heib 	.post_srq_recv = mthca_tavor_post_srq_recv,
111756e2a431SKamal Heib 	.query_srq = mthca_query_srq,
111868e326deSLeon Romanovsky 
111968e326deSLeon Romanovsky 	INIT_RDMA_OBJ_SIZE(ib_srq, mthca_srq, ibsrq),
112056e2a431SKamal Heib };
112156e2a431SKamal Heib 
112256e2a431SKamal Heib static const struct ib_device_ops mthca_dev_arbel_ops = {
112356e2a431SKamal Heib 	.post_recv = mthca_arbel_post_receive,
112456e2a431SKamal Heib 	.post_send = mthca_arbel_post_send,
112556e2a431SKamal Heib 	.req_notify_cq = mthca_arbel_arm_cq,
112656e2a431SKamal Heib };
112756e2a431SKamal Heib 
112856e2a431SKamal Heib static const struct ib_device_ops mthca_dev_tavor_ops = {
112956e2a431SKamal Heib 	.post_recv = mthca_tavor_post_receive,
113056e2a431SKamal Heib 	.post_send = mthca_tavor_post_send,
113156e2a431SKamal Heib 	.req_notify_cq = mthca_tavor_arm_cq,
113256e2a431SKamal Heib };
113356e2a431SKamal Heib 
mthca_register_device(struct mthca_dev * dev)11341da177e4SLinus Torvalds int mthca_register_device(struct mthca_dev *dev)
11351da177e4SLinus Torvalds {
11361da177e4SLinus Torvalds 	int ret;
11371da177e4SLinus Torvalds 
1138cf311cd4SSean Hefty 	ret = mthca_init_node_data(dev);
1139cf311cd4SSean Hefty 	if (ret)
1140cf311cd4SSean Hefty 		return ret;
1141cf311cd4SSean Hefty 
114207ebafbaSTom Tucker 	dev->ib_dev.node_type            = RDMA_NODE_IB_CA;
11431da177e4SLinus Torvalds 	dev->ib_dev.phys_port_cnt        = dev->limits.num_ports;
1144f4fd0b22SMichael S. Tsirkin 	dev->ib_dev.num_comp_vectors     = 1;
114526e37270SBart Van Assche 	dev->ib_dev.dev.parent           = &dev->pdev->dev;
1146ec34a922SRoland Dreier 
1147ec34a922SRoland Dreier 	if (dev->mthca_flags & MTHCA_FLAG_SRQ) {
1148ec34a922SRoland Dreier 		if (mthca_is_memfree(dev))
114956e2a431SKamal Heib 			ib_set_device_ops(&dev->ib_dev,
115056e2a431SKamal Heib 					  &mthca_dev_arbel_srq_ops);
1151ec34a922SRoland Dreier 		else
115256e2a431SKamal Heib 			ib_set_device_ops(&dev->ib_dev,
115356e2a431SKamal Heib 					  &mthca_dev_tavor_srq_ops);
1154ec34a922SRoland Dreier 	}
1155ec34a922SRoland Dreier 
115656e2a431SKamal Heib 	ib_set_device_ops(&dev->ib_dev, &mthca_dev_ops);
11571da177e4SLinus Torvalds 
115856e2a431SKamal Heib 	if (mthca_is_memfree(dev))
115956e2a431SKamal Heib 		ib_set_device_ops(&dev->ib_dev, &mthca_dev_arbel_ops);
116056e2a431SKamal Heib 	else
116156e2a431SKamal Heib 		ib_set_device_ops(&dev->ib_dev, &mthca_dev_tavor_ops);
11621da177e4SLinus Torvalds 
1163fd9cfdd1SRoland Dreier 	mutex_init(&dev->cap_mask_mutex);
11641da177e4SLinus Torvalds 
1165e0477b34SJason Gunthorpe 	ret = ib_register_device(&dev->ib_dev, "mthca%d", &dev->pdev->dev);
11661da177e4SLinus Torvalds 	if (ret)
11671da177e4SLinus Torvalds 		return ret;
11681da177e4SLinus Torvalds 
11693d155f8cSRoland Dreier 	mthca_start_catas_poll(dev);
11703d155f8cSRoland Dreier 
11711da177e4SLinus Torvalds 	return 0;
11721da177e4SLinus Torvalds }
11731da177e4SLinus Torvalds 
mthca_unregister_device(struct mthca_dev * dev)11741da177e4SLinus Torvalds void mthca_unregister_device(struct mthca_dev *dev)
11751da177e4SLinus Torvalds {
11763d155f8cSRoland Dreier 	mthca_stop_catas_poll(dev);
11771da177e4SLinus Torvalds 	ib_unregister_device(&dev->ib_dev);
11781da177e4SLinus Torvalds }
1179