Path: blob/master/drivers/infiniband/hw/mthca/mthca_main.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 Mellanox Technologies. All rights reserved.4*5* This software is available to you under a choice of one of two6* licenses. You may choose to be licensed under the terms of the GNU7* General Public License (GPL) Version 2, available from the file8* COPYING in the main directory of this source tree, or the9* OpenIB.org BSD license below:10*11* Redistribution and use in source and binary forms, with or12* without modification, are permitted provided that the following13* conditions are met:14*15* - Redistributions of source code must retain the above16* copyright notice, this list of conditions and the following17* disclaimer.18*19* - Redistributions in binary form must reproduce the above20* copyright notice, this list of conditions and the following21* disclaimer in the documentation and/or other materials22* provided with the distribution.23*24* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,25* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF26* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND27* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS28* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN29* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN30* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE31* SOFTWARE.32*/3334#include <linux/module.h>35#include <linux/init.h>36#include <linux/errno.h>37#include <linux/pci.h>38#include <linux/interrupt.h>39#include <linux/gfp.h>4041#include "mthca_dev.h"42#include "mthca_config_reg.h"43#include "mthca_cmd.h"44#include "mthca_profile.h"45#include "mthca_memfree.h"46#include "mthca_wqe.h"4748MODULE_AUTHOR("Roland Dreier");49MODULE_DESCRIPTION("Mellanox InfiniBand HCA low-level driver");50MODULE_LICENSE("Dual BSD/GPL");51MODULE_VERSION(DRV_VERSION);5253#ifdef CONFIG_INFINIBAND_MTHCA_DEBUG5455int mthca_debug_level = 0;56module_param_named(debug_level, mthca_debug_level, int, 0644);57MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0");5859#endif /* CONFIG_INFINIBAND_MTHCA_DEBUG */6061#ifdef CONFIG_PCI_MSI6263static int msi_x = 1;64module_param(msi_x, int, 0444);65MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");6667#else /* CONFIG_PCI_MSI */6869#define msi_x (0)7071#endif /* CONFIG_PCI_MSI */7273static int tune_pci = 0;74module_param(tune_pci, int, 0444);75MODULE_PARM_DESC(tune_pci, "increase PCI burst from the default set by BIOS if nonzero");7677DEFINE_MUTEX(mthca_device_mutex);7879#define MTHCA_DEFAULT_NUM_QP (1 << 16)80#define MTHCA_DEFAULT_RDB_PER_QP (1 << 2)81#define MTHCA_DEFAULT_NUM_CQ (1 << 16)82#define MTHCA_DEFAULT_NUM_MCG (1 << 13)83#define MTHCA_DEFAULT_NUM_MPT (1 << 17)84#define MTHCA_DEFAULT_NUM_MTT (1 << 20)85#define MTHCA_DEFAULT_NUM_UDAV (1 << 15)86#define MTHCA_DEFAULT_NUM_RESERVED_MTTS (1 << 18)87#define MTHCA_DEFAULT_NUM_UARC_SIZE (1 << 18)8889static struct mthca_profile hca_profile = {90.num_qp = MTHCA_DEFAULT_NUM_QP,91.rdb_per_qp = MTHCA_DEFAULT_RDB_PER_QP,92.num_cq = MTHCA_DEFAULT_NUM_CQ,93.num_mcg = MTHCA_DEFAULT_NUM_MCG,94.num_mpt = MTHCA_DEFAULT_NUM_MPT,95.num_mtt = MTHCA_DEFAULT_NUM_MTT,96.num_udav = MTHCA_DEFAULT_NUM_UDAV, /* Tavor only */97.fmr_reserved_mtts = MTHCA_DEFAULT_NUM_RESERVED_MTTS, /* Tavor only */98.uarc_size = MTHCA_DEFAULT_NUM_UARC_SIZE, /* Arbel only */99};100101module_param_named(num_qp, hca_profile.num_qp, int, 0444);102MODULE_PARM_DESC(num_qp, "maximum number of QPs per HCA");103104module_param_named(rdb_per_qp, hca_profile.rdb_per_qp, int, 0444);105MODULE_PARM_DESC(rdb_per_qp, "number of RDB buffers per QP");106107module_param_named(num_cq, hca_profile.num_cq, int, 0444);108MODULE_PARM_DESC(num_cq, "maximum number of CQs per HCA");109110module_param_named(num_mcg, hca_profile.num_mcg, int, 0444);111MODULE_PARM_DESC(num_mcg, "maximum number of multicast groups per HCA");112113module_param_named(num_mpt, hca_profile.num_mpt, int, 0444);114MODULE_PARM_DESC(num_mpt,115"maximum number of memory protection table entries per HCA");116117module_param_named(num_mtt, hca_profile.num_mtt, int, 0444);118MODULE_PARM_DESC(num_mtt,119"maximum number of memory translation table segments per HCA");120121module_param_named(num_udav, hca_profile.num_udav, int, 0444);122MODULE_PARM_DESC(num_udav, "maximum number of UD address vectors per HCA");123124module_param_named(fmr_reserved_mtts, hca_profile.fmr_reserved_mtts, int, 0444);125MODULE_PARM_DESC(fmr_reserved_mtts,126"number of memory translation table segments reserved for FMR");127128static int log_mtts_per_seg = ilog2(MTHCA_MTT_SEG_SIZE / 8);129module_param_named(log_mtts_per_seg, log_mtts_per_seg, int, 0444);130MODULE_PARM_DESC(log_mtts_per_seg, "Log2 number of MTT entries per segment (1-5)");131132static char mthca_version[] __devinitdata =133DRV_NAME ": Mellanox InfiniBand HCA driver v"134DRV_VERSION " (" DRV_RELDATE ")\n";135136static int mthca_tune_pci(struct mthca_dev *mdev)137{138if (!tune_pci)139return 0;140141/* First try to max out Read Byte Count */142if (pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX)) {143if (pcix_set_mmrbc(mdev->pdev, pcix_get_max_mmrbc(mdev->pdev))) {144mthca_err(mdev, "Couldn't set PCI-X max read count, "145"aborting.\n");146return -ENODEV;147}148} else if (!(mdev->mthca_flags & MTHCA_FLAG_PCIE))149mthca_info(mdev, "No PCI-X capability, not setting RBC.\n");150151if (pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP)) {152if (pcie_set_readrq(mdev->pdev, 4096)) {153mthca_err(mdev, "Couldn't write PCI Express read request, "154"aborting.\n");155return -ENODEV;156}157} else if (mdev->mthca_flags & MTHCA_FLAG_PCIE)158mthca_info(mdev, "No PCI Express capability, "159"not setting Max Read Request Size.\n");160161return 0;162}163164static int mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim *dev_lim)165{166int err;167u8 status;168169mdev->limits.mtt_seg_size = (1 << log_mtts_per_seg) * 8;170err = mthca_QUERY_DEV_LIM(mdev, dev_lim, &status);171if (err) {172mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n");173return err;174}175if (status) {176mthca_err(mdev, "QUERY_DEV_LIM returned status 0x%02x, "177"aborting.\n", status);178return -EINVAL;179}180if (dev_lim->min_page_sz > PAGE_SIZE) {181mthca_err(mdev, "HCA minimum page size of %d bigger than "182"kernel PAGE_SIZE of %ld, aborting.\n",183dev_lim->min_page_sz, PAGE_SIZE);184return -ENODEV;185}186if (dev_lim->num_ports > MTHCA_MAX_PORTS) {187mthca_err(mdev, "HCA has %d ports, but we only support %d, "188"aborting.\n",189dev_lim->num_ports, MTHCA_MAX_PORTS);190return -ENODEV;191}192193if (dev_lim->uar_size > pci_resource_len(mdev->pdev, 2)) {194mthca_err(mdev, "HCA reported UAR size of 0x%x bigger than "195"PCI resource 2 size of 0x%llx, aborting.\n",196dev_lim->uar_size,197(unsigned long long)pci_resource_len(mdev->pdev, 2));198return -ENODEV;199}200201mdev->limits.num_ports = dev_lim->num_ports;202mdev->limits.vl_cap = dev_lim->max_vl;203mdev->limits.mtu_cap = dev_lim->max_mtu;204mdev->limits.gid_table_len = dev_lim->max_gids;205mdev->limits.pkey_table_len = dev_lim->max_pkeys;206mdev->limits.local_ca_ack_delay = dev_lim->local_ca_ack_delay;207/*208* Need to allow for worst case send WQE overhead and check209* whether max_desc_sz imposes a lower limit than max_sg; UD210* send has the biggest overhead.211*/212mdev->limits.max_sg = min_t(int, dev_lim->max_sg,213(dev_lim->max_desc_sz -214sizeof (struct mthca_next_seg) -215(mthca_is_memfree(mdev) ?216sizeof (struct mthca_arbel_ud_seg) :217sizeof (struct mthca_tavor_ud_seg))) /218sizeof (struct mthca_data_seg));219mdev->limits.max_wqes = dev_lim->max_qp_sz;220mdev->limits.max_qp_init_rdma = dev_lim->max_requester_per_qp;221mdev->limits.reserved_qps = dev_lim->reserved_qps;222mdev->limits.max_srq_wqes = dev_lim->max_srq_sz;223mdev->limits.reserved_srqs = dev_lim->reserved_srqs;224mdev->limits.reserved_eecs = dev_lim->reserved_eecs;225mdev->limits.max_desc_sz = dev_lim->max_desc_sz;226mdev->limits.max_srq_sge = mthca_max_srq_sge(mdev);227/*228* Subtract 1 from the limit because we need to allocate a229* spare CQE so the HCA HW can tell the difference between an230* empty CQ and a full CQ.231*/232mdev->limits.max_cqes = dev_lim->max_cq_sz - 1;233mdev->limits.reserved_cqs = dev_lim->reserved_cqs;234mdev->limits.reserved_eqs = dev_lim->reserved_eqs;235mdev->limits.reserved_mtts = dev_lim->reserved_mtts;236mdev->limits.reserved_mrws = dev_lim->reserved_mrws;237mdev->limits.reserved_uars = dev_lim->reserved_uars;238mdev->limits.reserved_pds = dev_lim->reserved_pds;239mdev->limits.port_width_cap = dev_lim->max_port_width;240mdev->limits.page_size_cap = ~(u32) (dev_lim->min_page_sz - 1);241mdev->limits.flags = dev_lim->flags;242/*243* For old FW that doesn't return static rate support, use a244* value of 0x3 (only static rate values of 0 or 1 are handled),245* except on Sinai, where even old FW can handle static rate246* values of 2 and 3.247*/248if (dev_lim->stat_rate_support)249mdev->limits.stat_rate_support = dev_lim->stat_rate_support;250else if (mdev->mthca_flags & MTHCA_FLAG_SINAI_OPT)251mdev->limits.stat_rate_support = 0xf;252else253mdev->limits.stat_rate_support = 0x3;254255/* IB_DEVICE_RESIZE_MAX_WR not supported by driver.256May be doable since hardware supports it for SRQ.257258IB_DEVICE_N_NOTIFY_CQ is supported by hardware but not by driver.259260IB_DEVICE_SRQ_RESIZE is supported by hardware but SRQ is not261supported by driver. */262mdev->device_cap_flags = IB_DEVICE_CHANGE_PHY_PORT |263IB_DEVICE_PORT_ACTIVE_EVENT |264IB_DEVICE_SYS_IMAGE_GUID |265IB_DEVICE_RC_RNR_NAK_GEN;266267if (dev_lim->flags & DEV_LIM_FLAG_BAD_PKEY_CNTR)268mdev->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR;269270if (dev_lim->flags & DEV_LIM_FLAG_BAD_QKEY_CNTR)271mdev->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR;272273if (dev_lim->flags & DEV_LIM_FLAG_RAW_MULTI)274mdev->device_cap_flags |= IB_DEVICE_RAW_MULTI;275276if (dev_lim->flags & DEV_LIM_FLAG_AUTO_PATH_MIG)277mdev->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG;278279if (dev_lim->flags & DEV_LIM_FLAG_UD_AV_PORT_ENFORCE)280mdev->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE;281282if (dev_lim->flags & DEV_LIM_FLAG_SRQ)283mdev->mthca_flags |= MTHCA_FLAG_SRQ;284285if (mthca_is_memfree(mdev))286if (dev_lim->flags & DEV_LIM_FLAG_IPOIB_CSUM)287mdev->device_cap_flags |= IB_DEVICE_UD_IP_CSUM;288289return 0;290}291292static int mthca_init_tavor(struct mthca_dev *mdev)293{294s64 size;295u8 status;296int err;297struct mthca_dev_lim dev_lim;298struct mthca_profile profile;299struct mthca_init_hca_param init_hca;300301err = mthca_SYS_EN(mdev, &status);302if (err) {303mthca_err(mdev, "SYS_EN command failed, aborting.\n");304return err;305}306if (status) {307mthca_err(mdev, "SYS_EN returned status 0x%02x, "308"aborting.\n", status);309return -EINVAL;310}311312err = mthca_QUERY_FW(mdev, &status);313if (err) {314mthca_err(mdev, "QUERY_FW command failed, aborting.\n");315goto err_disable;316}317if (status) {318mthca_err(mdev, "QUERY_FW returned status 0x%02x, "319"aborting.\n", status);320err = -EINVAL;321goto err_disable;322}323err = mthca_QUERY_DDR(mdev, &status);324if (err) {325mthca_err(mdev, "QUERY_DDR command failed, aborting.\n");326goto err_disable;327}328if (status) {329mthca_err(mdev, "QUERY_DDR returned status 0x%02x, "330"aborting.\n", status);331err = -EINVAL;332goto err_disable;333}334335err = mthca_dev_lim(mdev, &dev_lim);336if (err) {337mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n");338goto err_disable;339}340341profile = hca_profile;342profile.num_uar = dev_lim.uar_size / PAGE_SIZE;343profile.uarc_size = 0;344if (mdev->mthca_flags & MTHCA_FLAG_SRQ)345profile.num_srq = dev_lim.max_srqs;346347size = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca);348if (size < 0) {349err = size;350goto err_disable;351}352353err = mthca_INIT_HCA(mdev, &init_hca, &status);354if (err) {355mthca_err(mdev, "INIT_HCA command failed, aborting.\n");356goto err_disable;357}358if (status) {359mthca_err(mdev, "INIT_HCA returned status 0x%02x, "360"aborting.\n", status);361err = -EINVAL;362goto err_disable;363}364365return 0;366367err_disable:368mthca_SYS_DIS(mdev, &status);369370return err;371}372373static int mthca_load_fw(struct mthca_dev *mdev)374{375u8 status;376int err;377378/* FIXME: use HCA-attached memory for FW if present */379380mdev->fw.arbel.fw_icm =381mthca_alloc_icm(mdev, mdev->fw.arbel.fw_pages,382GFP_HIGHUSER | __GFP_NOWARN, 0);383if (!mdev->fw.arbel.fw_icm) {384mthca_err(mdev, "Couldn't allocate FW area, aborting.\n");385return -ENOMEM;386}387388err = mthca_MAP_FA(mdev, mdev->fw.arbel.fw_icm, &status);389if (err) {390mthca_err(mdev, "MAP_FA command failed, aborting.\n");391goto err_free;392}393if (status) {394mthca_err(mdev, "MAP_FA returned status 0x%02x, aborting.\n", status);395err = -EINVAL;396goto err_free;397}398err = mthca_RUN_FW(mdev, &status);399if (err) {400mthca_err(mdev, "RUN_FW command failed, aborting.\n");401goto err_unmap_fa;402}403if (status) {404mthca_err(mdev, "RUN_FW returned status 0x%02x, aborting.\n", status);405err = -EINVAL;406goto err_unmap_fa;407}408409return 0;410411err_unmap_fa:412mthca_UNMAP_FA(mdev, &status);413414err_free:415mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0);416return err;417}418419static int mthca_init_icm(struct mthca_dev *mdev,420struct mthca_dev_lim *dev_lim,421struct mthca_init_hca_param *init_hca,422u64 icm_size)423{424u64 aux_pages;425u8 status;426int err;427428err = mthca_SET_ICM_SIZE(mdev, icm_size, &aux_pages, &status);429if (err) {430mthca_err(mdev, "SET_ICM_SIZE command failed, aborting.\n");431return err;432}433if (status) {434mthca_err(mdev, "SET_ICM_SIZE returned status 0x%02x, "435"aborting.\n", status);436return -EINVAL;437}438439mthca_dbg(mdev, "%lld KB of HCA context requires %lld KB aux memory.\n",440(unsigned long long) icm_size >> 10,441(unsigned long long) aux_pages << 2);442443mdev->fw.arbel.aux_icm = mthca_alloc_icm(mdev, aux_pages,444GFP_HIGHUSER | __GFP_NOWARN, 0);445if (!mdev->fw.arbel.aux_icm) {446mthca_err(mdev, "Couldn't allocate aux memory, aborting.\n");447return -ENOMEM;448}449450err = mthca_MAP_ICM_AUX(mdev, mdev->fw.arbel.aux_icm, &status);451if (err) {452mthca_err(mdev, "MAP_ICM_AUX command failed, aborting.\n");453goto err_free_aux;454}455if (status) {456mthca_err(mdev, "MAP_ICM_AUX returned status 0x%02x, aborting.\n", status);457err = -EINVAL;458goto err_free_aux;459}460461err = mthca_map_eq_icm(mdev, init_hca->eqc_base);462if (err) {463mthca_err(mdev, "Failed to map EQ context memory, aborting.\n");464goto err_unmap_aux;465}466467/* CPU writes to non-reserved MTTs, while HCA might DMA to reserved mtts */468mdev->limits.reserved_mtts = ALIGN(mdev->limits.reserved_mtts * mdev->limits.mtt_seg_size,469dma_get_cache_alignment()) / mdev->limits.mtt_seg_size;470471mdev->mr_table.mtt_table = mthca_alloc_icm_table(mdev, init_hca->mtt_base,472mdev->limits.mtt_seg_size,473mdev->limits.num_mtt_segs,474mdev->limits.reserved_mtts,4751, 0);476if (!mdev->mr_table.mtt_table) {477mthca_err(mdev, "Failed to map MTT context memory, aborting.\n");478err = -ENOMEM;479goto err_unmap_eq;480}481482mdev->mr_table.mpt_table = mthca_alloc_icm_table(mdev, init_hca->mpt_base,483dev_lim->mpt_entry_sz,484mdev->limits.num_mpts,485mdev->limits.reserved_mrws,4861, 1);487if (!mdev->mr_table.mpt_table) {488mthca_err(mdev, "Failed to map MPT context memory, aborting.\n");489err = -ENOMEM;490goto err_unmap_mtt;491}492493mdev->qp_table.qp_table = mthca_alloc_icm_table(mdev, init_hca->qpc_base,494dev_lim->qpc_entry_sz,495mdev->limits.num_qps,496mdev->limits.reserved_qps,4970, 0);498if (!mdev->qp_table.qp_table) {499mthca_err(mdev, "Failed to map QP context memory, aborting.\n");500err = -ENOMEM;501goto err_unmap_mpt;502}503504mdev->qp_table.eqp_table = mthca_alloc_icm_table(mdev, init_hca->eqpc_base,505dev_lim->eqpc_entry_sz,506mdev->limits.num_qps,507mdev->limits.reserved_qps,5080, 0);509if (!mdev->qp_table.eqp_table) {510mthca_err(mdev, "Failed to map EQP context memory, aborting.\n");511err = -ENOMEM;512goto err_unmap_qp;513}514515mdev->qp_table.rdb_table = mthca_alloc_icm_table(mdev, init_hca->rdb_base,516MTHCA_RDB_ENTRY_SIZE,517mdev->limits.num_qps <<518mdev->qp_table.rdb_shift, 0,5190, 0);520if (!mdev->qp_table.rdb_table) {521mthca_err(mdev, "Failed to map RDB context memory, aborting\n");522err = -ENOMEM;523goto err_unmap_eqp;524}525526mdev->cq_table.table = mthca_alloc_icm_table(mdev, init_hca->cqc_base,527dev_lim->cqc_entry_sz,528mdev->limits.num_cqs,529mdev->limits.reserved_cqs,5300, 0);531if (!mdev->cq_table.table) {532mthca_err(mdev, "Failed to map CQ context memory, aborting.\n");533err = -ENOMEM;534goto err_unmap_rdb;535}536537if (mdev->mthca_flags & MTHCA_FLAG_SRQ) {538mdev->srq_table.table =539mthca_alloc_icm_table(mdev, init_hca->srqc_base,540dev_lim->srq_entry_sz,541mdev->limits.num_srqs,542mdev->limits.reserved_srqs,5430, 0);544if (!mdev->srq_table.table) {545mthca_err(mdev, "Failed to map SRQ context memory, "546"aborting.\n");547err = -ENOMEM;548goto err_unmap_cq;549}550}551552/*553* It's not strictly required, but for simplicity just map the554* whole multicast group table now. The table isn't very big555* and it's a lot easier than trying to track ref counts.556*/557mdev->mcg_table.table = mthca_alloc_icm_table(mdev, init_hca->mc_base,558MTHCA_MGM_ENTRY_SIZE,559mdev->limits.num_mgms +560mdev->limits.num_amgms,561mdev->limits.num_mgms +562mdev->limits.num_amgms,5630, 0);564if (!mdev->mcg_table.table) {565mthca_err(mdev, "Failed to map MCG context memory, aborting.\n");566err = -ENOMEM;567goto err_unmap_srq;568}569570return 0;571572err_unmap_srq:573if (mdev->mthca_flags & MTHCA_FLAG_SRQ)574mthca_free_icm_table(mdev, mdev->srq_table.table);575576err_unmap_cq:577mthca_free_icm_table(mdev, mdev->cq_table.table);578579err_unmap_rdb:580mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);581582err_unmap_eqp:583mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);584585err_unmap_qp:586mthca_free_icm_table(mdev, mdev->qp_table.qp_table);587588err_unmap_mpt:589mthca_free_icm_table(mdev, mdev->mr_table.mpt_table);590591err_unmap_mtt:592mthca_free_icm_table(mdev, mdev->mr_table.mtt_table);593594err_unmap_eq:595mthca_unmap_eq_icm(mdev);596597err_unmap_aux:598mthca_UNMAP_ICM_AUX(mdev, &status);599600err_free_aux:601mthca_free_icm(mdev, mdev->fw.arbel.aux_icm, 0);602603return err;604}605606static void mthca_free_icms(struct mthca_dev *mdev)607{608u8 status;609610mthca_free_icm_table(mdev, mdev->mcg_table.table);611if (mdev->mthca_flags & MTHCA_FLAG_SRQ)612mthca_free_icm_table(mdev, mdev->srq_table.table);613mthca_free_icm_table(mdev, mdev->cq_table.table);614mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);615mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);616mthca_free_icm_table(mdev, mdev->qp_table.qp_table);617mthca_free_icm_table(mdev, mdev->mr_table.mpt_table);618mthca_free_icm_table(mdev, mdev->mr_table.mtt_table);619mthca_unmap_eq_icm(mdev);620621mthca_UNMAP_ICM_AUX(mdev, &status);622mthca_free_icm(mdev, mdev->fw.arbel.aux_icm, 0);623}624625static int mthca_init_arbel(struct mthca_dev *mdev)626{627struct mthca_dev_lim dev_lim;628struct mthca_profile profile;629struct mthca_init_hca_param init_hca;630s64 icm_size;631u8 status;632int err;633634err = mthca_QUERY_FW(mdev, &status);635if (err) {636mthca_err(mdev, "QUERY_FW command failed, aborting.\n");637return err;638}639if (status) {640mthca_err(mdev, "QUERY_FW returned status 0x%02x, "641"aborting.\n", status);642return -EINVAL;643}644645err = mthca_ENABLE_LAM(mdev, &status);646if (err) {647mthca_err(mdev, "ENABLE_LAM command failed, aborting.\n");648return err;649}650if (status == MTHCA_CMD_STAT_LAM_NOT_PRE) {651mthca_dbg(mdev, "No HCA-attached memory (running in MemFree mode)\n");652mdev->mthca_flags |= MTHCA_FLAG_NO_LAM;653} else if (status) {654mthca_err(mdev, "ENABLE_LAM returned status 0x%02x, "655"aborting.\n", status);656return -EINVAL;657}658659err = mthca_load_fw(mdev);660if (err) {661mthca_err(mdev, "Failed to start FW, aborting.\n");662goto err_disable;663}664665err = mthca_dev_lim(mdev, &dev_lim);666if (err) {667mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n");668goto err_stop_fw;669}670671profile = hca_profile;672profile.num_uar = dev_lim.uar_size / PAGE_SIZE;673profile.num_udav = 0;674if (mdev->mthca_flags & MTHCA_FLAG_SRQ)675profile.num_srq = dev_lim.max_srqs;676677icm_size = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca);678if (icm_size < 0) {679err = icm_size;680goto err_stop_fw;681}682683err = mthca_init_icm(mdev, &dev_lim, &init_hca, icm_size);684if (err)685goto err_stop_fw;686687err = mthca_INIT_HCA(mdev, &init_hca, &status);688if (err) {689mthca_err(mdev, "INIT_HCA command failed, aborting.\n");690goto err_free_icm;691}692if (status) {693mthca_err(mdev, "INIT_HCA returned status 0x%02x, "694"aborting.\n", status);695err = -EINVAL;696goto err_free_icm;697}698699return 0;700701err_free_icm:702mthca_free_icms(mdev);703704err_stop_fw:705mthca_UNMAP_FA(mdev, &status);706mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0);707708err_disable:709if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM))710mthca_DISABLE_LAM(mdev, &status);711712return err;713}714715static void mthca_close_hca(struct mthca_dev *mdev)716{717u8 status;718719mthca_CLOSE_HCA(mdev, 0, &status);720721if (mthca_is_memfree(mdev)) {722mthca_free_icms(mdev);723724mthca_UNMAP_FA(mdev, &status);725mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0);726727if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM))728mthca_DISABLE_LAM(mdev, &status);729} else730mthca_SYS_DIS(mdev, &status);731}732733static int mthca_init_hca(struct mthca_dev *mdev)734{735u8 status;736int err;737struct mthca_adapter adapter;738739if (mthca_is_memfree(mdev))740err = mthca_init_arbel(mdev);741else742err = mthca_init_tavor(mdev);743744if (err)745return err;746747err = mthca_QUERY_ADAPTER(mdev, &adapter, &status);748if (err) {749mthca_err(mdev, "QUERY_ADAPTER command failed, aborting.\n");750goto err_close;751}752if (status) {753mthca_err(mdev, "QUERY_ADAPTER returned status 0x%02x, "754"aborting.\n", status);755err = -EINVAL;756goto err_close;757}758759mdev->eq_table.inta_pin = adapter.inta_pin;760if (!mthca_is_memfree(mdev))761mdev->rev_id = adapter.revision_id;762memcpy(mdev->board_id, adapter.board_id, sizeof mdev->board_id);763764return 0;765766err_close:767mthca_close_hca(mdev);768return err;769}770771static int mthca_setup_hca(struct mthca_dev *dev)772{773int err;774u8 status;775776MTHCA_INIT_DOORBELL_LOCK(&dev->doorbell_lock);777778err = mthca_init_uar_table(dev);779if (err) {780mthca_err(dev, "Failed to initialize "781"user access region table, aborting.\n");782return err;783}784785err = mthca_uar_alloc(dev, &dev->driver_uar);786if (err) {787mthca_err(dev, "Failed to allocate driver access region, "788"aborting.\n");789goto err_uar_table_free;790}791792dev->kar = ioremap((phys_addr_t) dev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE);793if (!dev->kar) {794mthca_err(dev, "Couldn't map kernel access region, "795"aborting.\n");796err = -ENOMEM;797goto err_uar_free;798}799800err = mthca_init_pd_table(dev);801if (err) {802mthca_err(dev, "Failed to initialize "803"protection domain table, aborting.\n");804goto err_kar_unmap;805}806807err = mthca_init_mr_table(dev);808if (err) {809mthca_err(dev, "Failed to initialize "810"memory region table, aborting.\n");811goto err_pd_table_free;812}813814err = mthca_pd_alloc(dev, 1, &dev->driver_pd);815if (err) {816mthca_err(dev, "Failed to create driver PD, "817"aborting.\n");818goto err_mr_table_free;819}820821err = mthca_init_eq_table(dev);822if (err) {823mthca_err(dev, "Failed to initialize "824"event queue table, aborting.\n");825goto err_pd_free;826}827828err = mthca_cmd_use_events(dev);829if (err) {830mthca_err(dev, "Failed to switch to event-driven "831"firmware commands, aborting.\n");832goto err_eq_table_free;833}834835err = mthca_NOP(dev, &status);836if (err || status) {837if (dev->mthca_flags & MTHCA_FLAG_MSI_X) {838mthca_warn(dev, "NOP command failed to generate interrupt "839"(IRQ %d).\n",840dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector);841mthca_warn(dev, "Trying again with MSI-X disabled.\n");842} else {843mthca_err(dev, "NOP command failed to generate interrupt "844"(IRQ %d), aborting.\n",845dev->pdev->irq);846mthca_err(dev, "BIOS or ACPI interrupt routing problem?\n");847}848849goto err_cmd_poll;850}851852mthca_dbg(dev, "NOP command IRQ test passed\n");853854err = mthca_init_cq_table(dev);855if (err) {856mthca_err(dev, "Failed to initialize "857"completion queue table, aborting.\n");858goto err_cmd_poll;859}860861err = mthca_init_srq_table(dev);862if (err) {863mthca_err(dev, "Failed to initialize "864"shared receive queue table, aborting.\n");865goto err_cq_table_free;866}867868err = mthca_init_qp_table(dev);869if (err) {870mthca_err(dev, "Failed to initialize "871"queue pair table, aborting.\n");872goto err_srq_table_free;873}874875err = mthca_init_av_table(dev);876if (err) {877mthca_err(dev, "Failed to initialize "878"address vector table, aborting.\n");879goto err_qp_table_free;880}881882err = mthca_init_mcg_table(dev);883if (err) {884mthca_err(dev, "Failed to initialize "885"multicast group table, aborting.\n");886goto err_av_table_free;887}888889return 0;890891err_av_table_free:892mthca_cleanup_av_table(dev);893894err_qp_table_free:895mthca_cleanup_qp_table(dev);896897err_srq_table_free:898mthca_cleanup_srq_table(dev);899900err_cq_table_free:901mthca_cleanup_cq_table(dev);902903err_cmd_poll:904mthca_cmd_use_polling(dev);905906err_eq_table_free:907mthca_cleanup_eq_table(dev);908909err_pd_free:910mthca_pd_free(dev, &dev->driver_pd);911912err_mr_table_free:913mthca_cleanup_mr_table(dev);914915err_pd_table_free:916mthca_cleanup_pd_table(dev);917918err_kar_unmap:919iounmap(dev->kar);920921err_uar_free:922mthca_uar_free(dev, &dev->driver_uar);923924err_uar_table_free:925mthca_cleanup_uar_table(dev);926return err;927}928929static int mthca_enable_msi_x(struct mthca_dev *mdev)930{931struct msix_entry entries[3];932int err;933934entries[0].entry = 0;935entries[1].entry = 1;936entries[2].entry = 2;937938err = pci_enable_msix(mdev->pdev, entries, ARRAY_SIZE(entries));939if (err) {940if (err > 0)941mthca_info(mdev, "Only %d MSI-X vectors available, "942"not using MSI-X\n", err);943return err;944}945946mdev->eq_table.eq[MTHCA_EQ_COMP ].msi_x_vector = entries[0].vector;947mdev->eq_table.eq[MTHCA_EQ_ASYNC].msi_x_vector = entries[1].vector;948mdev->eq_table.eq[MTHCA_EQ_CMD ].msi_x_vector = entries[2].vector;949950return 0;951}952953/* Types of supported HCA */954enum {955TAVOR, /* MT23108 */956ARBEL_COMPAT, /* MT25208 in Tavor compat mode */957ARBEL_NATIVE, /* MT25208 with extended features */958SINAI /* MT25204 */959};960961#define MTHCA_FW_VER(major, minor, subminor) \962(((u64) (major) << 32) | ((u64) (minor) << 16) | (u64) (subminor))963964static struct {965u64 latest_fw;966u32 flags;967} mthca_hca_table[] = {968[TAVOR] = { .latest_fw = MTHCA_FW_VER(3, 5, 0),969.flags = 0 },970[ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 8, 200),971.flags = MTHCA_FLAG_PCIE },972[ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 3, 0),973.flags = MTHCA_FLAG_MEMFREE |974MTHCA_FLAG_PCIE },975[SINAI] = { .latest_fw = MTHCA_FW_VER(1, 2, 0),976.flags = MTHCA_FLAG_MEMFREE |977MTHCA_FLAG_PCIE |978MTHCA_FLAG_SINAI_OPT }979};980981static int __mthca_init_one(struct pci_dev *pdev, int hca_type)982{983int ddr_hidden = 0;984int err;985struct mthca_dev *mdev;986987printk(KERN_INFO PFX "Initializing %s\n",988pci_name(pdev));989990err = pci_enable_device(pdev);991if (err) {992dev_err(&pdev->dev, "Cannot enable PCI device, "993"aborting.\n");994return err;995}996997/*998* Check for BARs. We expect 0: 1MB, 2: 8MB, 4: DDR (may not999* be present)1000*/1001if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||1002pci_resource_len(pdev, 0) != 1 << 20) {1003dev_err(&pdev->dev, "Missing DCS, aborting.\n");1004err = -ENODEV;1005goto err_disable_pdev;1006}1007if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {1008dev_err(&pdev->dev, "Missing UAR, aborting.\n");1009err = -ENODEV;1010goto err_disable_pdev;1011}1012if (!(pci_resource_flags(pdev, 4) & IORESOURCE_MEM))1013ddr_hidden = 1;10141015err = pci_request_regions(pdev, DRV_NAME);1016if (err) {1017dev_err(&pdev->dev, "Cannot obtain PCI resources, "1018"aborting.\n");1019goto err_disable_pdev;1020}10211022pci_set_master(pdev);10231024err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));1025if (err) {1026dev_warn(&pdev->dev, "Warning: couldn't set 64-bit PCI DMA mask.\n");1027err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));1028if (err) {1029dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting.\n");1030goto err_free_res;1031}1032}1033err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));1034if (err) {1035dev_warn(&pdev->dev, "Warning: couldn't set 64-bit "1036"consistent PCI DMA mask.\n");1037err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));1038if (err) {1039dev_err(&pdev->dev, "Can't set consistent PCI DMA mask, "1040"aborting.\n");1041goto err_free_res;1042}1043}10441045/* We can handle large RDMA requests, so allow larger segments. */1046dma_set_max_seg_size(&pdev->dev, 1024 * 1024 * 1024);10471048mdev = (struct mthca_dev *) ib_alloc_device(sizeof *mdev);1049if (!mdev) {1050dev_err(&pdev->dev, "Device struct alloc failed, "1051"aborting.\n");1052err = -ENOMEM;1053goto err_free_res;1054}10551056mdev->pdev = pdev;10571058mdev->mthca_flags = mthca_hca_table[hca_type].flags;1059if (ddr_hidden)1060mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN;10611062/*1063* Now reset the HCA before we touch the PCI capabilities or1064* attempt a firmware command, since a boot ROM may have left1065* the HCA in an undefined state.1066*/1067err = mthca_reset(mdev);1068if (err) {1069mthca_err(mdev, "Failed to reset HCA, aborting.\n");1070goto err_free_dev;1071}10721073if (mthca_cmd_init(mdev)) {1074mthca_err(mdev, "Failed to init command interface, aborting.\n");1075goto err_free_dev;1076}10771078err = mthca_tune_pci(mdev);1079if (err)1080goto err_cmd;10811082err = mthca_init_hca(mdev);1083if (err)1084goto err_cmd;10851086if (mdev->fw_ver < mthca_hca_table[hca_type].latest_fw) {1087mthca_warn(mdev, "HCA FW version %d.%d.%03d is old (%d.%d.%03d is current).\n",1088(int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,1089(int) (mdev->fw_ver & 0xffff),1090(int) (mthca_hca_table[hca_type].latest_fw >> 32),1091(int) (mthca_hca_table[hca_type].latest_fw >> 16) & 0xffff,1092(int) (mthca_hca_table[hca_type].latest_fw & 0xffff));1093mthca_warn(mdev, "If you have problems, try updating your HCA FW.\n");1094}10951096if (msi_x && !mthca_enable_msi_x(mdev))1097mdev->mthca_flags |= MTHCA_FLAG_MSI_X;10981099err = mthca_setup_hca(mdev);1100if (err == -EBUSY && (mdev->mthca_flags & MTHCA_FLAG_MSI_X)) {1101if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)1102pci_disable_msix(pdev);1103mdev->mthca_flags &= ~MTHCA_FLAG_MSI_X;11041105err = mthca_setup_hca(mdev);1106}11071108if (err)1109goto err_close;11101111err = mthca_register_device(mdev);1112if (err)1113goto err_cleanup;11141115err = mthca_create_agents(mdev);1116if (err)1117goto err_unregister;11181119pci_set_drvdata(pdev, mdev);1120mdev->hca_type = hca_type;11211122mdev->active = true;11231124return 0;11251126err_unregister:1127mthca_unregister_device(mdev);11281129err_cleanup:1130mthca_cleanup_mcg_table(mdev);1131mthca_cleanup_av_table(mdev);1132mthca_cleanup_qp_table(mdev);1133mthca_cleanup_srq_table(mdev);1134mthca_cleanup_cq_table(mdev);1135mthca_cmd_use_polling(mdev);1136mthca_cleanup_eq_table(mdev);11371138mthca_pd_free(mdev, &mdev->driver_pd);11391140mthca_cleanup_mr_table(mdev);1141mthca_cleanup_pd_table(mdev);1142mthca_cleanup_uar_table(mdev);11431144err_close:1145if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)1146pci_disable_msix(pdev);11471148mthca_close_hca(mdev);11491150err_cmd:1151mthca_cmd_cleanup(mdev);11521153err_free_dev:1154ib_dealloc_device(&mdev->ib_dev);11551156err_free_res:1157pci_release_regions(pdev);11581159err_disable_pdev:1160pci_disable_device(pdev);1161pci_set_drvdata(pdev, NULL);1162return err;1163}11641165static void __mthca_remove_one(struct pci_dev *pdev)1166{1167struct mthca_dev *mdev = pci_get_drvdata(pdev);1168u8 status;1169int p;11701171if (mdev) {1172mthca_free_agents(mdev);1173mthca_unregister_device(mdev);11741175for (p = 1; p <= mdev->limits.num_ports; ++p)1176mthca_CLOSE_IB(mdev, p, &status);11771178mthca_cleanup_mcg_table(mdev);1179mthca_cleanup_av_table(mdev);1180mthca_cleanup_qp_table(mdev);1181mthca_cleanup_srq_table(mdev);1182mthca_cleanup_cq_table(mdev);1183mthca_cmd_use_polling(mdev);1184mthca_cleanup_eq_table(mdev);11851186mthca_pd_free(mdev, &mdev->driver_pd);11871188mthca_cleanup_mr_table(mdev);1189mthca_cleanup_pd_table(mdev);11901191iounmap(mdev->kar);1192mthca_uar_free(mdev, &mdev->driver_uar);1193mthca_cleanup_uar_table(mdev);1194mthca_close_hca(mdev);1195mthca_cmd_cleanup(mdev);11961197if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)1198pci_disable_msix(pdev);11991200ib_dealloc_device(&mdev->ib_dev);1201pci_release_regions(pdev);1202pci_disable_device(pdev);1203pci_set_drvdata(pdev, NULL);1204}1205}12061207int __mthca_restart_one(struct pci_dev *pdev)1208{1209struct mthca_dev *mdev;1210int hca_type;12111212mdev = pci_get_drvdata(pdev);1213if (!mdev)1214return -ENODEV;1215hca_type = mdev->hca_type;1216__mthca_remove_one(pdev);1217return __mthca_init_one(pdev, hca_type);1218}12191220static int __devinit mthca_init_one(struct pci_dev *pdev,1221const struct pci_device_id *id)1222{1223int ret;12241225mutex_lock(&mthca_device_mutex);12261227printk_once(KERN_INFO "%s", mthca_version);12281229if (id->driver_data >= ARRAY_SIZE(mthca_hca_table)) {1230printk(KERN_ERR PFX "%s has invalid driver data %lx\n",1231pci_name(pdev), id->driver_data);1232mutex_unlock(&mthca_device_mutex);1233return -ENODEV;1234}12351236ret = __mthca_init_one(pdev, id->driver_data);12371238mutex_unlock(&mthca_device_mutex);12391240return ret;1241}12421243static void __devexit mthca_remove_one(struct pci_dev *pdev)1244{1245mutex_lock(&mthca_device_mutex);1246__mthca_remove_one(pdev);1247mutex_unlock(&mthca_device_mutex);1248}12491250static struct pci_device_id mthca_pci_table[] = {1251{ PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_TAVOR),1252.driver_data = TAVOR },1253{ PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_TAVOR),1254.driver_data = TAVOR },1255{ PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT),1256.driver_data = ARBEL_COMPAT },1257{ PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT),1258.driver_data = ARBEL_COMPAT },1259{ PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_ARBEL),1260.driver_data = ARBEL_NATIVE },1261{ PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_ARBEL),1262.driver_data = ARBEL_NATIVE },1263{ PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_SINAI),1264.driver_data = SINAI },1265{ PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_SINAI),1266.driver_data = SINAI },1267{ PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_SINAI_OLD),1268.driver_data = SINAI },1269{ PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_SINAI_OLD),1270.driver_data = SINAI },1271{ 0, }1272};12731274MODULE_DEVICE_TABLE(pci, mthca_pci_table);12751276static struct pci_driver mthca_driver = {1277.name = DRV_NAME,1278.id_table = mthca_pci_table,1279.probe = mthca_init_one,1280.remove = __devexit_p(mthca_remove_one)1281};12821283static void __init __mthca_check_profile_val(const char *name, int *pval,1284int pval_default)1285{1286/* value must be positive and power of 2 */1287int old_pval = *pval;12881289if (old_pval <= 0)1290*pval = pval_default;1291else1292*pval = roundup_pow_of_two(old_pval);12931294if (old_pval != *pval) {1295printk(KERN_WARNING PFX "Invalid value %d for %s in module parameter.\n",1296old_pval, name);1297printk(KERN_WARNING PFX "Corrected %s to %d.\n", name, *pval);1298}1299}13001301#define mthca_check_profile_val(name, default) \1302__mthca_check_profile_val(#name, &hca_profile.name, default)13031304static void __init mthca_validate_profile(void)1305{1306mthca_check_profile_val(num_qp, MTHCA_DEFAULT_NUM_QP);1307mthca_check_profile_val(rdb_per_qp, MTHCA_DEFAULT_RDB_PER_QP);1308mthca_check_profile_val(num_cq, MTHCA_DEFAULT_NUM_CQ);1309mthca_check_profile_val(num_mcg, MTHCA_DEFAULT_NUM_MCG);1310mthca_check_profile_val(num_mpt, MTHCA_DEFAULT_NUM_MPT);1311mthca_check_profile_val(num_mtt, MTHCA_DEFAULT_NUM_MTT);1312mthca_check_profile_val(num_udav, MTHCA_DEFAULT_NUM_UDAV);1313mthca_check_profile_val(fmr_reserved_mtts, MTHCA_DEFAULT_NUM_RESERVED_MTTS);13141315if (hca_profile.fmr_reserved_mtts >= hca_profile.num_mtt) {1316printk(KERN_WARNING PFX "Invalid fmr_reserved_mtts module parameter %d.\n",1317hca_profile.fmr_reserved_mtts);1318printk(KERN_WARNING PFX "(Must be smaller than num_mtt %d)\n",1319hca_profile.num_mtt);1320hca_profile.fmr_reserved_mtts = hca_profile.num_mtt / 2;1321printk(KERN_WARNING PFX "Corrected fmr_reserved_mtts to %d.\n",1322hca_profile.fmr_reserved_mtts);1323}13241325if ((log_mtts_per_seg < 1) || (log_mtts_per_seg > 5)) {1326printk(KERN_WARNING PFX "bad log_mtts_per_seg (%d). Using default - %d\n",1327log_mtts_per_seg, ilog2(MTHCA_MTT_SEG_SIZE / 8));1328log_mtts_per_seg = ilog2(MTHCA_MTT_SEG_SIZE / 8);1329}1330}13311332static int __init mthca_init(void)1333{1334int ret;13351336mthca_validate_profile();13371338ret = mthca_catas_init();1339if (ret)1340return ret;13411342ret = pci_register_driver(&mthca_driver);1343if (ret < 0) {1344mthca_catas_cleanup();1345return ret;1346}13471348return 0;1349}13501351static void __exit mthca_cleanup(void)1352{1353pci_unregister_driver(&mthca_driver);1354mthca_catas_cleanup();1355}13561357module_init(mthca_init);1358module_exit(mthca_cleanup);135913601361