133ec1ccbSHans Petter Selasky /*
233ec1ccbSHans Petter Selasky * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
333ec1ccbSHans Petter Selasky * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
433ec1ccbSHans Petter Selasky * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved.
533ec1ccbSHans Petter Selasky * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
633ec1ccbSHans Petter Selasky * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
733ec1ccbSHans Petter Selasky *
833ec1ccbSHans Petter Selasky * This software is available to you under a choice of one of two
933ec1ccbSHans Petter Selasky * licenses. You may choose to be licensed under the terms of the GNU
1033ec1ccbSHans Petter Selasky * General Public License (GPL) Version 2, available from the file
1133ec1ccbSHans Petter Selasky * COPYING in the main directory of this source tree, or the
1233ec1ccbSHans Petter Selasky * OpenIB.org BSD license below:
1333ec1ccbSHans Petter Selasky *
1433ec1ccbSHans Petter Selasky * Redistribution and use in source and binary forms, with or
1533ec1ccbSHans Petter Selasky * without modification, are permitted provided that the following
1633ec1ccbSHans Petter Selasky * conditions are met:
1733ec1ccbSHans Petter Selasky *
1833ec1ccbSHans Petter Selasky * - Redistributions of source code must retain the above
1933ec1ccbSHans Petter Selasky * copyright notice, this list of conditions and the following
2033ec1ccbSHans Petter Selasky * disclaimer.
2133ec1ccbSHans Petter Selasky *
2233ec1ccbSHans Petter Selasky * - Redistributions in binary form must reproduce the above
2333ec1ccbSHans Petter Selasky * copyright notice, this list of conditions and the following
2433ec1ccbSHans Petter Selasky * disclaimer in the documentation and/or other materials
2533ec1ccbSHans Petter Selasky * provided with the distribution.
2633ec1ccbSHans Petter Selasky *
2733ec1ccbSHans Petter Selasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2833ec1ccbSHans Petter Selasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2933ec1ccbSHans Petter Selasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
3033ec1ccbSHans Petter Selasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
3133ec1ccbSHans Petter Selasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
3233ec1ccbSHans Petter Selasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3333ec1ccbSHans Petter Selasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3433ec1ccbSHans Petter Selasky * SOFTWARE.
3533ec1ccbSHans Petter Selasky */
3633ec1ccbSHans Petter Selasky
3733ec1ccbSHans Petter Selasky #include <rdma/ib_smi.h>
3833ec1ccbSHans Petter Selasky #include <rdma/ib_umem.h>
3933ec1ccbSHans Petter Selasky #include <rdma/ib_user_verbs.h>
40*b633e08cSHans Petter Selasky #include <rdma/uverbs_ioctl.h>
4133ec1ccbSHans Petter Selasky
4233ec1ccbSHans Petter Selasky #include <linux/sched.h>
4333ec1ccbSHans Petter Selasky #include <linux/slab.h>
4433ec1ccbSHans Petter Selasky #include <linux/mm.h>
4533ec1ccbSHans Petter Selasky #include <linux/fs.h>
4633ec1ccbSHans Petter Selasky
4733ec1ccbSHans Petter Selasky #include "mthca_dev.h"
4833ec1ccbSHans Petter Selasky #include "mthca_cmd.h"
4933ec1ccbSHans Petter Selasky #include <rdma/mthca-abi.h>
5033ec1ccbSHans Petter Selasky #include "mthca_memfree.h"
5133ec1ccbSHans Petter Selasky
init_query_mad(struct ib_smp * mad)5233ec1ccbSHans Petter Selasky static void init_query_mad(struct ib_smp *mad)
5333ec1ccbSHans Petter Selasky {
5433ec1ccbSHans Petter Selasky mad->base_version = 1;
5533ec1ccbSHans Petter Selasky mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
5633ec1ccbSHans Petter Selasky mad->class_version = 1;
5733ec1ccbSHans Petter Selasky mad->method = IB_MGMT_METHOD_GET;
5833ec1ccbSHans Petter Selasky }
5933ec1ccbSHans Petter Selasky
mthca_query_device(struct ib_device * ibdev,struct ib_device_attr * props,struct ib_udata * uhw)6033ec1ccbSHans Petter Selasky static int mthca_query_device(struct ib_device *ibdev, struct ib_device_attr *props,
6133ec1ccbSHans Petter Selasky struct ib_udata *uhw)
6233ec1ccbSHans Petter Selasky {
6333ec1ccbSHans Petter Selasky struct ib_smp *in_mad = NULL;
6433ec1ccbSHans Petter Selasky struct ib_smp *out_mad = NULL;
6533ec1ccbSHans Petter Selasky int err = -ENOMEM;
6633ec1ccbSHans Petter Selasky struct mthca_dev *mdev = to_mdev(ibdev);
6733ec1ccbSHans Petter Selasky
6833ec1ccbSHans Petter Selasky if (uhw->inlen || uhw->outlen)
6933ec1ccbSHans Petter Selasky return -EINVAL;
7033ec1ccbSHans Petter Selasky
7133ec1ccbSHans Petter Selasky in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL);
7233ec1ccbSHans Petter Selasky out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
7333ec1ccbSHans Petter Selasky if (!in_mad || !out_mad)
7433ec1ccbSHans Petter Selasky goto out;
7533ec1ccbSHans Petter Selasky
7633ec1ccbSHans Petter Selasky memset(props, 0, sizeof *props);
7733ec1ccbSHans Petter Selasky
7833ec1ccbSHans Petter Selasky props->fw_ver = mdev->fw_ver;
7933ec1ccbSHans Petter Selasky
8033ec1ccbSHans Petter Selasky init_query_mad(in_mad);
8133ec1ccbSHans Petter Selasky in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
8233ec1ccbSHans Petter Selasky
8333ec1ccbSHans Petter Selasky err = mthca_MAD_IFC(mdev, 1, 1,
8433ec1ccbSHans Petter Selasky 1, NULL, NULL, in_mad, out_mad);
8533ec1ccbSHans Petter Selasky if (err)
8633ec1ccbSHans Petter Selasky goto out;
8733ec1ccbSHans Petter Selasky
8833ec1ccbSHans Petter Selasky props->device_cap_flags = mdev->device_cap_flags;
8933ec1ccbSHans Petter Selasky props->vendor_id = be32_to_cpup((__be32 *) (out_mad->data + 36)) &
9033ec1ccbSHans Petter Selasky 0xffffff;
9133ec1ccbSHans Petter Selasky props->vendor_part_id = be16_to_cpup((__be16 *) (out_mad->data + 30));
9233ec1ccbSHans Petter Selasky props->hw_ver = be32_to_cpup((__be32 *) (out_mad->data + 32));
9333ec1ccbSHans Petter Selasky memcpy(&props->sys_image_guid, out_mad->data + 4, 8);
9433ec1ccbSHans Petter Selasky
9533ec1ccbSHans Petter Selasky props->max_mr_size = ~0ull;
9633ec1ccbSHans Petter Selasky props->page_size_cap = mdev->limits.page_size_cap;
9733ec1ccbSHans Petter Selasky props->max_qp = mdev->limits.num_qps - mdev->limits.reserved_qps;
9833ec1ccbSHans Petter Selasky props->max_qp_wr = mdev->limits.max_wqes;
9933ec1ccbSHans Petter Selasky props->max_sge = mdev->limits.max_sg;
10033ec1ccbSHans Petter Selasky props->max_sge_rd = props->max_sge;
10133ec1ccbSHans Petter Selasky props->max_cq = mdev->limits.num_cqs - mdev->limits.reserved_cqs;
10233ec1ccbSHans Petter Selasky props->max_cqe = mdev->limits.max_cqes;
10333ec1ccbSHans Petter Selasky props->max_mr = mdev->limits.num_mpts - mdev->limits.reserved_mrws;
10433ec1ccbSHans Petter Selasky props->max_pd = mdev->limits.num_pds - mdev->limits.reserved_pds;
10533ec1ccbSHans Petter Selasky props->max_qp_rd_atom = 1 << mdev->qp_table.rdb_shift;
10633ec1ccbSHans Petter Selasky props->max_qp_init_rd_atom = mdev->limits.max_qp_init_rdma;
10733ec1ccbSHans Petter Selasky props->max_res_rd_atom = props->max_qp_rd_atom * props->max_qp;
10833ec1ccbSHans Petter Selasky props->max_srq = mdev->limits.num_srqs - mdev->limits.reserved_srqs;
10933ec1ccbSHans Petter Selasky props->max_srq_wr = mdev->limits.max_srq_wqes;
11033ec1ccbSHans Petter Selasky props->max_srq_sge = mdev->limits.max_srq_sge;
11133ec1ccbSHans Petter Selasky props->local_ca_ack_delay = mdev->limits.local_ca_ack_delay;
11233ec1ccbSHans Petter Selasky props->atomic_cap = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ?
11333ec1ccbSHans Petter Selasky IB_ATOMIC_HCA : IB_ATOMIC_NONE;
11433ec1ccbSHans Petter Selasky props->max_pkeys = mdev->limits.pkey_table_len;
11533ec1ccbSHans Petter Selasky props->max_mcast_grp = mdev->limits.num_mgms + mdev->limits.num_amgms;
11633ec1ccbSHans Petter Selasky props->max_mcast_qp_attach = MTHCA_QP_PER_MGM;
11733ec1ccbSHans Petter Selasky props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
11833ec1ccbSHans Petter Selasky props->max_mcast_grp;
11933ec1ccbSHans Petter Selasky /*
12033ec1ccbSHans Petter Selasky * If Sinai memory key optimization is being used, then only
12133ec1ccbSHans Petter Selasky * the 8-bit key portion will change. For other HCAs, the
12233ec1ccbSHans Petter Selasky * unused index bits will also be used for FMR remapping.
12333ec1ccbSHans Petter Selasky */
12433ec1ccbSHans Petter Selasky if (mdev->mthca_flags & MTHCA_FLAG_SINAI_OPT)
12533ec1ccbSHans Petter Selasky props->max_map_per_fmr = 255;
12633ec1ccbSHans Petter Selasky else
12733ec1ccbSHans Petter Selasky props->max_map_per_fmr =
12833ec1ccbSHans Petter Selasky (1 << (32 - ilog2(mdev->limits.num_mpts))) - 1;
12933ec1ccbSHans Petter Selasky
13033ec1ccbSHans Petter Selasky err = 0;
13133ec1ccbSHans Petter Selasky out:
13233ec1ccbSHans Petter Selasky kfree(in_mad);
13333ec1ccbSHans Petter Selasky kfree(out_mad);
13433ec1ccbSHans Petter Selasky return err;
13533ec1ccbSHans Petter Selasky }
13633ec1ccbSHans Petter Selasky
mthca_query_port(struct ib_device * ibdev,u8 port,struct ib_port_attr * props)13733ec1ccbSHans Petter Selasky static int mthca_query_port(struct ib_device *ibdev,
13833ec1ccbSHans Petter Selasky u8 port, struct ib_port_attr *props)
13933ec1ccbSHans Petter Selasky {
14033ec1ccbSHans Petter Selasky struct ib_smp *in_mad = NULL;
14133ec1ccbSHans Petter Selasky struct ib_smp *out_mad = NULL;
14233ec1ccbSHans Petter Selasky int err = -ENOMEM;
14333ec1ccbSHans Petter Selasky
14433ec1ccbSHans Petter Selasky in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL);
14533ec1ccbSHans Petter Selasky out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
14633ec1ccbSHans Petter Selasky if (!in_mad || !out_mad)
14733ec1ccbSHans Petter Selasky goto out;
14833ec1ccbSHans Petter Selasky
14933ec1ccbSHans Petter Selasky memset(props, 0, sizeof *props);
15033ec1ccbSHans Petter Selasky
15133ec1ccbSHans Petter Selasky init_query_mad(in_mad);
15233ec1ccbSHans Petter Selasky in_mad->attr_id = IB_SMP_ATTR_PORT_INFO;
15333ec1ccbSHans Petter Selasky in_mad->attr_mod = cpu_to_be32(port);
15433ec1ccbSHans Petter Selasky
15533ec1ccbSHans Petter Selasky err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,
15633ec1ccbSHans Petter Selasky port, NULL, NULL, in_mad, out_mad);
15733ec1ccbSHans Petter Selasky if (err)
15833ec1ccbSHans Petter Selasky goto out;
15933ec1ccbSHans Petter Selasky
16033ec1ccbSHans Petter Selasky props->lid = be16_to_cpup((__be16 *) (out_mad->data + 16));
16133ec1ccbSHans Petter Selasky props->lmc = out_mad->data[34] & 0x7;
16233ec1ccbSHans Petter Selasky props->sm_lid = be16_to_cpup((__be16 *) (out_mad->data + 18));
16333ec1ccbSHans Petter Selasky props->sm_sl = out_mad->data[36] & 0xf;
16433ec1ccbSHans Petter Selasky props->state = out_mad->data[32] & 0xf;
16533ec1ccbSHans Petter Selasky props->phys_state = out_mad->data[33] >> 4;
16633ec1ccbSHans Petter Selasky props->port_cap_flags = be32_to_cpup((__be32 *) (out_mad->data + 20));
16733ec1ccbSHans Petter Selasky props->gid_tbl_len = to_mdev(ibdev)->limits.gid_table_len;
16833ec1ccbSHans Petter Selasky props->max_msg_sz = 0x80000000;
16933ec1ccbSHans Petter Selasky props->pkey_tbl_len = to_mdev(ibdev)->limits.pkey_table_len;
17033ec1ccbSHans Petter Selasky props->bad_pkey_cntr = be16_to_cpup((__be16 *) (out_mad->data + 46));
17133ec1ccbSHans Petter Selasky props->qkey_viol_cntr = be16_to_cpup((__be16 *) (out_mad->data + 48));
17233ec1ccbSHans Petter Selasky props->active_width = out_mad->data[31] & 0xf;
17333ec1ccbSHans Petter Selasky props->active_speed = out_mad->data[35] >> 4;
17433ec1ccbSHans Petter Selasky props->max_mtu = out_mad->data[41] & 0xf;
17533ec1ccbSHans Petter Selasky props->active_mtu = out_mad->data[36] >> 4;
17633ec1ccbSHans Petter Selasky props->subnet_timeout = out_mad->data[51] & 0x1f;
17733ec1ccbSHans Petter Selasky props->max_vl_num = out_mad->data[37] >> 4;
17833ec1ccbSHans Petter Selasky props->init_type_reply = out_mad->data[41] >> 4;
17933ec1ccbSHans Petter Selasky
18033ec1ccbSHans Petter Selasky out:
18133ec1ccbSHans Petter Selasky kfree(in_mad);
18233ec1ccbSHans Petter Selasky kfree(out_mad);
18333ec1ccbSHans Petter Selasky return err;
18433ec1ccbSHans Petter Selasky }
18533ec1ccbSHans Petter Selasky
mthca_modify_device(struct ib_device * ibdev,int mask,struct ib_device_modify * props)18633ec1ccbSHans Petter Selasky static int mthca_modify_device(struct ib_device *ibdev,
18733ec1ccbSHans Petter Selasky int mask,
18833ec1ccbSHans Petter Selasky struct ib_device_modify *props)
18933ec1ccbSHans Petter Selasky {
19033ec1ccbSHans Petter Selasky if (mask & ~IB_DEVICE_MODIFY_NODE_DESC)
19133ec1ccbSHans Petter Selasky return -EOPNOTSUPP;
19233ec1ccbSHans Petter Selasky
19333ec1ccbSHans Petter Selasky if (mask & IB_DEVICE_MODIFY_NODE_DESC) {
19433ec1ccbSHans Petter Selasky if (mutex_lock_interruptible(&to_mdev(ibdev)->cap_mask_mutex))
19533ec1ccbSHans Petter Selasky return -ERESTARTSYS;
19633ec1ccbSHans Petter Selasky memcpy(ibdev->node_desc, props->node_desc,
19733ec1ccbSHans Petter Selasky IB_DEVICE_NODE_DESC_MAX);
19833ec1ccbSHans Petter Selasky mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex);
19933ec1ccbSHans Petter Selasky }
20033ec1ccbSHans Petter Selasky
20133ec1ccbSHans Petter Selasky return 0;
20233ec1ccbSHans Petter Selasky }
20333ec1ccbSHans Petter Selasky
mthca_modify_port(struct ib_device * ibdev,u8 port,int port_modify_mask,struct ib_port_modify * props)20433ec1ccbSHans Petter Selasky static int mthca_modify_port(struct ib_device *ibdev,
20533ec1ccbSHans Petter Selasky u8 port, int port_modify_mask,
20633ec1ccbSHans Petter Selasky struct ib_port_modify *props)
20733ec1ccbSHans Petter Selasky {
20833ec1ccbSHans Petter Selasky struct mthca_set_ib_param set_ib;
20933ec1ccbSHans Petter Selasky struct ib_port_attr attr;
21033ec1ccbSHans Petter Selasky int err;
21133ec1ccbSHans Petter Selasky
21233ec1ccbSHans Petter Selasky if (mutex_lock_interruptible(&to_mdev(ibdev)->cap_mask_mutex))
21333ec1ccbSHans Petter Selasky return -ERESTARTSYS;
21433ec1ccbSHans Petter Selasky
21533ec1ccbSHans Petter Selasky err = mthca_query_port(ibdev, port, &attr);
21633ec1ccbSHans Petter Selasky if (err)
21733ec1ccbSHans Petter Selasky goto out;
21833ec1ccbSHans Petter Selasky
21933ec1ccbSHans Petter Selasky set_ib.set_si_guid = 0;
22033ec1ccbSHans Petter Selasky set_ib.reset_qkey_viol = !!(port_modify_mask & IB_PORT_RESET_QKEY_CNTR);
22133ec1ccbSHans Petter Selasky
22233ec1ccbSHans Petter Selasky set_ib.cap_mask = (attr.port_cap_flags | props->set_port_cap_mask) &
22333ec1ccbSHans Petter Selasky ~props->clr_port_cap_mask;
22433ec1ccbSHans Petter Selasky
22533ec1ccbSHans Petter Selasky err = mthca_SET_IB(to_mdev(ibdev), &set_ib, port);
22633ec1ccbSHans Petter Selasky if (err)
22733ec1ccbSHans Petter Selasky goto out;
22833ec1ccbSHans Petter Selasky out:
22933ec1ccbSHans Petter Selasky mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex);
23033ec1ccbSHans Petter Selasky return err;
23133ec1ccbSHans Petter Selasky }
23233ec1ccbSHans Petter Selasky
mthca_query_pkey(struct ib_device * ibdev,u8 port,u16 index,u16 * pkey)23333ec1ccbSHans Petter Selasky static int mthca_query_pkey(struct ib_device *ibdev,
23433ec1ccbSHans Petter Selasky u8 port, u16 index, u16 *pkey)
23533ec1ccbSHans Petter Selasky {
23633ec1ccbSHans Petter Selasky struct ib_smp *in_mad = NULL;
23733ec1ccbSHans Petter Selasky struct ib_smp *out_mad = NULL;
23833ec1ccbSHans Petter Selasky int err = -ENOMEM;
23933ec1ccbSHans Petter Selasky
24033ec1ccbSHans Petter Selasky in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL);
24133ec1ccbSHans Petter Selasky out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
24233ec1ccbSHans Petter Selasky if (!in_mad || !out_mad)
24333ec1ccbSHans Petter Selasky goto out;
24433ec1ccbSHans Petter Selasky
24533ec1ccbSHans Petter Selasky init_query_mad(in_mad);
24633ec1ccbSHans Petter Selasky in_mad->attr_id = IB_SMP_ATTR_PKEY_TABLE;
24733ec1ccbSHans Petter Selasky in_mad->attr_mod = cpu_to_be32(index / 32);
24833ec1ccbSHans Petter Selasky
24933ec1ccbSHans Petter Selasky err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,
25033ec1ccbSHans Petter Selasky port, NULL, NULL, in_mad, out_mad);
25133ec1ccbSHans Petter Selasky if (err)
25233ec1ccbSHans Petter Selasky goto out;
25333ec1ccbSHans Petter Selasky
25433ec1ccbSHans Petter Selasky *pkey = be16_to_cpu(((__be16 *) out_mad->data)[index % 32]);
25533ec1ccbSHans Petter Selasky
25633ec1ccbSHans Petter Selasky out:
25733ec1ccbSHans Petter Selasky kfree(in_mad);
25833ec1ccbSHans Petter Selasky kfree(out_mad);
25933ec1ccbSHans Petter Selasky return err;
26033ec1ccbSHans Petter Selasky }
26133ec1ccbSHans Petter Selasky
mthca_query_gid(struct ib_device * ibdev,u8 port,int index,union ib_gid * gid)26233ec1ccbSHans Petter Selasky static int mthca_query_gid(struct ib_device *ibdev, u8 port,
26333ec1ccbSHans Petter Selasky int index, union ib_gid *gid)
26433ec1ccbSHans Petter Selasky {
26533ec1ccbSHans Petter Selasky struct ib_smp *in_mad = NULL;
26633ec1ccbSHans Petter Selasky struct ib_smp *out_mad = NULL;
26733ec1ccbSHans Petter Selasky int err = -ENOMEM;
26833ec1ccbSHans Petter Selasky
26933ec1ccbSHans Petter Selasky in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL);
27033ec1ccbSHans Petter Selasky out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
27133ec1ccbSHans Petter Selasky if (!in_mad || !out_mad)
27233ec1ccbSHans Petter Selasky goto out;
27333ec1ccbSHans Petter Selasky
27433ec1ccbSHans Petter Selasky init_query_mad(in_mad);
27533ec1ccbSHans Petter Selasky in_mad->attr_id = IB_SMP_ATTR_PORT_INFO;
27633ec1ccbSHans Petter Selasky in_mad->attr_mod = cpu_to_be32(port);
27733ec1ccbSHans Petter Selasky
27833ec1ccbSHans Petter Selasky err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,
27933ec1ccbSHans Petter Selasky port, NULL, NULL, in_mad, out_mad);
28033ec1ccbSHans Petter Selasky if (err)
28133ec1ccbSHans Petter Selasky goto out;
28233ec1ccbSHans Petter Selasky
28333ec1ccbSHans Petter Selasky memcpy(gid->raw, out_mad->data + 8, 8);
28433ec1ccbSHans Petter Selasky
28533ec1ccbSHans Petter Selasky init_query_mad(in_mad);
28633ec1ccbSHans Petter Selasky in_mad->attr_id = IB_SMP_ATTR_GUID_INFO;
28733ec1ccbSHans Petter Selasky in_mad->attr_mod = cpu_to_be32(index / 8);
28833ec1ccbSHans Petter Selasky
28933ec1ccbSHans Petter Selasky err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,
29033ec1ccbSHans Petter Selasky port, NULL, NULL, in_mad, out_mad);
29133ec1ccbSHans Petter Selasky if (err)
29233ec1ccbSHans Petter Selasky goto out;
29333ec1ccbSHans Petter Selasky
29433ec1ccbSHans Petter Selasky memcpy(gid->raw + 8, out_mad->data + (index % 8) * 8, 8);
29533ec1ccbSHans Petter Selasky
29633ec1ccbSHans Petter Selasky out:
29733ec1ccbSHans Petter Selasky kfree(in_mad);
29833ec1ccbSHans Petter Selasky kfree(out_mad);
29933ec1ccbSHans Petter Selasky return err;
30033ec1ccbSHans Petter Selasky }
30133ec1ccbSHans Petter Selasky
mthca_alloc_ucontext(struct ib_ucontext * uctx,struct ib_udata * udata)302*b633e08cSHans Petter Selasky static int mthca_alloc_ucontext(struct ib_ucontext *uctx,
30333ec1ccbSHans Petter Selasky struct ib_udata *udata)
30433ec1ccbSHans Petter Selasky {
305*b633e08cSHans Petter Selasky struct ib_device *ibdev = uctx->device;
306*b633e08cSHans Petter Selasky struct mthca_alloc_ucontext_resp uresp = {};
307*b633e08cSHans Petter Selasky struct mthca_ucontext *context = to_mucontext(uctx);
30833ec1ccbSHans Petter Selasky int err;
30933ec1ccbSHans Petter Selasky
31033ec1ccbSHans Petter Selasky if (!(to_mdev(ibdev)->active))
311*b633e08cSHans Petter Selasky return -EAGAIN;
31233ec1ccbSHans Petter Selasky
31333ec1ccbSHans Petter Selasky uresp.qp_tab_size = to_mdev(ibdev)->limits.num_qps;
31433ec1ccbSHans Petter Selasky if (mthca_is_memfree(to_mdev(ibdev)))
31533ec1ccbSHans Petter Selasky uresp.uarc_size = to_mdev(ibdev)->uar_table.uarc_size;
31633ec1ccbSHans Petter Selasky else
31733ec1ccbSHans Petter Selasky uresp.uarc_size = 0;
31833ec1ccbSHans Petter Selasky
31933ec1ccbSHans Petter Selasky err = mthca_uar_alloc(to_mdev(ibdev), &context->uar);
320*b633e08cSHans Petter Selasky if (err)
321*b633e08cSHans Petter Selasky return err;
32233ec1ccbSHans Petter Selasky
32333ec1ccbSHans Petter Selasky context->db_tab = mthca_init_user_db_tab(to_mdev(ibdev));
32433ec1ccbSHans Petter Selasky if (IS_ERR(context->db_tab)) {
32533ec1ccbSHans Petter Selasky err = PTR_ERR(context->db_tab);
32633ec1ccbSHans Petter Selasky mthca_uar_free(to_mdev(ibdev), &context->uar);
327*b633e08cSHans Petter Selasky return err;
32833ec1ccbSHans Petter Selasky }
32933ec1ccbSHans Petter Selasky
330*b633e08cSHans Petter Selasky if (ib_copy_to_udata(udata, &uresp, sizeof(uresp))) {
33133ec1ccbSHans Petter Selasky mthca_cleanup_user_db_tab(to_mdev(ibdev), &context->uar, context->db_tab);
33233ec1ccbSHans Petter Selasky mthca_uar_free(to_mdev(ibdev), &context->uar);
333*b633e08cSHans Petter Selasky return -EFAULT;
33433ec1ccbSHans Petter Selasky }
33533ec1ccbSHans Petter Selasky
33633ec1ccbSHans Petter Selasky context->reg_mr_warned = 0;
33733ec1ccbSHans Petter Selasky
338*b633e08cSHans Petter Selasky return 0;
33933ec1ccbSHans Petter Selasky }
34033ec1ccbSHans Petter Selasky
mthca_dealloc_ucontext(struct ib_ucontext * context)341*b633e08cSHans Petter Selasky static void mthca_dealloc_ucontext(struct ib_ucontext *context)
34233ec1ccbSHans Petter Selasky {
34333ec1ccbSHans Petter Selasky mthca_cleanup_user_db_tab(to_mdev(context->device), &to_mucontext(context)->uar,
34433ec1ccbSHans Petter Selasky to_mucontext(context)->db_tab);
34533ec1ccbSHans Petter Selasky mthca_uar_free(to_mdev(context->device), &to_mucontext(context)->uar);
34633ec1ccbSHans Petter Selasky }
34733ec1ccbSHans Petter Selasky
mthca_mmap_uar(struct ib_ucontext * context,struct vm_area_struct * vma)34833ec1ccbSHans Petter Selasky static int mthca_mmap_uar(struct ib_ucontext *context,
34933ec1ccbSHans Petter Selasky struct vm_area_struct *vma)
35033ec1ccbSHans Petter Selasky {
35133ec1ccbSHans Petter Selasky if (vma->vm_end - vma->vm_start != PAGE_SIZE)
35233ec1ccbSHans Petter Selasky return -EINVAL;
35333ec1ccbSHans Petter Selasky
35433ec1ccbSHans Petter Selasky vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
35533ec1ccbSHans Petter Selasky
35633ec1ccbSHans Petter Selasky if (io_remap_pfn_range(vma, vma->vm_start,
35733ec1ccbSHans Petter Selasky to_mucontext(context)->uar.pfn,
35833ec1ccbSHans Petter Selasky PAGE_SIZE, vma->vm_page_prot))
35933ec1ccbSHans Petter Selasky return -EAGAIN;
36033ec1ccbSHans Petter Selasky
36133ec1ccbSHans Petter Selasky return 0;
36233ec1ccbSHans Petter Selasky }
36333ec1ccbSHans Petter Selasky
mthca_alloc_pd(struct ib_pd * ibpd,struct ib_udata * udata)364*b633e08cSHans Petter Selasky static int mthca_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
36533ec1ccbSHans Petter Selasky {
366*b633e08cSHans Petter Selasky struct ib_device *ibdev = ibpd->device;
367*b633e08cSHans Petter Selasky struct mthca_pd *pd = to_mpd(ibpd);
36833ec1ccbSHans Petter Selasky int err;
36933ec1ccbSHans Petter Selasky
370*b633e08cSHans Petter Selasky err = mthca_pd_alloc(to_mdev(ibdev), !udata, pd);
371*b633e08cSHans Petter Selasky if (err)
372*b633e08cSHans Petter Selasky return err;
37333ec1ccbSHans Petter Selasky
374*b633e08cSHans Petter Selasky if (udata) {
37533ec1ccbSHans Petter Selasky if (ib_copy_to_udata(udata, &pd->pd_num, sizeof (__u32))) {
37633ec1ccbSHans Petter Selasky mthca_pd_free(to_mdev(ibdev), pd);
377*b633e08cSHans Petter Selasky return -EFAULT;
37833ec1ccbSHans Petter Selasky }
37933ec1ccbSHans Petter Selasky }
38033ec1ccbSHans Petter Selasky
381*b633e08cSHans Petter Selasky return 0;
38233ec1ccbSHans Petter Selasky }
38333ec1ccbSHans Petter Selasky
mthca_dealloc_pd(struct ib_pd * pd,struct ib_udata * udata)384*b633e08cSHans Petter Selasky static void mthca_dealloc_pd(struct ib_pd *pd, struct ib_udata *udata)
38533ec1ccbSHans Petter Selasky {
38633ec1ccbSHans Petter Selasky mthca_pd_free(to_mdev(pd->device), to_mpd(pd));
38733ec1ccbSHans Petter Selasky }
38833ec1ccbSHans Petter Selasky
mthca_ah_create(struct ib_ah * ibah,struct ib_ah_attr * init_attr,u32 flags,struct ib_udata * udata)389*b633e08cSHans Petter Selasky static int mthca_ah_create(struct ib_ah *ibah,
390*b633e08cSHans Petter Selasky struct ib_ah_attr *init_attr, u32 flags,
3911456d97cSHans Petter Selasky struct ib_udata *udata)
392*b633e08cSHans Petter Selasky
39333ec1ccbSHans Petter Selasky {
394*b633e08cSHans Petter Selasky struct mthca_ah *ah = to_mah(ibah);
39533ec1ccbSHans Petter Selasky
396*b633e08cSHans Petter Selasky return mthca_create_ah(to_mdev(ibah->device), to_mpd(ibah->pd),
397*b633e08cSHans Petter Selasky init_attr, ah);
39833ec1ccbSHans Petter Selasky }
39933ec1ccbSHans Petter Selasky
mthca_ah_destroy(struct ib_ah * ah,u32 flags)400*b633e08cSHans Petter Selasky static void mthca_ah_destroy(struct ib_ah *ah, u32 flags)
40133ec1ccbSHans Petter Selasky {
40233ec1ccbSHans Petter Selasky mthca_destroy_ah(to_mdev(ah->device), to_mah(ah));
40333ec1ccbSHans Petter Selasky }
40433ec1ccbSHans Petter Selasky
mthca_create_srq(struct ib_srq * ibsrq,struct ib_srq_init_attr * init_attr,struct ib_udata * udata)405*b633e08cSHans Petter Selasky static int mthca_create_srq(struct ib_srq *ibsrq,
40633ec1ccbSHans Petter Selasky struct ib_srq_init_attr *init_attr,
40733ec1ccbSHans Petter Selasky struct ib_udata *udata)
40833ec1ccbSHans Petter Selasky {
40933ec1ccbSHans Petter Selasky struct mthca_create_srq ucmd;
410*b633e08cSHans Petter Selasky struct mthca_ucontext *context = rdma_udata_to_drv_context(
411*b633e08cSHans Petter Selasky udata, struct mthca_ucontext, ibucontext);
412*b633e08cSHans Petter Selasky struct mthca_srq *srq = to_msrq(ibsrq);
41333ec1ccbSHans Petter Selasky int err;
41433ec1ccbSHans Petter Selasky
41533ec1ccbSHans Petter Selasky if (init_attr->srq_type != IB_SRQT_BASIC)
416*b633e08cSHans Petter Selasky return -EOPNOTSUPP;
41733ec1ccbSHans Petter Selasky
418*b633e08cSHans Petter Selasky if (udata) {
419*b633e08cSHans Petter Selasky if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)))
420*b633e08cSHans Petter Selasky return -EFAULT;
42133ec1ccbSHans Petter Selasky
422*b633e08cSHans Petter Selasky err = mthca_map_user_db(to_mdev(ibsrq->device), &context->uar,
42333ec1ccbSHans Petter Selasky context->db_tab, ucmd.db_index,
42433ec1ccbSHans Petter Selasky ucmd.db_page);
42533ec1ccbSHans Petter Selasky
42633ec1ccbSHans Petter Selasky if (err)
427*b633e08cSHans Petter Selasky return err;
42833ec1ccbSHans Petter Selasky
42933ec1ccbSHans Petter Selasky srq->mr.ibmr.lkey = ucmd.lkey;
43033ec1ccbSHans Petter Selasky srq->db_index = ucmd.db_index;
43133ec1ccbSHans Petter Selasky }
43233ec1ccbSHans Petter Selasky
433*b633e08cSHans Petter Selasky err = mthca_alloc_srq(to_mdev(ibsrq->device), to_mpd(ibsrq->pd),
434*b633e08cSHans Petter Selasky &init_attr->attr, srq, udata);
43533ec1ccbSHans Petter Selasky
436*b633e08cSHans Petter Selasky if (err && udata)
437*b633e08cSHans Petter Selasky mthca_unmap_user_db(to_mdev(ibsrq->device), &context->uar,
43833ec1ccbSHans Petter Selasky context->db_tab, ucmd.db_index);
43933ec1ccbSHans Petter Selasky
44033ec1ccbSHans Petter Selasky if (err)
441*b633e08cSHans Petter Selasky return err;
44233ec1ccbSHans Petter Selasky
44333ec1ccbSHans Petter Selasky if (context && ib_copy_to_udata(udata, &srq->srqn, sizeof(__u32))) {
444*b633e08cSHans Petter Selasky mthca_free_srq(to_mdev(ibsrq->device), srq);
445*b633e08cSHans Petter Selasky return -EFAULT;
44633ec1ccbSHans Petter Selasky }
44733ec1ccbSHans Petter Selasky
448*b633e08cSHans Petter Selasky return 0;
44933ec1ccbSHans Petter Selasky }
45033ec1ccbSHans Petter Selasky
mthca_destroy_srq(struct ib_srq * srq,struct ib_udata * udata)451*b633e08cSHans Petter Selasky static void mthca_destroy_srq(struct ib_srq *srq, struct ib_udata *udata)
45233ec1ccbSHans Petter Selasky {
453*b633e08cSHans Petter Selasky if (udata) {
454*b633e08cSHans Petter Selasky struct mthca_ucontext *context =
455*b633e08cSHans Petter Selasky rdma_udata_to_drv_context(
456*b633e08cSHans Petter Selasky udata,
457*b633e08cSHans Petter Selasky struct mthca_ucontext,
458*b633e08cSHans Petter Selasky ibucontext);
45933ec1ccbSHans Petter Selasky
46033ec1ccbSHans Petter Selasky mthca_unmap_user_db(to_mdev(srq->device), &context->uar,
46133ec1ccbSHans Petter Selasky context->db_tab, to_msrq(srq)->db_index);
46233ec1ccbSHans Petter Selasky }
46333ec1ccbSHans Petter Selasky
46433ec1ccbSHans Petter Selasky mthca_free_srq(to_mdev(srq->device), to_msrq(srq));
46533ec1ccbSHans Petter Selasky }
46633ec1ccbSHans Petter Selasky
mthca_create_qp(struct ib_pd * pd,struct ib_qp_init_attr * init_attr,struct ib_udata * udata)46733ec1ccbSHans Petter Selasky static struct ib_qp *mthca_create_qp(struct ib_pd *pd,
46833ec1ccbSHans Petter Selasky struct ib_qp_init_attr *init_attr,
46933ec1ccbSHans Petter Selasky struct ib_udata *udata)
47033ec1ccbSHans Petter Selasky {
471*b633e08cSHans Petter Selasky struct mthca_ucontext *context = rdma_udata_to_drv_context(
472*b633e08cSHans Petter Selasky udata, struct mthca_ucontext, ibucontext);
47333ec1ccbSHans Petter Selasky struct mthca_create_qp ucmd;
47433ec1ccbSHans Petter Selasky struct mthca_qp *qp;
47533ec1ccbSHans Petter Selasky int err;
47633ec1ccbSHans Petter Selasky
47733ec1ccbSHans Petter Selasky if (init_attr->create_flags)
47833ec1ccbSHans Petter Selasky return ERR_PTR(-EINVAL);
47933ec1ccbSHans Petter Selasky
48033ec1ccbSHans Petter Selasky switch (init_attr->qp_type) {
48133ec1ccbSHans Petter Selasky case IB_QPT_RC:
48233ec1ccbSHans Petter Selasky case IB_QPT_UC:
48333ec1ccbSHans Petter Selasky case IB_QPT_UD:
48433ec1ccbSHans Petter Selasky {
485*b633e08cSHans Petter Selasky qp = kzalloc(sizeof(*qp), GFP_KERNEL);
48633ec1ccbSHans Petter Selasky if (!qp)
48733ec1ccbSHans Petter Selasky return ERR_PTR(-ENOMEM);
48833ec1ccbSHans Petter Selasky
489*b633e08cSHans Petter Selasky if (udata) {
49033ec1ccbSHans Petter Selasky if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) {
49133ec1ccbSHans Petter Selasky kfree(qp);
49233ec1ccbSHans Petter Selasky return ERR_PTR(-EFAULT);
49333ec1ccbSHans Petter Selasky }
49433ec1ccbSHans Petter Selasky
49533ec1ccbSHans Petter Selasky err = mthca_map_user_db(to_mdev(pd->device), &context->uar,
49633ec1ccbSHans Petter Selasky context->db_tab,
49733ec1ccbSHans Petter Selasky ucmd.sq_db_index, ucmd.sq_db_page);
49833ec1ccbSHans Petter Selasky if (err) {
49933ec1ccbSHans Petter Selasky kfree(qp);
50033ec1ccbSHans Petter Selasky return ERR_PTR(err);
50133ec1ccbSHans Petter Selasky }
50233ec1ccbSHans Petter Selasky
50333ec1ccbSHans Petter Selasky err = mthca_map_user_db(to_mdev(pd->device), &context->uar,
50433ec1ccbSHans Petter Selasky context->db_tab,
50533ec1ccbSHans Petter Selasky ucmd.rq_db_index, ucmd.rq_db_page);
50633ec1ccbSHans Petter Selasky if (err) {
50733ec1ccbSHans Petter Selasky mthca_unmap_user_db(to_mdev(pd->device),
50833ec1ccbSHans Petter Selasky &context->uar,
50933ec1ccbSHans Petter Selasky context->db_tab,
51033ec1ccbSHans Petter Selasky ucmd.sq_db_index);
51133ec1ccbSHans Petter Selasky kfree(qp);
51233ec1ccbSHans Petter Selasky return ERR_PTR(err);
51333ec1ccbSHans Petter Selasky }
51433ec1ccbSHans Petter Selasky
51533ec1ccbSHans Petter Selasky qp->mr.ibmr.lkey = ucmd.lkey;
51633ec1ccbSHans Petter Selasky qp->sq.db_index = ucmd.sq_db_index;
51733ec1ccbSHans Petter Selasky qp->rq.db_index = ucmd.rq_db_index;
51833ec1ccbSHans Petter Selasky }
51933ec1ccbSHans Petter Selasky
52033ec1ccbSHans Petter Selasky err = mthca_alloc_qp(to_mdev(pd->device), to_mpd(pd),
52133ec1ccbSHans Petter Selasky to_mcq(init_attr->send_cq),
52233ec1ccbSHans Petter Selasky to_mcq(init_attr->recv_cq),
52333ec1ccbSHans Petter Selasky init_attr->qp_type, init_attr->sq_sig_type,
524*b633e08cSHans Petter Selasky &init_attr->cap, qp, udata);
52533ec1ccbSHans Petter Selasky
526*b633e08cSHans Petter Selasky if (err && udata) {
52733ec1ccbSHans Petter Selasky mthca_unmap_user_db(to_mdev(pd->device),
52833ec1ccbSHans Petter Selasky &context->uar,
52933ec1ccbSHans Petter Selasky context->db_tab,
53033ec1ccbSHans Petter Selasky ucmd.sq_db_index);
53133ec1ccbSHans Petter Selasky mthca_unmap_user_db(to_mdev(pd->device),
53233ec1ccbSHans Petter Selasky &context->uar,
53333ec1ccbSHans Petter Selasky context->db_tab,
53433ec1ccbSHans Petter Selasky ucmd.rq_db_index);
53533ec1ccbSHans Petter Selasky }
53633ec1ccbSHans Petter Selasky
53733ec1ccbSHans Petter Selasky qp->ibqp.qp_num = qp->qpn;
53833ec1ccbSHans Petter Selasky break;
53933ec1ccbSHans Petter Selasky }
54033ec1ccbSHans Petter Selasky case IB_QPT_SMI:
54133ec1ccbSHans Petter Selasky case IB_QPT_GSI:
54233ec1ccbSHans Petter Selasky {
543*b633e08cSHans Petter Selasky qp = kzalloc(sizeof(*qp), GFP_KERNEL);
54433ec1ccbSHans Petter Selasky if (!qp)
54533ec1ccbSHans Petter Selasky return ERR_PTR(-ENOMEM);
54633ec1ccbSHans Petter Selasky
54733ec1ccbSHans Petter Selasky qp->ibqp.qp_num = init_attr->qp_type == IB_QPT_SMI ? 0 : 1;
54833ec1ccbSHans Petter Selasky
54933ec1ccbSHans Petter Selasky err = mthca_alloc_sqp(to_mdev(pd->device), to_mpd(pd),
55033ec1ccbSHans Petter Selasky to_mcq(init_attr->send_cq),
55133ec1ccbSHans Petter Selasky to_mcq(init_attr->recv_cq),
55233ec1ccbSHans Petter Selasky init_attr->sq_sig_type, &init_attr->cap,
55333ec1ccbSHans Petter Selasky qp->ibqp.qp_num, init_attr->port_num,
554*b633e08cSHans Petter Selasky to_msqp(qp), udata);
55533ec1ccbSHans Petter Selasky break;
55633ec1ccbSHans Petter Selasky }
55733ec1ccbSHans Petter Selasky default:
55833ec1ccbSHans Petter Selasky /* Don't support raw QPs */
55933ec1ccbSHans Petter Selasky return ERR_PTR(-ENOSYS);
56033ec1ccbSHans Petter Selasky }
56133ec1ccbSHans Petter Selasky
56233ec1ccbSHans Petter Selasky if (err) {
56333ec1ccbSHans Petter Selasky kfree(qp);
56433ec1ccbSHans Petter Selasky return ERR_PTR(err);
56533ec1ccbSHans Petter Selasky }
56633ec1ccbSHans Petter Selasky
56733ec1ccbSHans Petter Selasky init_attr->cap.max_send_wr = qp->sq.max;
56833ec1ccbSHans Petter Selasky init_attr->cap.max_recv_wr = qp->rq.max;
56933ec1ccbSHans Petter Selasky init_attr->cap.max_send_sge = qp->sq.max_gs;
57033ec1ccbSHans Petter Selasky init_attr->cap.max_recv_sge = qp->rq.max_gs;
57133ec1ccbSHans Petter Selasky init_attr->cap.max_inline_data = qp->max_inline_data;
57233ec1ccbSHans Petter Selasky
57333ec1ccbSHans Petter Selasky return &qp->ibqp;
57433ec1ccbSHans Petter Selasky }
57533ec1ccbSHans Petter Selasky
mthca_destroy_qp(struct ib_qp * qp,struct ib_udata * udata)576*b633e08cSHans Petter Selasky static int mthca_destroy_qp(struct ib_qp *qp, struct ib_udata *udata)
57733ec1ccbSHans Petter Selasky {
578*b633e08cSHans Petter Selasky if (udata) {
579*b633e08cSHans Petter Selasky struct mthca_ucontext *context =
580*b633e08cSHans Petter Selasky rdma_udata_to_drv_context(
581*b633e08cSHans Petter Selasky udata,
582*b633e08cSHans Petter Selasky struct mthca_ucontext,
583*b633e08cSHans Petter Selasky ibucontext);
584*b633e08cSHans Petter Selasky
58533ec1ccbSHans Petter Selasky mthca_unmap_user_db(to_mdev(qp->device),
586*b633e08cSHans Petter Selasky &context->uar,
587*b633e08cSHans Petter Selasky context->db_tab,
58833ec1ccbSHans Petter Selasky to_mqp(qp)->sq.db_index);
58933ec1ccbSHans Petter Selasky mthca_unmap_user_db(to_mdev(qp->device),
590*b633e08cSHans Petter Selasky &context->uar,
591*b633e08cSHans Petter Selasky context->db_tab,
59233ec1ccbSHans Petter Selasky to_mqp(qp)->rq.db_index);
59333ec1ccbSHans Petter Selasky }
59433ec1ccbSHans Petter Selasky mthca_free_qp(to_mdev(qp->device), to_mqp(qp));
595*b633e08cSHans Petter Selasky kfree(to_mqp(qp));
59633ec1ccbSHans Petter Selasky return 0;
59733ec1ccbSHans Petter Selasky }
59833ec1ccbSHans Petter Selasky
mthca_create_cq(struct ib_cq * ibcq,const struct ib_cq_init_attr * attr,struct ib_udata * udata)599*b633e08cSHans Petter Selasky static int mthca_create_cq(struct ib_cq *ibcq,
60033ec1ccbSHans Petter Selasky const struct ib_cq_init_attr *attr,
60133ec1ccbSHans Petter Selasky struct ib_udata *udata)
60233ec1ccbSHans Petter Selasky {
603*b633e08cSHans Petter Selasky struct ib_device *ibdev = ibcq->device;
60433ec1ccbSHans Petter Selasky int entries = attr->cqe;
60533ec1ccbSHans Petter Selasky struct mthca_create_cq ucmd;
60633ec1ccbSHans Petter Selasky struct mthca_cq *cq;
60733ec1ccbSHans Petter Selasky int nent;
60833ec1ccbSHans Petter Selasky int err;
609*b633e08cSHans Petter Selasky struct mthca_ucontext *context = rdma_udata_to_drv_context(
610*b633e08cSHans Petter Selasky udata, struct mthca_ucontext, ibucontext);
61133ec1ccbSHans Petter Selasky
61233ec1ccbSHans Petter Selasky if (attr->flags)
613*b633e08cSHans Petter Selasky return -EOPNOTSUPP;
61433ec1ccbSHans Petter Selasky
61533ec1ccbSHans Petter Selasky if (entries < 1 || entries > to_mdev(ibdev)->limits.max_cqes)
616*b633e08cSHans Petter Selasky return -EINVAL;
61733ec1ccbSHans Petter Selasky
618*b633e08cSHans Petter Selasky if (udata) {
619*b633e08cSHans Petter Selasky if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)))
620*b633e08cSHans Petter Selasky return -EFAULT;
62133ec1ccbSHans Petter Selasky
622*b633e08cSHans Petter Selasky err = mthca_map_user_db(to_mdev(ibdev), &context->uar,
623*b633e08cSHans Petter Selasky context->db_tab, ucmd.set_db_index,
624*b633e08cSHans Petter Selasky ucmd.set_db_page);
62533ec1ccbSHans Petter Selasky if (err)
626*b633e08cSHans Petter Selasky return err;
62733ec1ccbSHans Petter Selasky
628*b633e08cSHans Petter Selasky err = mthca_map_user_db(to_mdev(ibdev), &context->uar,
629*b633e08cSHans Petter Selasky context->db_tab, ucmd.arm_db_index,
630*b633e08cSHans Petter Selasky ucmd.arm_db_page);
63133ec1ccbSHans Petter Selasky if (err)
63233ec1ccbSHans Petter Selasky goto err_unmap_set;
63333ec1ccbSHans Petter Selasky }
63433ec1ccbSHans Petter Selasky
635*b633e08cSHans Petter Selasky cq = to_mcq(ibcq);
63633ec1ccbSHans Petter Selasky
637*b633e08cSHans Petter Selasky if (udata) {
63833ec1ccbSHans Petter Selasky cq->buf.mr.ibmr.lkey = ucmd.lkey;
63933ec1ccbSHans Petter Selasky cq->set_ci_db_index = ucmd.set_db_index;
64033ec1ccbSHans Petter Selasky cq->arm_db_index = ucmd.arm_db_index;
64133ec1ccbSHans Petter Selasky }
64233ec1ccbSHans Petter Selasky
64333ec1ccbSHans Petter Selasky for (nent = 1; nent <= entries; nent <<= 1)
64433ec1ccbSHans Petter Selasky ; /* nothing */
64533ec1ccbSHans Petter Selasky
646*b633e08cSHans Petter Selasky err = mthca_init_cq(to_mdev(ibdev), nent, context,
647*b633e08cSHans Petter Selasky udata ? ucmd.pdn : to_mdev(ibdev)->driver_pd.pd_num,
64833ec1ccbSHans Petter Selasky cq);
64933ec1ccbSHans Petter Selasky if (err)
650*b633e08cSHans Petter Selasky goto err_unmap_arm;
65133ec1ccbSHans Petter Selasky
652*b633e08cSHans Petter Selasky if (udata && ib_copy_to_udata(udata, &cq->cqn, sizeof(__u32))) {
65333ec1ccbSHans Petter Selasky mthca_free_cq(to_mdev(ibdev), cq);
65433ec1ccbSHans Petter Selasky err = -EFAULT;
655*b633e08cSHans Petter Selasky goto err_unmap_arm;
65633ec1ccbSHans Petter Selasky }
65733ec1ccbSHans Petter Selasky
65833ec1ccbSHans Petter Selasky cq->resize_buf = NULL;
65933ec1ccbSHans Petter Selasky
660*b633e08cSHans Petter Selasky return 0;
66133ec1ccbSHans Petter Selasky
66233ec1ccbSHans Petter Selasky err_unmap_arm:
663*b633e08cSHans Petter Selasky if (udata)
664*b633e08cSHans Petter Selasky mthca_unmap_user_db(to_mdev(ibdev), &context->uar,
665*b633e08cSHans Petter Selasky context->db_tab, ucmd.arm_db_index);
66633ec1ccbSHans Petter Selasky
66733ec1ccbSHans Petter Selasky err_unmap_set:
668*b633e08cSHans Petter Selasky if (udata)
669*b633e08cSHans Petter Selasky mthca_unmap_user_db(to_mdev(ibdev), &context->uar,
670*b633e08cSHans Petter Selasky context->db_tab, ucmd.set_db_index);
67133ec1ccbSHans Petter Selasky
672*b633e08cSHans Petter Selasky return err;
67333ec1ccbSHans Petter Selasky }
67433ec1ccbSHans Petter Selasky
mthca_alloc_resize_buf(struct mthca_dev * dev,struct mthca_cq * cq,int entries)67533ec1ccbSHans Petter Selasky static int mthca_alloc_resize_buf(struct mthca_dev *dev, struct mthca_cq *cq,
67633ec1ccbSHans Petter Selasky int entries)
67733ec1ccbSHans Petter Selasky {
67833ec1ccbSHans Petter Selasky int ret;
67933ec1ccbSHans Petter Selasky
68033ec1ccbSHans Petter Selasky spin_lock_irq(&cq->lock);
68133ec1ccbSHans Petter Selasky if (cq->resize_buf) {
68233ec1ccbSHans Petter Selasky ret = -EBUSY;
68333ec1ccbSHans Petter Selasky goto unlock;
68433ec1ccbSHans Petter Selasky }
68533ec1ccbSHans Petter Selasky
68633ec1ccbSHans Petter Selasky cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_ATOMIC);
68733ec1ccbSHans Petter Selasky if (!cq->resize_buf) {
68833ec1ccbSHans Petter Selasky ret = -ENOMEM;
68933ec1ccbSHans Petter Selasky goto unlock;
69033ec1ccbSHans Petter Selasky }
69133ec1ccbSHans Petter Selasky
69233ec1ccbSHans Petter Selasky cq->resize_buf->state = CQ_RESIZE_ALLOC;
69333ec1ccbSHans Petter Selasky
69433ec1ccbSHans Petter Selasky ret = 0;
69533ec1ccbSHans Petter Selasky
69633ec1ccbSHans Petter Selasky unlock:
69733ec1ccbSHans Petter Selasky spin_unlock_irq(&cq->lock);
69833ec1ccbSHans Petter Selasky
69933ec1ccbSHans Petter Selasky if (ret)
70033ec1ccbSHans Petter Selasky return ret;
70133ec1ccbSHans Petter Selasky
70233ec1ccbSHans Petter Selasky ret = mthca_alloc_cq_buf(dev, &cq->resize_buf->buf, entries);
70333ec1ccbSHans Petter Selasky if (ret) {
70433ec1ccbSHans Petter Selasky spin_lock_irq(&cq->lock);
70533ec1ccbSHans Petter Selasky kfree(cq->resize_buf);
70633ec1ccbSHans Petter Selasky cq->resize_buf = NULL;
70733ec1ccbSHans Petter Selasky spin_unlock_irq(&cq->lock);
70833ec1ccbSHans Petter Selasky return ret;
70933ec1ccbSHans Petter Selasky }
71033ec1ccbSHans Petter Selasky
71133ec1ccbSHans Petter Selasky cq->resize_buf->cqe = entries - 1;
71233ec1ccbSHans Petter Selasky
71333ec1ccbSHans Petter Selasky spin_lock_irq(&cq->lock);
71433ec1ccbSHans Petter Selasky cq->resize_buf->state = CQ_RESIZE_READY;
71533ec1ccbSHans Petter Selasky spin_unlock_irq(&cq->lock);
71633ec1ccbSHans Petter Selasky
71733ec1ccbSHans Petter Selasky return 0;
71833ec1ccbSHans Petter Selasky }
71933ec1ccbSHans Petter Selasky
mthca_resize_cq(struct ib_cq * ibcq,int entries,struct ib_udata * udata)72033ec1ccbSHans Petter Selasky static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
72133ec1ccbSHans Petter Selasky {
72233ec1ccbSHans Petter Selasky struct mthca_dev *dev = to_mdev(ibcq->device);
72333ec1ccbSHans Petter Selasky struct mthca_cq *cq = to_mcq(ibcq);
72433ec1ccbSHans Petter Selasky struct mthca_resize_cq ucmd;
72533ec1ccbSHans Petter Selasky u32 lkey;
72633ec1ccbSHans Petter Selasky int ret;
72733ec1ccbSHans Petter Selasky
72833ec1ccbSHans Petter Selasky if (entries < 1 || entries > dev->limits.max_cqes)
72933ec1ccbSHans Petter Selasky return -EINVAL;
73033ec1ccbSHans Petter Selasky
73133ec1ccbSHans Petter Selasky mutex_lock(&cq->mutex);
73233ec1ccbSHans Petter Selasky
73333ec1ccbSHans Petter Selasky entries = roundup_pow_of_two(entries + 1);
73433ec1ccbSHans Petter Selasky if (entries == ibcq->cqe + 1) {
73533ec1ccbSHans Petter Selasky ret = 0;
73633ec1ccbSHans Petter Selasky goto out;
73733ec1ccbSHans Petter Selasky }
73833ec1ccbSHans Petter Selasky
73933ec1ccbSHans Petter Selasky if (cq->is_kernel) {
74033ec1ccbSHans Petter Selasky ret = mthca_alloc_resize_buf(dev, cq, entries);
74133ec1ccbSHans Petter Selasky if (ret)
74233ec1ccbSHans Petter Selasky goto out;
74333ec1ccbSHans Petter Selasky lkey = cq->resize_buf->buf.mr.ibmr.lkey;
74433ec1ccbSHans Petter Selasky } else {
74533ec1ccbSHans Petter Selasky if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) {
74633ec1ccbSHans Petter Selasky ret = -EFAULT;
74733ec1ccbSHans Petter Selasky goto out;
74833ec1ccbSHans Petter Selasky }
74933ec1ccbSHans Petter Selasky lkey = ucmd.lkey;
75033ec1ccbSHans Petter Selasky }
75133ec1ccbSHans Petter Selasky
75233ec1ccbSHans Petter Selasky ret = mthca_RESIZE_CQ(dev, cq->cqn, lkey, ilog2(entries));
75333ec1ccbSHans Petter Selasky
75433ec1ccbSHans Petter Selasky if (ret) {
75533ec1ccbSHans Petter Selasky if (cq->resize_buf) {
75633ec1ccbSHans Petter Selasky mthca_free_cq_buf(dev, &cq->resize_buf->buf,
75733ec1ccbSHans Petter Selasky cq->resize_buf->cqe);
75833ec1ccbSHans Petter Selasky kfree(cq->resize_buf);
75933ec1ccbSHans Petter Selasky spin_lock_irq(&cq->lock);
76033ec1ccbSHans Petter Selasky cq->resize_buf = NULL;
76133ec1ccbSHans Petter Selasky spin_unlock_irq(&cq->lock);
76233ec1ccbSHans Petter Selasky }
76333ec1ccbSHans Petter Selasky goto out;
76433ec1ccbSHans Petter Selasky }
76533ec1ccbSHans Petter Selasky
76633ec1ccbSHans Petter Selasky if (cq->is_kernel) {
76733ec1ccbSHans Petter Selasky struct mthca_cq_buf tbuf;
76833ec1ccbSHans Petter Selasky int tcqe;
76933ec1ccbSHans Petter Selasky
77033ec1ccbSHans Petter Selasky spin_lock_irq(&cq->lock);
77133ec1ccbSHans Petter Selasky if (cq->resize_buf->state == CQ_RESIZE_READY) {
77233ec1ccbSHans Petter Selasky mthca_cq_resize_copy_cqes(cq);
77333ec1ccbSHans Petter Selasky tbuf = cq->buf;
77433ec1ccbSHans Petter Selasky tcqe = cq->ibcq.cqe;
77533ec1ccbSHans Petter Selasky cq->buf = cq->resize_buf->buf;
77633ec1ccbSHans Petter Selasky cq->ibcq.cqe = cq->resize_buf->cqe;
77733ec1ccbSHans Petter Selasky } else {
77833ec1ccbSHans Petter Selasky tbuf = cq->resize_buf->buf;
77933ec1ccbSHans Petter Selasky tcqe = cq->resize_buf->cqe;
78033ec1ccbSHans Petter Selasky }
78133ec1ccbSHans Petter Selasky
78233ec1ccbSHans Petter Selasky kfree(cq->resize_buf);
78333ec1ccbSHans Petter Selasky cq->resize_buf = NULL;
78433ec1ccbSHans Petter Selasky spin_unlock_irq(&cq->lock);
78533ec1ccbSHans Petter Selasky
78633ec1ccbSHans Petter Selasky mthca_free_cq_buf(dev, &tbuf, tcqe);
78733ec1ccbSHans Petter Selasky } else
78833ec1ccbSHans Petter Selasky ibcq->cqe = entries - 1;
78933ec1ccbSHans Petter Selasky
79033ec1ccbSHans Petter Selasky out:
79133ec1ccbSHans Petter Selasky mutex_unlock(&cq->mutex);
79233ec1ccbSHans Petter Selasky
79333ec1ccbSHans Petter Selasky return ret;
79433ec1ccbSHans Petter Selasky }
79533ec1ccbSHans Petter Selasky
mthca_destroy_cq(struct ib_cq * cq,struct ib_udata * udata)796*b633e08cSHans Petter Selasky static void mthca_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)
79733ec1ccbSHans Petter Selasky {
798*b633e08cSHans Petter Selasky if (udata) {
799*b633e08cSHans Petter Selasky struct mthca_ucontext *context =
800*b633e08cSHans Petter Selasky rdma_udata_to_drv_context(
801*b633e08cSHans Petter Selasky udata,
802*b633e08cSHans Petter Selasky struct mthca_ucontext,
803*b633e08cSHans Petter Selasky ibucontext);
804*b633e08cSHans Petter Selasky
80533ec1ccbSHans Petter Selasky mthca_unmap_user_db(to_mdev(cq->device),
806*b633e08cSHans Petter Selasky &context->uar,
807*b633e08cSHans Petter Selasky context->db_tab,
80833ec1ccbSHans Petter Selasky to_mcq(cq)->arm_db_index);
80933ec1ccbSHans Petter Selasky mthca_unmap_user_db(to_mdev(cq->device),
810*b633e08cSHans Petter Selasky &context->uar,
811*b633e08cSHans Petter Selasky context->db_tab,
81233ec1ccbSHans Petter Selasky to_mcq(cq)->set_ci_db_index);
81333ec1ccbSHans Petter Selasky }
81433ec1ccbSHans Petter Selasky mthca_free_cq(to_mdev(cq->device), to_mcq(cq));
81533ec1ccbSHans Petter Selasky }
81633ec1ccbSHans Petter Selasky
convert_access(int acc)81733ec1ccbSHans Petter Selasky static inline u32 convert_access(int acc)
81833ec1ccbSHans Petter Selasky {
81933ec1ccbSHans Petter Selasky return (acc & IB_ACCESS_REMOTE_ATOMIC ? MTHCA_MPT_FLAG_ATOMIC : 0) |
82033ec1ccbSHans Petter Selasky (acc & IB_ACCESS_REMOTE_WRITE ? MTHCA_MPT_FLAG_REMOTE_WRITE : 0) |
82133ec1ccbSHans Petter Selasky (acc & IB_ACCESS_REMOTE_READ ? MTHCA_MPT_FLAG_REMOTE_READ : 0) |
82233ec1ccbSHans Petter Selasky (acc & IB_ACCESS_LOCAL_WRITE ? MTHCA_MPT_FLAG_LOCAL_WRITE : 0) |
82333ec1ccbSHans Petter Selasky MTHCA_MPT_FLAG_LOCAL_READ;
82433ec1ccbSHans Petter Selasky }
82533ec1ccbSHans Petter Selasky
mthca_get_dma_mr(struct ib_pd * pd,int acc)82633ec1ccbSHans Petter Selasky static struct ib_mr *mthca_get_dma_mr(struct ib_pd *pd, int acc)
82733ec1ccbSHans Petter Selasky {
82833ec1ccbSHans Petter Selasky struct mthca_mr *mr;
82933ec1ccbSHans Petter Selasky int err;
83033ec1ccbSHans Petter Selasky
83133ec1ccbSHans Petter Selasky mr = kmalloc(sizeof *mr, GFP_KERNEL);
83233ec1ccbSHans Petter Selasky if (!mr)
83333ec1ccbSHans Petter Selasky return ERR_PTR(-ENOMEM);
83433ec1ccbSHans Petter Selasky
83533ec1ccbSHans Petter Selasky err = mthca_mr_alloc_notrans(to_mdev(pd->device),
83633ec1ccbSHans Petter Selasky to_mpd(pd)->pd_num,
83733ec1ccbSHans Petter Selasky convert_access(acc), mr);
83833ec1ccbSHans Petter Selasky
83933ec1ccbSHans Petter Selasky if (err) {
84033ec1ccbSHans Petter Selasky kfree(mr);
84133ec1ccbSHans Petter Selasky return ERR_PTR(err);
84233ec1ccbSHans Petter Selasky }
84333ec1ccbSHans Petter Selasky
84433ec1ccbSHans Petter Selasky mr->umem = NULL;
84533ec1ccbSHans Petter Selasky
84633ec1ccbSHans Petter Selasky return &mr->ibmr;
84733ec1ccbSHans Petter Selasky }
84833ec1ccbSHans Petter Selasky
mthca_reg_user_mr(struct ib_pd * pd,u64 start,u64 length,u64 virt,int acc,struct ib_udata * udata)84933ec1ccbSHans Petter Selasky static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
85033ec1ccbSHans Petter Selasky u64 virt, int acc, struct ib_udata *udata)
85133ec1ccbSHans Petter Selasky {
85233ec1ccbSHans Petter Selasky struct mthca_dev *dev = to_mdev(pd->device);
85333ec1ccbSHans Petter Selasky struct scatterlist *sg;
85433ec1ccbSHans Petter Selasky struct mthca_mr *mr;
85533ec1ccbSHans Petter Selasky struct mthca_reg_mr ucmd;
85633ec1ccbSHans Petter Selasky u64 *pages;
85733ec1ccbSHans Petter Selasky int shift, n, len;
85833ec1ccbSHans Petter Selasky int i, k, entry;
85933ec1ccbSHans Petter Selasky int err = 0;
86033ec1ccbSHans Petter Selasky int write_mtt_size;
86133ec1ccbSHans Petter Selasky
86233ec1ccbSHans Petter Selasky if (udata->inlen - sizeof (struct ib_uverbs_cmd_hdr) < sizeof ucmd) {
86333ec1ccbSHans Petter Selasky if (!to_mucontext(pd->uobject->context)->reg_mr_warned) {
86433ec1ccbSHans Petter Selasky mthca_warn(dev, "Process '%s' did not pass in MR attrs.\n",
86533ec1ccbSHans Petter Selasky current->comm);
86633ec1ccbSHans Petter Selasky mthca_warn(dev, " Update libmthca to fix this.\n");
86733ec1ccbSHans Petter Selasky }
86833ec1ccbSHans Petter Selasky ++to_mucontext(pd->uobject->context)->reg_mr_warned;
86933ec1ccbSHans Petter Selasky ucmd.mr_attrs = 0;
87033ec1ccbSHans Petter Selasky } else if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
87133ec1ccbSHans Petter Selasky return ERR_PTR(-EFAULT);
87233ec1ccbSHans Petter Selasky
87333ec1ccbSHans Petter Selasky mr = kmalloc(sizeof *mr, GFP_KERNEL);
87433ec1ccbSHans Petter Selasky if (!mr)
87533ec1ccbSHans Petter Selasky return ERR_PTR(-ENOMEM);
87633ec1ccbSHans Petter Selasky
87733ec1ccbSHans Petter Selasky mr->umem = ib_umem_get(pd->uobject->context, start, length, acc,
87833ec1ccbSHans Petter Selasky ucmd.mr_attrs & MTHCA_MR_DMASYNC);
87933ec1ccbSHans Petter Selasky
88033ec1ccbSHans Petter Selasky if (IS_ERR(mr->umem)) {
88133ec1ccbSHans Petter Selasky err = PTR_ERR(mr->umem);
88233ec1ccbSHans Petter Selasky goto err;
88333ec1ccbSHans Petter Selasky }
88433ec1ccbSHans Petter Selasky
88533ec1ccbSHans Petter Selasky shift = ffs(mr->umem->page_size) - 1;
88633ec1ccbSHans Petter Selasky n = mr->umem->nmap;
88733ec1ccbSHans Petter Selasky
88833ec1ccbSHans Petter Selasky mr->mtt = mthca_alloc_mtt(dev, n);
88933ec1ccbSHans Petter Selasky if (IS_ERR(mr->mtt)) {
89033ec1ccbSHans Petter Selasky err = PTR_ERR(mr->mtt);
89133ec1ccbSHans Petter Selasky goto err_umem;
89233ec1ccbSHans Petter Selasky }
89333ec1ccbSHans Petter Selasky
89433ec1ccbSHans Petter Selasky pages = (u64 *) __get_free_page(GFP_KERNEL);
89533ec1ccbSHans Petter Selasky if (!pages) {
89633ec1ccbSHans Petter Selasky err = -ENOMEM;
89733ec1ccbSHans Petter Selasky goto err_mtt;
89833ec1ccbSHans Petter Selasky }
89933ec1ccbSHans Petter Selasky
90033ec1ccbSHans Petter Selasky i = n = 0;
90133ec1ccbSHans Petter Selasky
90233ec1ccbSHans Petter Selasky write_mtt_size = min(mthca_write_mtt_size(dev), (int) (PAGE_SIZE / sizeof *pages));
90333ec1ccbSHans Petter Selasky
90433ec1ccbSHans Petter Selasky for_each_sg(mr->umem->sg_head.sgl, sg, mr->umem->nmap, entry) {
90533ec1ccbSHans Petter Selasky len = sg_dma_len(sg) >> shift;
90633ec1ccbSHans Petter Selasky for (k = 0; k < len; ++k) {
90733ec1ccbSHans Petter Selasky pages[i++] = sg_dma_address(sg) +
90833ec1ccbSHans Petter Selasky mr->umem->page_size * k;
90933ec1ccbSHans Petter Selasky /*
91033ec1ccbSHans Petter Selasky * Be friendly to write_mtt and pass it chunks
91133ec1ccbSHans Petter Selasky * of appropriate size.
91233ec1ccbSHans Petter Selasky */
91333ec1ccbSHans Petter Selasky if (i == write_mtt_size) {
91433ec1ccbSHans Petter Selasky err = mthca_write_mtt(dev, mr->mtt, n, pages, i);
91533ec1ccbSHans Petter Selasky if (err)
91633ec1ccbSHans Petter Selasky goto mtt_done;
91733ec1ccbSHans Petter Selasky n += i;
91833ec1ccbSHans Petter Selasky i = 0;
91933ec1ccbSHans Petter Selasky }
92033ec1ccbSHans Petter Selasky }
92133ec1ccbSHans Petter Selasky }
92233ec1ccbSHans Petter Selasky
92333ec1ccbSHans Petter Selasky if (i)
92433ec1ccbSHans Petter Selasky err = mthca_write_mtt(dev, mr->mtt, n, pages, i);
92533ec1ccbSHans Petter Selasky mtt_done:
92633ec1ccbSHans Petter Selasky free_page((unsigned long) pages);
92733ec1ccbSHans Petter Selasky if (err)
92833ec1ccbSHans Petter Selasky goto err_mtt;
92933ec1ccbSHans Petter Selasky
93033ec1ccbSHans Petter Selasky err = mthca_mr_alloc(dev, to_mpd(pd)->pd_num, shift, virt, length,
93133ec1ccbSHans Petter Selasky convert_access(acc), mr);
93233ec1ccbSHans Petter Selasky
93333ec1ccbSHans Petter Selasky if (err)
93433ec1ccbSHans Petter Selasky goto err_mtt;
93533ec1ccbSHans Petter Selasky
93633ec1ccbSHans Petter Selasky return &mr->ibmr;
93733ec1ccbSHans Petter Selasky
93833ec1ccbSHans Petter Selasky err_mtt:
93933ec1ccbSHans Petter Selasky mthca_free_mtt(dev, mr->mtt);
94033ec1ccbSHans Petter Selasky
94133ec1ccbSHans Petter Selasky err_umem:
94233ec1ccbSHans Petter Selasky ib_umem_release(mr->umem);
94333ec1ccbSHans Petter Selasky
94433ec1ccbSHans Petter Selasky err:
94533ec1ccbSHans Petter Selasky kfree(mr);
94633ec1ccbSHans Petter Selasky return ERR_PTR(err);
94733ec1ccbSHans Petter Selasky }
94833ec1ccbSHans Petter Selasky
mthca_dereg_mr(struct ib_mr * mr,struct ib_udata * udata)949*b633e08cSHans Petter Selasky static int mthca_dereg_mr(struct ib_mr *mr, struct ib_udata *udata)
95033ec1ccbSHans Petter Selasky {
95133ec1ccbSHans Petter Selasky struct mthca_mr *mmr = to_mmr(mr);
95233ec1ccbSHans Petter Selasky
95333ec1ccbSHans Petter Selasky mthca_free_mr(to_mdev(mr->device), mmr);
95433ec1ccbSHans Petter Selasky ib_umem_release(mmr->umem);
95533ec1ccbSHans Petter Selasky kfree(mmr);
95633ec1ccbSHans Petter Selasky
95733ec1ccbSHans Petter Selasky return 0;
95833ec1ccbSHans Petter Selasky }
95933ec1ccbSHans Petter Selasky
mthca_alloc_fmr(struct ib_pd * pd,int mr_access_flags,struct ib_fmr_attr * fmr_attr)96033ec1ccbSHans Petter Selasky static struct ib_fmr *mthca_alloc_fmr(struct ib_pd *pd, int mr_access_flags,
96133ec1ccbSHans Petter Selasky struct ib_fmr_attr *fmr_attr)
96233ec1ccbSHans Petter Selasky {
96333ec1ccbSHans Petter Selasky struct mthca_fmr *fmr;
96433ec1ccbSHans Petter Selasky int err;
96533ec1ccbSHans Petter Selasky
96633ec1ccbSHans Petter Selasky fmr = kmalloc(sizeof *fmr, GFP_KERNEL);
96733ec1ccbSHans Petter Selasky if (!fmr)
96833ec1ccbSHans Petter Selasky return ERR_PTR(-ENOMEM);
96933ec1ccbSHans Petter Selasky
97033ec1ccbSHans Petter Selasky memcpy(&fmr->attr, fmr_attr, sizeof *fmr_attr);
97133ec1ccbSHans Petter Selasky err = mthca_fmr_alloc(to_mdev(pd->device), to_mpd(pd)->pd_num,
97233ec1ccbSHans Petter Selasky convert_access(mr_access_flags), fmr);
97333ec1ccbSHans Petter Selasky
97433ec1ccbSHans Petter Selasky if (err) {
97533ec1ccbSHans Petter Selasky kfree(fmr);
97633ec1ccbSHans Petter Selasky return ERR_PTR(err);
97733ec1ccbSHans Petter Selasky }
97833ec1ccbSHans Petter Selasky
97933ec1ccbSHans Petter Selasky return &fmr->ibmr;
98033ec1ccbSHans Petter Selasky }
98133ec1ccbSHans Petter Selasky
mthca_dealloc_fmr(struct ib_fmr * fmr)98233ec1ccbSHans Petter Selasky static int mthca_dealloc_fmr(struct ib_fmr *fmr)
98333ec1ccbSHans Petter Selasky {
98433ec1ccbSHans Petter Selasky struct mthca_fmr *mfmr = to_mfmr(fmr);
98533ec1ccbSHans Petter Selasky int err;
98633ec1ccbSHans Petter Selasky
98733ec1ccbSHans Petter Selasky err = mthca_free_fmr(to_mdev(fmr->device), mfmr);
98833ec1ccbSHans Petter Selasky if (err)
98933ec1ccbSHans Petter Selasky return err;
99033ec1ccbSHans Petter Selasky
99133ec1ccbSHans Petter Selasky kfree(mfmr);
99233ec1ccbSHans Petter Selasky return 0;
99333ec1ccbSHans Petter Selasky }
99433ec1ccbSHans Petter Selasky
mthca_unmap_fmr(struct list_head * fmr_list)99533ec1ccbSHans Petter Selasky static int mthca_unmap_fmr(struct list_head *fmr_list)
99633ec1ccbSHans Petter Selasky {
99733ec1ccbSHans Petter Selasky struct ib_fmr *fmr;
99833ec1ccbSHans Petter Selasky int err;
99933ec1ccbSHans Petter Selasky struct mthca_dev *mdev = NULL;
100033ec1ccbSHans Petter Selasky
100133ec1ccbSHans Petter Selasky list_for_each_entry(fmr, fmr_list, list) {
100233ec1ccbSHans Petter Selasky if (mdev && to_mdev(fmr->device) != mdev)
100333ec1ccbSHans Petter Selasky return -EINVAL;
100433ec1ccbSHans Petter Selasky mdev = to_mdev(fmr->device);
100533ec1ccbSHans Petter Selasky }
100633ec1ccbSHans Petter Selasky
100733ec1ccbSHans Petter Selasky if (!mdev)
100833ec1ccbSHans Petter Selasky return 0;
100933ec1ccbSHans Petter Selasky
101033ec1ccbSHans Petter Selasky if (mthca_is_memfree(mdev)) {
101133ec1ccbSHans Petter Selasky list_for_each_entry(fmr, fmr_list, list)
101233ec1ccbSHans Petter Selasky mthca_arbel_fmr_unmap(mdev, to_mfmr(fmr));
101333ec1ccbSHans Petter Selasky
101433ec1ccbSHans Petter Selasky wmb();
101533ec1ccbSHans Petter Selasky } else
101633ec1ccbSHans Petter Selasky list_for_each_entry(fmr, fmr_list, list)
101733ec1ccbSHans Petter Selasky mthca_tavor_fmr_unmap(mdev, to_mfmr(fmr));
101833ec1ccbSHans Petter Selasky
101933ec1ccbSHans Petter Selasky err = mthca_SYNC_TPT(mdev);
102033ec1ccbSHans Petter Selasky return err;
102133ec1ccbSHans Petter Selasky }
102233ec1ccbSHans Petter Selasky
show_rev(struct device * device,struct device_attribute * attr,char * buf)102333ec1ccbSHans Petter Selasky static ssize_t show_rev(struct device *device, struct device_attribute *attr,
102433ec1ccbSHans Petter Selasky char *buf)
102533ec1ccbSHans Petter Selasky {
102633ec1ccbSHans Petter Selasky struct mthca_dev *dev =
102733ec1ccbSHans Petter Selasky container_of(device, struct mthca_dev, ib_dev.dev);
102833ec1ccbSHans Petter Selasky return sprintf(buf, "%x\n", dev->rev_id);
102933ec1ccbSHans Petter Selasky }
103033ec1ccbSHans Petter Selasky
show_hca(struct device * device,struct device_attribute * attr,char * buf)103133ec1ccbSHans Petter Selasky static ssize_t show_hca(struct device *device, struct device_attribute *attr,
103233ec1ccbSHans Petter Selasky char *buf)
103333ec1ccbSHans Petter Selasky {
103433ec1ccbSHans Petter Selasky struct mthca_dev *dev =
103533ec1ccbSHans Petter Selasky container_of(device, struct mthca_dev, ib_dev.dev);
103633ec1ccbSHans Petter Selasky switch (dev->pdev->device) {
103733ec1ccbSHans Petter Selasky case PCI_DEVICE_ID_MELLANOX_TAVOR:
103833ec1ccbSHans Petter Selasky return sprintf(buf, "MT23108\n");
103933ec1ccbSHans Petter Selasky case PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT:
104033ec1ccbSHans Petter Selasky return sprintf(buf, "MT25208 (MT23108 compat mode)\n");
104133ec1ccbSHans Petter Selasky case PCI_DEVICE_ID_MELLANOX_ARBEL:
104233ec1ccbSHans Petter Selasky return sprintf(buf, "MT25208\n");
104333ec1ccbSHans Petter Selasky case PCI_DEVICE_ID_MELLANOX_SINAI:
104433ec1ccbSHans Petter Selasky case PCI_DEVICE_ID_MELLANOX_SINAI_OLD:
104533ec1ccbSHans Petter Selasky return sprintf(buf, "MT25204\n");
104633ec1ccbSHans Petter Selasky default:
104733ec1ccbSHans Petter Selasky return sprintf(buf, "unknown\n");
104833ec1ccbSHans Petter Selasky }
104933ec1ccbSHans Petter Selasky }
105033ec1ccbSHans Petter Selasky
show_board(struct device * device,struct device_attribute * attr,char * buf)105133ec1ccbSHans Petter Selasky static ssize_t show_board(struct device *device, struct device_attribute *attr,
105233ec1ccbSHans Petter Selasky char *buf)
105333ec1ccbSHans Petter Selasky {
105433ec1ccbSHans Petter Selasky struct mthca_dev *dev =
105533ec1ccbSHans Petter Selasky container_of(device, struct mthca_dev, ib_dev.dev);
105633ec1ccbSHans Petter Selasky return sprintf(buf, "%.*s\n", MTHCA_BOARD_ID_LEN, dev->board_id);
105733ec1ccbSHans Petter Selasky }
105833ec1ccbSHans Petter Selasky
105933ec1ccbSHans Petter Selasky static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
106033ec1ccbSHans Petter Selasky static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
106133ec1ccbSHans Petter Selasky static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
106233ec1ccbSHans Petter Selasky
106333ec1ccbSHans Petter Selasky static struct device_attribute *mthca_dev_attributes[] = {
106433ec1ccbSHans Petter Selasky &dev_attr_hw_rev,
106533ec1ccbSHans Petter Selasky &dev_attr_hca_type,
106633ec1ccbSHans Petter Selasky &dev_attr_board_id
106733ec1ccbSHans Petter Selasky };
106833ec1ccbSHans Petter Selasky
mthca_init_node_data(struct mthca_dev * dev)106933ec1ccbSHans Petter Selasky static int mthca_init_node_data(struct mthca_dev *dev)
107033ec1ccbSHans Petter Selasky {
107133ec1ccbSHans Petter Selasky struct ib_smp *in_mad = NULL;
107233ec1ccbSHans Petter Selasky struct ib_smp *out_mad = NULL;
107333ec1ccbSHans Petter Selasky int err = -ENOMEM;
107433ec1ccbSHans Petter Selasky
107533ec1ccbSHans Petter Selasky in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL);
107633ec1ccbSHans Petter Selasky out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
107733ec1ccbSHans Petter Selasky if (!in_mad || !out_mad)
107833ec1ccbSHans Petter Selasky goto out;
107933ec1ccbSHans Petter Selasky
108033ec1ccbSHans Petter Selasky init_query_mad(in_mad);
108133ec1ccbSHans Petter Selasky in_mad->attr_id = IB_SMP_ATTR_NODE_DESC;
108233ec1ccbSHans Petter Selasky
108333ec1ccbSHans Petter Selasky err = mthca_MAD_IFC(dev, 1, 1,
108433ec1ccbSHans Petter Selasky 1, NULL, NULL, in_mad, out_mad);
108533ec1ccbSHans Petter Selasky if (err)
108633ec1ccbSHans Petter Selasky goto out;
108733ec1ccbSHans Petter Selasky
108833ec1ccbSHans Petter Selasky memcpy(dev->ib_dev.node_desc, out_mad->data, IB_DEVICE_NODE_DESC_MAX);
108933ec1ccbSHans Petter Selasky
109033ec1ccbSHans Petter Selasky in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
109133ec1ccbSHans Petter Selasky
109233ec1ccbSHans Petter Selasky err = mthca_MAD_IFC(dev, 1, 1,
109333ec1ccbSHans Petter Selasky 1, NULL, NULL, in_mad, out_mad);
109433ec1ccbSHans Petter Selasky if (err)
109533ec1ccbSHans Petter Selasky goto out;
109633ec1ccbSHans Petter Selasky
109733ec1ccbSHans Petter Selasky if (mthca_is_memfree(dev))
109833ec1ccbSHans Petter Selasky dev->rev_id = be32_to_cpup((__be32 *) (out_mad->data + 32));
109933ec1ccbSHans Petter Selasky memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8);
110033ec1ccbSHans Petter Selasky
110133ec1ccbSHans Petter Selasky out:
110233ec1ccbSHans Petter Selasky kfree(in_mad);
110333ec1ccbSHans Petter Selasky kfree(out_mad);
110433ec1ccbSHans Petter Selasky return err;
110533ec1ccbSHans Petter Selasky }
110633ec1ccbSHans Petter Selasky
mthca_port_immutable(struct ib_device * ibdev,u8 port_num,struct ib_port_immutable * immutable)110733ec1ccbSHans Petter Selasky static int mthca_port_immutable(struct ib_device *ibdev, u8 port_num,
110833ec1ccbSHans Petter Selasky struct ib_port_immutable *immutable)
110933ec1ccbSHans Petter Selasky {
111033ec1ccbSHans Petter Selasky struct ib_port_attr attr;
111133ec1ccbSHans Petter Selasky int err;
111233ec1ccbSHans Petter Selasky
111333ec1ccbSHans Petter Selasky err = mthca_query_port(ibdev, port_num, &attr);
111433ec1ccbSHans Petter Selasky if (err)
111533ec1ccbSHans Petter Selasky return err;
111633ec1ccbSHans Petter Selasky
111733ec1ccbSHans Petter Selasky immutable->pkey_tbl_len = attr.pkey_tbl_len;
111833ec1ccbSHans Petter Selasky immutable->gid_tbl_len = attr.gid_tbl_len;
111933ec1ccbSHans Petter Selasky immutable->core_cap_flags = RDMA_CORE_PORT_IBA_IB;
112033ec1ccbSHans Petter Selasky immutable->max_mad_size = IB_MGMT_MAD_SIZE;
112133ec1ccbSHans Petter Selasky
112233ec1ccbSHans Petter Selasky return 0;
112333ec1ccbSHans Petter Selasky }
112433ec1ccbSHans Petter Selasky
get_dev_fw_str(struct ib_device * device,char * str,size_t str_len)112533ec1ccbSHans Petter Selasky static void get_dev_fw_str(struct ib_device *device, char *str,
112633ec1ccbSHans Petter Selasky size_t str_len)
112733ec1ccbSHans Petter Selasky {
112833ec1ccbSHans Petter Selasky struct mthca_dev *dev =
112933ec1ccbSHans Petter Selasky container_of(device, struct mthca_dev, ib_dev);
113033ec1ccbSHans Petter Selasky snprintf(str, str_len, "%d.%d.%d",
113133ec1ccbSHans Petter Selasky (int) (dev->fw_ver >> 32),
113233ec1ccbSHans Petter Selasky (int) (dev->fw_ver >> 16) & 0xffff,
113333ec1ccbSHans Petter Selasky (int) dev->fw_ver & 0xffff);
113433ec1ccbSHans Petter Selasky }
113533ec1ccbSHans Petter Selasky
mthca_register_device(struct mthca_dev * dev)113633ec1ccbSHans Petter Selasky int mthca_register_device(struct mthca_dev *dev)
113733ec1ccbSHans Petter Selasky {
113833ec1ccbSHans Petter Selasky int ret;
113933ec1ccbSHans Petter Selasky int i;
114033ec1ccbSHans Petter Selasky
114133ec1ccbSHans Petter Selasky ret = mthca_init_node_data(dev);
114233ec1ccbSHans Petter Selasky if (ret)
114333ec1ccbSHans Petter Selasky return ret;
114433ec1ccbSHans Petter Selasky
1145*b633e08cSHans Petter Selasky #define mthca_ib_ah mthca_ah
1146*b633e08cSHans Petter Selasky #define mthca_ib_cq mthca_cq
1147*b633e08cSHans Petter Selasky #define mthca_ib_pd mthca_pd
1148*b633e08cSHans Petter Selasky #define mthca_ib_qp mthca_qp
1149*b633e08cSHans Petter Selasky #define mthca_ib_srq mthca_srq
1150*b633e08cSHans Petter Selasky #define mthca_ib_ucontext mthca_ucontext
1151*b633e08cSHans Petter Selasky INIT_IB_DEVICE_OPS(&dev->ib_dev.ops, mthca, MTHCA);
115233ec1ccbSHans Petter Selasky strlcpy(dev->ib_dev.name, "mthca%d", IB_DEVICE_NAME_MAX);
115333ec1ccbSHans Petter Selasky dev->ib_dev.owner = THIS_MODULE;
115433ec1ccbSHans Petter Selasky
115533ec1ccbSHans Petter Selasky dev->ib_dev.uverbs_abi_ver = MTHCA_UVERBS_ABI_VERSION;
115633ec1ccbSHans Petter Selasky dev->ib_dev.uverbs_cmd_mask =
115733ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
115833ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
115933ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_QUERY_PORT) |
116033ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_ALLOC_PD) |
116133ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |
116233ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_REG_MR) |
116333ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_DEREG_MR) |
116433ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
116533ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_CREATE_CQ) |
116633ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_RESIZE_CQ) |
116733ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
116833ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_CREATE_QP) |
116933ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_QUERY_QP) |
117033ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
117133ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
117233ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) |
117333ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_DETACH_MCAST);
117433ec1ccbSHans Petter Selasky dev->ib_dev.node_type = RDMA_NODE_IB_CA;
117533ec1ccbSHans Petter Selasky dev->ib_dev.phys_port_cnt = dev->limits.num_ports;
117633ec1ccbSHans Petter Selasky dev->ib_dev.num_comp_vectors = 1;
117733ec1ccbSHans Petter Selasky dev->ib_dev.dma_device = &dev->pdev->dev;
117833ec1ccbSHans Petter Selasky dev->ib_dev.query_device = mthca_query_device;
117933ec1ccbSHans Petter Selasky dev->ib_dev.query_port = mthca_query_port;
118033ec1ccbSHans Petter Selasky dev->ib_dev.modify_device = mthca_modify_device;
118133ec1ccbSHans Petter Selasky dev->ib_dev.modify_port = mthca_modify_port;
118233ec1ccbSHans Petter Selasky dev->ib_dev.query_pkey = mthca_query_pkey;
118333ec1ccbSHans Petter Selasky dev->ib_dev.query_gid = mthca_query_gid;
118433ec1ccbSHans Petter Selasky dev->ib_dev.alloc_ucontext = mthca_alloc_ucontext;
118533ec1ccbSHans Petter Selasky dev->ib_dev.dealloc_ucontext = mthca_dealloc_ucontext;
118633ec1ccbSHans Petter Selasky dev->ib_dev.mmap = mthca_mmap_uar;
118733ec1ccbSHans Petter Selasky dev->ib_dev.alloc_pd = mthca_alloc_pd;
118833ec1ccbSHans Petter Selasky dev->ib_dev.dealloc_pd = mthca_dealloc_pd;
118933ec1ccbSHans Petter Selasky dev->ib_dev.create_ah = mthca_ah_create;
119033ec1ccbSHans Petter Selasky dev->ib_dev.query_ah = mthca_ah_query;
119133ec1ccbSHans Petter Selasky dev->ib_dev.destroy_ah = mthca_ah_destroy;
119233ec1ccbSHans Petter Selasky
119333ec1ccbSHans Petter Selasky if (dev->mthca_flags & MTHCA_FLAG_SRQ) {
119433ec1ccbSHans Petter Selasky dev->ib_dev.create_srq = mthca_create_srq;
119533ec1ccbSHans Petter Selasky dev->ib_dev.modify_srq = mthca_modify_srq;
119633ec1ccbSHans Petter Selasky dev->ib_dev.query_srq = mthca_query_srq;
119733ec1ccbSHans Petter Selasky dev->ib_dev.destroy_srq = mthca_destroy_srq;
119833ec1ccbSHans Petter Selasky dev->ib_dev.uverbs_cmd_mask |=
119933ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) |
120033ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) |
120133ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) |
120233ec1ccbSHans Petter Selasky (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ);
120333ec1ccbSHans Petter Selasky
120433ec1ccbSHans Petter Selasky if (mthca_is_memfree(dev))
120533ec1ccbSHans Petter Selasky dev->ib_dev.post_srq_recv = mthca_arbel_post_srq_recv;
120633ec1ccbSHans Petter Selasky else
120733ec1ccbSHans Petter Selasky dev->ib_dev.post_srq_recv = mthca_tavor_post_srq_recv;
120833ec1ccbSHans Petter Selasky }
120933ec1ccbSHans Petter Selasky
121033ec1ccbSHans Petter Selasky dev->ib_dev.create_qp = mthca_create_qp;
121133ec1ccbSHans Petter Selasky dev->ib_dev.modify_qp = mthca_modify_qp;
121233ec1ccbSHans Petter Selasky dev->ib_dev.query_qp = mthca_query_qp;
121333ec1ccbSHans Petter Selasky dev->ib_dev.destroy_qp = mthca_destroy_qp;
121433ec1ccbSHans Petter Selasky dev->ib_dev.create_cq = mthca_create_cq;
121533ec1ccbSHans Petter Selasky dev->ib_dev.resize_cq = mthca_resize_cq;
121633ec1ccbSHans Petter Selasky dev->ib_dev.destroy_cq = mthca_destroy_cq;
121733ec1ccbSHans Petter Selasky dev->ib_dev.poll_cq = mthca_poll_cq;
121833ec1ccbSHans Petter Selasky dev->ib_dev.get_dma_mr = mthca_get_dma_mr;
121933ec1ccbSHans Petter Selasky dev->ib_dev.reg_user_mr = mthca_reg_user_mr;
122033ec1ccbSHans Petter Selasky dev->ib_dev.dereg_mr = mthca_dereg_mr;
122133ec1ccbSHans Petter Selasky dev->ib_dev.get_port_immutable = mthca_port_immutable;
122233ec1ccbSHans Petter Selasky dev->ib_dev.get_dev_fw_str = get_dev_fw_str;
122333ec1ccbSHans Petter Selasky
122433ec1ccbSHans Petter Selasky if (dev->mthca_flags & MTHCA_FLAG_FMR) {
122533ec1ccbSHans Petter Selasky dev->ib_dev.alloc_fmr = mthca_alloc_fmr;
122633ec1ccbSHans Petter Selasky dev->ib_dev.unmap_fmr = mthca_unmap_fmr;
122733ec1ccbSHans Petter Selasky dev->ib_dev.dealloc_fmr = mthca_dealloc_fmr;
122833ec1ccbSHans Petter Selasky if (mthca_is_memfree(dev))
122933ec1ccbSHans Petter Selasky dev->ib_dev.map_phys_fmr = mthca_arbel_map_phys_fmr;
123033ec1ccbSHans Petter Selasky else
123133ec1ccbSHans Petter Selasky dev->ib_dev.map_phys_fmr = mthca_tavor_map_phys_fmr;
123233ec1ccbSHans Petter Selasky }
123333ec1ccbSHans Petter Selasky
123433ec1ccbSHans Petter Selasky dev->ib_dev.attach_mcast = mthca_multicast_attach;
123533ec1ccbSHans Petter Selasky dev->ib_dev.detach_mcast = mthca_multicast_detach;
123633ec1ccbSHans Petter Selasky dev->ib_dev.process_mad = mthca_process_mad;
123733ec1ccbSHans Petter Selasky
123833ec1ccbSHans Petter Selasky if (mthca_is_memfree(dev)) {
123933ec1ccbSHans Petter Selasky dev->ib_dev.req_notify_cq = mthca_arbel_arm_cq;
124033ec1ccbSHans Petter Selasky dev->ib_dev.post_send = mthca_arbel_post_send;
124133ec1ccbSHans Petter Selasky dev->ib_dev.post_recv = mthca_arbel_post_receive;
124233ec1ccbSHans Petter Selasky } else {
124333ec1ccbSHans Petter Selasky dev->ib_dev.req_notify_cq = mthca_tavor_arm_cq;
124433ec1ccbSHans Petter Selasky dev->ib_dev.post_send = mthca_tavor_post_send;
124533ec1ccbSHans Petter Selasky dev->ib_dev.post_recv = mthca_tavor_post_receive;
124633ec1ccbSHans Petter Selasky }
124733ec1ccbSHans Petter Selasky
124833ec1ccbSHans Petter Selasky mutex_init(&dev->cap_mask_mutex);
124933ec1ccbSHans Petter Selasky
125033ec1ccbSHans Petter Selasky ret = ib_register_device(&dev->ib_dev, NULL);
125133ec1ccbSHans Petter Selasky if (ret)
125233ec1ccbSHans Petter Selasky return ret;
125333ec1ccbSHans Petter Selasky
125433ec1ccbSHans Petter Selasky for (i = 0; i < ARRAY_SIZE(mthca_dev_attributes); ++i) {
125533ec1ccbSHans Petter Selasky ret = device_create_file(&dev->ib_dev.dev,
125633ec1ccbSHans Petter Selasky mthca_dev_attributes[i]);
125733ec1ccbSHans Petter Selasky if (ret) {
125833ec1ccbSHans Petter Selasky ib_unregister_device(&dev->ib_dev);
125933ec1ccbSHans Petter Selasky return ret;
126033ec1ccbSHans Petter Selasky }
126133ec1ccbSHans Petter Selasky }
126233ec1ccbSHans Petter Selasky
126333ec1ccbSHans Petter Selasky mthca_start_catas_poll(dev);
126433ec1ccbSHans Petter Selasky
126533ec1ccbSHans Petter Selasky return 0;
126633ec1ccbSHans Petter Selasky }
126733ec1ccbSHans Petter Selasky
mthca_unregister_device(struct mthca_dev * dev)126833ec1ccbSHans Petter Selasky void mthca_unregister_device(struct mthca_dev *dev)
126933ec1ccbSHans Petter Selasky {
127033ec1ccbSHans Petter Selasky mthca_stop_catas_poll(dev);
127133ec1ccbSHans Petter Selasky ib_unregister_device(&dev->ib_dev);
127233ec1ccbSHans Petter Selasky }
1273