Path: blob/master/drivers/infiniband/hw/mthca/mthca_provider.c
15112 views
/*1* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.2* Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.3* Copyright (c) 2005, 2006 Cisco Systems. All rights reserved.4* Copyright (c) 2005 Mellanox Technologies. All rights reserved.5* Copyright (c) 2004 Voltaire, Inc. All rights reserved.6*7* This software is available to you under a choice of one of two8* licenses. You may choose to be licensed under the terms of the GNU9* General Public License (GPL) Version 2, available from the file10* COPYING in the main directory of this source tree, or the11* OpenIB.org BSD license below:12*13* Redistribution and use in source and binary forms, with or14* without modification, are permitted provided that the following15* conditions are met:16*17* - Redistributions of source code must retain the above18* copyright notice, this list of conditions and the following19* disclaimer.20*21* - Redistributions in binary form must reproduce the above22* copyright notice, this list of conditions and the following23* disclaimer in the documentation and/or other materials24* provided with the distribution.25*26* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,27* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF28* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND29* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS30* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN31* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN32* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE33* SOFTWARE.34*/3536#include <rdma/ib_smi.h>37#include <rdma/ib_umem.h>38#include <rdma/ib_user_verbs.h>3940#include <linux/sched.h>41#include <linux/slab.h>42#include <linux/mm.h>4344#include "mthca_dev.h"45#include "mthca_cmd.h"46#include "mthca_user.h"47#include "mthca_memfree.h"4849static void init_query_mad(struct ib_smp *mad)50{51mad->base_version = 1;52mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;53mad->class_version = 1;54mad->method = IB_MGMT_METHOD_GET;55}5657static int mthca_query_device(struct ib_device *ibdev,58struct ib_device_attr *props)59{60struct ib_smp *in_mad = NULL;61struct ib_smp *out_mad = NULL;62int err = -ENOMEM;63struct mthca_dev *mdev = to_mdev(ibdev);6465u8 status;6667in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL);68out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);69if (!in_mad || !out_mad)70goto out;7172memset(props, 0, sizeof *props);7374props->fw_ver = mdev->fw_ver;7576init_query_mad(in_mad);77in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;7879err = mthca_MAD_IFC(mdev, 1, 1,801, NULL, NULL, in_mad, out_mad,81&status);82if (err)83goto out;84if (status) {85err = -EINVAL;86goto out;87}8889props->device_cap_flags = mdev->device_cap_flags;90props->vendor_id = be32_to_cpup((__be32 *) (out_mad->data + 36)) &910xffffff;92props->vendor_part_id = be16_to_cpup((__be16 *) (out_mad->data + 30));93props->hw_ver = be32_to_cpup((__be32 *) (out_mad->data + 32));94memcpy(&props->sys_image_guid, out_mad->data + 4, 8);9596props->max_mr_size = ~0ull;97props->page_size_cap = mdev->limits.page_size_cap;98props->max_qp = mdev->limits.num_qps - mdev->limits.reserved_qps;99props->max_qp_wr = mdev->limits.max_wqes;100props->max_sge = mdev->limits.max_sg;101props->max_cq = mdev->limits.num_cqs - mdev->limits.reserved_cqs;102props->max_cqe = mdev->limits.max_cqes;103props->max_mr = mdev->limits.num_mpts - mdev->limits.reserved_mrws;104props->max_pd = mdev->limits.num_pds - mdev->limits.reserved_pds;105props->max_qp_rd_atom = 1 << mdev->qp_table.rdb_shift;106props->max_qp_init_rd_atom = mdev->limits.max_qp_init_rdma;107props->max_res_rd_atom = props->max_qp_rd_atom * props->max_qp;108props->max_srq = mdev->limits.num_srqs - mdev->limits.reserved_srqs;109props->max_srq_wr = mdev->limits.max_srq_wqes;110props->max_srq_sge = mdev->limits.max_srq_sge;111props->local_ca_ack_delay = mdev->limits.local_ca_ack_delay;112props->atomic_cap = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ?113IB_ATOMIC_HCA : IB_ATOMIC_NONE;114props->max_pkeys = mdev->limits.pkey_table_len;115props->max_mcast_grp = mdev->limits.num_mgms + mdev->limits.num_amgms;116props->max_mcast_qp_attach = MTHCA_QP_PER_MGM;117props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *118props->max_mcast_grp;119/*120* If Sinai memory key optimization is being used, then only121* the 8-bit key portion will change. For other HCAs, the122* unused index bits will also be used for FMR remapping.123*/124if (mdev->mthca_flags & MTHCA_FLAG_SINAI_OPT)125props->max_map_per_fmr = 255;126else127props->max_map_per_fmr =128(1 << (32 - ilog2(mdev->limits.num_mpts))) - 1;129130err = 0;131out:132kfree(in_mad);133kfree(out_mad);134return err;135}136137static int mthca_query_port(struct ib_device *ibdev,138u8 port, struct ib_port_attr *props)139{140struct ib_smp *in_mad = NULL;141struct ib_smp *out_mad = NULL;142int err = -ENOMEM;143u8 status;144145in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL);146out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);147if (!in_mad || !out_mad)148goto out;149150memset(props, 0, sizeof *props);151152init_query_mad(in_mad);153in_mad->attr_id = IB_SMP_ATTR_PORT_INFO;154in_mad->attr_mod = cpu_to_be32(port);155156err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,157port, NULL, NULL, in_mad, out_mad,158&status);159if (err)160goto out;161if (status) {162err = -EINVAL;163goto out;164}165166props->lid = be16_to_cpup((__be16 *) (out_mad->data + 16));167props->lmc = out_mad->data[34] & 0x7;168props->sm_lid = be16_to_cpup((__be16 *) (out_mad->data + 18));169props->sm_sl = out_mad->data[36] & 0xf;170props->state = out_mad->data[32] & 0xf;171props->phys_state = out_mad->data[33] >> 4;172props->port_cap_flags = be32_to_cpup((__be32 *) (out_mad->data + 20));173props->gid_tbl_len = to_mdev(ibdev)->limits.gid_table_len;174props->max_msg_sz = 0x80000000;175props->pkey_tbl_len = to_mdev(ibdev)->limits.pkey_table_len;176props->bad_pkey_cntr = be16_to_cpup((__be16 *) (out_mad->data + 46));177props->qkey_viol_cntr = be16_to_cpup((__be16 *) (out_mad->data + 48));178props->active_width = out_mad->data[31] & 0xf;179props->active_speed = out_mad->data[35] >> 4;180props->max_mtu = out_mad->data[41] & 0xf;181props->active_mtu = out_mad->data[36] >> 4;182props->subnet_timeout = out_mad->data[51] & 0x1f;183props->max_vl_num = out_mad->data[37] >> 4;184props->init_type_reply = out_mad->data[41] >> 4;185186out:187kfree(in_mad);188kfree(out_mad);189return err;190}191192static int mthca_modify_device(struct ib_device *ibdev,193int mask,194struct ib_device_modify *props)195{196if (mask & ~IB_DEVICE_MODIFY_NODE_DESC)197return -EOPNOTSUPP;198199if (mask & IB_DEVICE_MODIFY_NODE_DESC) {200if (mutex_lock_interruptible(&to_mdev(ibdev)->cap_mask_mutex))201return -ERESTARTSYS;202memcpy(ibdev->node_desc, props->node_desc, 64);203mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex);204}205206return 0;207}208209static int mthca_modify_port(struct ib_device *ibdev,210u8 port, int port_modify_mask,211struct ib_port_modify *props)212{213struct mthca_set_ib_param set_ib;214struct ib_port_attr attr;215int err;216u8 status;217218if (mutex_lock_interruptible(&to_mdev(ibdev)->cap_mask_mutex))219return -ERESTARTSYS;220221err = mthca_query_port(ibdev, port, &attr);222if (err)223goto out;224225set_ib.set_si_guid = 0;226set_ib.reset_qkey_viol = !!(port_modify_mask & IB_PORT_RESET_QKEY_CNTR);227228set_ib.cap_mask = (attr.port_cap_flags | props->set_port_cap_mask) &229~props->clr_port_cap_mask;230231err = mthca_SET_IB(to_mdev(ibdev), &set_ib, port, &status);232if (err)233goto out;234if (status) {235err = -EINVAL;236goto out;237}238239out:240mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex);241return err;242}243244static int mthca_query_pkey(struct ib_device *ibdev,245u8 port, u16 index, u16 *pkey)246{247struct ib_smp *in_mad = NULL;248struct ib_smp *out_mad = NULL;249int err = -ENOMEM;250u8 status;251252in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL);253out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);254if (!in_mad || !out_mad)255goto out;256257init_query_mad(in_mad);258in_mad->attr_id = IB_SMP_ATTR_PKEY_TABLE;259in_mad->attr_mod = cpu_to_be32(index / 32);260261err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,262port, NULL, NULL, in_mad, out_mad,263&status);264if (err)265goto out;266if (status) {267err = -EINVAL;268goto out;269}270271*pkey = be16_to_cpu(((__be16 *) out_mad->data)[index % 32]);272273out:274kfree(in_mad);275kfree(out_mad);276return err;277}278279static int mthca_query_gid(struct ib_device *ibdev, u8 port,280int index, union ib_gid *gid)281{282struct ib_smp *in_mad = NULL;283struct ib_smp *out_mad = NULL;284int err = -ENOMEM;285u8 status;286287in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL);288out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);289if (!in_mad || !out_mad)290goto out;291292init_query_mad(in_mad);293in_mad->attr_id = IB_SMP_ATTR_PORT_INFO;294in_mad->attr_mod = cpu_to_be32(port);295296err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,297port, NULL, NULL, in_mad, out_mad,298&status);299if (err)300goto out;301if (status) {302err = -EINVAL;303goto out;304}305306memcpy(gid->raw, out_mad->data + 8, 8);307308init_query_mad(in_mad);309in_mad->attr_id = IB_SMP_ATTR_GUID_INFO;310in_mad->attr_mod = cpu_to_be32(index / 8);311312err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,313port, NULL, NULL, in_mad, out_mad,314&status);315if (err)316goto out;317if (status) {318err = -EINVAL;319goto out;320}321322memcpy(gid->raw + 8, out_mad->data + (index % 8) * 8, 8);323324out:325kfree(in_mad);326kfree(out_mad);327return err;328}329330static struct ib_ucontext *mthca_alloc_ucontext(struct ib_device *ibdev,331struct ib_udata *udata)332{333struct mthca_alloc_ucontext_resp uresp;334struct mthca_ucontext *context;335int err;336337if (!(to_mdev(ibdev)->active))338return ERR_PTR(-EAGAIN);339340memset(&uresp, 0, sizeof uresp);341342uresp.qp_tab_size = to_mdev(ibdev)->limits.num_qps;343if (mthca_is_memfree(to_mdev(ibdev)))344uresp.uarc_size = to_mdev(ibdev)->uar_table.uarc_size;345else346uresp.uarc_size = 0;347348context = kmalloc(sizeof *context, GFP_KERNEL);349if (!context)350return ERR_PTR(-ENOMEM);351352err = mthca_uar_alloc(to_mdev(ibdev), &context->uar);353if (err) {354kfree(context);355return ERR_PTR(err);356}357358context->db_tab = mthca_init_user_db_tab(to_mdev(ibdev));359if (IS_ERR(context->db_tab)) {360err = PTR_ERR(context->db_tab);361mthca_uar_free(to_mdev(ibdev), &context->uar);362kfree(context);363return ERR_PTR(err);364}365366if (ib_copy_to_udata(udata, &uresp, sizeof uresp)) {367mthca_cleanup_user_db_tab(to_mdev(ibdev), &context->uar, context->db_tab);368mthca_uar_free(to_mdev(ibdev), &context->uar);369kfree(context);370return ERR_PTR(-EFAULT);371}372373context->reg_mr_warned = 0;374375return &context->ibucontext;376}377378static int mthca_dealloc_ucontext(struct ib_ucontext *context)379{380mthca_cleanup_user_db_tab(to_mdev(context->device), &to_mucontext(context)->uar,381to_mucontext(context)->db_tab);382mthca_uar_free(to_mdev(context->device), &to_mucontext(context)->uar);383kfree(to_mucontext(context));384385return 0;386}387388static int mthca_mmap_uar(struct ib_ucontext *context,389struct vm_area_struct *vma)390{391if (vma->vm_end - vma->vm_start != PAGE_SIZE)392return -EINVAL;393394vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);395396if (io_remap_pfn_range(vma, vma->vm_start,397to_mucontext(context)->uar.pfn,398PAGE_SIZE, vma->vm_page_prot))399return -EAGAIN;400401return 0;402}403404static struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev,405struct ib_ucontext *context,406struct ib_udata *udata)407{408struct mthca_pd *pd;409int err;410411pd = kmalloc(sizeof *pd, GFP_KERNEL);412if (!pd)413return ERR_PTR(-ENOMEM);414415err = mthca_pd_alloc(to_mdev(ibdev), !context, pd);416if (err) {417kfree(pd);418return ERR_PTR(err);419}420421if (context) {422if (ib_copy_to_udata(udata, &pd->pd_num, sizeof (__u32))) {423mthca_pd_free(to_mdev(ibdev), pd);424kfree(pd);425return ERR_PTR(-EFAULT);426}427}428429return &pd->ibpd;430}431432static int mthca_dealloc_pd(struct ib_pd *pd)433{434mthca_pd_free(to_mdev(pd->device), to_mpd(pd));435kfree(pd);436437return 0;438}439440static struct ib_ah *mthca_ah_create(struct ib_pd *pd,441struct ib_ah_attr *ah_attr)442{443int err;444struct mthca_ah *ah;445446ah = kmalloc(sizeof *ah, GFP_ATOMIC);447if (!ah)448return ERR_PTR(-ENOMEM);449450err = mthca_create_ah(to_mdev(pd->device), to_mpd(pd), ah_attr, ah);451if (err) {452kfree(ah);453return ERR_PTR(err);454}455456return &ah->ibah;457}458459static int mthca_ah_destroy(struct ib_ah *ah)460{461mthca_destroy_ah(to_mdev(ah->device), to_mah(ah));462kfree(ah);463464return 0;465}466467static struct ib_srq *mthca_create_srq(struct ib_pd *pd,468struct ib_srq_init_attr *init_attr,469struct ib_udata *udata)470{471struct mthca_create_srq ucmd;472struct mthca_ucontext *context = NULL;473struct mthca_srq *srq;474int err;475476srq = kmalloc(sizeof *srq, GFP_KERNEL);477if (!srq)478return ERR_PTR(-ENOMEM);479480if (pd->uobject) {481context = to_mucontext(pd->uobject->context);482483if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) {484err = -EFAULT;485goto err_free;486}487488err = mthca_map_user_db(to_mdev(pd->device), &context->uar,489context->db_tab, ucmd.db_index,490ucmd.db_page);491492if (err)493goto err_free;494495srq->mr.ibmr.lkey = ucmd.lkey;496srq->db_index = ucmd.db_index;497}498499err = mthca_alloc_srq(to_mdev(pd->device), to_mpd(pd),500&init_attr->attr, srq);501502if (err && pd->uobject)503mthca_unmap_user_db(to_mdev(pd->device), &context->uar,504context->db_tab, ucmd.db_index);505506if (err)507goto err_free;508509if (context && ib_copy_to_udata(udata, &srq->srqn, sizeof (__u32))) {510mthca_free_srq(to_mdev(pd->device), srq);511err = -EFAULT;512goto err_free;513}514515return &srq->ibsrq;516517err_free:518kfree(srq);519520return ERR_PTR(err);521}522523static int mthca_destroy_srq(struct ib_srq *srq)524{525struct mthca_ucontext *context;526527if (srq->uobject) {528context = to_mucontext(srq->uobject->context);529530mthca_unmap_user_db(to_mdev(srq->device), &context->uar,531context->db_tab, to_msrq(srq)->db_index);532}533534mthca_free_srq(to_mdev(srq->device), to_msrq(srq));535kfree(srq);536537return 0;538}539540static struct ib_qp *mthca_create_qp(struct ib_pd *pd,541struct ib_qp_init_attr *init_attr,542struct ib_udata *udata)543{544struct mthca_create_qp ucmd;545struct mthca_qp *qp;546int err;547548if (init_attr->create_flags)549return ERR_PTR(-EINVAL);550551switch (init_attr->qp_type) {552case IB_QPT_RC:553case IB_QPT_UC:554case IB_QPT_UD:555{556struct mthca_ucontext *context;557558qp = kmalloc(sizeof *qp, GFP_KERNEL);559if (!qp)560return ERR_PTR(-ENOMEM);561562if (pd->uobject) {563context = to_mucontext(pd->uobject->context);564565if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) {566kfree(qp);567return ERR_PTR(-EFAULT);568}569570err = mthca_map_user_db(to_mdev(pd->device), &context->uar,571context->db_tab,572ucmd.sq_db_index, ucmd.sq_db_page);573if (err) {574kfree(qp);575return ERR_PTR(err);576}577578err = mthca_map_user_db(to_mdev(pd->device), &context->uar,579context->db_tab,580ucmd.rq_db_index, ucmd.rq_db_page);581if (err) {582mthca_unmap_user_db(to_mdev(pd->device),583&context->uar,584context->db_tab,585ucmd.sq_db_index);586kfree(qp);587return ERR_PTR(err);588}589590qp->mr.ibmr.lkey = ucmd.lkey;591qp->sq.db_index = ucmd.sq_db_index;592qp->rq.db_index = ucmd.rq_db_index;593}594595err = mthca_alloc_qp(to_mdev(pd->device), to_mpd(pd),596to_mcq(init_attr->send_cq),597to_mcq(init_attr->recv_cq),598init_attr->qp_type, init_attr->sq_sig_type,599&init_attr->cap, qp);600601if (err && pd->uobject) {602context = to_mucontext(pd->uobject->context);603604mthca_unmap_user_db(to_mdev(pd->device),605&context->uar,606context->db_tab,607ucmd.sq_db_index);608mthca_unmap_user_db(to_mdev(pd->device),609&context->uar,610context->db_tab,611ucmd.rq_db_index);612}613614qp->ibqp.qp_num = qp->qpn;615break;616}617case IB_QPT_SMI:618case IB_QPT_GSI:619{620/* Don't allow userspace to create special QPs */621if (pd->uobject)622return ERR_PTR(-EINVAL);623624qp = kmalloc(sizeof (struct mthca_sqp), GFP_KERNEL);625if (!qp)626return ERR_PTR(-ENOMEM);627628qp->ibqp.qp_num = init_attr->qp_type == IB_QPT_SMI ? 0 : 1;629630err = mthca_alloc_sqp(to_mdev(pd->device), to_mpd(pd),631to_mcq(init_attr->send_cq),632to_mcq(init_attr->recv_cq),633init_attr->sq_sig_type, &init_attr->cap,634qp->ibqp.qp_num, init_attr->port_num,635to_msqp(qp));636break;637}638default:639/* Don't support raw QPs */640return ERR_PTR(-ENOSYS);641}642643if (err) {644kfree(qp);645return ERR_PTR(err);646}647648init_attr->cap.max_send_wr = qp->sq.max;649init_attr->cap.max_recv_wr = qp->rq.max;650init_attr->cap.max_send_sge = qp->sq.max_gs;651init_attr->cap.max_recv_sge = qp->rq.max_gs;652init_attr->cap.max_inline_data = qp->max_inline_data;653654return &qp->ibqp;655}656657static int mthca_destroy_qp(struct ib_qp *qp)658{659if (qp->uobject) {660mthca_unmap_user_db(to_mdev(qp->device),661&to_mucontext(qp->uobject->context)->uar,662to_mucontext(qp->uobject->context)->db_tab,663to_mqp(qp)->sq.db_index);664mthca_unmap_user_db(to_mdev(qp->device),665&to_mucontext(qp->uobject->context)->uar,666to_mucontext(qp->uobject->context)->db_tab,667to_mqp(qp)->rq.db_index);668}669mthca_free_qp(to_mdev(qp->device), to_mqp(qp));670kfree(qp);671return 0;672}673674static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries,675int comp_vector,676struct ib_ucontext *context,677struct ib_udata *udata)678{679struct mthca_create_cq ucmd;680struct mthca_cq *cq;681int nent;682int err;683684if (entries < 1 || entries > to_mdev(ibdev)->limits.max_cqes)685return ERR_PTR(-EINVAL);686687if (context) {688if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))689return ERR_PTR(-EFAULT);690691err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,692to_mucontext(context)->db_tab,693ucmd.set_db_index, ucmd.set_db_page);694if (err)695return ERR_PTR(err);696697err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,698to_mucontext(context)->db_tab,699ucmd.arm_db_index, ucmd.arm_db_page);700if (err)701goto err_unmap_set;702}703704cq = kmalloc(sizeof *cq, GFP_KERNEL);705if (!cq) {706err = -ENOMEM;707goto err_unmap_arm;708}709710if (context) {711cq->buf.mr.ibmr.lkey = ucmd.lkey;712cq->set_ci_db_index = ucmd.set_db_index;713cq->arm_db_index = ucmd.arm_db_index;714}715716for (nent = 1; nent <= entries; nent <<= 1)717; /* nothing */718719err = mthca_init_cq(to_mdev(ibdev), nent,720context ? to_mucontext(context) : NULL,721context ? ucmd.pdn : to_mdev(ibdev)->driver_pd.pd_num,722cq);723if (err)724goto err_free;725726if (context && ib_copy_to_udata(udata, &cq->cqn, sizeof (__u32))) {727mthca_free_cq(to_mdev(ibdev), cq);728goto err_free;729}730731cq->resize_buf = NULL;732733return &cq->ibcq;734735err_free:736kfree(cq);737738err_unmap_arm:739if (context)740mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,741to_mucontext(context)->db_tab, ucmd.arm_db_index);742743err_unmap_set:744if (context)745mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,746to_mucontext(context)->db_tab, ucmd.set_db_index);747748return ERR_PTR(err);749}750751static int mthca_alloc_resize_buf(struct mthca_dev *dev, struct mthca_cq *cq,752int entries)753{754int ret;755756spin_lock_irq(&cq->lock);757if (cq->resize_buf) {758ret = -EBUSY;759goto unlock;760}761762cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_ATOMIC);763if (!cq->resize_buf) {764ret = -ENOMEM;765goto unlock;766}767768cq->resize_buf->state = CQ_RESIZE_ALLOC;769770ret = 0;771772unlock:773spin_unlock_irq(&cq->lock);774775if (ret)776return ret;777778ret = mthca_alloc_cq_buf(dev, &cq->resize_buf->buf, entries);779if (ret) {780spin_lock_irq(&cq->lock);781kfree(cq->resize_buf);782cq->resize_buf = NULL;783spin_unlock_irq(&cq->lock);784return ret;785}786787cq->resize_buf->cqe = entries - 1;788789spin_lock_irq(&cq->lock);790cq->resize_buf->state = CQ_RESIZE_READY;791spin_unlock_irq(&cq->lock);792793return 0;794}795796static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)797{798struct mthca_dev *dev = to_mdev(ibcq->device);799struct mthca_cq *cq = to_mcq(ibcq);800struct mthca_resize_cq ucmd;801u32 lkey;802u8 status;803int ret;804805if (entries < 1 || entries > dev->limits.max_cqes)806return -EINVAL;807808mutex_lock(&cq->mutex);809810entries = roundup_pow_of_two(entries + 1);811if (entries == ibcq->cqe + 1) {812ret = 0;813goto out;814}815816if (cq->is_kernel) {817ret = mthca_alloc_resize_buf(dev, cq, entries);818if (ret)819goto out;820lkey = cq->resize_buf->buf.mr.ibmr.lkey;821} else {822if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) {823ret = -EFAULT;824goto out;825}826lkey = ucmd.lkey;827}828829ret = mthca_RESIZE_CQ(dev, cq->cqn, lkey, ilog2(entries), &status);830if (status)831ret = -EINVAL;832833if (ret) {834if (cq->resize_buf) {835mthca_free_cq_buf(dev, &cq->resize_buf->buf,836cq->resize_buf->cqe);837kfree(cq->resize_buf);838spin_lock_irq(&cq->lock);839cq->resize_buf = NULL;840spin_unlock_irq(&cq->lock);841}842goto out;843}844845if (cq->is_kernel) {846struct mthca_cq_buf tbuf;847int tcqe;848849spin_lock_irq(&cq->lock);850if (cq->resize_buf->state == CQ_RESIZE_READY) {851mthca_cq_resize_copy_cqes(cq);852tbuf = cq->buf;853tcqe = cq->ibcq.cqe;854cq->buf = cq->resize_buf->buf;855cq->ibcq.cqe = cq->resize_buf->cqe;856} else {857tbuf = cq->resize_buf->buf;858tcqe = cq->resize_buf->cqe;859}860861kfree(cq->resize_buf);862cq->resize_buf = NULL;863spin_unlock_irq(&cq->lock);864865mthca_free_cq_buf(dev, &tbuf, tcqe);866} else867ibcq->cqe = entries - 1;868869out:870mutex_unlock(&cq->mutex);871872return ret;873}874875static int mthca_destroy_cq(struct ib_cq *cq)876{877if (cq->uobject) {878mthca_unmap_user_db(to_mdev(cq->device),879&to_mucontext(cq->uobject->context)->uar,880to_mucontext(cq->uobject->context)->db_tab,881to_mcq(cq)->arm_db_index);882mthca_unmap_user_db(to_mdev(cq->device),883&to_mucontext(cq->uobject->context)->uar,884to_mucontext(cq->uobject->context)->db_tab,885to_mcq(cq)->set_ci_db_index);886}887mthca_free_cq(to_mdev(cq->device), to_mcq(cq));888kfree(cq);889890return 0;891}892893static inline u32 convert_access(int acc)894{895return (acc & IB_ACCESS_REMOTE_ATOMIC ? MTHCA_MPT_FLAG_ATOMIC : 0) |896(acc & IB_ACCESS_REMOTE_WRITE ? MTHCA_MPT_FLAG_REMOTE_WRITE : 0) |897(acc & IB_ACCESS_REMOTE_READ ? MTHCA_MPT_FLAG_REMOTE_READ : 0) |898(acc & IB_ACCESS_LOCAL_WRITE ? MTHCA_MPT_FLAG_LOCAL_WRITE : 0) |899MTHCA_MPT_FLAG_LOCAL_READ;900}901902static struct ib_mr *mthca_get_dma_mr(struct ib_pd *pd, int acc)903{904struct mthca_mr *mr;905int err;906907mr = kmalloc(sizeof *mr, GFP_KERNEL);908if (!mr)909return ERR_PTR(-ENOMEM);910911err = mthca_mr_alloc_notrans(to_mdev(pd->device),912to_mpd(pd)->pd_num,913convert_access(acc), mr);914915if (err) {916kfree(mr);917return ERR_PTR(err);918}919920mr->umem = NULL;921922return &mr->ibmr;923}924925static struct ib_mr *mthca_reg_phys_mr(struct ib_pd *pd,926struct ib_phys_buf *buffer_list,927int num_phys_buf,928int acc,929u64 *iova_start)930{931struct mthca_mr *mr;932u64 *page_list;933u64 total_size;934unsigned long mask;935int shift;936int npages;937int err;938int i, j, n;939940mask = buffer_list[0].addr ^ *iova_start;941total_size = 0;942for (i = 0; i < num_phys_buf; ++i) {943if (i != 0)944mask |= buffer_list[i].addr;945if (i != num_phys_buf - 1)946mask |= buffer_list[i].addr + buffer_list[i].size;947948total_size += buffer_list[i].size;949}950951if (mask & ~PAGE_MASK)952return ERR_PTR(-EINVAL);953954shift = __ffs(mask | 1 << 31);955956buffer_list[0].size += buffer_list[0].addr & ((1ULL << shift) - 1);957buffer_list[0].addr &= ~0ull << shift;958959mr = kmalloc(sizeof *mr, GFP_KERNEL);960if (!mr)961return ERR_PTR(-ENOMEM);962963npages = 0;964for (i = 0; i < num_phys_buf; ++i)965npages += (buffer_list[i].size + (1ULL << shift) - 1) >> shift;966967if (!npages)968return &mr->ibmr;969970page_list = kmalloc(npages * sizeof *page_list, GFP_KERNEL);971if (!page_list) {972kfree(mr);973return ERR_PTR(-ENOMEM);974}975976n = 0;977for (i = 0; i < num_phys_buf; ++i)978for (j = 0;979j < (buffer_list[i].size + (1ULL << shift) - 1) >> shift;980++j)981page_list[n++] = buffer_list[i].addr + ((u64) j << shift);982983mthca_dbg(to_mdev(pd->device), "Registering memory at %llx (iova %llx) "984"in PD %x; shift %d, npages %d.\n",985(unsigned long long) buffer_list[0].addr,986(unsigned long long) *iova_start,987to_mpd(pd)->pd_num,988shift, npages);989990err = mthca_mr_alloc_phys(to_mdev(pd->device),991to_mpd(pd)->pd_num,992page_list, shift, npages,993*iova_start, total_size,994convert_access(acc), mr);995996if (err) {997kfree(page_list);998kfree(mr);999return ERR_PTR(err);1000}10011002kfree(page_list);1003mr->umem = NULL;10041005return &mr->ibmr;1006}10071008static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,1009u64 virt, int acc, struct ib_udata *udata)1010{1011struct mthca_dev *dev = to_mdev(pd->device);1012struct ib_umem_chunk *chunk;1013struct mthca_mr *mr;1014struct mthca_reg_mr ucmd;1015u64 *pages;1016int shift, n, len;1017int i, j, k;1018int err = 0;1019int write_mtt_size;10201021if (udata->inlen - sizeof (struct ib_uverbs_cmd_hdr) < sizeof ucmd) {1022if (!to_mucontext(pd->uobject->context)->reg_mr_warned) {1023mthca_warn(dev, "Process '%s' did not pass in MR attrs.\n",1024current->comm);1025mthca_warn(dev, " Update libmthca to fix this.\n");1026}1027++to_mucontext(pd->uobject->context)->reg_mr_warned;1028ucmd.mr_attrs = 0;1029} else if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))1030return ERR_PTR(-EFAULT);10311032mr = kmalloc(sizeof *mr, GFP_KERNEL);1033if (!mr)1034return ERR_PTR(-ENOMEM);10351036mr->umem = ib_umem_get(pd->uobject->context, start, length, acc,1037ucmd.mr_attrs & MTHCA_MR_DMASYNC);10381039if (IS_ERR(mr->umem)) {1040err = PTR_ERR(mr->umem);1041goto err;1042}10431044shift = ffs(mr->umem->page_size) - 1;10451046n = 0;1047list_for_each_entry(chunk, &mr->umem->chunk_list, list)1048n += chunk->nents;10491050mr->mtt = mthca_alloc_mtt(dev, n);1051if (IS_ERR(mr->mtt)) {1052err = PTR_ERR(mr->mtt);1053goto err_umem;1054}10551056pages = (u64 *) __get_free_page(GFP_KERNEL);1057if (!pages) {1058err = -ENOMEM;1059goto err_mtt;1060}10611062i = n = 0;10631064write_mtt_size = min(mthca_write_mtt_size(dev), (int) (PAGE_SIZE / sizeof *pages));10651066list_for_each_entry(chunk, &mr->umem->chunk_list, list)1067for (j = 0; j < chunk->nmap; ++j) {1068len = sg_dma_len(&chunk->page_list[j]) >> shift;1069for (k = 0; k < len; ++k) {1070pages[i++] = sg_dma_address(&chunk->page_list[j]) +1071mr->umem->page_size * k;1072/*1073* Be friendly to write_mtt and pass it chunks1074* of appropriate size.1075*/1076if (i == write_mtt_size) {1077err = mthca_write_mtt(dev, mr->mtt, n, pages, i);1078if (err)1079goto mtt_done;1080n += i;1081i = 0;1082}1083}1084}10851086if (i)1087err = mthca_write_mtt(dev, mr->mtt, n, pages, i);1088mtt_done:1089free_page((unsigned long) pages);1090if (err)1091goto err_mtt;10921093err = mthca_mr_alloc(dev, to_mpd(pd)->pd_num, shift, virt, length,1094convert_access(acc), mr);10951096if (err)1097goto err_mtt;10981099return &mr->ibmr;11001101err_mtt:1102mthca_free_mtt(dev, mr->mtt);11031104err_umem:1105ib_umem_release(mr->umem);11061107err:1108kfree(mr);1109return ERR_PTR(err);1110}11111112static int mthca_dereg_mr(struct ib_mr *mr)1113{1114struct mthca_mr *mmr = to_mmr(mr);11151116mthca_free_mr(to_mdev(mr->device), mmr);1117if (mmr->umem)1118ib_umem_release(mmr->umem);1119kfree(mmr);11201121return 0;1122}11231124static struct ib_fmr *mthca_alloc_fmr(struct ib_pd *pd, int mr_access_flags,1125struct ib_fmr_attr *fmr_attr)1126{1127struct mthca_fmr *fmr;1128int err;11291130fmr = kmalloc(sizeof *fmr, GFP_KERNEL);1131if (!fmr)1132return ERR_PTR(-ENOMEM);11331134memcpy(&fmr->attr, fmr_attr, sizeof *fmr_attr);1135err = mthca_fmr_alloc(to_mdev(pd->device), to_mpd(pd)->pd_num,1136convert_access(mr_access_flags), fmr);11371138if (err) {1139kfree(fmr);1140return ERR_PTR(err);1141}11421143return &fmr->ibmr;1144}11451146static int mthca_dealloc_fmr(struct ib_fmr *fmr)1147{1148struct mthca_fmr *mfmr = to_mfmr(fmr);1149int err;11501151err = mthca_free_fmr(to_mdev(fmr->device), mfmr);1152if (err)1153return err;11541155kfree(mfmr);1156return 0;1157}11581159static int mthca_unmap_fmr(struct list_head *fmr_list)1160{1161struct ib_fmr *fmr;1162int err;1163u8 status;1164struct mthca_dev *mdev = NULL;11651166list_for_each_entry(fmr, fmr_list, list) {1167if (mdev && to_mdev(fmr->device) != mdev)1168return -EINVAL;1169mdev = to_mdev(fmr->device);1170}11711172if (!mdev)1173return 0;11741175if (mthca_is_memfree(mdev)) {1176list_for_each_entry(fmr, fmr_list, list)1177mthca_arbel_fmr_unmap(mdev, to_mfmr(fmr));11781179wmb();1180} else1181list_for_each_entry(fmr, fmr_list, list)1182mthca_tavor_fmr_unmap(mdev, to_mfmr(fmr));11831184err = mthca_SYNC_TPT(mdev, &status);1185if (err)1186return err;1187if (status)1188return -EINVAL;1189return 0;1190}11911192static ssize_t show_rev(struct device *device, struct device_attribute *attr,1193char *buf)1194{1195struct mthca_dev *dev =1196container_of(device, struct mthca_dev, ib_dev.dev);1197return sprintf(buf, "%x\n", dev->rev_id);1198}11991200static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr,1201char *buf)1202{1203struct mthca_dev *dev =1204container_of(device, struct mthca_dev, ib_dev.dev);1205return sprintf(buf, "%d.%d.%d\n", (int) (dev->fw_ver >> 32),1206(int) (dev->fw_ver >> 16) & 0xffff,1207(int) dev->fw_ver & 0xffff);1208}12091210static ssize_t show_hca(struct device *device, struct device_attribute *attr,1211char *buf)1212{1213struct mthca_dev *dev =1214container_of(device, struct mthca_dev, ib_dev.dev);1215switch (dev->pdev->device) {1216case PCI_DEVICE_ID_MELLANOX_TAVOR:1217return sprintf(buf, "MT23108\n");1218case PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT:1219return sprintf(buf, "MT25208 (MT23108 compat mode)\n");1220case PCI_DEVICE_ID_MELLANOX_ARBEL:1221return sprintf(buf, "MT25208\n");1222case PCI_DEVICE_ID_MELLANOX_SINAI:1223case PCI_DEVICE_ID_MELLANOX_SINAI_OLD:1224return sprintf(buf, "MT25204\n");1225default:1226return sprintf(buf, "unknown\n");1227}1228}12291230static ssize_t show_board(struct device *device, struct device_attribute *attr,1231char *buf)1232{1233struct mthca_dev *dev =1234container_of(device, struct mthca_dev, ib_dev.dev);1235return sprintf(buf, "%.*s\n", MTHCA_BOARD_ID_LEN, dev->board_id);1236}12371238static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);1239static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);1240static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);1241static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);12421243static struct device_attribute *mthca_dev_attributes[] = {1244&dev_attr_hw_rev,1245&dev_attr_fw_ver,1246&dev_attr_hca_type,1247&dev_attr_board_id1248};12491250static int mthca_init_node_data(struct mthca_dev *dev)1251{1252struct ib_smp *in_mad = NULL;1253struct ib_smp *out_mad = NULL;1254int err = -ENOMEM;1255u8 status;12561257in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL);1258out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);1259if (!in_mad || !out_mad)1260goto out;12611262init_query_mad(in_mad);1263in_mad->attr_id = IB_SMP_ATTR_NODE_DESC;12641265err = mthca_MAD_IFC(dev, 1, 1,12661, NULL, NULL, in_mad, out_mad,1267&status);1268if (err)1269goto out;1270if (status) {1271err = -EINVAL;1272goto out;1273}12741275memcpy(dev->ib_dev.node_desc, out_mad->data, 64);12761277in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;12781279err = mthca_MAD_IFC(dev, 1, 1,12801, NULL, NULL, in_mad, out_mad,1281&status);1282if (err)1283goto out;1284if (status) {1285err = -EINVAL;1286goto out;1287}12881289if (mthca_is_memfree(dev))1290dev->rev_id = be32_to_cpup((__be32 *) (out_mad->data + 32));1291memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8);12921293out:1294kfree(in_mad);1295kfree(out_mad);1296return err;1297}12981299int mthca_register_device(struct mthca_dev *dev)1300{1301int ret;1302int i;13031304ret = mthca_init_node_data(dev);1305if (ret)1306return ret;13071308strlcpy(dev->ib_dev.name, "mthca%d", IB_DEVICE_NAME_MAX);1309dev->ib_dev.owner = THIS_MODULE;13101311dev->ib_dev.uverbs_abi_ver = MTHCA_UVERBS_ABI_VERSION;1312dev->ib_dev.uverbs_cmd_mask =1313(1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |1314(1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |1315(1ull << IB_USER_VERBS_CMD_QUERY_PORT) |1316(1ull << IB_USER_VERBS_CMD_ALLOC_PD) |1317(1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |1318(1ull << IB_USER_VERBS_CMD_REG_MR) |1319(1ull << IB_USER_VERBS_CMD_DEREG_MR) |1320(1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |1321(1ull << IB_USER_VERBS_CMD_CREATE_CQ) |1322(1ull << IB_USER_VERBS_CMD_RESIZE_CQ) |1323(1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |1324(1ull << IB_USER_VERBS_CMD_CREATE_QP) |1325(1ull << IB_USER_VERBS_CMD_QUERY_QP) |1326(1ull << IB_USER_VERBS_CMD_MODIFY_QP) |1327(1ull << IB_USER_VERBS_CMD_DESTROY_QP) |1328(1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) |1329(1ull << IB_USER_VERBS_CMD_DETACH_MCAST);1330dev->ib_dev.node_type = RDMA_NODE_IB_CA;1331dev->ib_dev.phys_port_cnt = dev->limits.num_ports;1332dev->ib_dev.num_comp_vectors = 1;1333dev->ib_dev.dma_device = &dev->pdev->dev;1334dev->ib_dev.query_device = mthca_query_device;1335dev->ib_dev.query_port = mthca_query_port;1336dev->ib_dev.modify_device = mthca_modify_device;1337dev->ib_dev.modify_port = mthca_modify_port;1338dev->ib_dev.query_pkey = mthca_query_pkey;1339dev->ib_dev.query_gid = mthca_query_gid;1340dev->ib_dev.alloc_ucontext = mthca_alloc_ucontext;1341dev->ib_dev.dealloc_ucontext = mthca_dealloc_ucontext;1342dev->ib_dev.mmap = mthca_mmap_uar;1343dev->ib_dev.alloc_pd = mthca_alloc_pd;1344dev->ib_dev.dealloc_pd = mthca_dealloc_pd;1345dev->ib_dev.create_ah = mthca_ah_create;1346dev->ib_dev.query_ah = mthca_ah_query;1347dev->ib_dev.destroy_ah = mthca_ah_destroy;13481349if (dev->mthca_flags & MTHCA_FLAG_SRQ) {1350dev->ib_dev.create_srq = mthca_create_srq;1351dev->ib_dev.modify_srq = mthca_modify_srq;1352dev->ib_dev.query_srq = mthca_query_srq;1353dev->ib_dev.destroy_srq = mthca_destroy_srq;1354dev->ib_dev.uverbs_cmd_mask |=1355(1ull << IB_USER_VERBS_CMD_CREATE_SRQ) |1356(1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) |1357(1ull << IB_USER_VERBS_CMD_QUERY_SRQ) |1358(1ull << IB_USER_VERBS_CMD_DESTROY_SRQ);13591360if (mthca_is_memfree(dev))1361dev->ib_dev.post_srq_recv = mthca_arbel_post_srq_recv;1362else1363dev->ib_dev.post_srq_recv = mthca_tavor_post_srq_recv;1364}13651366dev->ib_dev.create_qp = mthca_create_qp;1367dev->ib_dev.modify_qp = mthca_modify_qp;1368dev->ib_dev.query_qp = mthca_query_qp;1369dev->ib_dev.destroy_qp = mthca_destroy_qp;1370dev->ib_dev.create_cq = mthca_create_cq;1371dev->ib_dev.resize_cq = mthca_resize_cq;1372dev->ib_dev.destroy_cq = mthca_destroy_cq;1373dev->ib_dev.poll_cq = mthca_poll_cq;1374dev->ib_dev.get_dma_mr = mthca_get_dma_mr;1375dev->ib_dev.reg_phys_mr = mthca_reg_phys_mr;1376dev->ib_dev.reg_user_mr = mthca_reg_user_mr;1377dev->ib_dev.dereg_mr = mthca_dereg_mr;13781379if (dev->mthca_flags & MTHCA_FLAG_FMR) {1380dev->ib_dev.alloc_fmr = mthca_alloc_fmr;1381dev->ib_dev.unmap_fmr = mthca_unmap_fmr;1382dev->ib_dev.dealloc_fmr = mthca_dealloc_fmr;1383if (mthca_is_memfree(dev))1384dev->ib_dev.map_phys_fmr = mthca_arbel_map_phys_fmr;1385else1386dev->ib_dev.map_phys_fmr = mthca_tavor_map_phys_fmr;1387}13881389dev->ib_dev.attach_mcast = mthca_multicast_attach;1390dev->ib_dev.detach_mcast = mthca_multicast_detach;1391dev->ib_dev.process_mad = mthca_process_mad;13921393if (mthca_is_memfree(dev)) {1394dev->ib_dev.req_notify_cq = mthca_arbel_arm_cq;1395dev->ib_dev.post_send = mthca_arbel_post_send;1396dev->ib_dev.post_recv = mthca_arbel_post_receive;1397} else {1398dev->ib_dev.req_notify_cq = mthca_tavor_arm_cq;1399dev->ib_dev.post_send = mthca_tavor_post_send;1400dev->ib_dev.post_recv = mthca_tavor_post_receive;1401}14021403mutex_init(&dev->cap_mask_mutex);14041405ret = ib_register_device(&dev->ib_dev, NULL);1406if (ret)1407return ret;14081409for (i = 0; i < ARRAY_SIZE(mthca_dev_attributes); ++i) {1410ret = device_create_file(&dev->ib_dev.dev,1411mthca_dev_attributes[i]);1412if (ret) {1413ib_unregister_device(&dev->ib_dev);1414return ret;1415}1416}14171418mthca_start_catas_poll(dev);14191420return 0;1421}14221423void mthca_unregister_device(struct mthca_dev *dev)1424{1425mthca_stop_catas_poll(dev);1426ib_unregister_device(&dev->ib_dev);1427}142814291430