11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 3cd4e8fb4STom Duffy * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 42a1d9b7fSRoland Dreier * Copyright (c) 2005 Mellanox Technologies. All rights reserved. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This software is available to you under a choice of one of two 71da177e4SLinus Torvalds * licenses. You may choose to be licensed under the terms of the GNU 81da177e4SLinus Torvalds * General Public License (GPL) Version 2, available from the file 91da177e4SLinus Torvalds * COPYING in the main directory of this source tree, or the 101da177e4SLinus Torvalds * OpenIB.org BSD license below: 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * Redistribution and use in source and binary forms, with or 131da177e4SLinus Torvalds * without modification, are permitted provided that the following 141da177e4SLinus Torvalds * conditions are met: 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * - Redistributions of source code must retain the above 171da177e4SLinus Torvalds * copyright notice, this list of conditions and the following 181da177e4SLinus Torvalds * disclaimer. 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds * - Redistributions in binary form must reproduce the above 211da177e4SLinus Torvalds * copyright notice, this list of conditions and the following 221da177e4SLinus Torvalds * disclaimer in the documentation and/or other materials 231da177e4SLinus Torvalds * provided with the distribution. 241da177e4SLinus Torvalds * 251da177e4SLinus Torvalds * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 261da177e4SLinus Torvalds * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 271da177e4SLinus Torvalds * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 281da177e4SLinus Torvalds * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 291da177e4SLinus Torvalds * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 301da177e4SLinus Torvalds * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 311da177e4SLinus Torvalds * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 321da177e4SLinus Torvalds * SOFTWARE. 331da177e4SLinus Torvalds * 341da177e4SLinus Torvalds * $Id: mthca_main.c 1396 2004-12-28 04:10:27Z roland $ 351da177e4SLinus Torvalds */ 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds #include <linux/module.h> 381da177e4SLinus Torvalds #include <linux/init.h> 391da177e4SLinus Torvalds #include <linux/errno.h> 401da177e4SLinus Torvalds #include <linux/pci.h> 411da177e4SLinus Torvalds #include <linux/interrupt.h> 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds #include "mthca_dev.h" 441da177e4SLinus Torvalds #include "mthca_config_reg.h" 451da177e4SLinus Torvalds #include "mthca_cmd.h" 461da177e4SLinus Torvalds #include "mthca_profile.h" 471da177e4SLinus Torvalds #include "mthca_memfree.h" 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds MODULE_AUTHOR("Roland Dreier"); 501da177e4SLinus Torvalds MODULE_DESCRIPTION("Mellanox InfiniBand HCA low-level driver"); 511da177e4SLinus Torvalds MODULE_LICENSE("Dual BSD/GPL"); 521da177e4SLinus Torvalds MODULE_VERSION(DRV_VERSION); 531da177e4SLinus Torvalds 54227c939bSRoland Dreier #ifdef CONFIG_INFINIBAND_MTHCA_DEBUG 55227c939bSRoland Dreier 56227c939bSRoland Dreier int mthca_debug_level = 0; 57227c939bSRoland Dreier module_param_named(debug_level, mthca_debug_level, int, 0644); 58227c939bSRoland Dreier MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); 59227c939bSRoland Dreier 60227c939bSRoland Dreier #endif /* CONFIG_INFINIBAND_MTHCA_DEBUG */ 61227c939bSRoland Dreier 621da177e4SLinus Torvalds #ifdef CONFIG_PCI_MSI 631da177e4SLinus Torvalds 64017aadc4SMichael S. Tsirkin static int msi_x = 1; 651da177e4SLinus Torvalds module_param(msi_x, int, 0444); 661da177e4SLinus Torvalds MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero"); 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds #else /* CONFIG_PCI_MSI */ 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds #define msi_x (0) 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds #endif /* CONFIG_PCI_MSI */ 731da177e4SLinus Torvalds 74abf45dbbSMichael S. Tsirkin static int tune_pci = 0; 75abf45dbbSMichael S. Tsirkin module_param(tune_pci, int, 0444); 76abf45dbbSMichael S. Tsirkin MODULE_PARM_DESC(tune_pci, "increase PCI burst from the default set by BIOS if nonzero"); 77abf45dbbSMichael S. Tsirkin 780b0df6f2SRoland Dreier DEFINE_MUTEX(mthca_device_mutex); 79b3b30f5eSJack Morgenstein 8082da703eSLeonid Arsh #define MTHCA_DEFAULT_NUM_QP (1 << 16) 8182da703eSLeonid Arsh #define MTHCA_DEFAULT_RDB_PER_QP (1 << 2) 8282da703eSLeonid Arsh #define MTHCA_DEFAULT_NUM_CQ (1 << 16) 8382da703eSLeonid Arsh #define MTHCA_DEFAULT_NUM_MCG (1 << 13) 8482da703eSLeonid Arsh #define MTHCA_DEFAULT_NUM_MPT (1 << 17) 8582da703eSLeonid Arsh #define MTHCA_DEFAULT_NUM_MTT (1 << 20) 8682da703eSLeonid Arsh #define MTHCA_DEFAULT_NUM_UDAV (1 << 15) 8782da703eSLeonid Arsh #define MTHCA_DEFAULT_NUM_RESERVED_MTTS (1 << 18) 8882da703eSLeonid Arsh #define MTHCA_DEFAULT_NUM_UARC_SIZE (1 << 18) 8982da703eSLeonid Arsh 9082da703eSLeonid Arsh static struct mthca_profile hca_profile = { 9182da703eSLeonid Arsh .num_qp = MTHCA_DEFAULT_NUM_QP, 9282da703eSLeonid Arsh .rdb_per_qp = MTHCA_DEFAULT_RDB_PER_QP, 9382da703eSLeonid Arsh .num_cq = MTHCA_DEFAULT_NUM_CQ, 9482da703eSLeonid Arsh .num_mcg = MTHCA_DEFAULT_NUM_MCG, 9582da703eSLeonid Arsh .num_mpt = MTHCA_DEFAULT_NUM_MPT, 9682da703eSLeonid Arsh .num_mtt = MTHCA_DEFAULT_NUM_MTT, 9782da703eSLeonid Arsh .num_udav = MTHCA_DEFAULT_NUM_UDAV, /* Tavor only */ 9882da703eSLeonid Arsh .fmr_reserved_mtts = MTHCA_DEFAULT_NUM_RESERVED_MTTS, /* Tavor only */ 9982da703eSLeonid Arsh .uarc_size = MTHCA_DEFAULT_NUM_UARC_SIZE, /* Arbel only */ 10082da703eSLeonid Arsh }; 10182da703eSLeonid Arsh 10282da703eSLeonid Arsh module_param_named(num_qp, hca_profile.num_qp, int, 0444); 10382da703eSLeonid Arsh MODULE_PARM_DESC(num_qp, "maximum number of QPs per HCA"); 10482da703eSLeonid Arsh 10582da703eSLeonid Arsh module_param_named(rdb_per_qp, hca_profile.rdb_per_qp, int, 0444); 10682da703eSLeonid Arsh MODULE_PARM_DESC(rdb_per_qp, "number of RDB buffers per QP"); 10782da703eSLeonid Arsh 10882da703eSLeonid Arsh module_param_named(num_cq, hca_profile.num_cq, int, 0444); 10982da703eSLeonid Arsh MODULE_PARM_DESC(num_cq, "maximum number of CQs per HCA"); 11082da703eSLeonid Arsh 11182da703eSLeonid Arsh module_param_named(num_mcg, hca_profile.num_mcg, int, 0444); 11282da703eSLeonid Arsh MODULE_PARM_DESC(num_mcg, "maximum number of multicast groups per HCA"); 11382da703eSLeonid Arsh 11482da703eSLeonid Arsh module_param_named(num_mpt, hca_profile.num_mpt, int, 0444); 11582da703eSLeonid Arsh MODULE_PARM_DESC(num_mpt, 11682da703eSLeonid Arsh "maximum number of memory protection table entries per HCA"); 11782da703eSLeonid Arsh 11882da703eSLeonid Arsh module_param_named(num_mtt, hca_profile.num_mtt, int, 0444); 11982da703eSLeonid Arsh MODULE_PARM_DESC(num_mtt, 12082da703eSLeonid Arsh "maximum number of memory translation table segments per HCA"); 12182da703eSLeonid Arsh 12282da703eSLeonid Arsh module_param_named(num_udav, hca_profile.num_udav, int, 0444); 12382da703eSLeonid Arsh MODULE_PARM_DESC(num_udav, "maximum number of UD address vectors per HCA"); 12482da703eSLeonid Arsh 12582da703eSLeonid Arsh module_param_named(fmr_reserved_mtts, hca_profile.fmr_reserved_mtts, int, 0444); 12682da703eSLeonid Arsh MODULE_PARM_DESC(fmr_reserved_mtts, 12782da703eSLeonid Arsh "number of memory translation table segments reserved for FMR"); 12882da703eSLeonid Arsh 1291da177e4SLinus Torvalds static const char mthca_version[] __devinitdata = 130177214afSBernhard Fischer DRV_NAME ": Mellanox InfiniBand HCA driver v" 1311da177e4SLinus Torvalds DRV_VERSION " (" DRV_RELDATE ")\n"; 1321da177e4SLinus Torvalds 133f4f3d0f0SRoland Dreier static int mthca_tune_pci(struct mthca_dev *mdev) 1341da177e4SLinus Torvalds { 135abf45dbbSMichael S. Tsirkin if (!tune_pci) 136abf45dbbSMichael S. Tsirkin return 0; 137abf45dbbSMichael S. Tsirkin 1381da177e4SLinus Torvalds /* First try to max out Read Byte Count */ 139a855b1a7SPeter Oruba if (pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX)) { 140a855b1a7SPeter Oruba if (pcix_set_mmrbc(mdev->pdev, pcix_get_max_mmrbc(mdev->pdev))) { 141a855b1a7SPeter Oruba mthca_err(mdev, "Couldn't set PCI-X max read count, " 1421da177e4SLinus Torvalds "aborting.\n"); 1431da177e4SLinus Torvalds return -ENODEV; 1441da177e4SLinus Torvalds } 14568a3c212SRoland Dreier } else if (!(mdev->mthca_flags & MTHCA_FLAG_PCIE)) 1461da177e4SLinus Torvalds mthca_info(mdev, "No PCI-X capability, not setting RBC.\n"); 1471da177e4SLinus Torvalds 148a855b1a7SPeter Oruba if (pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP)) { 149a855b1a7SPeter Oruba if (pcie_set_readrq(mdev->pdev, 4096)) { 150a855b1a7SPeter Oruba mthca_err(mdev, "Couldn't write PCI Express read request, " 151a855b1a7SPeter Oruba "aborting.\n"); 1521da177e4SLinus Torvalds return -ENODEV; 1531da177e4SLinus Torvalds } 15468a3c212SRoland Dreier } else if (mdev->mthca_flags & MTHCA_FLAG_PCIE) 1551da177e4SLinus Torvalds mthca_info(mdev, "No PCI Express capability, " 1561da177e4SLinus Torvalds "not setting Max Read Request Size.\n"); 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds return 0; 1591da177e4SLinus Torvalds } 1601da177e4SLinus Torvalds 161f4f3d0f0SRoland Dreier static int mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim *dev_lim) 1621da177e4SLinus Torvalds { 1631da177e4SLinus Torvalds int err; 1641da177e4SLinus Torvalds u8 status; 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds err = mthca_QUERY_DEV_LIM(mdev, dev_lim, &status); 1671da177e4SLinus Torvalds if (err) { 1681da177e4SLinus Torvalds mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n"); 1691da177e4SLinus Torvalds return err; 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds if (status) { 1721da177e4SLinus Torvalds mthca_err(mdev, "QUERY_DEV_LIM returned status 0x%02x, " 1731da177e4SLinus Torvalds "aborting.\n", status); 1741da177e4SLinus Torvalds return -EINVAL; 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds if (dev_lim->min_page_sz > PAGE_SIZE) { 1771da177e4SLinus Torvalds mthca_err(mdev, "HCA minimum page size of %d bigger than " 1781da177e4SLinus Torvalds "kernel PAGE_SIZE of %ld, aborting.\n", 1791da177e4SLinus Torvalds dev_lim->min_page_sz, PAGE_SIZE); 1801da177e4SLinus Torvalds return -ENODEV; 1811da177e4SLinus Torvalds } 1821da177e4SLinus Torvalds if (dev_lim->num_ports > MTHCA_MAX_PORTS) { 1831da177e4SLinus Torvalds mthca_err(mdev, "HCA has %d ports, but we only support %d, " 1841da177e4SLinus Torvalds "aborting.\n", 1851da177e4SLinus Torvalds dev_lim->num_ports, MTHCA_MAX_PORTS); 1861da177e4SLinus Torvalds return -ENODEV; 1871da177e4SLinus Torvalds } 1881da177e4SLinus Torvalds 189cbd2981aSMichael S. Tsirkin if (dev_lim->uar_size > pci_resource_len(mdev->pdev, 2)) { 190cbd2981aSMichael S. Tsirkin mthca_err(mdev, "HCA reported UAR size of 0x%x bigger than " 191e29419ffSGreg Kroah-Hartman "PCI resource 2 size of 0x%llx, aborting.\n", 192e29419ffSGreg Kroah-Hartman dev_lim->uar_size, 193e29419ffSGreg Kroah-Hartman (unsigned long long)pci_resource_len(mdev->pdev, 2)); 194cbd2981aSMichael S. Tsirkin return -ENODEV; 195cbd2981aSMichael S. Tsirkin } 196cbd2981aSMichael S. Tsirkin 1971da177e4SLinus Torvalds mdev->limits.num_ports = dev_lim->num_ports; 1981da177e4SLinus Torvalds mdev->limits.vl_cap = dev_lim->max_vl; 1991da177e4SLinus Torvalds mdev->limits.mtu_cap = dev_lim->max_mtu; 2001da177e4SLinus Torvalds mdev->limits.gid_table_len = dev_lim->max_gids; 2011da177e4SLinus Torvalds mdev->limits.pkey_table_len = dev_lim->max_pkeys; 2021da177e4SLinus Torvalds mdev->limits.local_ca_ack_delay = dev_lim->local_ca_ack_delay; 2031da177e4SLinus Torvalds mdev->limits.max_sg = dev_lim->max_sg; 204efaae8f7SJack Morgenstein mdev->limits.max_wqes = dev_lim->max_qp_sz; 205efaae8f7SJack Morgenstein mdev->limits.max_qp_init_rdma = dev_lim->max_requester_per_qp; 2061da177e4SLinus Torvalds mdev->limits.reserved_qps = dev_lim->reserved_qps; 207efaae8f7SJack Morgenstein mdev->limits.max_srq_wqes = dev_lim->max_srq_sz; 2081da177e4SLinus Torvalds mdev->limits.reserved_srqs = dev_lim->reserved_srqs; 2091da177e4SLinus Torvalds mdev->limits.reserved_eecs = dev_lim->reserved_eecs; 21077369ed3SJack Morgenstein mdev->limits.max_desc_sz = dev_lim->max_desc_sz; 21159fef3b1SJack Morgenstein mdev->limits.max_srq_sge = mthca_max_srq_sge(mdev); 212efaae8f7SJack Morgenstein /* 213efaae8f7SJack Morgenstein * Subtract 1 from the limit because we need to allocate a 214efaae8f7SJack Morgenstein * spare CQE so the HCA HW can tell the difference between an 215efaae8f7SJack Morgenstein * empty CQ and a full CQ. 216efaae8f7SJack Morgenstein */ 217efaae8f7SJack Morgenstein mdev->limits.max_cqes = dev_lim->max_cq_sz - 1; 2181da177e4SLinus Torvalds mdev->limits.reserved_cqs = dev_lim->reserved_cqs; 2191da177e4SLinus Torvalds mdev->limits.reserved_eqs = dev_lim->reserved_eqs; 2201da177e4SLinus Torvalds mdev->limits.reserved_mtts = dev_lim->reserved_mtts; 2211da177e4SLinus Torvalds mdev->limits.reserved_mrws = dev_lim->reserved_mrws; 2221da177e4SLinus Torvalds mdev->limits.reserved_uars = dev_lim->reserved_uars; 2231da177e4SLinus Torvalds mdev->limits.reserved_pds = dev_lim->reserved_pds; 224da6561c2SRoland Dreier mdev->limits.port_width_cap = dev_lim->max_port_width; 2250f69ce1eSJack Morgenstein mdev->limits.page_size_cap = ~(u32) (dev_lim->min_page_sz - 1); 22633033b79SJack Morgenstein mdev->limits.flags = dev_lim->flags; 227bf6a9e31SJack Morgenstein /* 228bf6a9e31SJack Morgenstein * For old FW that doesn't return static rate support, use a 229bf6a9e31SJack Morgenstein * value of 0x3 (only static rate values of 0 or 1 are handled), 230bf6a9e31SJack Morgenstein * except on Sinai, where even old FW can handle static rate 231bf6a9e31SJack Morgenstein * values of 2 and 3. 232bf6a9e31SJack Morgenstein */ 233bf6a9e31SJack Morgenstein if (dev_lim->stat_rate_support) 234bf6a9e31SJack Morgenstein mdev->limits.stat_rate_support = dev_lim->stat_rate_support; 235bf6a9e31SJack Morgenstein else if (mdev->mthca_flags & MTHCA_FLAG_SINAI_OPT) 236bf6a9e31SJack Morgenstein mdev->limits.stat_rate_support = 0xf; 237bf6a9e31SJack Morgenstein else 238bf6a9e31SJack Morgenstein mdev->limits.stat_rate_support = 0x3; 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds /* IB_DEVICE_RESIZE_MAX_WR not supported by driver. 2411da177e4SLinus Torvalds May be doable since hardware supports it for SRQ. 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds IB_DEVICE_N_NOTIFY_CQ is supported by hardware but not by driver. 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds IB_DEVICE_SRQ_RESIZE is supported by hardware but SRQ is not 2461da177e4SLinus Torvalds supported by driver. */ 2471da177e4SLinus Torvalds mdev->device_cap_flags = IB_DEVICE_CHANGE_PHY_PORT | 2481da177e4SLinus Torvalds IB_DEVICE_PORT_ACTIVE_EVENT | 2491da177e4SLinus Torvalds IB_DEVICE_SYS_IMAGE_GUID | 2501da177e4SLinus Torvalds IB_DEVICE_RC_RNR_NAK_GEN; 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds if (dev_lim->flags & DEV_LIM_FLAG_BAD_PKEY_CNTR) 2531da177e4SLinus Torvalds mdev->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR; 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds if (dev_lim->flags & DEV_LIM_FLAG_BAD_QKEY_CNTR) 2561da177e4SLinus Torvalds mdev->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR; 2571da177e4SLinus Torvalds 2581da177e4SLinus Torvalds if (dev_lim->flags & DEV_LIM_FLAG_RAW_MULTI) 2591da177e4SLinus Torvalds mdev->device_cap_flags |= IB_DEVICE_RAW_MULTI; 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds if (dev_lim->flags & DEV_LIM_FLAG_AUTO_PATH_MIG) 2621da177e4SLinus Torvalds mdev->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG; 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds if (dev_lim->flags & DEV_LIM_FLAG_UD_AV_PORT_ENFORCE) 2651da177e4SLinus Torvalds mdev->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE; 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds if (dev_lim->flags & DEV_LIM_FLAG_SRQ) 2681da177e4SLinus Torvalds mdev->mthca_flags |= MTHCA_FLAG_SRQ; 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds return 0; 2711da177e4SLinus Torvalds } 2721da177e4SLinus Torvalds 273f4f3d0f0SRoland Dreier static int mthca_init_tavor(struct mthca_dev *mdev) 2741da177e4SLinus Torvalds { 2751da177e4SLinus Torvalds u8 status; 2761da177e4SLinus Torvalds int err; 2771da177e4SLinus Torvalds struct mthca_dev_lim dev_lim; 2781da177e4SLinus Torvalds struct mthca_profile profile; 2791da177e4SLinus Torvalds struct mthca_init_hca_param init_hca; 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds err = mthca_SYS_EN(mdev, &status); 2821da177e4SLinus Torvalds if (err) { 2831da177e4SLinus Torvalds mthca_err(mdev, "SYS_EN command failed, aborting.\n"); 2841da177e4SLinus Torvalds return err; 2851da177e4SLinus Torvalds } 2861da177e4SLinus Torvalds if (status) { 2871da177e4SLinus Torvalds mthca_err(mdev, "SYS_EN returned status 0x%02x, " 2881da177e4SLinus Torvalds "aborting.\n", status); 2891da177e4SLinus Torvalds return -EINVAL; 2901da177e4SLinus Torvalds } 2911da177e4SLinus Torvalds 2921da177e4SLinus Torvalds err = mthca_QUERY_FW(mdev, &status); 2931da177e4SLinus Torvalds if (err) { 2941da177e4SLinus Torvalds mthca_err(mdev, "QUERY_FW command failed, aborting.\n"); 2951da177e4SLinus Torvalds goto err_disable; 2961da177e4SLinus Torvalds } 2971da177e4SLinus Torvalds if (status) { 2981da177e4SLinus Torvalds mthca_err(mdev, "QUERY_FW returned status 0x%02x, " 2991da177e4SLinus Torvalds "aborting.\n", status); 3001da177e4SLinus Torvalds err = -EINVAL; 3011da177e4SLinus Torvalds goto err_disable; 3021da177e4SLinus Torvalds } 3031da177e4SLinus Torvalds err = mthca_QUERY_DDR(mdev, &status); 3041da177e4SLinus Torvalds if (err) { 3051da177e4SLinus Torvalds mthca_err(mdev, "QUERY_DDR command failed, aborting.\n"); 3061da177e4SLinus Torvalds goto err_disable; 3071da177e4SLinus Torvalds } 3081da177e4SLinus Torvalds if (status) { 3091da177e4SLinus Torvalds mthca_err(mdev, "QUERY_DDR returned status 0x%02x, " 3101da177e4SLinus Torvalds "aborting.\n", status); 3111da177e4SLinus Torvalds err = -EINVAL; 3121da177e4SLinus Torvalds goto err_disable; 3131da177e4SLinus Torvalds } 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds err = mthca_dev_lim(mdev, &dev_lim); 316aa2f9367SJack Morgenstein if (err) { 317aa2f9367SJack Morgenstein mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n"); 318aa2f9367SJack Morgenstein goto err_disable; 319aa2f9367SJack Morgenstein } 3201da177e4SLinus Torvalds 32182da703eSLeonid Arsh profile = hca_profile; 3221da177e4SLinus Torvalds profile.num_uar = dev_lim.uar_size / PAGE_SIZE; 3231da177e4SLinus Torvalds profile.uarc_size = 0; 324ec34a922SRoland Dreier if (mdev->mthca_flags & MTHCA_FLAG_SRQ) 325ec34a922SRoland Dreier profile.num_srq = dev_lim.max_srqs; 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds err = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca); 3281da177e4SLinus Torvalds if (err < 0) 3291da177e4SLinus Torvalds goto err_disable; 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds err = mthca_INIT_HCA(mdev, &init_hca, &status); 3321da177e4SLinus Torvalds if (err) { 3331da177e4SLinus Torvalds mthca_err(mdev, "INIT_HCA command failed, aborting.\n"); 3341da177e4SLinus Torvalds goto err_disable; 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds if (status) { 3371da177e4SLinus Torvalds mthca_err(mdev, "INIT_HCA returned status 0x%02x, " 3381da177e4SLinus Torvalds "aborting.\n", status); 3391da177e4SLinus Torvalds err = -EINVAL; 3401da177e4SLinus Torvalds goto err_disable; 3411da177e4SLinus Torvalds } 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds return 0; 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds err_disable: 3461da177e4SLinus Torvalds mthca_SYS_DIS(mdev, &status); 3471da177e4SLinus Torvalds 3481da177e4SLinus Torvalds return err; 3491da177e4SLinus Torvalds } 3501da177e4SLinus Torvalds 351f4f3d0f0SRoland Dreier static int mthca_load_fw(struct mthca_dev *mdev) 3521da177e4SLinus Torvalds { 3531da177e4SLinus Torvalds u8 status; 3541da177e4SLinus Torvalds int err; 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds /* FIXME: use HCA-attached memory for FW if present */ 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds mdev->fw.arbel.fw_icm = 3591da177e4SLinus Torvalds mthca_alloc_icm(mdev, mdev->fw.arbel.fw_pages, 360391e4deaSMichael S. Tsirkin GFP_HIGHUSER | __GFP_NOWARN, 0); 3611da177e4SLinus Torvalds if (!mdev->fw.arbel.fw_icm) { 3621da177e4SLinus Torvalds mthca_err(mdev, "Couldn't allocate FW area, aborting.\n"); 3631da177e4SLinus Torvalds return -ENOMEM; 3641da177e4SLinus Torvalds } 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds err = mthca_MAP_FA(mdev, mdev->fw.arbel.fw_icm, &status); 3671da177e4SLinus Torvalds if (err) { 3681da177e4SLinus Torvalds mthca_err(mdev, "MAP_FA command failed, aborting.\n"); 3691da177e4SLinus Torvalds goto err_free; 3701da177e4SLinus Torvalds } 3711da177e4SLinus Torvalds if (status) { 3721da177e4SLinus Torvalds mthca_err(mdev, "MAP_FA returned status 0x%02x, aborting.\n", status); 3731da177e4SLinus Torvalds err = -EINVAL; 3741da177e4SLinus Torvalds goto err_free; 3751da177e4SLinus Torvalds } 3761da177e4SLinus Torvalds err = mthca_RUN_FW(mdev, &status); 3771da177e4SLinus Torvalds if (err) { 3781da177e4SLinus Torvalds mthca_err(mdev, "RUN_FW command failed, aborting.\n"); 3791da177e4SLinus Torvalds goto err_unmap_fa; 3801da177e4SLinus Torvalds } 3811da177e4SLinus Torvalds if (status) { 3821da177e4SLinus Torvalds mthca_err(mdev, "RUN_FW returned status 0x%02x, aborting.\n", status); 3831da177e4SLinus Torvalds err = -EINVAL; 3841da177e4SLinus Torvalds goto err_unmap_fa; 3851da177e4SLinus Torvalds } 3861da177e4SLinus Torvalds 3871da177e4SLinus Torvalds return 0; 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds err_unmap_fa: 3901da177e4SLinus Torvalds mthca_UNMAP_FA(mdev, &status); 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds err_free: 393391e4deaSMichael S. Tsirkin mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0); 3941da177e4SLinus Torvalds return err; 3951da177e4SLinus Torvalds } 3961da177e4SLinus Torvalds 397f4f3d0f0SRoland Dreier static int mthca_init_icm(struct mthca_dev *mdev, 3981da177e4SLinus Torvalds struct mthca_dev_lim *dev_lim, 3991da177e4SLinus Torvalds struct mthca_init_hca_param *init_hca, 4001da177e4SLinus Torvalds u64 icm_size) 4011da177e4SLinus Torvalds { 4021da177e4SLinus Torvalds u64 aux_pages; 4031da177e4SLinus Torvalds u8 status; 4041da177e4SLinus Torvalds int err; 4051da177e4SLinus Torvalds 4061da177e4SLinus Torvalds err = mthca_SET_ICM_SIZE(mdev, icm_size, &aux_pages, &status); 4071da177e4SLinus Torvalds if (err) { 4081da177e4SLinus Torvalds mthca_err(mdev, "SET_ICM_SIZE command failed, aborting.\n"); 4091da177e4SLinus Torvalds return err; 4101da177e4SLinus Torvalds } 4111da177e4SLinus Torvalds if (status) { 4121da177e4SLinus Torvalds mthca_err(mdev, "SET_ICM_SIZE returned status 0x%02x, " 4131da177e4SLinus Torvalds "aborting.\n", status); 4141da177e4SLinus Torvalds return -EINVAL; 4151da177e4SLinus Torvalds } 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds mthca_dbg(mdev, "%lld KB of HCA context requires %lld KB aux memory.\n", 4181da177e4SLinus Torvalds (unsigned long long) icm_size >> 10, 4191da177e4SLinus Torvalds (unsigned long long) aux_pages << 2); 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds mdev->fw.arbel.aux_icm = mthca_alloc_icm(mdev, aux_pages, 422391e4deaSMichael S. Tsirkin GFP_HIGHUSER | __GFP_NOWARN, 0); 4231da177e4SLinus Torvalds if (!mdev->fw.arbel.aux_icm) { 4241da177e4SLinus Torvalds mthca_err(mdev, "Couldn't allocate aux memory, aborting.\n"); 4251da177e4SLinus Torvalds return -ENOMEM; 4261da177e4SLinus Torvalds } 4271da177e4SLinus Torvalds 4281da177e4SLinus Torvalds err = mthca_MAP_ICM_AUX(mdev, mdev->fw.arbel.aux_icm, &status); 4291da177e4SLinus Torvalds if (err) { 4301da177e4SLinus Torvalds mthca_err(mdev, "MAP_ICM_AUX command failed, aborting.\n"); 4311da177e4SLinus Torvalds goto err_free_aux; 4321da177e4SLinus Torvalds } 4331da177e4SLinus Torvalds if (status) { 4341da177e4SLinus Torvalds mthca_err(mdev, "MAP_ICM_AUX returned status 0x%02x, aborting.\n", status); 4351da177e4SLinus Torvalds err = -EINVAL; 4361da177e4SLinus Torvalds goto err_free_aux; 4371da177e4SLinus Torvalds } 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds err = mthca_map_eq_icm(mdev, init_hca->eqc_base); 4401da177e4SLinus Torvalds if (err) { 4411da177e4SLinus Torvalds mthca_err(mdev, "Failed to map EQ context memory, aborting.\n"); 4421da177e4SLinus Torvalds goto err_unmap_aux; 4431da177e4SLinus Torvalds } 4441da177e4SLinus Torvalds 4451d1f19cfSMichael S. Tsirkin /* CPU writes to non-reserved MTTs, while HCA might DMA to reserved mtts */ 4461d1f19cfSMichael S. Tsirkin mdev->limits.reserved_mtts = ALIGN(mdev->limits.reserved_mtts * MTHCA_MTT_SEG_SIZE, 4471d1f19cfSMichael S. Tsirkin dma_get_cache_alignment()) / MTHCA_MTT_SEG_SIZE; 4481d1f19cfSMichael S. Tsirkin 4491da177e4SLinus Torvalds mdev->mr_table.mtt_table = mthca_alloc_icm_table(mdev, init_hca->mtt_base, 45044ea6687SRoland Dreier MTHCA_MTT_SEG_SIZE, 4511da177e4SLinus Torvalds mdev->limits.num_mtt_segs, 452391e4deaSMichael S. Tsirkin mdev->limits.reserved_mtts, 453391e4deaSMichael S. Tsirkin 1, 0); 4541da177e4SLinus Torvalds if (!mdev->mr_table.mtt_table) { 4551da177e4SLinus Torvalds mthca_err(mdev, "Failed to map MTT context memory, aborting.\n"); 4561da177e4SLinus Torvalds err = -ENOMEM; 4571da177e4SLinus Torvalds goto err_unmap_eq; 4581da177e4SLinus Torvalds } 4591da177e4SLinus Torvalds 4601da177e4SLinus Torvalds mdev->mr_table.mpt_table = mthca_alloc_icm_table(mdev, init_hca->mpt_base, 4611da177e4SLinus Torvalds dev_lim->mpt_entry_sz, 4621da177e4SLinus Torvalds mdev->limits.num_mpts, 463391e4deaSMichael S. Tsirkin mdev->limits.reserved_mrws, 464391e4deaSMichael S. Tsirkin 1, 1); 4651da177e4SLinus Torvalds if (!mdev->mr_table.mpt_table) { 4661da177e4SLinus Torvalds mthca_err(mdev, "Failed to map MPT context memory, aborting.\n"); 4671da177e4SLinus Torvalds err = -ENOMEM; 4681da177e4SLinus Torvalds goto err_unmap_mtt; 4691da177e4SLinus Torvalds } 4701da177e4SLinus Torvalds 4711da177e4SLinus Torvalds mdev->qp_table.qp_table = mthca_alloc_icm_table(mdev, init_hca->qpc_base, 4721da177e4SLinus Torvalds dev_lim->qpc_entry_sz, 4731da177e4SLinus Torvalds mdev->limits.num_qps, 474391e4deaSMichael S. Tsirkin mdev->limits.reserved_qps, 475391e4deaSMichael S. Tsirkin 0, 0); 4761da177e4SLinus Torvalds if (!mdev->qp_table.qp_table) { 4771da177e4SLinus Torvalds mthca_err(mdev, "Failed to map QP context memory, aborting.\n"); 4781da177e4SLinus Torvalds err = -ENOMEM; 4791da177e4SLinus Torvalds goto err_unmap_mpt; 4801da177e4SLinus Torvalds } 4811da177e4SLinus Torvalds 4821da177e4SLinus Torvalds mdev->qp_table.eqp_table = mthca_alloc_icm_table(mdev, init_hca->eqpc_base, 4831da177e4SLinus Torvalds dev_lim->eqpc_entry_sz, 4841da177e4SLinus Torvalds mdev->limits.num_qps, 485391e4deaSMichael S. Tsirkin mdev->limits.reserved_qps, 486391e4deaSMichael S. Tsirkin 0, 0); 4871da177e4SLinus Torvalds if (!mdev->qp_table.eqp_table) { 4881da177e4SLinus Torvalds mthca_err(mdev, "Failed to map EQP context memory, aborting.\n"); 4891da177e4SLinus Torvalds err = -ENOMEM; 4901da177e4SLinus Torvalds goto err_unmap_qp; 4911da177e4SLinus Torvalds } 4921da177e4SLinus Torvalds 49308aeb14eSRoland Dreier mdev->qp_table.rdb_table = mthca_alloc_icm_table(mdev, init_hca->rdb_base, 49408aeb14eSRoland Dreier MTHCA_RDB_ENTRY_SIZE, 49508aeb14eSRoland Dreier mdev->limits.num_qps << 496391e4deaSMichael S. Tsirkin mdev->qp_table.rdb_shift, 0, 49708aeb14eSRoland Dreier 0, 0); 49808aeb14eSRoland Dreier if (!mdev->qp_table.rdb_table) { 49908aeb14eSRoland Dreier mthca_err(mdev, "Failed to map RDB context memory, aborting\n"); 50008aeb14eSRoland Dreier err = -ENOMEM; 50119272d43SRoland Dreier goto err_unmap_eqp; 50208aeb14eSRoland Dreier } 50308aeb14eSRoland Dreier 5041da177e4SLinus Torvalds mdev->cq_table.table = mthca_alloc_icm_table(mdev, init_hca->cqc_base, 5051da177e4SLinus Torvalds dev_lim->cqc_entry_sz, 5061da177e4SLinus Torvalds mdev->limits.num_cqs, 507391e4deaSMichael S. Tsirkin mdev->limits.reserved_cqs, 508391e4deaSMichael S. Tsirkin 0, 0); 5091da177e4SLinus Torvalds if (!mdev->cq_table.table) { 5101da177e4SLinus Torvalds mthca_err(mdev, "Failed to map CQ context memory, aborting.\n"); 5111da177e4SLinus Torvalds err = -ENOMEM; 51208aeb14eSRoland Dreier goto err_unmap_rdb; 5131da177e4SLinus Torvalds } 5141da177e4SLinus Torvalds 515ec34a922SRoland Dreier if (mdev->mthca_flags & MTHCA_FLAG_SRQ) { 516ec34a922SRoland Dreier mdev->srq_table.table = 517ec34a922SRoland Dreier mthca_alloc_icm_table(mdev, init_hca->srqc_base, 518ec34a922SRoland Dreier dev_lim->srq_entry_sz, 519ec34a922SRoland Dreier mdev->limits.num_srqs, 520391e4deaSMichael S. Tsirkin mdev->limits.reserved_srqs, 521391e4deaSMichael S. Tsirkin 0, 0); 522ec34a922SRoland Dreier if (!mdev->srq_table.table) { 523ec34a922SRoland Dreier mthca_err(mdev, "Failed to map SRQ context memory, " 524ec34a922SRoland Dreier "aborting.\n"); 525ec34a922SRoland Dreier err = -ENOMEM; 526ec34a922SRoland Dreier goto err_unmap_cq; 527ec34a922SRoland Dreier } 528ec34a922SRoland Dreier } 529ec34a922SRoland Dreier 5301da177e4SLinus Torvalds /* 5311da177e4SLinus Torvalds * It's not strictly required, but for simplicity just map the 5321da177e4SLinus Torvalds * whole multicast group table now. The table isn't very big 5331da177e4SLinus Torvalds * and it's a lot easier than trying to track ref counts. 5341da177e4SLinus Torvalds */ 5351da177e4SLinus Torvalds mdev->mcg_table.table = mthca_alloc_icm_table(mdev, init_hca->mc_base, 5361da177e4SLinus Torvalds MTHCA_MGM_ENTRY_SIZE, 5371da177e4SLinus Torvalds mdev->limits.num_mgms + 5381da177e4SLinus Torvalds mdev->limits.num_amgms, 5391da177e4SLinus Torvalds mdev->limits.num_mgms + 5401da177e4SLinus Torvalds mdev->limits.num_amgms, 541391e4deaSMichael S. Tsirkin 0, 0); 5421da177e4SLinus Torvalds if (!mdev->mcg_table.table) { 5431da177e4SLinus Torvalds mthca_err(mdev, "Failed to map MCG context memory, aborting.\n"); 5441da177e4SLinus Torvalds err = -ENOMEM; 545ec34a922SRoland Dreier goto err_unmap_srq; 5461da177e4SLinus Torvalds } 5471da177e4SLinus Torvalds 5481da177e4SLinus Torvalds return 0; 5491da177e4SLinus Torvalds 550ec34a922SRoland Dreier err_unmap_srq: 551ec34a922SRoland Dreier if (mdev->mthca_flags & MTHCA_FLAG_SRQ) 552ec34a922SRoland Dreier mthca_free_icm_table(mdev, mdev->srq_table.table); 553ec34a922SRoland Dreier 5541da177e4SLinus Torvalds err_unmap_cq: 5551da177e4SLinus Torvalds mthca_free_icm_table(mdev, mdev->cq_table.table); 5561da177e4SLinus Torvalds 55708aeb14eSRoland Dreier err_unmap_rdb: 55808aeb14eSRoland Dreier mthca_free_icm_table(mdev, mdev->qp_table.rdb_table); 55908aeb14eSRoland Dreier 5601da177e4SLinus Torvalds err_unmap_eqp: 5611da177e4SLinus Torvalds mthca_free_icm_table(mdev, mdev->qp_table.eqp_table); 5621da177e4SLinus Torvalds 5631da177e4SLinus Torvalds err_unmap_qp: 5641da177e4SLinus Torvalds mthca_free_icm_table(mdev, mdev->qp_table.qp_table); 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds err_unmap_mpt: 5671da177e4SLinus Torvalds mthca_free_icm_table(mdev, mdev->mr_table.mpt_table); 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds err_unmap_mtt: 5701da177e4SLinus Torvalds mthca_free_icm_table(mdev, mdev->mr_table.mtt_table); 5711da177e4SLinus Torvalds 5721da177e4SLinus Torvalds err_unmap_eq: 5731da177e4SLinus Torvalds mthca_unmap_eq_icm(mdev); 5741da177e4SLinus Torvalds 5751da177e4SLinus Torvalds err_unmap_aux: 5761da177e4SLinus Torvalds mthca_UNMAP_ICM_AUX(mdev, &status); 5771da177e4SLinus Torvalds 5781da177e4SLinus Torvalds err_free_aux: 579391e4deaSMichael S. Tsirkin mthca_free_icm(mdev, mdev->fw.arbel.aux_icm, 0); 5801da177e4SLinus Torvalds 5811da177e4SLinus Torvalds return err; 5821da177e4SLinus Torvalds } 5831da177e4SLinus Torvalds 584aba7a22fSMichael S. Tsirkin static void mthca_free_icms(struct mthca_dev *mdev) 585aba7a22fSMichael S. Tsirkin { 586aba7a22fSMichael S. Tsirkin u8 status; 587aba7a22fSMichael S. Tsirkin 588aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->mcg_table.table); 589aba7a22fSMichael S. Tsirkin if (mdev->mthca_flags & MTHCA_FLAG_SRQ) 590aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->srq_table.table); 591aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->cq_table.table); 592aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->qp_table.rdb_table); 593aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->qp_table.eqp_table); 594aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->qp_table.qp_table); 595aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->mr_table.mpt_table); 596aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->mr_table.mtt_table); 597aba7a22fSMichael S. Tsirkin mthca_unmap_eq_icm(mdev); 598aba7a22fSMichael S. Tsirkin 599aba7a22fSMichael S. Tsirkin mthca_UNMAP_ICM_AUX(mdev, &status); 600391e4deaSMichael S. Tsirkin mthca_free_icm(mdev, mdev->fw.arbel.aux_icm, 0); 601aba7a22fSMichael S. Tsirkin } 602aba7a22fSMichael S. Tsirkin 603f4f3d0f0SRoland Dreier static int mthca_init_arbel(struct mthca_dev *mdev) 6041da177e4SLinus Torvalds { 6051da177e4SLinus Torvalds struct mthca_dev_lim dev_lim; 6061da177e4SLinus Torvalds struct mthca_profile profile; 6071da177e4SLinus Torvalds struct mthca_init_hca_param init_hca; 6081da177e4SLinus Torvalds u64 icm_size; 6091da177e4SLinus Torvalds u8 status; 6101da177e4SLinus Torvalds int err; 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds err = mthca_QUERY_FW(mdev, &status); 6131da177e4SLinus Torvalds if (err) { 6141da177e4SLinus Torvalds mthca_err(mdev, "QUERY_FW command failed, aborting.\n"); 6151da177e4SLinus Torvalds return err; 6161da177e4SLinus Torvalds } 6171da177e4SLinus Torvalds if (status) { 6181da177e4SLinus Torvalds mthca_err(mdev, "QUERY_FW returned status 0x%02x, " 6191da177e4SLinus Torvalds "aborting.\n", status); 6201da177e4SLinus Torvalds return -EINVAL; 6211da177e4SLinus Torvalds } 6221da177e4SLinus Torvalds 6231da177e4SLinus Torvalds err = mthca_ENABLE_LAM(mdev, &status); 6241da177e4SLinus Torvalds if (err) { 6251da177e4SLinus Torvalds mthca_err(mdev, "ENABLE_LAM command failed, aborting.\n"); 6261da177e4SLinus Torvalds return err; 6271da177e4SLinus Torvalds } 6281da177e4SLinus Torvalds if (status == MTHCA_CMD_STAT_LAM_NOT_PRE) { 6291da177e4SLinus Torvalds mthca_dbg(mdev, "No HCA-attached memory (running in MemFree mode)\n"); 6301da177e4SLinus Torvalds mdev->mthca_flags |= MTHCA_FLAG_NO_LAM; 6311da177e4SLinus Torvalds } else if (status) { 6321da177e4SLinus Torvalds mthca_err(mdev, "ENABLE_LAM returned status 0x%02x, " 6331da177e4SLinus Torvalds "aborting.\n", status); 6341da177e4SLinus Torvalds return -EINVAL; 6351da177e4SLinus Torvalds } 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds err = mthca_load_fw(mdev); 6381da177e4SLinus Torvalds if (err) { 6391da177e4SLinus Torvalds mthca_err(mdev, "Failed to start FW, aborting.\n"); 6401da177e4SLinus Torvalds goto err_disable; 6411da177e4SLinus Torvalds } 6421da177e4SLinus Torvalds 6431da177e4SLinus Torvalds err = mthca_dev_lim(mdev, &dev_lim); 6441da177e4SLinus Torvalds if (err) { 6451da177e4SLinus Torvalds mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n"); 6461da177e4SLinus Torvalds goto err_stop_fw; 6471da177e4SLinus Torvalds } 6481da177e4SLinus Torvalds 64982da703eSLeonid Arsh profile = hca_profile; 6501da177e4SLinus Torvalds profile.num_uar = dev_lim.uar_size / PAGE_SIZE; 6511da177e4SLinus Torvalds profile.num_udav = 0; 652ec34a922SRoland Dreier if (mdev->mthca_flags & MTHCA_FLAG_SRQ) 653ec34a922SRoland Dreier profile.num_srq = dev_lim.max_srqs; 6541da177e4SLinus Torvalds 6551da177e4SLinus Torvalds icm_size = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca); 6561da177e4SLinus Torvalds if ((int) icm_size < 0) { 6571da177e4SLinus Torvalds err = icm_size; 6581da177e4SLinus Torvalds goto err_stop_fw; 6591da177e4SLinus Torvalds } 6601da177e4SLinus Torvalds 6611da177e4SLinus Torvalds err = mthca_init_icm(mdev, &dev_lim, &init_hca, icm_size); 6621da177e4SLinus Torvalds if (err) 6631da177e4SLinus Torvalds goto err_stop_fw; 6641da177e4SLinus Torvalds 6651da177e4SLinus Torvalds err = mthca_INIT_HCA(mdev, &init_hca, &status); 6661da177e4SLinus Torvalds if (err) { 6671da177e4SLinus Torvalds mthca_err(mdev, "INIT_HCA command failed, aborting.\n"); 6681da177e4SLinus Torvalds goto err_free_icm; 6691da177e4SLinus Torvalds } 6701da177e4SLinus Torvalds if (status) { 6711da177e4SLinus Torvalds mthca_err(mdev, "INIT_HCA returned status 0x%02x, " 6721da177e4SLinus Torvalds "aborting.\n", status); 6731da177e4SLinus Torvalds err = -EINVAL; 6741da177e4SLinus Torvalds goto err_free_icm; 6751da177e4SLinus Torvalds } 6761da177e4SLinus Torvalds 6771da177e4SLinus Torvalds return 0; 6781da177e4SLinus Torvalds 6791da177e4SLinus Torvalds err_free_icm: 680aba7a22fSMichael S. Tsirkin mthca_free_icms(mdev); 6811da177e4SLinus Torvalds 6821da177e4SLinus Torvalds err_stop_fw: 6831da177e4SLinus Torvalds mthca_UNMAP_FA(mdev, &status); 684391e4deaSMichael S. Tsirkin mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0); 6851da177e4SLinus Torvalds 6861da177e4SLinus Torvalds err_disable: 6871da177e4SLinus Torvalds if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM)) 6881da177e4SLinus Torvalds mthca_DISABLE_LAM(mdev, &status); 6891da177e4SLinus Torvalds 6901da177e4SLinus Torvalds return err; 6911da177e4SLinus Torvalds } 6921da177e4SLinus Torvalds 6932e8b981cSMichael S. Tsirkin static void mthca_close_hca(struct mthca_dev *mdev) 6942e8b981cSMichael S. Tsirkin { 6952e8b981cSMichael S. Tsirkin u8 status; 6962e8b981cSMichael S. Tsirkin 6972e8b981cSMichael S. Tsirkin mthca_CLOSE_HCA(mdev, 0, &status); 6982e8b981cSMichael S. Tsirkin 6992e8b981cSMichael S. Tsirkin if (mthca_is_memfree(mdev)) { 700aba7a22fSMichael S. Tsirkin mthca_free_icms(mdev); 7012e8b981cSMichael S. Tsirkin 7022e8b981cSMichael S. Tsirkin mthca_UNMAP_FA(mdev, &status); 703391e4deaSMichael S. Tsirkin mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0); 7042e8b981cSMichael S. Tsirkin 7052e8b981cSMichael S. Tsirkin if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM)) 7062e8b981cSMichael S. Tsirkin mthca_DISABLE_LAM(mdev, &status); 7072e8b981cSMichael S. Tsirkin } else 7082e8b981cSMichael S. Tsirkin mthca_SYS_DIS(mdev, &status); 7092e8b981cSMichael S. Tsirkin } 7102e8b981cSMichael S. Tsirkin 711f4f3d0f0SRoland Dreier static int mthca_init_hca(struct mthca_dev *mdev) 7121da177e4SLinus Torvalds { 7132e8b981cSMichael S. Tsirkin u8 status; 7142e8b981cSMichael S. Tsirkin int err; 7152e8b981cSMichael S. Tsirkin struct mthca_adapter adapter; 7162e8b981cSMichael S. Tsirkin 717d10ddbf6SRoland Dreier if (mthca_is_memfree(mdev)) 7182e8b981cSMichael S. Tsirkin err = mthca_init_arbel(mdev); 7191da177e4SLinus Torvalds else 7202e8b981cSMichael S. Tsirkin err = mthca_init_tavor(mdev); 7212e8b981cSMichael S. Tsirkin 7222e8b981cSMichael S. Tsirkin if (err) 7232e8b981cSMichael S. Tsirkin return err; 7242e8b981cSMichael S. Tsirkin 7252e8b981cSMichael S. Tsirkin err = mthca_QUERY_ADAPTER(mdev, &adapter, &status); 7262e8b981cSMichael S. Tsirkin if (err) { 7272e8b981cSMichael S. Tsirkin mthca_err(mdev, "QUERY_ADAPTER command failed, aborting.\n"); 7282e8b981cSMichael S. Tsirkin goto err_close; 7292e8b981cSMichael S. Tsirkin } 7302e8b981cSMichael S. Tsirkin if (status) { 7312e8b981cSMichael S. Tsirkin mthca_err(mdev, "QUERY_ADAPTER returned status 0x%02x, " 7322e8b981cSMichael S. Tsirkin "aborting.\n", status); 7332e8b981cSMichael S. Tsirkin err = -EINVAL; 7342e8b981cSMichael S. Tsirkin goto err_close; 7352e8b981cSMichael S. Tsirkin } 7362e8b981cSMichael S. Tsirkin 7372e8b981cSMichael S. Tsirkin mdev->eq_table.inta_pin = adapter.inta_pin; 7382e8b981cSMichael S. Tsirkin mdev->rev_id = adapter.revision_id; 7392e8b981cSMichael S. Tsirkin memcpy(mdev->board_id, adapter.board_id, sizeof mdev->board_id); 7402e8b981cSMichael S. Tsirkin 7412e8b981cSMichael S. Tsirkin return 0; 7422e8b981cSMichael S. Tsirkin 7432e8b981cSMichael S. Tsirkin err_close: 7442e8b981cSMichael S. Tsirkin mthca_close_hca(mdev); 7452e8b981cSMichael S. Tsirkin return err; 7461da177e4SLinus Torvalds } 7471da177e4SLinus Torvalds 748f4f3d0f0SRoland Dreier static int mthca_setup_hca(struct mthca_dev *dev) 7491da177e4SLinus Torvalds { 7501da177e4SLinus Torvalds int err; 7511da177e4SLinus Torvalds u8 status; 7521da177e4SLinus Torvalds 7531da177e4SLinus Torvalds MTHCA_INIT_DOORBELL_LOCK(&dev->doorbell_lock); 7541da177e4SLinus Torvalds 7551da177e4SLinus Torvalds err = mthca_init_uar_table(dev); 7561da177e4SLinus Torvalds if (err) { 7571da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 7581da177e4SLinus Torvalds "user access region table, aborting.\n"); 7591da177e4SLinus Torvalds return err; 7601da177e4SLinus Torvalds } 7611da177e4SLinus Torvalds 7621da177e4SLinus Torvalds err = mthca_uar_alloc(dev, &dev->driver_uar); 7631da177e4SLinus Torvalds if (err) { 7641da177e4SLinus Torvalds mthca_err(dev, "Failed to allocate driver access region, " 7651da177e4SLinus Torvalds "aborting.\n"); 7661da177e4SLinus Torvalds goto err_uar_table_free; 7671da177e4SLinus Torvalds } 7681da177e4SLinus Torvalds 7691da177e4SLinus Torvalds dev->kar = ioremap(dev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE); 7701da177e4SLinus Torvalds if (!dev->kar) { 7711da177e4SLinus Torvalds mthca_err(dev, "Couldn't map kernel access region, " 7721da177e4SLinus Torvalds "aborting.\n"); 7731da177e4SLinus Torvalds err = -ENOMEM; 7741da177e4SLinus Torvalds goto err_uar_free; 7751da177e4SLinus Torvalds } 7761da177e4SLinus Torvalds 7771da177e4SLinus Torvalds err = mthca_init_pd_table(dev); 7781da177e4SLinus Torvalds if (err) { 7791da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 7801da177e4SLinus Torvalds "protection domain table, aborting.\n"); 7811da177e4SLinus Torvalds goto err_kar_unmap; 7821da177e4SLinus Torvalds } 7831da177e4SLinus Torvalds 7841da177e4SLinus Torvalds err = mthca_init_mr_table(dev); 7851da177e4SLinus Torvalds if (err) { 7861da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 7871da177e4SLinus Torvalds "memory region table, aborting.\n"); 7881da177e4SLinus Torvalds goto err_pd_table_free; 7891da177e4SLinus Torvalds } 7901da177e4SLinus Torvalds 79199264c1eSRoland Dreier err = mthca_pd_alloc(dev, 1, &dev->driver_pd); 7921da177e4SLinus Torvalds if (err) { 7931da177e4SLinus Torvalds mthca_err(dev, "Failed to create driver PD, " 7941da177e4SLinus Torvalds "aborting.\n"); 7951da177e4SLinus Torvalds goto err_mr_table_free; 7961da177e4SLinus Torvalds } 7971da177e4SLinus Torvalds 7981da177e4SLinus Torvalds err = mthca_init_eq_table(dev); 7991da177e4SLinus Torvalds if (err) { 8001da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 8011da177e4SLinus Torvalds "event queue table, aborting.\n"); 8021da177e4SLinus Torvalds goto err_pd_free; 8031da177e4SLinus Torvalds } 8041da177e4SLinus Torvalds 8051da177e4SLinus Torvalds err = mthca_cmd_use_events(dev); 8061da177e4SLinus Torvalds if (err) { 8071da177e4SLinus Torvalds mthca_err(dev, "Failed to switch to event-driven " 8081da177e4SLinus Torvalds "firmware commands, aborting.\n"); 8091da177e4SLinus Torvalds goto err_eq_table_free; 8101da177e4SLinus Torvalds } 8111da177e4SLinus Torvalds 8121da177e4SLinus Torvalds err = mthca_NOP(dev, &status); 8131da177e4SLinus Torvalds if (err || status) { 814e57895d3SAdrian Bunk if (dev->mthca_flags & MTHCA_FLAG_MSI_X) { 815017aadc4SMichael S. Tsirkin mthca_warn(dev, "NOP command failed to generate interrupt " 816017aadc4SMichael S. Tsirkin "(IRQ %d).\n", 817e57895d3SAdrian Bunk dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector); 818e57895d3SAdrian Bunk mthca_warn(dev, "Trying again with MSI-X disabled.\n"); 819017aadc4SMichael S. Tsirkin } else { 820017aadc4SMichael S. Tsirkin mthca_err(dev, "NOP command failed to generate interrupt " 821017aadc4SMichael S. Tsirkin "(IRQ %d), aborting.\n", 822017aadc4SMichael S. Tsirkin dev->pdev->irq); 8231da177e4SLinus Torvalds mthca_err(dev, "BIOS or ACPI interrupt routing problem?\n"); 824017aadc4SMichael S. Tsirkin } 8251da177e4SLinus Torvalds 8261da177e4SLinus Torvalds goto err_cmd_poll; 8271da177e4SLinus Torvalds } 8281da177e4SLinus Torvalds 8291da177e4SLinus Torvalds mthca_dbg(dev, "NOP command IRQ test passed\n"); 8301da177e4SLinus Torvalds 8311da177e4SLinus Torvalds err = mthca_init_cq_table(dev); 8321da177e4SLinus Torvalds if (err) { 8331da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 8341da177e4SLinus Torvalds "completion queue table, aborting.\n"); 8351da177e4SLinus Torvalds goto err_cmd_poll; 8361da177e4SLinus Torvalds } 8371da177e4SLinus Torvalds 838ec34a922SRoland Dreier err = mthca_init_srq_table(dev); 839ec34a922SRoland Dreier if (err) { 840ec34a922SRoland Dreier mthca_err(dev, "Failed to initialize " 841ec34a922SRoland Dreier "shared receive queue table, aborting.\n"); 842ec34a922SRoland Dreier goto err_cq_table_free; 843ec34a922SRoland Dreier } 844ec34a922SRoland Dreier 8451da177e4SLinus Torvalds err = mthca_init_qp_table(dev); 8461da177e4SLinus Torvalds if (err) { 8471da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 8481da177e4SLinus Torvalds "queue pair table, aborting.\n"); 849ec34a922SRoland Dreier goto err_srq_table_free; 8501da177e4SLinus Torvalds } 8511da177e4SLinus Torvalds 8521da177e4SLinus Torvalds err = mthca_init_av_table(dev); 8531da177e4SLinus Torvalds if (err) { 8541da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 8551da177e4SLinus Torvalds "address vector table, aborting.\n"); 8561da177e4SLinus Torvalds goto err_qp_table_free; 8571da177e4SLinus Torvalds } 8581da177e4SLinus Torvalds 8591da177e4SLinus Torvalds err = mthca_init_mcg_table(dev); 8601da177e4SLinus Torvalds if (err) { 8611da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 8621da177e4SLinus Torvalds "multicast group table, aborting.\n"); 8631da177e4SLinus Torvalds goto err_av_table_free; 8641da177e4SLinus Torvalds } 8651da177e4SLinus Torvalds 8661da177e4SLinus Torvalds return 0; 8671da177e4SLinus Torvalds 8681da177e4SLinus Torvalds err_av_table_free: 8691da177e4SLinus Torvalds mthca_cleanup_av_table(dev); 8701da177e4SLinus Torvalds 8711da177e4SLinus Torvalds err_qp_table_free: 8721da177e4SLinus Torvalds mthca_cleanup_qp_table(dev); 8731da177e4SLinus Torvalds 874ec34a922SRoland Dreier err_srq_table_free: 875ec34a922SRoland Dreier mthca_cleanup_srq_table(dev); 876ec34a922SRoland Dreier 8771da177e4SLinus Torvalds err_cq_table_free: 8781da177e4SLinus Torvalds mthca_cleanup_cq_table(dev); 8791da177e4SLinus Torvalds 8801da177e4SLinus Torvalds err_cmd_poll: 8811da177e4SLinus Torvalds mthca_cmd_use_polling(dev); 8821da177e4SLinus Torvalds 8831da177e4SLinus Torvalds err_eq_table_free: 8841da177e4SLinus Torvalds mthca_cleanup_eq_table(dev); 8851da177e4SLinus Torvalds 8861da177e4SLinus Torvalds err_pd_free: 8871da177e4SLinus Torvalds mthca_pd_free(dev, &dev->driver_pd); 8881da177e4SLinus Torvalds 8891da177e4SLinus Torvalds err_mr_table_free: 8901da177e4SLinus Torvalds mthca_cleanup_mr_table(dev); 8911da177e4SLinus Torvalds 8921da177e4SLinus Torvalds err_pd_table_free: 8931da177e4SLinus Torvalds mthca_cleanup_pd_table(dev); 8941da177e4SLinus Torvalds 8951da177e4SLinus Torvalds err_kar_unmap: 8961da177e4SLinus Torvalds iounmap(dev->kar); 8971da177e4SLinus Torvalds 8981da177e4SLinus Torvalds err_uar_free: 8991da177e4SLinus Torvalds mthca_uar_free(dev, &dev->driver_uar); 9001da177e4SLinus Torvalds 9011da177e4SLinus Torvalds err_uar_table_free: 9021da177e4SLinus Torvalds mthca_cleanup_uar_table(dev); 9031da177e4SLinus Torvalds return err; 9041da177e4SLinus Torvalds } 9051da177e4SLinus Torvalds 906f4f3d0f0SRoland Dreier static int mthca_request_regions(struct pci_dev *pdev, int ddr_hidden) 9071da177e4SLinus Torvalds { 9081da177e4SLinus Torvalds int err; 9091da177e4SLinus Torvalds 9101da177e4SLinus Torvalds /* 9111da177e4SLinus Torvalds * We can't just use pci_request_regions() because the MSI-X 9121da177e4SLinus Torvalds * table is right in the middle of the first BAR. If we did 9131da177e4SLinus Torvalds * pci_request_region and grab all of the first BAR, then 9141da177e4SLinus Torvalds * setting up MSI-X would fail, since the PCI core wants to do 9151da177e4SLinus Torvalds * request_mem_region on the MSI-X vector table. 9161da177e4SLinus Torvalds * 9171da177e4SLinus Torvalds * So just request what we need right now, and request any 9181da177e4SLinus Torvalds * other regions we need when setting up EQs. 9191da177e4SLinus Torvalds */ 9201da177e4SLinus Torvalds if (!request_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE, 9211da177e4SLinus Torvalds MTHCA_HCR_SIZE, DRV_NAME)) 9221da177e4SLinus Torvalds return -EBUSY; 9231da177e4SLinus Torvalds 9241da177e4SLinus Torvalds err = pci_request_region(pdev, 2, DRV_NAME); 9251da177e4SLinus Torvalds if (err) 9261da177e4SLinus Torvalds goto err_bar2_failed; 9271da177e4SLinus Torvalds 9281da177e4SLinus Torvalds if (!ddr_hidden) { 9291da177e4SLinus Torvalds err = pci_request_region(pdev, 4, DRV_NAME); 9301da177e4SLinus Torvalds if (err) 9311da177e4SLinus Torvalds goto err_bar4_failed; 9321da177e4SLinus Torvalds } 9331da177e4SLinus Torvalds 9341da177e4SLinus Torvalds return 0; 9351da177e4SLinus Torvalds 9361da177e4SLinus Torvalds err_bar4_failed: 9371da177e4SLinus Torvalds pci_release_region(pdev, 2); 9381da177e4SLinus Torvalds 9391da177e4SLinus Torvalds err_bar2_failed: 9401da177e4SLinus Torvalds release_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE, 9411da177e4SLinus Torvalds MTHCA_HCR_SIZE); 9421da177e4SLinus Torvalds 9431da177e4SLinus Torvalds return err; 9441da177e4SLinus Torvalds } 9451da177e4SLinus Torvalds 9461da177e4SLinus Torvalds static void mthca_release_regions(struct pci_dev *pdev, 9471da177e4SLinus Torvalds int ddr_hidden) 9481da177e4SLinus Torvalds { 9491da177e4SLinus Torvalds if (!ddr_hidden) 9501da177e4SLinus Torvalds pci_release_region(pdev, 4); 9511da177e4SLinus Torvalds 9521da177e4SLinus Torvalds pci_release_region(pdev, 2); 9531da177e4SLinus Torvalds 9541da177e4SLinus Torvalds release_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE, 9551da177e4SLinus Torvalds MTHCA_HCR_SIZE); 9561da177e4SLinus Torvalds } 9571da177e4SLinus Torvalds 958f4f3d0f0SRoland Dreier static int mthca_enable_msi_x(struct mthca_dev *mdev) 9591da177e4SLinus Torvalds { 9601da177e4SLinus Torvalds struct msix_entry entries[3]; 9611da177e4SLinus Torvalds int err; 9621da177e4SLinus Torvalds 9631da177e4SLinus Torvalds entries[0].entry = 0; 9641da177e4SLinus Torvalds entries[1].entry = 1; 9651da177e4SLinus Torvalds entries[2].entry = 2; 9661da177e4SLinus Torvalds 9671da177e4SLinus Torvalds err = pci_enable_msix(mdev->pdev, entries, ARRAY_SIZE(entries)); 9681da177e4SLinus Torvalds if (err) { 9691da177e4SLinus Torvalds if (err > 0) 9701da177e4SLinus Torvalds mthca_info(mdev, "Only %d MSI-X vectors available, " 9711da177e4SLinus Torvalds "not using MSI-X\n", err); 9721da177e4SLinus Torvalds return err; 9731da177e4SLinus Torvalds } 9741da177e4SLinus Torvalds 9751da177e4SLinus Torvalds mdev->eq_table.eq[MTHCA_EQ_COMP ].msi_x_vector = entries[0].vector; 9761da177e4SLinus Torvalds mdev->eq_table.eq[MTHCA_EQ_ASYNC].msi_x_vector = entries[1].vector; 9771da177e4SLinus Torvalds mdev->eq_table.eq[MTHCA_EQ_CMD ].msi_x_vector = entries[2].vector; 9781da177e4SLinus Torvalds 9791da177e4SLinus Torvalds return 0; 9801da177e4SLinus Torvalds } 9811da177e4SLinus Torvalds 98268a3c212SRoland Dreier /* Types of supported HCA */ 98368a3c212SRoland Dreier enum { 98468a3c212SRoland Dreier TAVOR, /* MT23108 */ 98568a3c212SRoland Dreier ARBEL_COMPAT, /* MT25208 in Tavor compat mode */ 98668a3c212SRoland Dreier ARBEL_NATIVE, /* MT25208 with extended features */ 98768a3c212SRoland Dreier SINAI /* MT25204 */ 98868a3c212SRoland Dreier }; 98968a3c212SRoland Dreier 99068a3c212SRoland Dreier #define MTHCA_FW_VER(major, minor, subminor) \ 99168a3c212SRoland Dreier (((u64) (major) << 32) | ((u64) (minor) << 16) | (u64) (subminor)) 99268a3c212SRoland Dreier 99368a3c212SRoland Dreier static struct { 99468a3c212SRoland Dreier u64 latest_fw; 995651eaac9SEli Cohen u32 flags; 99668a3c212SRoland Dreier } mthca_hca_table[] = { 9973f114853SRoland Dreier [TAVOR] = { .latest_fw = MTHCA_FW_VER(3, 5, 0), 998651eaac9SEli Cohen .flags = 0 }, 9993f114853SRoland Dreier [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 8, 200), 1000651eaac9SEli Cohen .flags = MTHCA_FLAG_PCIE }, 10013f114853SRoland Dreier [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 2, 0), 1002651eaac9SEli Cohen .flags = MTHCA_FLAG_MEMFREE | 1003651eaac9SEli Cohen MTHCA_FLAG_PCIE }, 10043f114853SRoland Dreier [SINAI] = { .latest_fw = MTHCA_FW_VER(1, 2, 0), 1005651eaac9SEli Cohen .flags = MTHCA_FLAG_MEMFREE | 1006651eaac9SEli Cohen MTHCA_FLAG_PCIE | 1007651eaac9SEli Cohen MTHCA_FLAG_SINAI_OPT } 100868a3c212SRoland Dreier }; 100968a3c212SRoland Dreier 1010b3b30f5eSJack Morgenstein static int __mthca_init_one(struct pci_dev *pdev, int hca_type) 10111da177e4SLinus Torvalds { 10121da177e4SLinus Torvalds int ddr_hidden = 0; 10131da177e4SLinus Torvalds int err; 10141da177e4SLinus Torvalds struct mthca_dev *mdev; 10151da177e4SLinus Torvalds 1016982245f0SAdrian Bunk printk(KERN_INFO PFX "Initializing %s\n", 1017982245f0SAdrian Bunk pci_name(pdev)); 10181da177e4SLinus Torvalds 10191da177e4SLinus Torvalds err = pci_enable_device(pdev); 10201da177e4SLinus Torvalds if (err) { 10211da177e4SLinus Torvalds dev_err(&pdev->dev, "Cannot enable PCI device, " 10221da177e4SLinus Torvalds "aborting.\n"); 10231da177e4SLinus Torvalds return err; 10241da177e4SLinus Torvalds } 10251da177e4SLinus Torvalds 10261da177e4SLinus Torvalds /* 10271da177e4SLinus Torvalds * Check for BARs. We expect 0: 1MB, 2: 8MB, 4: DDR (may not 10281da177e4SLinus Torvalds * be present) 10291da177e4SLinus Torvalds */ 10301da177e4SLinus Torvalds if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) || 10311da177e4SLinus Torvalds pci_resource_len(pdev, 0) != 1 << 20) { 1032177214afSBernhard Fischer dev_err(&pdev->dev, "Missing DCS, aborting.\n"); 10331da177e4SLinus Torvalds err = -ENODEV; 10341da177e4SLinus Torvalds goto err_disable_pdev; 10351da177e4SLinus Torvalds } 1036cbd2981aSMichael S. Tsirkin if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { 1037177214afSBernhard Fischer dev_err(&pdev->dev, "Missing UAR, aborting.\n"); 10381da177e4SLinus Torvalds err = -ENODEV; 10391da177e4SLinus Torvalds goto err_disable_pdev; 10401da177e4SLinus Torvalds } 10411da177e4SLinus Torvalds if (!(pci_resource_flags(pdev, 4) & IORESOURCE_MEM)) 10421da177e4SLinus Torvalds ddr_hidden = 1; 10431da177e4SLinus Torvalds 10441da177e4SLinus Torvalds err = mthca_request_regions(pdev, ddr_hidden); 10451da177e4SLinus Torvalds if (err) { 10461da177e4SLinus Torvalds dev_err(&pdev->dev, "Cannot obtain PCI resources, " 10471da177e4SLinus Torvalds "aborting.\n"); 10481da177e4SLinus Torvalds goto err_disable_pdev; 10491da177e4SLinus Torvalds } 10501da177e4SLinus Torvalds 10511da177e4SLinus Torvalds pci_set_master(pdev); 10521da177e4SLinus Torvalds 10531da177e4SLinus Torvalds err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); 10541da177e4SLinus Torvalds if (err) { 10551da177e4SLinus Torvalds dev_warn(&pdev->dev, "Warning: couldn't set 64-bit PCI DMA mask.\n"); 10561da177e4SLinus Torvalds err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); 10571da177e4SLinus Torvalds if (err) { 10581da177e4SLinus Torvalds dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting.\n"); 10591da177e4SLinus Torvalds goto err_free_res; 10601da177e4SLinus Torvalds } 10611da177e4SLinus Torvalds } 10621da177e4SLinus Torvalds err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); 10631da177e4SLinus Torvalds if (err) { 10641da177e4SLinus Torvalds dev_warn(&pdev->dev, "Warning: couldn't set 64-bit " 10651da177e4SLinus Torvalds "consistent PCI DMA mask.\n"); 10661da177e4SLinus Torvalds err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 10671da177e4SLinus Torvalds if (err) { 10681da177e4SLinus Torvalds dev_err(&pdev->dev, "Can't set consistent PCI DMA mask, " 10691da177e4SLinus Torvalds "aborting.\n"); 10701da177e4SLinus Torvalds goto err_free_res; 10711da177e4SLinus Torvalds } 10721da177e4SLinus Torvalds } 10731da177e4SLinus Torvalds 10741da177e4SLinus Torvalds mdev = (struct mthca_dev *) ib_alloc_device(sizeof *mdev); 10751da177e4SLinus Torvalds if (!mdev) { 10761da177e4SLinus Torvalds dev_err(&pdev->dev, "Device struct alloc failed, " 10771da177e4SLinus Torvalds "aborting.\n"); 10781da177e4SLinus Torvalds err = -ENOMEM; 10791da177e4SLinus Torvalds goto err_free_res; 10801da177e4SLinus Torvalds } 10811da177e4SLinus Torvalds 10821da177e4SLinus Torvalds mdev->pdev = pdev; 10831da177e4SLinus Torvalds 1084b3b30f5eSJack Morgenstein mdev->mthca_flags = mthca_hca_table[hca_type].flags; 10851da177e4SLinus Torvalds if (ddr_hidden) 10861da177e4SLinus Torvalds mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN; 10871da177e4SLinus Torvalds 10881da177e4SLinus Torvalds /* 10891da177e4SLinus Torvalds * Now reset the HCA before we touch the PCI capabilities or 10901da177e4SLinus Torvalds * attempt a firmware command, since a boot ROM may have left 10911da177e4SLinus Torvalds * the HCA in an undefined state. 10921da177e4SLinus Torvalds */ 10931da177e4SLinus Torvalds err = mthca_reset(mdev); 10941da177e4SLinus Torvalds if (err) { 10951da177e4SLinus Torvalds mthca_err(mdev, "Failed to reset HCA, aborting.\n"); 10961da177e4SLinus Torvalds goto err_free_dev; 10971da177e4SLinus Torvalds } 10981da177e4SLinus Torvalds 109980fd8238SRoland Dreier if (mthca_cmd_init(mdev)) { 110080fd8238SRoland Dreier mthca_err(mdev, "Failed to init command interface, aborting.\n"); 11011da177e4SLinus Torvalds goto err_free_dev; 11021da177e4SLinus Torvalds } 11031da177e4SLinus Torvalds 11041da177e4SLinus Torvalds err = mthca_tune_pci(mdev); 11051da177e4SLinus Torvalds if (err) 110680fd8238SRoland Dreier goto err_cmd; 11071da177e4SLinus Torvalds 11081da177e4SLinus Torvalds err = mthca_init_hca(mdev); 11091da177e4SLinus Torvalds if (err) 111080fd8238SRoland Dreier goto err_cmd; 11111da177e4SLinus Torvalds 1112b3b30f5eSJack Morgenstein if (mdev->fw_ver < mthca_hca_table[hca_type].latest_fw) { 1113e4daf738SRoland Dreier mthca_warn(mdev, "HCA FW version %d.%d.%03d is old (%d.%d.%03d is current).\n", 111468a3c212SRoland Dreier (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff, 111568a3c212SRoland Dreier (int) (mdev->fw_ver & 0xffff), 1116b3b30f5eSJack Morgenstein (int) (mthca_hca_table[hca_type].latest_fw >> 32), 1117b3b30f5eSJack Morgenstein (int) (mthca_hca_table[hca_type].latest_fw >> 16) & 0xffff, 1118b3b30f5eSJack Morgenstein (int) (mthca_hca_table[hca_type].latest_fw & 0xffff)); 111968a3c212SRoland Dreier mthca_warn(mdev, "If you have problems, try updating your HCA FW.\n"); 112068a3c212SRoland Dreier } 112168a3c212SRoland Dreier 1122017aadc4SMichael S. Tsirkin if (msi_x && !mthca_enable_msi_x(mdev)) 1123017aadc4SMichael S. Tsirkin mdev->mthca_flags |= MTHCA_FLAG_MSI_X; 1124017aadc4SMichael S. Tsirkin 11251da177e4SLinus Torvalds err = mthca_setup_hca(mdev); 1126e57895d3SAdrian Bunk if (err == -EBUSY && (mdev->mthca_flags & MTHCA_FLAG_MSI_X)) { 1127017aadc4SMichael S. Tsirkin if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) 1128017aadc4SMichael S. Tsirkin pci_disable_msix(pdev); 1129e57895d3SAdrian Bunk mdev->mthca_flags &= ~MTHCA_FLAG_MSI_X; 1130017aadc4SMichael S. Tsirkin 1131017aadc4SMichael S. Tsirkin err = mthca_setup_hca(mdev); 1132017aadc4SMichael S. Tsirkin } 1133017aadc4SMichael S. Tsirkin 11341da177e4SLinus Torvalds if (err) 11351da177e4SLinus Torvalds goto err_close; 11361da177e4SLinus Torvalds 11371da177e4SLinus Torvalds err = mthca_register_device(mdev); 11381da177e4SLinus Torvalds if (err) 11391da177e4SLinus Torvalds goto err_cleanup; 11401da177e4SLinus Torvalds 11411da177e4SLinus Torvalds err = mthca_create_agents(mdev); 11421da177e4SLinus Torvalds if (err) 11431da177e4SLinus Torvalds goto err_unregister; 11441da177e4SLinus Torvalds 11451da177e4SLinus Torvalds pci_set_drvdata(pdev, mdev); 1146b3b30f5eSJack Morgenstein mdev->hca_type = hca_type; 11471da177e4SLinus Torvalds 11481da177e4SLinus Torvalds return 0; 11491da177e4SLinus Torvalds 11501da177e4SLinus Torvalds err_unregister: 11511da177e4SLinus Torvalds mthca_unregister_device(mdev); 11521da177e4SLinus Torvalds 11531da177e4SLinus Torvalds err_cleanup: 11541da177e4SLinus Torvalds mthca_cleanup_mcg_table(mdev); 11551da177e4SLinus Torvalds mthca_cleanup_av_table(mdev); 11561da177e4SLinus Torvalds mthca_cleanup_qp_table(mdev); 1157ec34a922SRoland Dreier mthca_cleanup_srq_table(mdev); 11581da177e4SLinus Torvalds mthca_cleanup_cq_table(mdev); 11591da177e4SLinus Torvalds mthca_cmd_use_polling(mdev); 11601da177e4SLinus Torvalds mthca_cleanup_eq_table(mdev); 11611da177e4SLinus Torvalds 11621da177e4SLinus Torvalds mthca_pd_free(mdev, &mdev->driver_pd); 11631da177e4SLinus Torvalds 11641da177e4SLinus Torvalds mthca_cleanup_mr_table(mdev); 11651da177e4SLinus Torvalds mthca_cleanup_pd_table(mdev); 11661da177e4SLinus Torvalds mthca_cleanup_uar_table(mdev); 11671da177e4SLinus Torvalds 11681da177e4SLinus Torvalds err_close: 1169017aadc4SMichael S. Tsirkin if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) 1170017aadc4SMichael S. Tsirkin pci_disable_msix(pdev); 1171017aadc4SMichael S. Tsirkin 11721da177e4SLinus Torvalds mthca_close_hca(mdev); 11731da177e4SLinus Torvalds 117480fd8238SRoland Dreier err_cmd: 117580fd8238SRoland Dreier mthca_cmd_cleanup(mdev); 11761da177e4SLinus Torvalds 11771da177e4SLinus Torvalds err_free_dev: 11781da177e4SLinus Torvalds ib_dealloc_device(&mdev->ib_dev); 11791da177e4SLinus Torvalds 11801da177e4SLinus Torvalds err_free_res: 11811da177e4SLinus Torvalds mthca_release_regions(pdev, ddr_hidden); 11821da177e4SLinus Torvalds 11831da177e4SLinus Torvalds err_disable_pdev: 11841da177e4SLinus Torvalds pci_disable_device(pdev); 11851da177e4SLinus Torvalds pci_set_drvdata(pdev, NULL); 11861da177e4SLinus Torvalds return err; 11871da177e4SLinus Torvalds } 11881da177e4SLinus Torvalds 1189b3b30f5eSJack Morgenstein static void __mthca_remove_one(struct pci_dev *pdev) 11901da177e4SLinus Torvalds { 11911da177e4SLinus Torvalds struct mthca_dev *mdev = pci_get_drvdata(pdev); 11921da177e4SLinus Torvalds u8 status; 11931da177e4SLinus Torvalds int p; 11941da177e4SLinus Torvalds 11951da177e4SLinus Torvalds if (mdev) { 11961da177e4SLinus Torvalds mthca_free_agents(mdev); 11971da177e4SLinus Torvalds mthca_unregister_device(mdev); 11981da177e4SLinus Torvalds 11991da177e4SLinus Torvalds for (p = 1; p <= mdev->limits.num_ports; ++p) 12001da177e4SLinus Torvalds mthca_CLOSE_IB(mdev, p, &status); 12011da177e4SLinus Torvalds 12021da177e4SLinus Torvalds mthca_cleanup_mcg_table(mdev); 12031da177e4SLinus Torvalds mthca_cleanup_av_table(mdev); 12041da177e4SLinus Torvalds mthca_cleanup_qp_table(mdev); 1205ec34a922SRoland Dreier mthca_cleanup_srq_table(mdev); 12061da177e4SLinus Torvalds mthca_cleanup_cq_table(mdev); 12071da177e4SLinus Torvalds mthca_cmd_use_polling(mdev); 12081da177e4SLinus Torvalds mthca_cleanup_eq_table(mdev); 12091da177e4SLinus Torvalds 12101da177e4SLinus Torvalds mthca_pd_free(mdev, &mdev->driver_pd); 12111da177e4SLinus Torvalds 12121da177e4SLinus Torvalds mthca_cleanup_mr_table(mdev); 12131da177e4SLinus Torvalds mthca_cleanup_pd_table(mdev); 12141da177e4SLinus Torvalds 12151da177e4SLinus Torvalds iounmap(mdev->kar); 12161da177e4SLinus Torvalds mthca_uar_free(mdev, &mdev->driver_uar); 12171da177e4SLinus Torvalds mthca_cleanup_uar_table(mdev); 12181da177e4SLinus Torvalds mthca_close_hca(mdev); 121980fd8238SRoland Dreier mthca_cmd_cleanup(mdev); 12201da177e4SLinus Torvalds 12211da177e4SLinus Torvalds if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) 12221da177e4SLinus Torvalds pci_disable_msix(pdev); 12231da177e4SLinus Torvalds 12241da177e4SLinus Torvalds ib_dealloc_device(&mdev->ib_dev); 12251da177e4SLinus Torvalds mthca_release_regions(pdev, mdev->mthca_flags & 12261da177e4SLinus Torvalds MTHCA_FLAG_DDR_HIDDEN); 12271da177e4SLinus Torvalds pci_disable_device(pdev); 12281da177e4SLinus Torvalds pci_set_drvdata(pdev, NULL); 12291da177e4SLinus Torvalds } 12301da177e4SLinus Torvalds } 12311da177e4SLinus Torvalds 1232b3b30f5eSJack Morgenstein int __mthca_restart_one(struct pci_dev *pdev) 1233b3b30f5eSJack Morgenstein { 1234b3b30f5eSJack Morgenstein struct mthca_dev *mdev; 1235de57c9f1SAli Ayoub int hca_type; 1236b3b30f5eSJack Morgenstein 1237b3b30f5eSJack Morgenstein mdev = pci_get_drvdata(pdev); 1238b3b30f5eSJack Morgenstein if (!mdev) 1239b3b30f5eSJack Morgenstein return -ENODEV; 1240de57c9f1SAli Ayoub hca_type = mdev->hca_type; 1241b3b30f5eSJack Morgenstein __mthca_remove_one(pdev); 1242de57c9f1SAli Ayoub return __mthca_init_one(pdev, hca_type); 1243b3b30f5eSJack Morgenstein } 1244b3b30f5eSJack Morgenstein 1245b3b30f5eSJack Morgenstein static int __devinit mthca_init_one(struct pci_dev *pdev, 1246b3b30f5eSJack Morgenstein const struct pci_device_id *id) 1247b3b30f5eSJack Morgenstein { 1248b3b30f5eSJack Morgenstein static int mthca_version_printed = 0; 1249b3b30f5eSJack Morgenstein int ret; 1250b3b30f5eSJack Morgenstein 1251b3b30f5eSJack Morgenstein mutex_lock(&mthca_device_mutex); 1252b3b30f5eSJack Morgenstein 1253b3b30f5eSJack Morgenstein if (!mthca_version_printed) { 1254b3b30f5eSJack Morgenstein printk(KERN_INFO "%s", mthca_version); 1255b3b30f5eSJack Morgenstein ++mthca_version_printed; 1256b3b30f5eSJack Morgenstein } 1257b3b30f5eSJack Morgenstein 1258b3b30f5eSJack Morgenstein if (id->driver_data >= ARRAY_SIZE(mthca_hca_table)) { 1259b3b30f5eSJack Morgenstein printk(KERN_ERR PFX "%s has invalid driver data %lx\n", 1260b3b30f5eSJack Morgenstein pci_name(pdev), id->driver_data); 1261b3b30f5eSJack Morgenstein mutex_unlock(&mthca_device_mutex); 1262b3b30f5eSJack Morgenstein return -ENODEV; 1263b3b30f5eSJack Morgenstein } 1264b3b30f5eSJack Morgenstein 1265b3b30f5eSJack Morgenstein ret = __mthca_init_one(pdev, id->driver_data); 1266b3b30f5eSJack Morgenstein 1267b3b30f5eSJack Morgenstein mutex_unlock(&mthca_device_mutex); 1268b3b30f5eSJack Morgenstein 1269b3b30f5eSJack Morgenstein return ret; 1270b3b30f5eSJack Morgenstein } 1271b3b30f5eSJack Morgenstein 1272b3b30f5eSJack Morgenstein static void __devexit mthca_remove_one(struct pci_dev *pdev) 1273b3b30f5eSJack Morgenstein { 1274b3b30f5eSJack Morgenstein mutex_lock(&mthca_device_mutex); 1275b3b30f5eSJack Morgenstein __mthca_remove_one(pdev); 1276b3b30f5eSJack Morgenstein mutex_unlock(&mthca_device_mutex); 1277b3b30f5eSJack Morgenstein } 1278b3b30f5eSJack Morgenstein 12791da177e4SLinus Torvalds static struct pci_device_id mthca_pci_table[] = { 12801da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_TAVOR), 12811da177e4SLinus Torvalds .driver_data = TAVOR }, 12821da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_TAVOR), 12831da177e4SLinus Torvalds .driver_data = TAVOR }, 12841da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT), 12851da177e4SLinus Torvalds .driver_data = ARBEL_COMPAT }, 12861da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT), 12871da177e4SLinus Torvalds .driver_data = ARBEL_COMPAT }, 12881da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_ARBEL), 12891da177e4SLinus Torvalds .driver_data = ARBEL_NATIVE }, 12901da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_ARBEL), 12911da177e4SLinus Torvalds .driver_data = ARBEL_NATIVE }, 129268a3c212SRoland Dreier { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_SINAI), 129368a3c212SRoland Dreier .driver_data = SINAI }, 129468a3c212SRoland Dreier { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_SINAI), 129568a3c212SRoland Dreier .driver_data = SINAI }, 129668a3c212SRoland Dreier { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_SINAI_OLD), 129768a3c212SRoland Dreier .driver_data = SINAI }, 129868a3c212SRoland Dreier { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_SINAI_OLD), 129968a3c212SRoland Dreier .driver_data = SINAI }, 13001da177e4SLinus Torvalds { 0, } 13011da177e4SLinus Torvalds }; 13021da177e4SLinus Torvalds 13031da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, mthca_pci_table); 13041da177e4SLinus Torvalds 13051da177e4SLinus Torvalds static struct pci_driver mthca_driver = { 1306177214afSBernhard Fischer .name = DRV_NAME, 13071da177e4SLinus Torvalds .id_table = mthca_pci_table, 13081da177e4SLinus Torvalds .probe = mthca_init_one, 13091da177e4SLinus Torvalds .remove = __devexit_p(mthca_remove_one) 13101da177e4SLinus Torvalds }; 13111da177e4SLinus Torvalds 131282da703eSLeonid Arsh static void __init __mthca_check_profile_val(const char *name, int *pval, 131382da703eSLeonid Arsh int pval_default) 131482da703eSLeonid Arsh { 131582da703eSLeonid Arsh /* value must be positive and power of 2 */ 131682da703eSLeonid Arsh int old_pval = *pval; 131782da703eSLeonid Arsh 131882da703eSLeonid Arsh if (old_pval <= 0) 131982da703eSLeonid Arsh *pval = pval_default; 132082da703eSLeonid Arsh else 132182da703eSLeonid Arsh *pval = roundup_pow_of_two(old_pval); 132282da703eSLeonid Arsh 132382da703eSLeonid Arsh if (old_pval != *pval) { 132482da703eSLeonid Arsh printk(KERN_WARNING PFX "Invalid value %d for %s in module parameter.\n", 132582da703eSLeonid Arsh old_pval, name); 132682da703eSLeonid Arsh printk(KERN_WARNING PFX "Corrected %s to %d.\n", name, *pval); 132782da703eSLeonid Arsh } 132882da703eSLeonid Arsh } 132982da703eSLeonid Arsh 133082da703eSLeonid Arsh #define mthca_check_profile_val(name, default) \ 133182da703eSLeonid Arsh __mthca_check_profile_val(#name, &hca_profile.name, default) 133282da703eSLeonid Arsh 133382da703eSLeonid Arsh static void __init mthca_validate_profile(void) 133482da703eSLeonid Arsh { 133582da703eSLeonid Arsh mthca_check_profile_val(num_qp, MTHCA_DEFAULT_NUM_QP); 133682da703eSLeonid Arsh mthca_check_profile_val(rdb_per_qp, MTHCA_DEFAULT_RDB_PER_QP); 133782da703eSLeonid Arsh mthca_check_profile_val(num_cq, MTHCA_DEFAULT_NUM_CQ); 133882da703eSLeonid Arsh mthca_check_profile_val(num_mcg, MTHCA_DEFAULT_NUM_MCG); 133982da703eSLeonid Arsh mthca_check_profile_val(num_mpt, MTHCA_DEFAULT_NUM_MPT); 134082da703eSLeonid Arsh mthca_check_profile_val(num_mtt, MTHCA_DEFAULT_NUM_MTT); 134182da703eSLeonid Arsh mthca_check_profile_val(num_udav, MTHCA_DEFAULT_NUM_UDAV); 134282da703eSLeonid Arsh mthca_check_profile_val(fmr_reserved_mtts, MTHCA_DEFAULT_NUM_RESERVED_MTTS); 134382da703eSLeonid Arsh 134482da703eSLeonid Arsh if (hca_profile.fmr_reserved_mtts >= hca_profile.num_mtt) { 134582da703eSLeonid Arsh printk(KERN_WARNING PFX "Invalid fmr_reserved_mtts module parameter %d.\n", 134682da703eSLeonid Arsh hca_profile.fmr_reserved_mtts); 134782da703eSLeonid Arsh printk(KERN_WARNING PFX "(Must be smaller than num_mtt %d)\n", 134882da703eSLeonid Arsh hca_profile.num_mtt); 134982da703eSLeonid Arsh hca_profile.fmr_reserved_mtts = hca_profile.num_mtt / 2; 135082da703eSLeonid Arsh printk(KERN_WARNING PFX "Corrected fmr_reserved_mtts to %d.\n", 135182da703eSLeonid Arsh hca_profile.fmr_reserved_mtts); 135282da703eSLeonid Arsh } 135382da703eSLeonid Arsh } 135482da703eSLeonid Arsh 13551da177e4SLinus Torvalds static int __init mthca_init(void) 13561da177e4SLinus Torvalds { 13571da177e4SLinus Torvalds int ret; 13581da177e4SLinus Torvalds 135982da703eSLeonid Arsh mthca_validate_profile(); 136082da703eSLeonid Arsh 1361b3b30f5eSJack Morgenstein ret = mthca_catas_init(); 1362b3b30f5eSJack Morgenstein if (ret) 1363b3b30f5eSJack Morgenstein return ret; 1364b3b30f5eSJack Morgenstein 13651da177e4SLinus Torvalds ret = pci_register_driver(&mthca_driver); 1366b3b30f5eSJack Morgenstein if (ret < 0) { 1367b3b30f5eSJack Morgenstein mthca_catas_cleanup(); 1368b3b30f5eSJack Morgenstein return ret; 1369b3b30f5eSJack Morgenstein } 1370b3b30f5eSJack Morgenstein 1371b3b30f5eSJack Morgenstein return 0; 13721da177e4SLinus Torvalds } 13731da177e4SLinus Torvalds 13741da177e4SLinus Torvalds static void __exit mthca_cleanup(void) 13751da177e4SLinus Torvalds { 13761da177e4SLinus Torvalds pci_unregister_driver(&mthca_driver); 1377b3b30f5eSJack Morgenstein mthca_catas_cleanup(); 13781da177e4SLinus Torvalds } 13791da177e4SLinus Torvalds 13801da177e4SLinus Torvalds module_init(mthca_init); 13811da177e4SLinus Torvalds module_exit(mthca_cleanup); 1382