-/*
- * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
- * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * $Id$
- */
-
-#include "mthca_dev.h"
-#if defined(EVENT_TRACING)
-#ifdef offsetof
-#undef offsetof
-#endif
-#include "mthca_main.tmh"
-#endif
-#include "mthca_config_reg.h"
-#include "mthca_cmd.h"
-#include "mthca_profile.h"
-#include "mthca_memfree.h"
-
-static const char mthca_version[] =
- DRV_NAME ": HCA Driver v"
- DRV_VERSION " (" DRV_RELDATE ")";
-
-static struct mthca_profile default_profile = {
- 1 << 16, // num_qp
- 4, // rdb_per_qp
- 0, // num_srq
- 1 << 16, // num_cq
- 1 << 13, // num_mcg
- 1 << 17, // num_mpt
- 1 << 20, // num_mtt
- 1 << 15, // num_udav (Tavor only)
- 0, // num_uar
- 1 << 18, // uarc_size (Arbel only)
- 1 << 18, // fmr_reserved_mtts (Tavor only)
-};
-
-/* Types of supported HCA */
-enum __hca_type {
- TAVOR, /* MT23108 */
- ARBEL_COMPAT, /* MT25208 in Tavor compat mode */
- ARBEL_NATIVE, /* MT25218 with extended features */
- SINAI, /* MT25204 */
- LIVEFISH /* a burning device */
-};
-
-#define MTHCA_FW_VER(major, minor, subminor) \
- (((u64) (major) << 32) | ((u64) (minor) << 16) | (u64) (subminor))
-
-static struct {
- u64 max_unsupported_fw;
- u64 min_supported_fw;
- int is_memfree;
- int is_pcie;
-} mthca_hca_table[] = {
- { MTHCA_FW_VER(3, 3, 2), MTHCA_FW_VER(3, 4, 0), 0, 0 }, /* TAVOR */
- { MTHCA_FW_VER(4, 7, 0), MTHCA_FW_VER(4, 7, 400), 0, 1 }, /* ARBEL_COMPAT */
- { MTHCA_FW_VER(5, 1, 0), MTHCA_FW_VER(5, 1, 400), 1, 1 }, /* ARBEL_NATIVE */
- { MTHCA_FW_VER(1, 0, 800), MTHCA_FW_VER(1, 1, 0), 1, 1 }, /* SINAI */
- { MTHCA_FW_VER(0, 0, 0), MTHCA_FW_VER(0, 0, 0), 0, 0 } /* LIVEFISH */
-};
-
-
-#define HCA(v, d, t) \
- { PCI_VENDOR_ID_##v, PCI_DEVICE_ID_MELLANOX_##d, t }
-
-static struct pci_device_id {
- unsigned vendor;
- unsigned device;
- enum __hca_type driver_data;
-} mthca_pci_table[] = {
- HCA(MELLANOX, TAVOR, TAVOR),
- HCA(MELLANOX, ARBEL_COMPAT, ARBEL_COMPAT),
- HCA(MELLANOX, ARBEL, ARBEL_NATIVE),
- HCA(MELLANOX, SINAI_OLD, SINAI),
- HCA(MELLANOX, SINAI, SINAI),
- HCA(TOPSPIN, TAVOR, TAVOR),
- HCA(TOPSPIN, ARBEL_COMPAT, TAVOR),
- HCA(TOPSPIN, ARBEL, ARBEL_NATIVE),
- HCA(TOPSPIN, SINAI_OLD, SINAI),
- HCA(TOPSPIN, SINAI, SINAI),
- // live fishes
- HCA(MELLANOX, TAVOR_BD, LIVEFISH),
- HCA(MELLANOX, ARBEL_BD, LIVEFISH),
- HCA(MELLANOX, SINAI_OLD_BD, LIVEFISH),
- HCA(MELLANOX, SINAI_BD, LIVEFISH),
- HCA(TOPSPIN, TAVOR_BD, LIVEFISH),
- HCA(TOPSPIN, ARBEL_BD, LIVEFISH),
- HCA(TOPSPIN, SINAI_OLD_BD, LIVEFISH),
- HCA(TOPSPIN, SINAI_BD, LIVEFISH),
-};
-#define MTHCA_PCI_TABLE_SIZE (sizeof(mthca_pci_table)/sizeof(struct pci_device_id))
-
-// wrapper to driver's hca_tune_pci
-static NTSTATUS mthca_tune_pci(struct mthca_dev *mdev)
-{
- PDEVICE_OBJECT pdo = mdev->ext->cl_ext.p_self_do;
- return hca_tune_pci(pdo, &mdev->uplink_info);
-}
-
-int mthca_get_dev_info(struct mthca_dev *mdev, __be64 *node_guid, u32 *hw_id)
-{
- struct ib_device_attr props;
- struct ib_device *ib_dev = &mdev->ib_dev;
- int err = (ib_dev->query_device )(ib_dev, &props );
-
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("can't get guid - mthca_query_port() failed (%08X)\n", err ));
- return err;
- }
-
- //TODO: do we need to convert GUID to LE by cl_ntoh64(x) ?
- *node_guid = ib_dev->node_guid;
- *hw_id = props.hw_ver;
- return 0;
-}
-
-static struct pci_device_id * mthca_find_pci_dev(unsigned ven_id, unsigned dev_id)
-{
- struct pci_device_id *p_id = mthca_pci_table;
- int i;
-
- // find p_id (appropriate line in mthca_pci_table)
- for (i = 0; i < MTHCA_PCI_TABLE_SIZE; ++i, ++p_id) {
- if (p_id->device == dev_id && p_id->vendor == ven_id)
- return p_id;
- }
- return NULL;
-}
-
-
-static int mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim *dev_lim)
-{
- int err;
- u8 status;
-
- err = mthca_QUERY_DEV_LIM(mdev, dev_lim, &status);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_DEV_LIM command failed, aborting.\n"));
- return err;
- }
- if (status) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_DEV_LIM returned status 0x%02x, "
- "aborting.\n", status));
- return -EINVAL;
- }
- if (dev_lim->min_page_sz > PAGE_SIZE) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("HCA minimum page size of %d bigger than "
- "kernel PAGE_SIZE of %ld, aborting.\n",
- dev_lim->min_page_sz, PAGE_SIZE));
- return -ENODEV;
- }
- if (dev_lim->num_ports > MTHCA_MAX_PORTS) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("HCA has %d ports, but we only support %d, "
- "aborting.\n",
- dev_lim->num_ports, MTHCA_MAX_PORTS));
- return -ENODEV;
- }
-
- if (dev_lim->uar_size > (int)pci_resource_len(mdev, HCA_BAR_TYPE_UAR)) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW , ("HCA reported UAR size of 0x%x bigger than "
- "Bar%d size of 0x%lx, aborting.\n",
- dev_lim->uar_size, HCA_BAR_TYPE_UAR,
- (unsigned long)pci_resource_len(mdev, HCA_BAR_TYPE_UAR)));
- return -ENODEV;
- }
-
-
- mdev->limits.num_ports = dev_lim->num_ports;
- mdev->limits.vl_cap = dev_lim->max_vl;
- mdev->limits.mtu_cap = dev_lim->max_mtu;
- mdev->limits.gid_table_len = dev_lim->max_gids;
- mdev->limits.pkey_table_len = dev_lim->max_pkeys;
- mdev->limits.local_ca_ack_delay = dev_lim->local_ca_ack_delay;
- mdev->limits.max_sg = dev_lim->max_sg;
- mdev->limits.max_wqes = dev_lim->max_qp_sz;
- mdev->limits.max_qp_init_rdma = dev_lim->max_requester_per_qp;
- mdev->limits.reserved_qps = dev_lim->reserved_qps;
- mdev->limits.max_srq_wqes = dev_lim->max_srq_sz;
- mdev->limits.reserved_srqs = dev_lim->reserved_srqs;
- mdev->limits.reserved_eecs = dev_lim->reserved_eecs;
- mdev->limits.max_desc_sz = dev_lim->max_desc_sz;
- mdev->limits.max_srq_sge = mthca_max_srq_sge(mdev);
- /*
- * Subtract 1 from the limit because we need to allocate a
- * spare CQE so the HCA HW can tell the difference between an
- * empty CQ and a full CQ.
- */
- mdev->limits.max_cqes = dev_lim->max_cq_sz - 1;
- mdev->limits.reserved_cqs = dev_lim->reserved_cqs;
- mdev->limits.reserved_eqs = dev_lim->reserved_eqs;
- mdev->limits.reserved_mtts = dev_lim->reserved_mtts;
- mdev->limits.reserved_mrws = dev_lim->reserved_mrws;
- mdev->limits.reserved_uars = dev_lim->reserved_uars;
- mdev->limits.reserved_pds = dev_lim->reserved_pds;
- mdev->limits.port_width_cap = (u8)dev_lim->max_port_width;
- mdev->limits.page_size_cap = !(u32)(dev_lim->min_page_sz - 1);
- mdev->limits.flags = dev_lim->flags;
- mdev->limits.num_avs = mthca_is_memfree(mdev) ? 0 : dev_lim->hca.tavor.max_avs;
-
- /* IB_DEVICE_RESIZE_MAX_WR not supported by driver.
- May be doable since hardware supports it for SRQ.
-
- IB_DEVICE_N_NOTIFY_CQ is supported by hardware but not by driver.
-
- IB_DEVICE_SRQ_RESIZE is supported by hardware but SRQ is not
- supported by driver. */
- mdev->device_cap_flags = IB_DEVICE_CHANGE_PHY_PORT |
- IB_DEVICE_PORT_ACTIVE_EVENT |
- IB_DEVICE_SYS_IMAGE_GUID |
- IB_DEVICE_RC_RNR_NAK_GEN;
-
- if (dev_lim->flags & DEV_LIM_FLAG_BAD_PKEY_CNTR)
- mdev->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR;
-
- if (dev_lim->flags & DEV_LIM_FLAG_BAD_QKEY_CNTR)
- mdev->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR;
-
- if (dev_lim->flags & DEV_LIM_FLAG_RAW_MULTI)
- mdev->device_cap_flags |= IB_DEVICE_RAW_MULTI;
-
- if (dev_lim->flags & DEV_LIM_FLAG_AUTO_PATH_MIG)
- mdev->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG;
-
- if (dev_lim->flags & DEV_LIM_FLAG_UD_AV_PORT_ENFORCE)
- mdev->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE;
-
- if (dev_lim->flags & DEV_LIM_FLAG_SRQ)
- mdev->mthca_flags |= MTHCA_FLAG_SRQ;
-
- return 0;
-}
-
-static int mthca_init_tavor(struct mthca_dev *mdev)
-{
- u8 status;
- int err;
- struct mthca_dev_lim dev_lim;
- struct mthca_profile profile;
- struct mthca_init_hca_param init_hca;
-
- err = mthca_SYS_EN(mdev, &status);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("SYS_EN command failed, aborting.\n"));
- return err;
- }
- if (status) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("SYS_EN returned status 0x%02x, "
- "aborting.\n", status));
- return -EINVAL;
- }
-
- err = mthca_QUERY_FW(mdev, &status);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_FW command failed, aborting.\n"));
- goto err_disable;
- }
- if (status) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_FW returned status 0x%02x, "
- "aborting.\n", status));
- err = -EINVAL;
- goto err_disable;
- }
- err = mthca_QUERY_DDR(mdev, &status);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_DDR command failed, aborting.\n"));
- goto err_disable;
- }
- if (status) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,( "QUERY_DDR returned status 0x%02x, "
- "aborting.\n", status));
- err = -EINVAL;
- goto err_disable;
- }
-
- err = mthca_dev_lim(mdev, &dev_lim);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,( "QUERY_DEV_LIM command failed, aborting.\n"));
- goto err_disable;
- }
-
- profile = default_profile;
- profile.num_uar = dev_lim.uar_size / PAGE_SIZE;
- profile.uarc_size = 0;
-
- /* correct default profile */
- if ( g_profile_qp_num != 0 )
- profile.num_qp = g_profile_qp_num;
-
- if ( g_profile_rd_out != 0xffffffff )
- profile.rdb_per_qp = g_profile_rd_out;
-
- if (mdev->mthca_flags & MTHCA_FLAG_SRQ)
- profile.num_srq = dev_lim.max_srqs;
-
- err = (int)mthca_make_profile(mdev, &profile, &dev_lim, &init_hca);
- if (err < 0)
- goto err_disable;
-
- err = (int)mthca_INIT_HCA(mdev, &init_hca, &status);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("INIT_HCA command failed, aborting.\n"));
- goto err_disable;
- }
- if (status) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("INIT_HCA returned status 0x%02x, "
- "aborting.\n", status));
- err = -EINVAL;
- goto err_disable;
- }
-
- return 0;
-
-err_disable:
- mthca_SYS_DIS(mdev, &status);
-
- return err;
-}
-
-static int mthca_load_fw(struct mthca_dev *mdev)
-{
- u8 status;
- int err;
-
- /* FIXME: use HCA-attached memory for FW if present */
-
- mdev->fw.arbel.fw_icm =
- mthca_alloc_icm(mdev, mdev->fw.arbel.fw_pages,
- GFP_HIGHUSER | __GFP_NOWARN);
- if (!mdev->fw.arbel.fw_icm) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Couldn't allocate FW area, aborting.\n"));
- return -ENOMEM;
- }
-
- err = mthca_MAP_FA(mdev, mdev->fw.arbel.fw_icm, &status);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("MAP_FA command failed, aborting.\n"));
- goto err_free;
- }
- if (status) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("MAP_FA returned status 0x%02x, aborting.\n", status));
- err = -EINVAL;
- goto err_free;
- }
- err = mthca_RUN_FW(mdev, &status);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("RUN_FW command failed, aborting.\n"));
- goto err_unmap_fa;
- }
- if (status) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("RUN_FW returned status 0x%02x, aborting.\n", status));
- err = -EINVAL;
- goto err_unmap_fa;
- }
-
- return 0;
-
-err_unmap_fa:
- mthca_UNMAP_FA(mdev, &status);
-
-err_free:
- mthca_free_icm(mdev, mdev->fw.arbel.fw_icm);
- return err;
-}
-
-static int mthca_init_icm(struct mthca_dev *mdev,
- struct mthca_dev_lim *dev_lim,
- struct mthca_init_hca_param *init_hca,
- u64 icm_size)
-{
- u64 aux_pages;
- u8 status;
- int err;
-
- err = mthca_SET_ICM_SIZE(mdev, icm_size, &aux_pages, &status);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("SET_ICM_SIZE command failed, aborting.\n"));
- return err;
- }
- if (status) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("SET_ICM_SIZE returned status 0x%02x, "
- "aborting.\n", status));
- return -EINVAL;
- }
-
- HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW , ("%I64d KB of HCA context requires %I64d KB aux memory.\n",
- (u64) icm_size >> 10,
- (u64) aux_pages << 2));
-
- mdev->fw.arbel.aux_icm = mthca_alloc_icm(mdev, (int)aux_pages,
- GFP_HIGHUSER | __GFP_NOWARN);
- if (!mdev->fw.arbel.aux_icm) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Couldn't allocate aux memory, aborting.\n"));
- return -ENOMEM;
- }
-
- err = mthca_MAP_ICM_AUX(mdev, mdev->fw.arbel.aux_icm, &status);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("MAP_ICM_AUX command failed, aborting.\n"));
- goto err_free_aux;
- }
- if (status) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("MAP_ICM_AUX returned status 0x%02x, aborting.\n", status));
- err = -EINVAL;
- goto err_free_aux;
- }
-
- err = mthca_map_eq_icm(mdev, init_hca->eqc_base);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map EQ context memory, aborting.\n"));
- goto err_unmap_aux;
- }
-
- mdev->mr_table.mtt_table = mthca_alloc_icm_table(mdev, init_hca->mtt_base,
- MTHCA_MTT_SEG_SIZE,
- mdev->limits.num_mtt_segs,
- mdev->limits.reserved_mtts, 1);
- if (!mdev->mr_table.mtt_table) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map MTT context memory, aborting.\n"));
- err = -ENOMEM;
- goto err_unmap_eq;
- }
-
- mdev->mr_table.mpt_table = mthca_alloc_icm_table(mdev, init_hca->mpt_base,
- dev_lim->mpt_entry_sz,
- mdev->limits.num_mpts,
- mdev->limits.reserved_mrws, 1);
- if (!mdev->mr_table.mpt_table) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map MPT context memory, aborting.\n"));
- err = -ENOMEM;
- goto err_unmap_mtt;
- }
-
- mdev->qp_table.qp_table = mthca_alloc_icm_table(mdev, init_hca->qpc_base,
- dev_lim->qpc_entry_sz,
- mdev->limits.num_qps,
- mdev->limits.reserved_qps, 0);
- if (!mdev->qp_table.qp_table) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map QP context memory, aborting.\n"));
- err = -ENOMEM;
- goto err_unmap_mpt;
- }
-
- mdev->qp_table.eqp_table = mthca_alloc_icm_table(mdev, init_hca->eqpc_base,
- dev_lim->eqpc_entry_sz,
- mdev->limits.num_qps,
- mdev->limits.reserved_qps, 0);
- if (!mdev->qp_table.eqp_table) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map EQP context memory, aborting.\n"));
- err = -ENOMEM;
- goto err_unmap_qp;
- }
-
- mdev->qp_table.rdb_table = mthca_alloc_icm_table(mdev, init_hca->rdb_base,
- MTHCA_RDB_ENTRY_SIZE,
- mdev->limits.num_qps <<
- mdev->qp_table.rdb_shift,
- 0, 0);
- if (!mdev->qp_table.rdb_table) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map RDB context memory, aborting\n"));
- err = -ENOMEM;
- goto err_unmap_eqp;
- }
-
- mdev->cq_table.table = mthca_alloc_icm_table(mdev, init_hca->cqc_base,
- dev_lim->cqc_entry_sz,
- mdev->limits.num_cqs,
- mdev->limits.reserved_cqs, 0);
- if (!mdev->cq_table.table) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map CQ context memory, aborting.\n"));
- err = -ENOMEM;
- goto err_unmap_rdb;
- }
-
- if (mdev->mthca_flags & MTHCA_FLAG_SRQ) {
- mdev->srq_table.table =
- mthca_alloc_icm_table(mdev, init_hca->srqc_base,
- dev_lim->srq_entry_sz,
- mdev->limits.num_srqs,
- mdev->limits.reserved_srqs, 0);
- if (!mdev->srq_table.table) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map SRQ context memory, "
- "aborting.\n"));
- err = -ENOMEM;
- goto err_unmap_cq;
- }
- }
-
- /*
- * It's not strictly required, but for simplicity just map the
- * whole multicast group table now. The table isn't very big
- * and it's a lot easier than trying to track ref counts.
- */
- mdev->mcg_table.table = mthca_alloc_icm_table(mdev, init_hca->mc_base,
- MTHCA_MGM_ENTRY_SIZE,
- mdev->limits.num_mgms +
- mdev->limits.num_amgms,
- mdev->limits.num_mgms +
- mdev->limits.num_amgms,
- 0);
- if (!mdev->mcg_table.table) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map MCG context memory, aborting.\n"));
- err = -ENOMEM;
- goto err_unmap_srq;
- }
-
- return 0;
-
-err_unmap_srq:
- if (mdev->mthca_flags & MTHCA_FLAG_SRQ)
- mthca_free_icm_table(mdev, mdev->srq_table.table);
-
-err_unmap_cq:
- mthca_free_icm_table(mdev, mdev->cq_table.table);
-
-err_unmap_rdb:
- mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);
-
-err_unmap_eqp:
- mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);
-
-err_unmap_qp:
- mthca_free_icm_table(mdev, mdev->qp_table.qp_table);
-
-err_unmap_mpt:
- mthca_free_icm_table(mdev, mdev->mr_table.mpt_table);
-
-err_unmap_mtt:
- mthca_free_icm_table(mdev, mdev->mr_table.mtt_table);
-
-err_unmap_eq:
- mthca_unmap_eq_icm(mdev);
-
-err_unmap_aux:
- mthca_UNMAP_ICM_AUX(mdev, &status);
-
-err_free_aux:
- mthca_free_icm(mdev, mdev->fw.arbel.aux_icm);
-
- return err;
-}
-
-static int mthca_init_arbel(struct mthca_dev *mdev)
-{
- struct mthca_dev_lim dev_lim;
- struct mthca_profile profile;
- struct mthca_init_hca_param init_hca;
- u64 icm_size;
- u8 status;
- int err;
-
- err = mthca_QUERY_FW(mdev, &status);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_FW command failed, aborting.\n"));
- return err;
- }
- if (status) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_FW returned status 0x%02x, "
- "aborting.\n", status));
- return -EINVAL;
- }
-
- err = mthca_ENABLE_LAM(mdev, &status);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("ENABLE_LAM command failed, aborting.\n"));
- return err;
- }
- if (status == MTHCA_CMD_STAT_LAM_NOT_PRE) {
- HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,("No HCA-attached memory (running in MemFree mode)\n"));
- mdev->mthca_flags |= MTHCA_FLAG_NO_LAM;
- } else if (status) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("ENABLE_LAM returned status 0x%02x, "
- "aborting.\n", status));
- return -EINVAL;
- }
-
- err = mthca_load_fw(mdev);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to start FW, aborting.\n"));
- goto err_disable;
- }
-
- err = mthca_dev_lim(mdev, &dev_lim);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_DEV_LIM command failed, aborting.\n"));
- goto err_stop_fw;
- }
-
- profile = default_profile;
- profile.num_uar = dev_lim.uar_size / PAGE_SIZE;
- profile.num_udav = 0;
- if (mdev->mthca_flags & MTHCA_FLAG_SRQ)
- profile.num_srq = dev_lim.max_srqs;
-
- /* correct default profile */
- if ( g_profile_qp_num != 0 )
- profile.num_qp = g_profile_qp_num;
-
- if ( g_profile_rd_out != 0xffffffff )
- profile.rdb_per_qp = g_profile_rd_out;
-
- RtlZeroMemory( &init_hca, sizeof(init_hca));
- icm_size = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca);
- if ((int) icm_size < 0) {
- err = (int)icm_size;
- goto err_stop_fw;
- }
-
- err = mthca_init_icm(mdev, &dev_lim, &init_hca, icm_size);
- if (err)
- goto err_stop_fw;
-
- err = mthca_INIT_HCA(mdev, &init_hca, &status);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("INIT_HCA command failed, aborting.\n"));
- goto err_free_icm;
- }
- if (status) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("INIT_HCA returned status 0x%02x, "
- "aborting.\n", status));
- err = -EINVAL;
- goto err_free_icm;
- }
-
- return 0;
-
-err_free_icm:
- if (mdev->mthca_flags & MTHCA_FLAG_SRQ)
- mthca_free_icm_table(mdev, mdev->srq_table.table);
- mthca_free_icm_table(mdev, mdev->cq_table.table);
- mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);
- mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);
- mthca_free_icm_table(mdev, mdev->qp_table.qp_table);
- mthca_free_icm_table(mdev, mdev->mr_table.mpt_table);
- mthca_free_icm_table(mdev, mdev->mr_table.mtt_table);
- mthca_unmap_eq_icm(mdev);
-
- mthca_UNMAP_ICM_AUX(mdev, &status);
- mthca_free_icm(mdev, mdev->fw.arbel.aux_icm);
-
-err_stop_fw:
- mthca_UNMAP_FA(mdev, &status);
- mthca_free_icm(mdev, mdev->fw.arbel.fw_icm);
-
-err_disable:
- if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM))
- mthca_DISABLE_LAM(mdev, &status);
-
- return err;
-}
-
-static void mthca_close_hca(struct mthca_dev *mdev)
-{
- u8 status;
-
- mthca_CLOSE_HCA(mdev, 0, &status);
-
- if (mthca_is_memfree(mdev)) {
- if (mdev->mthca_flags & MTHCA_FLAG_SRQ)
- mthca_free_icm_table(mdev, mdev->srq_table.table);
- mthca_free_icm_table(mdev, mdev->cq_table.table);
- mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);
- mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);
- mthca_free_icm_table(mdev, mdev->qp_table.qp_table);
- mthca_free_icm_table(mdev, mdev->mr_table.mpt_table);
- mthca_free_icm_table(mdev, mdev->mr_table.mtt_table);
- mthca_free_icm_table(mdev, mdev->mcg_table.table);
- mthca_unmap_eq_icm(mdev);
-
- mthca_UNMAP_ICM_AUX(mdev, &status);
- mthca_free_icm(mdev, mdev->fw.arbel.aux_icm);
-
- mthca_UNMAP_FA(mdev, &status);
- mthca_free_icm(mdev, mdev->fw.arbel.fw_icm);
-
- if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM))
- mthca_DISABLE_LAM(mdev, &status);
- } else
- mthca_SYS_DIS(mdev, &status);
-}
-
-static int mthca_init_hca(struct mthca_dev *mdev)
-{
- u8 status;
- int err;
- struct mthca_adapter adapter;
-
- if (mthca_is_memfree(mdev))
- err = mthca_init_arbel(mdev);
- else
- err = mthca_init_tavor(mdev);
-
- if (err)
- return err;
-
- err = mthca_QUERY_ADAPTER(mdev, &adapter, &status);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_ADAPTER command failed, aborting.\n"));
- goto err_close;
- }
- if (status) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_ADAPTER returned status 0x%02x, "
- "aborting.\n", status));
- err = -EINVAL;
- goto err_close;
- }
-
- mdev->eq_table.inta_pin = adapter.inta_pin;
- mdev->rev_id = adapter.revision_id;
- memcpy(mdev->board_id, adapter.board_id, sizeof mdev->board_id);
-
- return 0;
-
-err_close:
- mthca_close_hca(mdev);
- return err;
-}
-
-static int mthca_setup_hca(struct mthca_dev *mdev)
-{
- int err;
- u8 status;
-
- MTHCA_INIT_DOORBELL_LOCK(&mdev->doorbell_lock);
-
- err = mthca_init_uar_table(mdev);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "
- "user access region table, aborting.\n"));
- return err;
- }
-
- err = mthca_uar_alloc(mdev, &mdev->driver_uar);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to allocate driver access region, "
- "aborting.\n"));
- goto err_uar_table_free;
- }
-
- mdev->kar = ioremap((io_addr_t)mdev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE,&mdev->kar_size);
- if (!mdev->kar) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Couldn't map kernel access region, "
- "aborting.\n"));
- err = -ENOMEM;
- goto err_uar_free;
- }
-
- err = mthca_init_pd_table(mdev);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "
- "protection domain table, aborting.\n"));
- goto err_kar_unmap;
- }
-
- err = mthca_init_mr_table(mdev);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "
- "memory region table, aborting.\n"));
- goto err_pd_table_free;
- }
-
- err = mthca_pd_alloc(mdev, 1, &mdev->driver_pd);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to create driver PD, "
- "aborting.\n"));
- goto err_mr_table_free;
- }
-
- err = mthca_init_eq_table(mdev);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW, ("Failed to initialize "
- "event queue table, aborting.\n"));
- goto err_pd_free;
- }
-
- err = mthca_cmd_use_events(mdev);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to switch to event-driven "
- "firmware commands, aborting.\n"));
- goto err_eq_table_free;
- }
-
- err = mthca_NOP(mdev, &status);
- if (err || status) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("NOP command failed to generate interrupt, aborting.\n"));
- if (mdev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)){
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Try again with MSI/MSI-X disabled.\n"));
- }else{
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("BIOS or ACPI interrupt routing problem?\n"));
- }
-
- goto err_cmd_poll;
- }
-
- HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_LOW ,("NOP command IRQ test passed\n"));
-
- err = mthca_init_cq_table(mdev);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "
- "completion queue table, aborting.\n"));
- goto err_cmd_poll;
- }
-
- err = mthca_init_srq_table(mdev);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "
- "shared receive queue table, aborting.\n"));
- goto err_cq_table_free;
- }
-
- err = mthca_init_qp_table(mdev);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW, ("Failed to initialize "
- "queue pair table, aborting.\n"));
- goto err_srq_table_free;
- }
-
- err = mthca_init_av_table(mdev);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "
- "address vector table, aborting.\n"));
- goto err_qp_table_free;
- }
-
- err = mthca_init_mcg_table(mdev);
- if (err) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "
- "multicast group table, aborting.\n"));
- goto err_av_table_free;
- }
-
- return 0;
-
-err_av_table_free:
- mthca_cleanup_av_table(mdev);
-
-err_qp_table_free:
- mthca_cleanup_qp_table(mdev);
-
-err_srq_table_free:
- mthca_cleanup_srq_table(mdev);
-
-err_cq_table_free:
- mthca_cleanup_cq_table(mdev);
-
-err_cmd_poll:
- mthca_cmd_use_polling(mdev);
-
-err_eq_table_free:
- mthca_cleanup_eq_table(mdev);
-
-err_pd_free:
- mthca_pd_free(mdev, &mdev->driver_pd);
-
-err_mr_table_free:
- mthca_cleanup_mr_table(mdev);
-
-err_pd_table_free:
- mthca_cleanup_pd_table(mdev);
-
-err_kar_unmap:
- iounmap(mdev->kar, mdev->kar_size);
-
-err_uar_free:
- mthca_uar_free(mdev, &mdev->driver_uar);
-
-err_uar_table_free:
- mthca_cleanup_uar_table(mdev);
- return err;
-}
-
-
-static int mthca_check_fw(struct mthca_dev *mdev, struct pci_device_id *p_id)
-{
- int err = 0;
-
- if (mdev->fw_ver < mthca_hca_table[p_id->driver_data].max_unsupported_fw) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("HCA FW version %d.%d.%d is not supported. Use %d.%d.%d or higher.\n",
- (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,
- (int) (mdev->fw_ver & 0xffff),
- (int) (mthca_hca_table[p_id->driver_data].min_supported_fw >> 32),
- (int) (mthca_hca_table[p_id->driver_data].min_supported_fw >> 16) & 0xffff,
- (int) (mthca_hca_table[p_id->driver_data].min_supported_fw & 0xffff)));
- err = -EINVAL;
- }
- else
- if (mdev->fw_ver < mthca_hca_table[p_id->driver_data].min_supported_fw) {
- HCA_PRINT_EV(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,
- ("The HCA FW version is %d.%d.%d, which is not the latest one. \n"
- "If you meet any issues with the HCA please first try to upgrade the FW to version %d.%d.%d or higher.\n",
- (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,
- (int) (mdev->fw_ver & 0xffff),
- (int) (mthca_hca_table[p_id->driver_data].min_supported_fw >> 32),
- (int) (mthca_hca_table[p_id->driver_data].min_supported_fw >> 16) & 0xffff,
- (int) (mthca_hca_table[p_id->driver_data].min_supported_fw & 0xffff)));
- }
- else {
- HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,("Current HCA FW version is %d.%d.%d. \n",
- (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,
- (int) (mdev->fw_ver & 0xffff)));
- }
-
- return err;
-}
-
-NTSTATUS mthca_init_one(hca_dev_ext_t *ext)
-{
- static int mthca_version_printed = 0;
- int err;
- NTSTATUS status;
- struct mthca_dev *mdev;
- struct pci_device_id *p_id;
-
- /* print version */
- if (!mthca_version_printed) {
- HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,("%s\n", mthca_version));
- ++mthca_version_printed;
- }
-
- /* find the type of device */
- p_id = mthca_find_pci_dev(
- (unsigned)ext->hcaConfig.VendorID,
- (unsigned)ext->hcaConfig.DeviceID);
- if (p_id == NULL) {
- status = STATUS_NO_SUCH_DEVICE;
- goto end;
- }
-
-run_as_livefish:
- /* allocate mdev structure */
- mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
- if (!mdev) {
- // can't use HCA_PRINT_EV here !
- HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Device struct alloc failed, "
- "aborting.\n"));
- status = STATUS_INSUFFICIENT_RESOURCES;
- goto end;
- }
-
- /* set some fields */
- mdev->ext = ext; /* pointer to DEVICE OBJECT extension */
- mdev->hca_type = p_id->driver_data;
- mdev->ib_dev.mdev = mdev;
- if (p_id->driver_data == LIVEFISH)
- mdev->mthca_flags |= MTHCA_FLAG_LIVEFISH;
- if (mthca_is_livefish(mdev))
- goto done;
- if (ext->hca_hidden)
- mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN;
- if (mthca_hca_table[p_id->driver_data].is_memfree)
- mdev->mthca_flags |= MTHCA_FLAG_MEMFREE;
- if (mthca_hca_table[p_id->driver_data].is_pcie)
- mdev->mthca_flags |= MTHCA_FLAG_PCIE;
-
-//TODO: after we have a FW, capable of reset,
-// write a routine, that only presses the button
-
- /*
- * Now reset the HCA before we touch the PCI capabilities or
- * attempt a firmware command, since a boot ROM may have left
- * the HCA in an undefined state.
- */
- status = hca_reset( mdev->ext->cl_ext.p_self_do, p_id->driver_data == TAVOR );
- if ( !NT_SUCCESS( status ) ) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to reset HCA, aborting.\n"));
- goto err_free_dev;
- }
-
- if (mthca_cmd_init(mdev)) {
- HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to init command interface, aborting.\n"));
- status = STATUS_DEVICE_DATA_ERROR;
- goto err_free_dev;
- }
-
- status = mthca_tune_pci(mdev);
- if ( !NT_SUCCESS( status ) ) {
- goto err_cmd;
- }
-
- err = mthca_init_hca(mdev);
- if (err) {
- status = STATUS_UNSUCCESSFUL;
- goto err_cmd;
- }
-
- err = mthca_check_fw(mdev, p_id);
- if (err) {
- status = STATUS_UNSUCCESSFUL;
- goto err_close;
- }
-
- err = mthca_setup_hca(mdev);
- if (err) {
- status = STATUS_UNSUCCESSFUL;
- goto err_close;
- }
-
- err = mthca_register_device(mdev);
- if (err) {
- status = STATUS_UNSUCCESSFUL;
- goto err_cleanup;
- }
-
- done:
- ext->hca.mdev = mdev;
- mdev->state = MTHCA_DEV_INITIALIZED;
- return 0;
-
-err_cleanup:
- mthca_cleanup_mcg_table(mdev);
- mthca_cleanup_av_table(mdev);
- mthca_cleanup_qp_table(mdev);
- mthca_cleanup_srq_table(mdev);
- mthca_cleanup_cq_table(mdev);
- mthca_cmd_use_polling(mdev);
- mthca_cleanup_eq_table(mdev);
-
- mthca_pd_free(mdev, &mdev->driver_pd);
-
- mthca_cleanup_mr_table(mdev);
- mthca_cleanup_pd_table(mdev);
- mthca_cleanup_uar_table(mdev);
-
-err_close:
- mthca_close_hca(mdev);
-
-err_cmd:
- mthca_cmd_cleanup(mdev);
-
-err_free_dev:
- kfree(mdev);
-
- /* we failed device initialization - try to simulate "livefish" device to facilitate using FW burning tools */
- {
- USHORT dev_id = ext->hcaConfig.DeviceID;
-
- if (dev_id == PCI_DEVICE_ID_MELLANOX_ARBEL)
- dev_id = PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT;
- p_id = mthca_find_pci_dev( (unsigned)ext->hcaConfig.VendorID, dev_id + 1 );
- if (p_id == NULL) {
- status = STATUS_NO_SUCH_DEVICE;
- goto end;
- }
- goto run_as_livefish;
- }
-
-end:
- return status;
-}
-
-void mthca_remove_one(hca_dev_ext_t *ext)
-{
- struct mthca_dev *mdev = ext->hca.mdev;
- u8 status;
- int p;
-
- ext->hca.mdev = NULL;
- if (mdev) {
- mdev->state = MTHCA_DEV_UNINITIALIZED;
- if (mthca_is_livefish(mdev))
- goto done;
- mthca_unregister_device(mdev);
-
- for (p = 1; p <= mdev->limits.num_ports; ++p)
- mthca_CLOSE_IB(mdev, p, &status);
-
- mthca_cleanup_mcg_table(mdev);
- mthca_cleanup_av_table(mdev);
- mthca_cleanup_qp_table(mdev);
- mthca_cleanup_srq_table(mdev);
- mthca_cleanup_cq_table(mdev);
- mthca_cmd_use_polling(mdev);
- mthca_cleanup_eq_table(mdev);
- mthca_pd_free(mdev, &mdev->driver_pd);
- mthca_cleanup_mr_table(mdev);
- mthca_cleanup_pd_table(mdev);
- iounmap(mdev->kar, mdev->kar_size);
- mthca_uar_free(mdev, &mdev->driver_uar);
- mthca_cleanup_uar_table(mdev);
- mthca_close_hca(mdev);
- mthca_cmd_cleanup(mdev);
-done:
- kfree(mdev);
- }
-}
-
-
-
+/*\r
+ * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.\r
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.\r
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.\r
+ *\r
+ * This software is available to you under a choice of one of two\r
+ * licenses. You may choose to be licensed under the terms of the GNU\r
+ * General Public License (GPL) Version 2, available from the file\r
+ * COPYING in the main directory of this source tree, or the\r
+ * OpenIB.org BSD license below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+#include "mthca_dev.h"\r
+#if defined(EVENT_TRACING)\r
+#ifdef offsetof\r
+#undef offsetof\r
+#endif\r
+#include "mthca_main.tmh"\r
+#endif\r
+#include "mthca_config_reg.h"\r
+#include "mthca_cmd.h"\r
+#include "mthca_profile.h"\r
+#include "mthca_memfree.h"\r
+\r
+static const char mthca_version[] =\r
+ DRV_NAME ": HCA Driver v"\r
+ DRV_VERSION " (" DRV_RELDATE ")";\r
+\r
+static struct mthca_profile default_profile = {\r
+ 1 << 16, // num_qp\r
+ 4, // rdb_per_qp\r
+ 0, // num_srq\r
+ 1 << 16, // num_cq\r
+ 1 << 13, // num_mcg\r
+ 1 << 17, // num_mpt\r
+ 1 << 20, // num_mtt\r
+ 1 << 15, // num_udav (Tavor only)\r
+ 0, // num_uar\r
+ 1 << 18, // uarc_size (Arbel only)\r
+ 1 << 18, // fmr_reserved_mtts (Tavor only)\r
+};\r
+\r
+/* Types of supported HCA */\r
+enum __hca_type {\r
+ TAVOR, /* MT23108 */\r
+ ARBEL_COMPAT, /* MT25208 in Tavor compat mode */\r
+ ARBEL_NATIVE, /* MT25218 with extended features */\r
+ SINAI, /* MT25204 */\r
+ LIVEFISH /* a burning device */\r
+};\r
+\r
+#define MTHCA_FW_VER(major, minor, subminor) \\r
+ (((u64) (major) << 32) | ((u64) (minor) << 16) | (u64) (subminor))\r
+\r
+static struct {\r
+ u64 max_unsupported_fw;\r
+ u64 min_supported_fw;\r
+ int is_memfree;\r
+ int is_pcie;\r
+} mthca_hca_table[] = {\r
+ { MTHCA_FW_VER(3, 3, 2), MTHCA_FW_VER(3, 4, 0), 0, 0 }, /* TAVOR */\r
+ { MTHCA_FW_VER(4, 7, 0), MTHCA_FW_VER(4, 7, 400), 0, 1 }, /* ARBEL_COMPAT */\r
+ { MTHCA_FW_VER(5, 1, 0), MTHCA_FW_VER(5, 1, 400), 1, 1 }, /* ARBEL_NATIVE */\r
+ { MTHCA_FW_VER(1, 0, 800), MTHCA_FW_VER(1, 1, 0), 1, 1 }, /* SINAI */\r
+ { MTHCA_FW_VER(0, 0, 0), MTHCA_FW_VER(0, 0, 0), 0, 0 } /* LIVEFISH */\r
+};\r
+\r
+\r
+#define HCA(v, d, t) \\r
+ { PCI_VENDOR_ID_##v, PCI_DEVICE_ID_MELLANOX_##d, t }\r
+\r
+static struct pci_device_id {\r
+ unsigned vendor;\r
+ unsigned device;\r
+ enum __hca_type driver_data;\r
+} mthca_pci_table[] = {\r
+ HCA(MELLANOX, TAVOR, TAVOR),\r
+ HCA(MELLANOX, ARBEL_COMPAT, ARBEL_COMPAT),\r
+ HCA(MELLANOX, ARBEL, ARBEL_NATIVE),\r
+ HCA(MELLANOX, SINAI_OLD, SINAI),\r
+ HCA(MELLANOX, SINAI, SINAI),\r
+ HCA(TOPSPIN, TAVOR, TAVOR),\r
+ HCA(TOPSPIN, ARBEL_COMPAT, TAVOR),\r
+ HCA(TOPSPIN, ARBEL, ARBEL_NATIVE),\r
+ HCA(TOPSPIN, SINAI_OLD, SINAI),\r
+ HCA(TOPSPIN, SINAI, SINAI),\r
+ // live fishes\r
+ HCA(MELLANOX, TAVOR_BD, LIVEFISH),\r
+ HCA(MELLANOX, ARBEL_BD, LIVEFISH),\r
+ HCA(MELLANOX, SINAI_OLD_BD, LIVEFISH),\r
+ HCA(MELLANOX, SINAI_BD, LIVEFISH),\r
+ HCA(TOPSPIN, TAVOR_BD, LIVEFISH),\r
+ HCA(TOPSPIN, ARBEL_BD, LIVEFISH),\r
+ HCA(TOPSPIN, SINAI_OLD_BD, LIVEFISH),\r
+ HCA(TOPSPIN, SINAI_BD, LIVEFISH),\r
+};\r
+#define MTHCA_PCI_TABLE_SIZE (sizeof(mthca_pci_table)/sizeof(struct pci_device_id))\r
+\r
+// wrapper to driver's hca_tune_pci\r
+static NTSTATUS mthca_tune_pci(struct mthca_dev *mdev)\r
+{\r
+ PDEVICE_OBJECT pdo = mdev->ext->cl_ext.p_self_do;\r
+ return hca_tune_pci(pdo, &mdev->uplink_info);\r
+}\r
+\r
+int mthca_get_dev_info(struct mthca_dev *mdev, __be64 *node_guid, u32 *hw_id)\r
+{\r
+ struct ib_device_attr props;\r
+ struct ib_device *ib_dev = &mdev->ib_dev;\r
+ int err = (ib_dev->query_device )(ib_dev, &props );\r
+\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("can't get guid - mthca_query_port() failed (%08X)\n", err ));\r
+ return err;\r
+ }\r
+\r
+ //TODO: do we need to convert GUID to LE by cl_ntoh64(x) ?\r
+ *node_guid = ib_dev->node_guid;\r
+ *hw_id = props.hw_ver;\r
+ return 0;\r
+}\r
+\r
+static struct pci_device_id * mthca_find_pci_dev(unsigned ven_id, unsigned dev_id)\r
+{\r
+ struct pci_device_id *p_id = mthca_pci_table;\r
+ int i;\r
+\r
+ // find p_id (appropriate line in mthca_pci_table)\r
+ for (i = 0; i < MTHCA_PCI_TABLE_SIZE; ++i, ++p_id) {\r
+ if (p_id->device == dev_id && p_id->vendor == ven_id)\r
+ return p_id;\r
+ }\r
+ return NULL;\r
+}\r
+\r
+\r
+static int mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim *dev_lim)\r
+{\r
+ int err;\r
+ u8 status;\r
+\r
+ err = mthca_QUERY_DEV_LIM(mdev, dev_lim, &status);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_DEV_LIM command failed, aborting.\n"));\r
+ return err;\r
+ }\r
+ if (status) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_DEV_LIM returned status 0x%02x, "\r
+ "aborting.\n", status));\r
+ return -EINVAL;\r
+ }\r
+ if (dev_lim->min_page_sz > PAGE_SIZE) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("HCA minimum page size of %d bigger than "\r
+ "kernel PAGE_SIZE of %ld, aborting.\n",\r
+ dev_lim->min_page_sz, PAGE_SIZE));\r
+ return -ENODEV;\r
+ }\r
+ if (dev_lim->num_ports > MTHCA_MAX_PORTS) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("HCA has %d ports, but we only support %d, "\r
+ "aborting.\n",\r
+ dev_lim->num_ports, MTHCA_MAX_PORTS));\r
+ return -ENODEV;\r
+ }\r
+\r
+ if (dev_lim->uar_size > (int)pci_resource_len(mdev, HCA_BAR_TYPE_UAR)) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW , ("HCA reported UAR size of 0x%x bigger than "\r
+ "Bar%d size of 0x%lx, aborting.\n",\r
+ dev_lim->uar_size, HCA_BAR_TYPE_UAR, \r
+ (unsigned long)pci_resource_len(mdev, HCA_BAR_TYPE_UAR)));\r
+ return -ENODEV;\r
+ }\r
+ \r
+\r
+ mdev->limits.num_ports = dev_lim->num_ports;\r
+ mdev->limits.vl_cap = dev_lim->max_vl;\r
+ mdev->limits.mtu_cap = dev_lim->max_mtu;\r
+ mdev->limits.gid_table_len = dev_lim->max_gids;\r
+ mdev->limits.pkey_table_len = dev_lim->max_pkeys;\r
+ mdev->limits.local_ca_ack_delay = dev_lim->local_ca_ack_delay;\r
+ mdev->limits.max_sg = dev_lim->max_sg;\r
+ mdev->limits.max_wqes = dev_lim->max_qp_sz;\r
+ mdev->limits.max_qp_init_rdma = dev_lim->max_requester_per_qp;\r
+ mdev->limits.reserved_qps = dev_lim->reserved_qps;\r
+ mdev->limits.max_srq_wqes = dev_lim->max_srq_sz;\r
+ mdev->limits.reserved_srqs = dev_lim->reserved_srqs;\r
+ mdev->limits.reserved_eecs = dev_lim->reserved_eecs;\r
+ mdev->limits.max_desc_sz = dev_lim->max_desc_sz;\r
+ mdev->limits.max_srq_sge = mthca_max_srq_sge(mdev);\r
+ /*\r
+ * Subtract 1 from the limit because we need to allocate a\r
+ * spare CQE so the HCA HW can tell the difference between an\r
+ * empty CQ and a full CQ.\r
+ */\r
+ mdev->limits.max_cqes = dev_lim->max_cq_sz - 1;\r
+ mdev->limits.reserved_cqs = dev_lim->reserved_cqs;\r
+ mdev->limits.reserved_eqs = dev_lim->reserved_eqs;\r
+ mdev->limits.reserved_mtts = dev_lim->reserved_mtts;\r
+ mdev->limits.reserved_mrws = dev_lim->reserved_mrws;\r
+ mdev->limits.reserved_uars = dev_lim->reserved_uars;\r
+ mdev->limits.reserved_pds = dev_lim->reserved_pds;\r
+ mdev->limits.port_width_cap = (u8)dev_lim->max_port_width;\r
+ mdev->limits.page_size_cap = !(u32)(dev_lim->min_page_sz - 1);\r
+ mdev->limits.flags = dev_lim->flags;\r
+ mdev->limits.num_avs = mthca_is_memfree(mdev) ? 0 : dev_lim->hca.tavor.max_avs;\r
+\r
+ /* IB_DEVICE_RESIZE_MAX_WR not supported by driver.\r
+ May be doable since hardware supports it for SRQ.\r
+\r
+ IB_DEVICE_N_NOTIFY_CQ is supported by hardware but not by driver.\r
+\r
+ IB_DEVICE_SRQ_RESIZE is supported by hardware but SRQ is not\r
+ supported by driver. */\r
+ mdev->device_cap_flags = IB_DEVICE_CHANGE_PHY_PORT |\r
+ IB_DEVICE_PORT_ACTIVE_EVENT |\r
+ IB_DEVICE_SYS_IMAGE_GUID |\r
+ IB_DEVICE_RC_RNR_NAK_GEN;\r
+\r
+ if (dev_lim->flags & DEV_LIM_FLAG_BAD_PKEY_CNTR)\r
+ mdev->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR;\r
+\r
+ if (dev_lim->flags & DEV_LIM_FLAG_BAD_QKEY_CNTR)\r
+ mdev->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR;\r
+\r
+ if (dev_lim->flags & DEV_LIM_FLAG_RAW_MULTI)\r
+ mdev->device_cap_flags |= IB_DEVICE_RAW_MULTI;\r
+\r
+ if (dev_lim->flags & DEV_LIM_FLAG_AUTO_PATH_MIG)\r
+ mdev->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG;\r
+\r
+ if (dev_lim->flags & DEV_LIM_FLAG_UD_AV_PORT_ENFORCE)\r
+ mdev->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE;\r
+\r
+ if (dev_lim->flags & DEV_LIM_FLAG_SRQ)\r
+ mdev->mthca_flags |= MTHCA_FLAG_SRQ;\r
+\r
+ return 0;\r
+}\r
+\r
+static int mthca_init_tavor(struct mthca_dev *mdev)\r
+{\r
+ u8 status;\r
+ int err;\r
+ struct mthca_dev_lim dev_lim;\r
+ struct mthca_profile profile;\r
+ struct mthca_init_hca_param init_hca;\r
+\r
+ err = mthca_SYS_EN(mdev, &status);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("SYS_EN command failed, aborting.\n"));\r
+ return err;\r
+ }\r
+ if (status) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("SYS_EN returned status 0x%02x, "\r
+ "aborting.\n", status));\r
+ return -EINVAL;\r
+ }\r
+\r
+ err = mthca_QUERY_FW(mdev, &status);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_FW command failed, aborting.\n"));\r
+ goto err_disable;\r
+ }\r
+ if (status) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_FW returned status 0x%02x, "\r
+ "aborting.\n", status));\r
+ err = -EINVAL;\r
+ goto err_disable;\r
+ }\r
+ err = mthca_QUERY_DDR(mdev, &status);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_DDR command failed, aborting.\n"));\r
+ goto err_disable;\r
+ }\r
+ if (status) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,( "QUERY_DDR returned status 0x%02x, "\r
+ "aborting.\n", status));\r
+ err = -EINVAL;\r
+ goto err_disable;\r
+ }\r
+\r
+ err = mthca_dev_lim(mdev, &dev_lim);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,( "QUERY_DEV_LIM command failed, aborting.\n"));\r
+ goto err_disable;\r
+ }\r
+\r
+ profile = default_profile;\r
+ profile.num_uar = dev_lim.uar_size / PAGE_SIZE;\r
+ profile.uarc_size = 0;\r
+\r
+ /* correct default profile */\r
+ if ( g_profile_qp_num != 0 ) \r
+ profile.num_qp = g_profile_qp_num;\r
+ \r
+ if ( g_profile_rd_out != 0xffffffff )\r
+ profile.rdb_per_qp = g_profile_rd_out;\r
+\r
+ if (mdev->mthca_flags & MTHCA_FLAG_SRQ)\r
+ profile.num_srq = dev_lim.max_srqs;\r
+\r
+ err = (int)mthca_make_profile(mdev, &profile, &dev_lim, &init_hca);\r
+ if (err < 0)\r
+ goto err_disable;\r
+\r
+ err = (int)mthca_INIT_HCA(mdev, &init_hca, &status);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("INIT_HCA command failed, aborting.\n"));\r
+ goto err_disable;\r
+ }\r
+ if (status) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("INIT_HCA returned status 0x%02x, "\r
+ "aborting.\n", status));\r
+ err = -EINVAL;\r
+ goto err_disable;\r
+ }\r
+\r
+ return 0;\r
+\r
+err_disable:\r
+ mthca_SYS_DIS(mdev, &status);\r
+\r
+ return err;\r
+}\r
+\r
+static int mthca_load_fw(struct mthca_dev *mdev)\r
+{\r
+ u8 status;\r
+ int err;\r
+\r
+ /* FIXME: use HCA-attached memory for FW if present */\r
+\r
+ mdev->fw.arbel.fw_icm =\r
+ mthca_alloc_icm(mdev, mdev->fw.arbel.fw_pages,\r
+ GFP_HIGHUSER | __GFP_NOWARN);\r
+ if (!mdev->fw.arbel.fw_icm) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Couldn't allocate FW area, aborting.\n"));\r
+ return -ENOMEM;\r
+ }\r
+\r
+ err = mthca_MAP_FA(mdev, mdev->fw.arbel.fw_icm, &status);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("MAP_FA command failed, aborting.\n"));\r
+ goto err_free;\r
+ }\r
+ if (status) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("MAP_FA returned status 0x%02x, aborting.\n", status));\r
+ err = -EINVAL;\r
+ goto err_free;\r
+ }\r
+ err = mthca_RUN_FW(mdev, &status);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("RUN_FW command failed, aborting.\n"));\r
+ goto err_unmap_fa;\r
+ }\r
+ if (status) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("RUN_FW returned status 0x%02x, aborting.\n", status));\r
+ err = -EINVAL;\r
+ goto err_unmap_fa;\r
+ }\r
+\r
+ return 0;\r
+\r
+err_unmap_fa:\r
+ mthca_UNMAP_FA(mdev, &status);\r
+\r
+err_free:\r
+ mthca_free_icm(mdev, mdev->fw.arbel.fw_icm);\r
+ return err;\r
+}\r
+\r
+static int mthca_init_icm(struct mthca_dev *mdev,\r
+ struct mthca_dev_lim *dev_lim,\r
+ struct mthca_init_hca_param *init_hca,\r
+ u64 icm_size)\r
+{\r
+ u64 aux_pages;\r
+ u8 status;\r
+ int err;\r
+\r
+ err = mthca_SET_ICM_SIZE(mdev, icm_size, &aux_pages, &status);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("SET_ICM_SIZE command failed, aborting.\n"));\r
+ return err;\r
+ }\r
+ if (status) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("SET_ICM_SIZE returned status 0x%02x, "\r
+ "aborting.\n", status));\r
+ return -EINVAL;\r
+ }\r
+\r
+ HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW , ("%I64d KB of HCA context requires %I64d KB aux memory.\n",\r
+ (u64) icm_size >> 10,\r
+ (u64) aux_pages << 2));\r
+\r
+ mdev->fw.arbel.aux_icm = mthca_alloc_icm(mdev, (int)aux_pages,\r
+ GFP_HIGHUSER | __GFP_NOWARN);\r
+ if (!mdev->fw.arbel.aux_icm) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Couldn't allocate aux memory, aborting.\n"));\r
+ return -ENOMEM;\r
+ }\r
+\r
+ err = mthca_MAP_ICM_AUX(mdev, mdev->fw.arbel.aux_icm, &status);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("MAP_ICM_AUX command failed, aborting.\n"));\r
+ goto err_free_aux;\r
+ }\r
+ if (status) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("MAP_ICM_AUX returned status 0x%02x, aborting.\n", status));\r
+ err = -EINVAL;\r
+ goto err_free_aux;\r
+ }\r
+\r
+ err = mthca_map_eq_icm(mdev, init_hca->eqc_base);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map EQ context memory, aborting.\n"));\r
+ goto err_unmap_aux;\r
+ }\r
+\r
+ mdev->mr_table.mtt_table = mthca_alloc_icm_table(mdev, init_hca->mtt_base,\r
+ MTHCA_MTT_SEG_SIZE,\r
+ mdev->limits.num_mtt_segs,\r
+ mdev->limits.reserved_mtts, 1);\r
+ if (!mdev->mr_table.mtt_table) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map MTT context memory, aborting.\n"));\r
+ err = -ENOMEM;\r
+ goto err_unmap_eq;\r
+ }\r
+\r
+ mdev->mr_table.mpt_table = mthca_alloc_icm_table(mdev, init_hca->mpt_base,\r
+ dev_lim->mpt_entry_sz,\r
+ mdev->limits.num_mpts,\r
+ mdev->limits.reserved_mrws, 1);\r
+ if (!mdev->mr_table.mpt_table) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map MPT context memory, aborting.\n"));\r
+ err = -ENOMEM;\r
+ goto err_unmap_mtt;\r
+ }\r
+\r
+ mdev->qp_table.qp_table = mthca_alloc_icm_table(mdev, init_hca->qpc_base,\r
+ dev_lim->qpc_entry_sz,\r
+ mdev->limits.num_qps,\r
+ mdev->limits.reserved_qps, 0);\r
+ if (!mdev->qp_table.qp_table) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map QP context memory, aborting.\n"));\r
+ err = -ENOMEM;\r
+ goto err_unmap_mpt;\r
+ }\r
+\r
+ mdev->qp_table.eqp_table = mthca_alloc_icm_table(mdev, init_hca->eqpc_base,\r
+ dev_lim->eqpc_entry_sz,\r
+ mdev->limits.num_qps,\r
+ mdev->limits.reserved_qps, 0);\r
+ if (!mdev->qp_table.eqp_table) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map EQP context memory, aborting.\n"));\r
+ err = -ENOMEM;\r
+ goto err_unmap_qp;\r
+ }\r
+\r
+ mdev->qp_table.rdb_table = mthca_alloc_icm_table(mdev, init_hca->rdb_base,\r
+ MTHCA_RDB_ENTRY_SIZE,\r
+ mdev->limits.num_qps <<\r
+ mdev->qp_table.rdb_shift,\r
+ 0, 0);\r
+ if (!mdev->qp_table.rdb_table) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map RDB context memory, aborting\n"));\r
+ err = -ENOMEM;\r
+ goto err_unmap_eqp;\r
+ }\r
+\r
+ mdev->cq_table.table = mthca_alloc_icm_table(mdev, init_hca->cqc_base,\r
+ dev_lim->cqc_entry_sz,\r
+ mdev->limits.num_cqs,\r
+ mdev->limits.reserved_cqs, 0);\r
+ if (!mdev->cq_table.table) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map CQ context memory, aborting.\n"));\r
+ err = -ENOMEM;\r
+ goto err_unmap_rdb;\r
+ }\r
+\r
+ if (mdev->mthca_flags & MTHCA_FLAG_SRQ) {\r
+ mdev->srq_table.table =\r
+ mthca_alloc_icm_table(mdev, init_hca->srqc_base,\r
+ dev_lim->srq_entry_sz,\r
+ mdev->limits.num_srqs,\r
+ mdev->limits.reserved_srqs, 0);\r
+ if (!mdev->srq_table.table) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map SRQ context memory, "\r
+ "aborting.\n"));\r
+ err = -ENOMEM;\r
+ goto err_unmap_cq;\r
+ }\r
+ }\r
+\r
+ /*\r
+ * It's not strictly required, but for simplicity just map the\r
+ * whole multicast group table now. The table isn't very big\r
+ * and it's a lot easier than trying to track ref counts.\r
+ */\r
+ mdev->mcg_table.table = mthca_alloc_icm_table(mdev, init_hca->mc_base,\r
+ MTHCA_MGM_ENTRY_SIZE,\r
+ mdev->limits.num_mgms +\r
+ mdev->limits.num_amgms,\r
+ mdev->limits.num_mgms +\r
+ mdev->limits.num_amgms,\r
+ 0);\r
+ if (!mdev->mcg_table.table) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map MCG context memory, aborting.\n"));\r
+ err = -ENOMEM;\r
+ goto err_unmap_srq;\r
+ }\r
+\r
+ return 0;\r
+\r
+err_unmap_srq:\r
+ if (mdev->mthca_flags & MTHCA_FLAG_SRQ)\r
+ mthca_free_icm_table(mdev, mdev->srq_table.table);\r
+\r
+err_unmap_cq:\r
+ mthca_free_icm_table(mdev, mdev->cq_table.table);\r
+\r
+err_unmap_rdb:\r
+ mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);\r
+\r
+err_unmap_eqp:\r
+ mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);\r
+\r
+err_unmap_qp:\r
+ mthca_free_icm_table(mdev, mdev->qp_table.qp_table);\r
+\r
+err_unmap_mpt:\r
+ mthca_free_icm_table(mdev, mdev->mr_table.mpt_table);\r
+\r
+err_unmap_mtt:\r
+ mthca_free_icm_table(mdev, mdev->mr_table.mtt_table);\r
+\r
+err_unmap_eq:\r
+ mthca_unmap_eq_icm(mdev);\r
+\r
+err_unmap_aux:\r
+ mthca_UNMAP_ICM_AUX(mdev, &status);\r
+\r
+err_free_aux:\r
+ mthca_free_icm(mdev, mdev->fw.arbel.aux_icm);\r
+\r
+ return err;\r
+}\r
+\r
+static int mthca_init_arbel(struct mthca_dev *mdev)\r
+{\r
+ struct mthca_dev_lim dev_lim;\r
+ struct mthca_profile profile;\r
+ struct mthca_init_hca_param init_hca;\r
+ u64 icm_size;\r
+ u8 status;\r
+ int err;\r
+\r
+ err = mthca_QUERY_FW(mdev, &status);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_FW command failed, aborting.\n"));\r
+ return err;\r
+ }\r
+ if (status) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_FW returned status 0x%02x, "\r
+ "aborting.\n", status));\r
+ return -EINVAL;\r
+ }\r
+\r
+ err = mthca_ENABLE_LAM(mdev, &status);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("ENABLE_LAM command failed, aborting.\n"));\r
+ return err;\r
+ }\r
+ if (status == MTHCA_CMD_STAT_LAM_NOT_PRE) {\r
+ HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,("No HCA-attached memory (running in MemFree mode)\n"));\r
+ mdev->mthca_flags |= MTHCA_FLAG_NO_LAM;\r
+ } else if (status) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("ENABLE_LAM returned status 0x%02x, "\r
+ "aborting.\n", status));\r
+ return -EINVAL;\r
+ }\r
+\r
+ err = mthca_load_fw(mdev);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to start FW, aborting.\n"));\r
+ goto err_disable;\r
+ }\r
+\r
+ err = mthca_dev_lim(mdev, &dev_lim);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_DEV_LIM command failed, aborting.\n"));\r
+ goto err_stop_fw;\r
+ }\r
+\r
+ profile = default_profile;\r
+ profile.num_uar = dev_lim.uar_size / PAGE_SIZE;\r
+ profile.num_udav = 0;\r
+ if (mdev->mthca_flags & MTHCA_FLAG_SRQ)\r
+ profile.num_srq = dev_lim.max_srqs;\r
+\r
+ /* correct default profile */\r
+ if ( g_profile_qp_num != 0 ) \r
+ profile.num_qp = g_profile_qp_num;\r
+ \r
+ if ( g_profile_rd_out != 0xffffffff )\r
+ profile.rdb_per_qp = g_profile_rd_out;\r
+\r
+ RtlZeroMemory( &init_hca, sizeof(init_hca));\r
+ icm_size = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca);\r
+ if ((int) icm_size < 0) {\r
+ err = (int)icm_size;\r
+ goto err_stop_fw;\r
+ }\r
+\r
+ err = mthca_init_icm(mdev, &dev_lim, &init_hca, icm_size);\r
+ if (err)\r
+ goto err_stop_fw;\r
+\r
+ err = mthca_INIT_HCA(mdev, &init_hca, &status);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("INIT_HCA command failed, aborting.\n"));\r
+ goto err_free_icm;\r
+ }\r
+ if (status) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("INIT_HCA returned status 0x%02x, "\r
+ "aborting.\n", status));\r
+ err = -EINVAL;\r
+ goto err_free_icm;\r
+ }\r
+\r
+ return 0;\r
+\r
+err_free_icm:\r
+ if (mdev->mthca_flags & MTHCA_FLAG_SRQ)\r
+ mthca_free_icm_table(mdev, mdev->srq_table.table);\r
+ mthca_free_icm_table(mdev, mdev->cq_table.table);\r
+ mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);\r
+ mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);\r
+ mthca_free_icm_table(mdev, mdev->qp_table.qp_table);\r
+ mthca_free_icm_table(mdev, mdev->mr_table.mpt_table);\r
+ mthca_free_icm_table(mdev, mdev->mr_table.mtt_table);\r
+ mthca_unmap_eq_icm(mdev);\r
+\r
+ mthca_UNMAP_ICM_AUX(mdev, &status);\r
+ mthca_free_icm(mdev, mdev->fw.arbel.aux_icm);\r
+\r
+err_stop_fw:\r
+ mthca_UNMAP_FA(mdev, &status);\r
+ mthca_free_icm(mdev, mdev->fw.arbel.fw_icm);\r
+\r
+err_disable:\r
+ if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM))\r
+ mthca_DISABLE_LAM(mdev, &status);\r
+\r
+ return err;\r
+}\r
+\r
+static void mthca_close_hca(struct mthca_dev *mdev)\r
+{\r
+ u8 status;\r
+\r
+ mthca_CLOSE_HCA(mdev, 0, &status);\r
+\r
+ if (mthca_is_memfree(mdev)) {\r
+ if (mdev->mthca_flags & MTHCA_FLAG_SRQ)\r
+ mthca_free_icm_table(mdev, mdev->srq_table.table);\r
+ mthca_free_icm_table(mdev, mdev->cq_table.table);\r
+ mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);\r
+ mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);\r
+ mthca_free_icm_table(mdev, mdev->qp_table.qp_table);\r
+ mthca_free_icm_table(mdev, mdev->mr_table.mpt_table);\r
+ mthca_free_icm_table(mdev, mdev->mr_table.mtt_table);\r
+ mthca_free_icm_table(mdev, mdev->mcg_table.table);\r
+ mthca_unmap_eq_icm(mdev);\r
+\r
+ mthca_UNMAP_ICM_AUX(mdev, &status);\r
+ mthca_free_icm(mdev, mdev->fw.arbel.aux_icm);\r
+\r
+ mthca_UNMAP_FA(mdev, &status);\r
+ mthca_free_icm(mdev, mdev->fw.arbel.fw_icm);\r
+\r
+ if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM))\r
+ mthca_DISABLE_LAM(mdev, &status);\r
+ } else\r
+ mthca_SYS_DIS(mdev, &status);\r
+}\r
+\r
+static int mthca_init_hca(struct mthca_dev *mdev)\r
+{\r
+ u8 status;\r
+ int err;\r
+ struct mthca_adapter adapter;\r
+\r
+ if (mthca_is_memfree(mdev))\r
+ err = mthca_init_arbel(mdev);\r
+ else\r
+ err = mthca_init_tavor(mdev);\r
+\r
+ if (err)\r
+ return err;\r
+\r
+ err = mthca_QUERY_ADAPTER(mdev, &adapter, &status);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_ADAPTER command failed, aborting.\n"));\r
+ goto err_close;\r
+ }\r
+ if (status) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_ADAPTER returned status 0x%02x, "\r
+ "aborting.\n", status));\r
+ err = -EINVAL;\r
+ goto err_close;\r
+ }\r
+\r
+ mdev->eq_table.inta_pin = adapter.inta_pin;\r
+ mdev->rev_id = adapter.revision_id;\r
+ memcpy(mdev->board_id, adapter.board_id, sizeof mdev->board_id);\r
+\r
+ return 0;\r
+\r
+err_close:\r
+ mthca_close_hca(mdev);\r
+ return err;\r
+}\r
+\r
+static int mthca_setup_hca(struct mthca_dev *mdev)\r
+{\r
+ int err;\r
+ u8 status;\r
+\r
+ MTHCA_INIT_DOORBELL_LOCK(&mdev->doorbell_lock);\r
+\r
+ err = mthca_init_uar_table(mdev);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "\r
+ "user access region table, aborting.\n"));\r
+ return err;\r
+ }\r
+\r
+ err = mthca_uar_alloc(mdev, &mdev->driver_uar);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to allocate driver access region, "\r
+ "aborting.\n"));\r
+ goto err_uar_table_free;\r
+ }\r
+\r
+ mdev->kar = ioremap((io_addr_t)mdev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE,&mdev->kar_size);\r
+ if (!mdev->kar) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Couldn't map kernel access region, "\r
+ "aborting.\n"));\r
+ err = -ENOMEM;\r
+ goto err_uar_free;\r
+ }\r
+\r
+ err = mthca_init_pd_table(mdev);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "\r
+ "protection domain table, aborting.\n"));\r
+ goto err_kar_unmap;\r
+ }\r
+\r
+ err = mthca_init_mr_table(mdev);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "\r
+ "memory region table, aborting.\n"));\r
+ goto err_pd_table_free;\r
+ }\r
+\r
+ err = mthca_pd_alloc(mdev, 1, &mdev->driver_pd);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to create driver PD, "\r
+ "aborting.\n"));\r
+ goto err_mr_table_free;\r
+ }\r
+\r
+ err = mthca_init_eq_table(mdev);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW, ("Failed to initialize "\r
+ "event queue table, aborting.\n"));\r
+ goto err_pd_free;\r
+ }\r
+\r
+ err = mthca_cmd_use_events(mdev);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to switch to event-driven "\r
+ "firmware commands, aborting.\n"));\r
+ goto err_eq_table_free;\r
+ }\r
+\r
+ err = mthca_NOP(mdev, &status);\r
+ if (err || status) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("NOP command failed to generate interrupt, aborting.\n"));\r
+ if (mdev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)){\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Try again with MSI/MSI-X disabled.\n"));\r
+ }else{\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("BIOS or ACPI interrupt routing problem?\n"));\r
+ }\r
+\r
+ goto err_cmd_poll;\r
+ }\r
+\r
+ HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_LOW ,("NOP command IRQ test passed\n"));\r
+\r
+ err = mthca_init_cq_table(mdev);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "\r
+ "completion queue table, aborting.\n"));\r
+ goto err_cmd_poll;\r
+ }\r
+\r
+ err = mthca_init_srq_table(mdev);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "\r
+ "shared receive queue table, aborting.\n"));\r
+ goto err_cq_table_free;\r
+ }\r
+\r
+ err = mthca_init_qp_table(mdev);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW, ("Failed to initialize "\r
+ "queue pair table, aborting.\n"));\r
+ goto err_srq_table_free;\r
+ }\r
+\r
+ err = mthca_init_av_table(mdev);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "\r
+ "address vector table, aborting.\n"));\r
+ goto err_qp_table_free;\r
+ }\r
+\r
+ err = mthca_init_mcg_table(mdev);\r
+ if (err) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "\r
+ "multicast group table, aborting.\n"));\r
+ goto err_av_table_free;\r
+ }\r
+\r
+ return 0;\r
+\r
+err_av_table_free:\r
+ mthca_cleanup_av_table(mdev);\r
+\r
+err_qp_table_free:\r
+ mthca_cleanup_qp_table(mdev);\r
+\r
+err_srq_table_free:\r
+ mthca_cleanup_srq_table(mdev);\r
+\r
+err_cq_table_free:\r
+ mthca_cleanup_cq_table(mdev);\r
+\r
+err_cmd_poll:\r
+ mthca_cmd_use_polling(mdev);\r
+\r
+err_eq_table_free:\r
+ mthca_cleanup_eq_table(mdev);\r
+\r
+err_pd_free:\r
+ mthca_pd_free(mdev, &mdev->driver_pd);\r
+\r
+err_mr_table_free:\r
+ mthca_cleanup_mr_table(mdev);\r
+\r
+err_pd_table_free:\r
+ mthca_cleanup_pd_table(mdev);\r
+\r
+err_kar_unmap:\r
+ iounmap(mdev->kar, mdev->kar_size);\r
+\r
+err_uar_free:\r
+ mthca_uar_free(mdev, &mdev->driver_uar);\r
+\r
+err_uar_table_free:\r
+ mthca_cleanup_uar_table(mdev);\r
+ return err;\r
+}\r
+\r
+\r
+static int mthca_check_fw(struct mthca_dev *mdev, struct pci_device_id *p_id)\r
+{\r
+ int err = 0;\r
+ \r
+ if (mdev->fw_ver < mthca_hca_table[p_id->driver_data].max_unsupported_fw) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("HCA FW version %d.%d.%d is not supported. Use %d.%d.%d or higher.\n",\r
+ (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,\r
+ (int) (mdev->fw_ver & 0xffff),\r
+ (int) (mthca_hca_table[p_id->driver_data].min_supported_fw >> 32),\r
+ (int) (mthca_hca_table[p_id->driver_data].min_supported_fw >> 16) & 0xffff,\r
+ (int) (mthca_hca_table[p_id->driver_data].min_supported_fw & 0xffff)));\r
+ err = -EINVAL;\r
+ }\r
+ else \r
+ if (mdev->fw_ver < mthca_hca_table[p_id->driver_data].min_supported_fw) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,\r
+ ("The HCA FW version is %d.%d.%d, which is not the latest one. \n"\r
+ "If you meet any issues with the HCA please first try to upgrade the FW to version %d.%d.%d or higher.\n",\r
+ (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,\r
+ (int) (mdev->fw_ver & 0xffff),\r
+ (int) (mthca_hca_table[p_id->driver_data].min_supported_fw >> 32),\r
+ (int) (mthca_hca_table[p_id->driver_data].min_supported_fw >> 16) & 0xffff,\r
+ (int) (mthca_hca_table[p_id->driver_data].min_supported_fw & 0xffff)));\r
+ }\r
+ else {\r
+ HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,("Current HCA FW version is %d.%d.%d. \n",\r
+ (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,\r
+ (int) (mdev->fw_ver & 0xffff)));\r
+ }\r
+\r
+ return err;\r
+}\r
+\r
+NTSTATUS mthca_init_one(hca_dev_ext_t *ext)\r
+{\r
+ static int mthca_version_printed = 0;\r
+ int err;\r
+ NTSTATUS status;\r
+ struct mthca_dev *mdev;\r
+ struct pci_device_id *p_id;\r
+\r
+ /* print version */\r
+ if (!mthca_version_printed) {\r
+ HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,("%s\n", mthca_version));\r
+ ++mthca_version_printed;\r
+ }\r
+\r
+ /* find the type of device */\r
+ p_id = mthca_find_pci_dev(\r
+ (unsigned)ext->hcaConfig.VendorID,\r
+ (unsigned)ext->hcaConfig.DeviceID);\r
+ if (p_id == NULL) {\r
+ status = STATUS_NO_SUCH_DEVICE;\r
+ goto end;\r
+ }\r
+\r
+ InitializeListHead(&ext->hca.hob.event_list);\r
+ KeInitializeSpinLock(&ext->hca.hob.event_list_lock);\r
+\r
+run_as_livefish:\r
+ /* allocate mdev structure */\r
+ mdev = kzalloc(sizeof *mdev, GFP_KERNEL);\r
+ if (!mdev) {\r
+ // can't use HCA_PRINT_EV here !\r
+ HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Device struct alloc failed, "\r
+ "aborting.\n"));\r
+ status = STATUS_INSUFFICIENT_RESOURCES;\r
+ goto end;\r
+ }\r
+ \r
+ /* set some fields */\r
+ mdev->ext = ext; /* pointer to DEVICE OBJECT extension */\r
+ mdev->hca_type = p_id->driver_data;\r
+ mdev->ib_dev.mdev = mdev;\r
+ if (p_id->driver_data == LIVEFISH)\r
+ mdev->mthca_flags |= MTHCA_FLAG_LIVEFISH;\r
+ if (mthca_is_livefish(mdev))\r
+ goto done;\r
+ if (ext->hca_hidden)\r
+ mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN;\r
+ if (mthca_hca_table[p_id->driver_data].is_memfree)\r
+ mdev->mthca_flags |= MTHCA_FLAG_MEMFREE;\r
+ if (mthca_hca_table[p_id->driver_data].is_pcie)\r
+ mdev->mthca_flags |= MTHCA_FLAG_PCIE;\r
+ \r
+//TODO: after we have a FW, capable of reset, \r
+// write a routine, that only presses the button\r
+\r
+ /*\r
+ * Now reset the HCA before we touch the PCI capabilities or\r
+ * attempt a firmware command, since a boot ROM may have left\r
+ * the HCA in an undefined state.\r
+ */\r
+ status = hca_reset( mdev->ext->cl_ext.p_self_do, p_id->driver_data == TAVOR );\r
+ if ( !NT_SUCCESS( status ) ) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to reset HCA, aborting.\n"));\r
+ goto err_free_dev;\r
+ }\r
+\r
+ if (mthca_cmd_init(mdev)) {\r
+ HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to init command interface, aborting.\n"));\r
+ status = STATUS_DEVICE_DATA_ERROR;\r
+ goto err_free_dev;\r
+ }\r
+\r
+ status = mthca_tune_pci(mdev);\r
+ if ( !NT_SUCCESS( status ) ) {\r
+ goto err_cmd;\r
+ }\r
+\r
+ err = mthca_init_hca(mdev); \r
+ if (err) {\r
+ status = STATUS_UNSUCCESSFUL;\r
+ goto err_cmd;\r
+ }\r
+\r
+ err = mthca_check_fw(mdev, p_id);\r
+ if (err) {\r
+ status = STATUS_UNSUCCESSFUL;\r
+ goto err_close;\r
+ }\r
+\r
+ err = mthca_setup_hca(mdev);\r
+ if (err) {\r
+ status = STATUS_UNSUCCESSFUL;\r
+ goto err_close;\r
+ }\r
+\r
+ err = mthca_register_device(mdev);\r
+ if (err) {\r
+ status = STATUS_UNSUCCESSFUL;\r
+ goto err_cleanup;\r
+ }\r
+\r
+ done:\r
+ ext->hca.mdev = mdev;\r
+ mdev->state = MTHCA_DEV_INITIALIZED;\r
+ return 0;\r
+\r
+err_cleanup:\r
+ mthca_cleanup_mcg_table(mdev);\r
+ mthca_cleanup_av_table(mdev);\r
+ mthca_cleanup_qp_table(mdev);\r
+ mthca_cleanup_srq_table(mdev);\r
+ mthca_cleanup_cq_table(mdev);\r
+ mthca_cmd_use_polling(mdev);\r
+ mthca_cleanup_eq_table(mdev);\r
+\r
+ mthca_pd_free(mdev, &mdev->driver_pd);\r
+\r
+ mthca_cleanup_mr_table(mdev);\r
+ mthca_cleanup_pd_table(mdev);\r
+ mthca_cleanup_uar_table(mdev);\r
+\r
+err_close:\r
+ mthca_close_hca(mdev);\r
+\r
+err_cmd:\r
+ mthca_cmd_cleanup(mdev);\r
+\r
+err_free_dev:\r
+ kfree(mdev);\r
+\r
+ /* we failed device initialization - try to simulate "livefish" device to facilitate using FW burning tools */\r
+ {\r
+ USHORT dev_id = ext->hcaConfig.DeviceID;\r
+ \r
+ if (dev_id == PCI_DEVICE_ID_MELLANOX_ARBEL)\r
+ dev_id = PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT;\r
+ p_id = mthca_find_pci_dev( (unsigned)ext->hcaConfig.VendorID, dev_id + 1 );\r
+ if (p_id == NULL) {\r
+ status = STATUS_NO_SUCH_DEVICE;\r
+ goto end;\r
+ }\r
+ goto run_as_livefish;\r
+ }\r
+ \r
+end:\r
+ return status;\r
+}\r
+\r
+void mthca_remove_one(hca_dev_ext_t *ext)\r
+{\r
+ struct mthca_dev *mdev = ext->hca.mdev;\r
+ u8 status;\r
+ int p;\r
+\r
+ ext->hca.mdev = NULL;\r
+ if (mdev) {\r
+ mdev->state = MTHCA_DEV_UNINITIALIZED;\r
+ if (mthca_is_livefish(mdev))\r
+ goto done;\r
+ mthca_unregister_device(mdev);\r
+\r
+ for (p = 1; p <= mdev->limits.num_ports; ++p)\r
+ mthca_CLOSE_IB(mdev, p, &status);\r
+\r
+ mthca_cleanup_mcg_table(mdev);\r
+ mthca_cleanup_av_table(mdev);\r
+ mthca_cleanup_qp_table(mdev);\r
+ mthca_cleanup_srq_table(mdev);\r
+ mthca_cleanup_cq_table(mdev);\r
+ mthca_cmd_use_polling(mdev);\r
+ mthca_cleanup_eq_table(mdev);\r
+ mthca_pd_free(mdev, &mdev->driver_pd);\r
+ mthca_cleanup_mr_table(mdev);\r
+ mthca_cleanup_pd_table(mdev);\r
+ iounmap(mdev->kar, mdev->kar_size);\r
+ mthca_uar_free(mdev, &mdev->driver_uar);\r
+ mthca_cleanup_uar_table(mdev);\r
+ mthca_close_hca(mdev);\r
+ mthca_cmd_cleanup(mdev);\r
+done:\r
+ kfree(mdev);\r
+ }\r
+}\r
+\r
+\r
+\r