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 641da177e4SLinus Torvalds static int msi_x = 0; 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 static int msi = 0; 691da177e4SLinus Torvalds module_param(msi, int, 0444); 701da177e4SLinus Torvalds MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero"); 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds #else /* CONFIG_PCI_MSI */ 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds #define msi_x (0) 751da177e4SLinus Torvalds #define msi (0) 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds #endif /* CONFIG_PCI_MSI */ 781da177e4SLinus Torvalds 79abf45dbbSMichael S. Tsirkin static int tune_pci = 0; 80abf45dbbSMichael S. Tsirkin module_param(tune_pci, int, 0444); 81abf45dbbSMichael S. Tsirkin MODULE_PARM_DESC(tune_pci, "increase PCI burst from the default set by BIOS if nonzero"); 82abf45dbbSMichael S. Tsirkin 83b3b30f5eSJack Morgenstein struct mutex mthca_device_mutex; 84b3b30f5eSJack Morgenstein 8582da703eSLeonid Arsh #define MTHCA_DEFAULT_NUM_QP (1 << 16) 8682da703eSLeonid Arsh #define MTHCA_DEFAULT_RDB_PER_QP (1 << 2) 8782da703eSLeonid Arsh #define MTHCA_DEFAULT_NUM_CQ (1 << 16) 8882da703eSLeonid Arsh #define MTHCA_DEFAULT_NUM_MCG (1 << 13) 8982da703eSLeonid Arsh #define MTHCA_DEFAULT_NUM_MPT (1 << 17) 9082da703eSLeonid Arsh #define MTHCA_DEFAULT_NUM_MTT (1 << 20) 9182da703eSLeonid Arsh #define MTHCA_DEFAULT_NUM_UDAV (1 << 15) 9282da703eSLeonid Arsh #define MTHCA_DEFAULT_NUM_RESERVED_MTTS (1 << 18) 9382da703eSLeonid Arsh #define MTHCA_DEFAULT_NUM_UARC_SIZE (1 << 18) 9482da703eSLeonid Arsh 9582da703eSLeonid Arsh static struct mthca_profile hca_profile = { 9682da703eSLeonid Arsh .num_qp = MTHCA_DEFAULT_NUM_QP, 9782da703eSLeonid Arsh .rdb_per_qp = MTHCA_DEFAULT_RDB_PER_QP, 9882da703eSLeonid Arsh .num_cq = MTHCA_DEFAULT_NUM_CQ, 9982da703eSLeonid Arsh .num_mcg = MTHCA_DEFAULT_NUM_MCG, 10082da703eSLeonid Arsh .num_mpt = MTHCA_DEFAULT_NUM_MPT, 10182da703eSLeonid Arsh .num_mtt = MTHCA_DEFAULT_NUM_MTT, 10282da703eSLeonid Arsh .num_udav = MTHCA_DEFAULT_NUM_UDAV, /* Tavor only */ 10382da703eSLeonid Arsh .fmr_reserved_mtts = MTHCA_DEFAULT_NUM_RESERVED_MTTS, /* Tavor only */ 10482da703eSLeonid Arsh .uarc_size = MTHCA_DEFAULT_NUM_UARC_SIZE, /* Arbel only */ 10582da703eSLeonid Arsh }; 10682da703eSLeonid Arsh 10782da703eSLeonid Arsh module_param_named(num_qp, hca_profile.num_qp, int, 0444); 10882da703eSLeonid Arsh MODULE_PARM_DESC(num_qp, "maximum number of QPs per HCA"); 10982da703eSLeonid Arsh 11082da703eSLeonid Arsh module_param_named(rdb_per_qp, hca_profile.rdb_per_qp, int, 0444); 11182da703eSLeonid Arsh MODULE_PARM_DESC(rdb_per_qp, "number of RDB buffers per QP"); 11282da703eSLeonid Arsh 11382da703eSLeonid Arsh module_param_named(num_cq, hca_profile.num_cq, int, 0444); 11482da703eSLeonid Arsh MODULE_PARM_DESC(num_cq, "maximum number of CQs per HCA"); 11582da703eSLeonid Arsh 11682da703eSLeonid Arsh module_param_named(num_mcg, hca_profile.num_mcg, int, 0444); 11782da703eSLeonid Arsh MODULE_PARM_DESC(num_mcg, "maximum number of multicast groups per HCA"); 11882da703eSLeonid Arsh 11982da703eSLeonid Arsh module_param_named(num_mpt, hca_profile.num_mpt, int, 0444); 12082da703eSLeonid Arsh MODULE_PARM_DESC(num_mpt, 12182da703eSLeonid Arsh "maximum number of memory protection table entries per HCA"); 12282da703eSLeonid Arsh 12382da703eSLeonid Arsh module_param_named(num_mtt, hca_profile.num_mtt, int, 0444); 12482da703eSLeonid Arsh MODULE_PARM_DESC(num_mtt, 12582da703eSLeonid Arsh "maximum number of memory translation table segments per HCA"); 12682da703eSLeonid Arsh 12782da703eSLeonid Arsh module_param_named(num_udav, hca_profile.num_udav, int, 0444); 12882da703eSLeonid Arsh MODULE_PARM_DESC(num_udav, "maximum number of UD address vectors per HCA"); 12982da703eSLeonid Arsh 13082da703eSLeonid Arsh module_param_named(fmr_reserved_mtts, hca_profile.fmr_reserved_mtts, int, 0444); 13182da703eSLeonid Arsh MODULE_PARM_DESC(fmr_reserved_mtts, 13282da703eSLeonid Arsh "number of memory translation table segments reserved for FMR"); 13382da703eSLeonid Arsh 1341da177e4SLinus Torvalds static const char mthca_version[] __devinitdata = 135177214afSBernhard Fischer DRV_NAME ": Mellanox InfiniBand HCA driver v" 1361da177e4SLinus Torvalds DRV_VERSION " (" DRV_RELDATE ")\n"; 1371da177e4SLinus Torvalds 138f4f3d0f0SRoland Dreier static int mthca_tune_pci(struct mthca_dev *mdev) 1391da177e4SLinus Torvalds { 1401da177e4SLinus Torvalds int cap; 1411da177e4SLinus Torvalds u16 val; 1421da177e4SLinus Torvalds 143abf45dbbSMichael S. Tsirkin if (!tune_pci) 144abf45dbbSMichael S. Tsirkin return 0; 145abf45dbbSMichael S. Tsirkin 1461da177e4SLinus Torvalds /* First try to max out Read Byte Count */ 1471da177e4SLinus Torvalds cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX); 1481da177e4SLinus Torvalds if (cap) { 1491da177e4SLinus Torvalds if (pci_read_config_word(mdev->pdev, cap + PCI_X_CMD, &val)) { 1501da177e4SLinus Torvalds mthca_err(mdev, "Couldn't read PCI-X command register, " 1511da177e4SLinus Torvalds "aborting.\n"); 1521da177e4SLinus Torvalds return -ENODEV; 1531da177e4SLinus Torvalds } 1541da177e4SLinus Torvalds val = (val & ~PCI_X_CMD_MAX_READ) | (3 << 2); 1551da177e4SLinus Torvalds if (pci_write_config_word(mdev->pdev, cap + PCI_X_CMD, val)) { 1561da177e4SLinus Torvalds mthca_err(mdev, "Couldn't write PCI-X command register, " 1571da177e4SLinus Torvalds "aborting.\n"); 1581da177e4SLinus Torvalds return -ENODEV; 1591da177e4SLinus Torvalds } 16068a3c212SRoland Dreier } else if (!(mdev->mthca_flags & MTHCA_FLAG_PCIE)) 1611da177e4SLinus Torvalds mthca_info(mdev, "No PCI-X capability, not setting RBC.\n"); 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP); 1641da177e4SLinus Torvalds if (cap) { 1651da177e4SLinus Torvalds if (pci_read_config_word(mdev->pdev, cap + PCI_EXP_DEVCTL, &val)) { 1661da177e4SLinus Torvalds mthca_err(mdev, "Couldn't read PCI Express device control " 1671da177e4SLinus Torvalds "register, aborting.\n"); 1681da177e4SLinus Torvalds return -ENODEV; 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds val = (val & ~PCI_EXP_DEVCTL_READRQ) | (5 << 12); 1711da177e4SLinus Torvalds if (pci_write_config_word(mdev->pdev, cap + PCI_EXP_DEVCTL, val)) { 1721da177e4SLinus Torvalds mthca_err(mdev, "Couldn't write PCI Express device control " 1731da177e4SLinus Torvalds "register, aborting.\n"); 1741da177e4SLinus Torvalds return -ENODEV; 1751da177e4SLinus Torvalds } 17668a3c212SRoland Dreier } else if (mdev->mthca_flags & MTHCA_FLAG_PCIE) 1771da177e4SLinus Torvalds mthca_info(mdev, "No PCI Express capability, " 1781da177e4SLinus Torvalds "not setting Max Read Request Size.\n"); 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds return 0; 1811da177e4SLinus Torvalds } 1821da177e4SLinus Torvalds 183f4f3d0f0SRoland Dreier static int mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim *dev_lim) 1841da177e4SLinus Torvalds { 1851da177e4SLinus Torvalds int err; 1861da177e4SLinus Torvalds u8 status; 1871da177e4SLinus Torvalds 1881da177e4SLinus Torvalds err = mthca_QUERY_DEV_LIM(mdev, dev_lim, &status); 1891da177e4SLinus Torvalds if (err) { 1901da177e4SLinus Torvalds mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n"); 1911da177e4SLinus Torvalds return err; 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds if (status) { 1941da177e4SLinus Torvalds mthca_err(mdev, "QUERY_DEV_LIM returned status 0x%02x, " 1951da177e4SLinus Torvalds "aborting.\n", status); 1961da177e4SLinus Torvalds return -EINVAL; 1971da177e4SLinus Torvalds } 1981da177e4SLinus Torvalds if (dev_lim->min_page_sz > PAGE_SIZE) { 1991da177e4SLinus Torvalds mthca_err(mdev, "HCA minimum page size of %d bigger than " 2001da177e4SLinus Torvalds "kernel PAGE_SIZE of %ld, aborting.\n", 2011da177e4SLinus Torvalds dev_lim->min_page_sz, PAGE_SIZE); 2021da177e4SLinus Torvalds return -ENODEV; 2031da177e4SLinus Torvalds } 2041da177e4SLinus Torvalds if (dev_lim->num_ports > MTHCA_MAX_PORTS) { 2051da177e4SLinus Torvalds mthca_err(mdev, "HCA has %d ports, but we only support %d, " 2061da177e4SLinus Torvalds "aborting.\n", 2071da177e4SLinus Torvalds dev_lim->num_ports, MTHCA_MAX_PORTS); 2081da177e4SLinus Torvalds return -ENODEV; 2091da177e4SLinus Torvalds } 2101da177e4SLinus Torvalds 211cbd2981aSMichael S. Tsirkin if (dev_lim->uar_size > pci_resource_len(mdev->pdev, 2)) { 212cbd2981aSMichael S. Tsirkin mthca_err(mdev, "HCA reported UAR size of 0x%x bigger than " 213e29419ffSGreg Kroah-Hartman "PCI resource 2 size of 0x%llx, aborting.\n", 214e29419ffSGreg Kroah-Hartman dev_lim->uar_size, 215e29419ffSGreg Kroah-Hartman (unsigned long long)pci_resource_len(mdev->pdev, 2)); 216cbd2981aSMichael S. Tsirkin return -ENODEV; 217cbd2981aSMichael S. Tsirkin } 218cbd2981aSMichael S. Tsirkin 2191da177e4SLinus Torvalds mdev->limits.num_ports = dev_lim->num_ports; 2201da177e4SLinus Torvalds mdev->limits.vl_cap = dev_lim->max_vl; 2211da177e4SLinus Torvalds mdev->limits.mtu_cap = dev_lim->max_mtu; 2221da177e4SLinus Torvalds mdev->limits.gid_table_len = dev_lim->max_gids; 2231da177e4SLinus Torvalds mdev->limits.pkey_table_len = dev_lim->max_pkeys; 2241da177e4SLinus Torvalds mdev->limits.local_ca_ack_delay = dev_lim->local_ca_ack_delay; 2251da177e4SLinus Torvalds mdev->limits.max_sg = dev_lim->max_sg; 226efaae8f7SJack Morgenstein mdev->limits.max_wqes = dev_lim->max_qp_sz; 227efaae8f7SJack Morgenstein mdev->limits.max_qp_init_rdma = dev_lim->max_requester_per_qp; 2281da177e4SLinus Torvalds mdev->limits.reserved_qps = dev_lim->reserved_qps; 229efaae8f7SJack Morgenstein mdev->limits.max_srq_wqes = dev_lim->max_srq_sz; 2301da177e4SLinus Torvalds mdev->limits.reserved_srqs = dev_lim->reserved_srqs; 2311da177e4SLinus Torvalds mdev->limits.reserved_eecs = dev_lim->reserved_eecs; 23277369ed3SJack Morgenstein mdev->limits.max_desc_sz = dev_lim->max_desc_sz; 23359fef3b1SJack Morgenstein mdev->limits.max_srq_sge = mthca_max_srq_sge(mdev); 234efaae8f7SJack Morgenstein /* 235efaae8f7SJack Morgenstein * Subtract 1 from the limit because we need to allocate a 236efaae8f7SJack Morgenstein * spare CQE so the HCA HW can tell the difference between an 237efaae8f7SJack Morgenstein * empty CQ and a full CQ. 238efaae8f7SJack Morgenstein */ 239efaae8f7SJack Morgenstein mdev->limits.max_cqes = dev_lim->max_cq_sz - 1; 2401da177e4SLinus Torvalds mdev->limits.reserved_cqs = dev_lim->reserved_cqs; 2411da177e4SLinus Torvalds mdev->limits.reserved_eqs = dev_lim->reserved_eqs; 2421da177e4SLinus Torvalds mdev->limits.reserved_mtts = dev_lim->reserved_mtts; 2431da177e4SLinus Torvalds mdev->limits.reserved_mrws = dev_lim->reserved_mrws; 2441da177e4SLinus Torvalds mdev->limits.reserved_uars = dev_lim->reserved_uars; 2451da177e4SLinus Torvalds mdev->limits.reserved_pds = dev_lim->reserved_pds; 246da6561c2SRoland Dreier mdev->limits.port_width_cap = dev_lim->max_port_width; 2470f69ce1eSJack Morgenstein mdev->limits.page_size_cap = ~(u32) (dev_lim->min_page_sz - 1); 24833033b79SJack Morgenstein mdev->limits.flags = dev_lim->flags; 249bf6a9e31SJack Morgenstein /* 250bf6a9e31SJack Morgenstein * For old FW that doesn't return static rate support, use a 251bf6a9e31SJack Morgenstein * value of 0x3 (only static rate values of 0 or 1 are handled), 252bf6a9e31SJack Morgenstein * except on Sinai, where even old FW can handle static rate 253bf6a9e31SJack Morgenstein * values of 2 and 3. 254bf6a9e31SJack Morgenstein */ 255bf6a9e31SJack Morgenstein if (dev_lim->stat_rate_support) 256bf6a9e31SJack Morgenstein mdev->limits.stat_rate_support = dev_lim->stat_rate_support; 257bf6a9e31SJack Morgenstein else if (mdev->mthca_flags & MTHCA_FLAG_SINAI_OPT) 258bf6a9e31SJack Morgenstein mdev->limits.stat_rate_support = 0xf; 259bf6a9e31SJack Morgenstein else 260bf6a9e31SJack Morgenstein mdev->limits.stat_rate_support = 0x3; 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds /* IB_DEVICE_RESIZE_MAX_WR not supported by driver. 2631da177e4SLinus Torvalds May be doable since hardware supports it for SRQ. 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds IB_DEVICE_N_NOTIFY_CQ is supported by hardware but not by driver. 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds IB_DEVICE_SRQ_RESIZE is supported by hardware but SRQ is not 2681da177e4SLinus Torvalds supported by driver. */ 2691da177e4SLinus Torvalds mdev->device_cap_flags = IB_DEVICE_CHANGE_PHY_PORT | 2701da177e4SLinus Torvalds IB_DEVICE_PORT_ACTIVE_EVENT | 2711da177e4SLinus Torvalds IB_DEVICE_SYS_IMAGE_GUID | 2721da177e4SLinus Torvalds IB_DEVICE_RC_RNR_NAK_GEN; 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds if (dev_lim->flags & DEV_LIM_FLAG_BAD_PKEY_CNTR) 2751da177e4SLinus Torvalds mdev->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR; 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds if (dev_lim->flags & DEV_LIM_FLAG_BAD_QKEY_CNTR) 2781da177e4SLinus Torvalds mdev->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR; 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds if (dev_lim->flags & DEV_LIM_FLAG_RAW_MULTI) 2811da177e4SLinus Torvalds mdev->device_cap_flags |= IB_DEVICE_RAW_MULTI; 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds if (dev_lim->flags & DEV_LIM_FLAG_AUTO_PATH_MIG) 2841da177e4SLinus Torvalds mdev->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG; 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds if (dev_lim->flags & DEV_LIM_FLAG_UD_AV_PORT_ENFORCE) 2871da177e4SLinus Torvalds mdev->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE; 2881da177e4SLinus Torvalds 2891da177e4SLinus Torvalds if (dev_lim->flags & DEV_LIM_FLAG_SRQ) 2901da177e4SLinus Torvalds mdev->mthca_flags |= MTHCA_FLAG_SRQ; 2911da177e4SLinus Torvalds 2921da177e4SLinus Torvalds return 0; 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds 295f4f3d0f0SRoland Dreier static int mthca_init_tavor(struct mthca_dev *mdev) 2961da177e4SLinus Torvalds { 2971da177e4SLinus Torvalds u8 status; 2981da177e4SLinus Torvalds int err; 2991da177e4SLinus Torvalds struct mthca_dev_lim dev_lim; 3001da177e4SLinus Torvalds struct mthca_profile profile; 3011da177e4SLinus Torvalds struct mthca_init_hca_param init_hca; 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds err = mthca_SYS_EN(mdev, &status); 3041da177e4SLinus Torvalds if (err) { 3051da177e4SLinus Torvalds mthca_err(mdev, "SYS_EN command failed, aborting.\n"); 3061da177e4SLinus Torvalds return err; 3071da177e4SLinus Torvalds } 3081da177e4SLinus Torvalds if (status) { 3091da177e4SLinus Torvalds mthca_err(mdev, "SYS_EN returned status 0x%02x, " 3101da177e4SLinus Torvalds "aborting.\n", status); 3111da177e4SLinus Torvalds return -EINVAL; 3121da177e4SLinus Torvalds } 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds err = mthca_QUERY_FW(mdev, &status); 3151da177e4SLinus Torvalds if (err) { 3161da177e4SLinus Torvalds mthca_err(mdev, "QUERY_FW command failed, aborting.\n"); 3171da177e4SLinus Torvalds goto err_disable; 3181da177e4SLinus Torvalds } 3191da177e4SLinus Torvalds if (status) { 3201da177e4SLinus Torvalds mthca_err(mdev, "QUERY_FW returned status 0x%02x, " 3211da177e4SLinus Torvalds "aborting.\n", status); 3221da177e4SLinus Torvalds err = -EINVAL; 3231da177e4SLinus Torvalds goto err_disable; 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds err = mthca_QUERY_DDR(mdev, &status); 3261da177e4SLinus Torvalds if (err) { 3271da177e4SLinus Torvalds mthca_err(mdev, "QUERY_DDR command failed, aborting.\n"); 3281da177e4SLinus Torvalds goto err_disable; 3291da177e4SLinus Torvalds } 3301da177e4SLinus Torvalds if (status) { 3311da177e4SLinus Torvalds mthca_err(mdev, "QUERY_DDR returned status 0x%02x, " 3321da177e4SLinus Torvalds "aborting.\n", status); 3331da177e4SLinus Torvalds err = -EINVAL; 3341da177e4SLinus Torvalds goto err_disable; 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds err = mthca_dev_lim(mdev, &dev_lim); 338aa2f9367SJack Morgenstein if (err) { 339aa2f9367SJack Morgenstein mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n"); 340aa2f9367SJack Morgenstein goto err_disable; 341aa2f9367SJack Morgenstein } 3421da177e4SLinus Torvalds 34382da703eSLeonid Arsh profile = hca_profile; 3441da177e4SLinus Torvalds profile.num_uar = dev_lim.uar_size / PAGE_SIZE; 3451da177e4SLinus Torvalds profile.uarc_size = 0; 346ec34a922SRoland Dreier if (mdev->mthca_flags & MTHCA_FLAG_SRQ) 347ec34a922SRoland Dreier profile.num_srq = dev_lim.max_srqs; 3481da177e4SLinus Torvalds 3491da177e4SLinus Torvalds err = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca); 3501da177e4SLinus Torvalds if (err < 0) 3511da177e4SLinus Torvalds goto err_disable; 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds err = mthca_INIT_HCA(mdev, &init_hca, &status); 3541da177e4SLinus Torvalds if (err) { 3551da177e4SLinus Torvalds mthca_err(mdev, "INIT_HCA command failed, aborting.\n"); 3561da177e4SLinus Torvalds goto err_disable; 3571da177e4SLinus Torvalds } 3581da177e4SLinus Torvalds if (status) { 3591da177e4SLinus Torvalds mthca_err(mdev, "INIT_HCA returned status 0x%02x, " 3601da177e4SLinus Torvalds "aborting.\n", status); 3611da177e4SLinus Torvalds err = -EINVAL; 3621da177e4SLinus Torvalds goto err_disable; 3631da177e4SLinus Torvalds } 3641da177e4SLinus Torvalds 3651da177e4SLinus Torvalds return 0; 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds err_disable: 3681da177e4SLinus Torvalds mthca_SYS_DIS(mdev, &status); 3691da177e4SLinus Torvalds 3701da177e4SLinus Torvalds return err; 3711da177e4SLinus Torvalds } 3721da177e4SLinus Torvalds 373f4f3d0f0SRoland Dreier static int mthca_load_fw(struct mthca_dev *mdev) 3741da177e4SLinus Torvalds { 3751da177e4SLinus Torvalds u8 status; 3761da177e4SLinus Torvalds int err; 3771da177e4SLinus Torvalds 3781da177e4SLinus Torvalds /* FIXME: use HCA-attached memory for FW if present */ 3791da177e4SLinus Torvalds 3801da177e4SLinus Torvalds mdev->fw.arbel.fw_icm = 3811da177e4SLinus Torvalds mthca_alloc_icm(mdev, mdev->fw.arbel.fw_pages, 3821da177e4SLinus Torvalds GFP_HIGHUSER | __GFP_NOWARN); 3831da177e4SLinus Torvalds if (!mdev->fw.arbel.fw_icm) { 3841da177e4SLinus Torvalds mthca_err(mdev, "Couldn't allocate FW area, aborting.\n"); 3851da177e4SLinus Torvalds return -ENOMEM; 3861da177e4SLinus Torvalds } 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds err = mthca_MAP_FA(mdev, mdev->fw.arbel.fw_icm, &status); 3891da177e4SLinus Torvalds if (err) { 3901da177e4SLinus Torvalds mthca_err(mdev, "MAP_FA command failed, aborting.\n"); 3911da177e4SLinus Torvalds goto err_free; 3921da177e4SLinus Torvalds } 3931da177e4SLinus Torvalds if (status) { 3941da177e4SLinus Torvalds mthca_err(mdev, "MAP_FA returned status 0x%02x, aborting.\n", status); 3951da177e4SLinus Torvalds err = -EINVAL; 3961da177e4SLinus Torvalds goto err_free; 3971da177e4SLinus Torvalds } 3981da177e4SLinus Torvalds err = mthca_RUN_FW(mdev, &status); 3991da177e4SLinus Torvalds if (err) { 4001da177e4SLinus Torvalds mthca_err(mdev, "RUN_FW command failed, aborting.\n"); 4011da177e4SLinus Torvalds goto err_unmap_fa; 4021da177e4SLinus Torvalds } 4031da177e4SLinus Torvalds if (status) { 4041da177e4SLinus Torvalds mthca_err(mdev, "RUN_FW returned status 0x%02x, aborting.\n", status); 4051da177e4SLinus Torvalds err = -EINVAL; 4061da177e4SLinus Torvalds goto err_unmap_fa; 4071da177e4SLinus Torvalds } 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds return 0; 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds err_unmap_fa: 4121da177e4SLinus Torvalds mthca_UNMAP_FA(mdev, &status); 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds err_free: 4151da177e4SLinus Torvalds mthca_free_icm(mdev, mdev->fw.arbel.fw_icm); 4161da177e4SLinus Torvalds return err; 4171da177e4SLinus Torvalds } 4181da177e4SLinus Torvalds 419f4f3d0f0SRoland Dreier static int mthca_init_icm(struct mthca_dev *mdev, 4201da177e4SLinus Torvalds struct mthca_dev_lim *dev_lim, 4211da177e4SLinus Torvalds struct mthca_init_hca_param *init_hca, 4221da177e4SLinus Torvalds u64 icm_size) 4231da177e4SLinus Torvalds { 4241da177e4SLinus Torvalds u64 aux_pages; 4251da177e4SLinus Torvalds u8 status; 4261da177e4SLinus Torvalds int err; 4271da177e4SLinus Torvalds 4281da177e4SLinus Torvalds err = mthca_SET_ICM_SIZE(mdev, icm_size, &aux_pages, &status); 4291da177e4SLinus Torvalds if (err) { 4301da177e4SLinus Torvalds mthca_err(mdev, "SET_ICM_SIZE command failed, aborting.\n"); 4311da177e4SLinus Torvalds return err; 4321da177e4SLinus Torvalds } 4331da177e4SLinus Torvalds if (status) { 4341da177e4SLinus Torvalds mthca_err(mdev, "SET_ICM_SIZE returned status 0x%02x, " 4351da177e4SLinus Torvalds "aborting.\n", status); 4361da177e4SLinus Torvalds return -EINVAL; 4371da177e4SLinus Torvalds } 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds mthca_dbg(mdev, "%lld KB of HCA context requires %lld KB aux memory.\n", 4401da177e4SLinus Torvalds (unsigned long long) icm_size >> 10, 4411da177e4SLinus Torvalds (unsigned long long) aux_pages << 2); 4421da177e4SLinus Torvalds 4431da177e4SLinus Torvalds mdev->fw.arbel.aux_icm = mthca_alloc_icm(mdev, aux_pages, 4441da177e4SLinus Torvalds GFP_HIGHUSER | __GFP_NOWARN); 4451da177e4SLinus Torvalds if (!mdev->fw.arbel.aux_icm) { 4461da177e4SLinus Torvalds mthca_err(mdev, "Couldn't allocate aux memory, aborting.\n"); 4471da177e4SLinus Torvalds return -ENOMEM; 4481da177e4SLinus Torvalds } 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds err = mthca_MAP_ICM_AUX(mdev, mdev->fw.arbel.aux_icm, &status); 4511da177e4SLinus Torvalds if (err) { 4521da177e4SLinus Torvalds mthca_err(mdev, "MAP_ICM_AUX command failed, aborting.\n"); 4531da177e4SLinus Torvalds goto err_free_aux; 4541da177e4SLinus Torvalds } 4551da177e4SLinus Torvalds if (status) { 4561da177e4SLinus Torvalds mthca_err(mdev, "MAP_ICM_AUX returned status 0x%02x, aborting.\n", status); 4571da177e4SLinus Torvalds err = -EINVAL; 4581da177e4SLinus Torvalds goto err_free_aux; 4591da177e4SLinus Torvalds } 4601da177e4SLinus Torvalds 4611da177e4SLinus Torvalds err = mthca_map_eq_icm(mdev, init_hca->eqc_base); 4621da177e4SLinus Torvalds if (err) { 4631da177e4SLinus Torvalds mthca_err(mdev, "Failed to map EQ context memory, aborting.\n"); 4641da177e4SLinus Torvalds goto err_unmap_aux; 4651da177e4SLinus Torvalds } 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds mdev->mr_table.mtt_table = mthca_alloc_icm_table(mdev, init_hca->mtt_base, 46844ea6687SRoland Dreier MTHCA_MTT_SEG_SIZE, 4691da177e4SLinus Torvalds mdev->limits.num_mtt_segs, 4701da177e4SLinus Torvalds mdev->limits.reserved_mtts, 1); 4711da177e4SLinus Torvalds if (!mdev->mr_table.mtt_table) { 4721da177e4SLinus Torvalds mthca_err(mdev, "Failed to map MTT context memory, aborting.\n"); 4731da177e4SLinus Torvalds err = -ENOMEM; 4741da177e4SLinus Torvalds goto err_unmap_eq; 4751da177e4SLinus Torvalds } 4761da177e4SLinus Torvalds 4771da177e4SLinus Torvalds mdev->mr_table.mpt_table = mthca_alloc_icm_table(mdev, init_hca->mpt_base, 4781da177e4SLinus Torvalds dev_lim->mpt_entry_sz, 4791da177e4SLinus Torvalds mdev->limits.num_mpts, 4801da177e4SLinus Torvalds mdev->limits.reserved_mrws, 1); 4811da177e4SLinus Torvalds if (!mdev->mr_table.mpt_table) { 4821da177e4SLinus Torvalds mthca_err(mdev, "Failed to map MPT context memory, aborting.\n"); 4831da177e4SLinus Torvalds err = -ENOMEM; 4841da177e4SLinus Torvalds goto err_unmap_mtt; 4851da177e4SLinus Torvalds } 4861da177e4SLinus Torvalds 4871da177e4SLinus Torvalds mdev->qp_table.qp_table = mthca_alloc_icm_table(mdev, init_hca->qpc_base, 4881da177e4SLinus Torvalds dev_lim->qpc_entry_sz, 4891da177e4SLinus Torvalds mdev->limits.num_qps, 4901da177e4SLinus Torvalds mdev->limits.reserved_qps, 0); 4911da177e4SLinus Torvalds if (!mdev->qp_table.qp_table) { 4921da177e4SLinus Torvalds mthca_err(mdev, "Failed to map QP context memory, aborting.\n"); 4931da177e4SLinus Torvalds err = -ENOMEM; 4941da177e4SLinus Torvalds goto err_unmap_mpt; 4951da177e4SLinus Torvalds } 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds mdev->qp_table.eqp_table = mthca_alloc_icm_table(mdev, init_hca->eqpc_base, 4981da177e4SLinus Torvalds dev_lim->eqpc_entry_sz, 4991da177e4SLinus Torvalds mdev->limits.num_qps, 5001da177e4SLinus Torvalds mdev->limits.reserved_qps, 0); 5011da177e4SLinus Torvalds if (!mdev->qp_table.eqp_table) { 5021da177e4SLinus Torvalds mthca_err(mdev, "Failed to map EQP context memory, aborting.\n"); 5031da177e4SLinus Torvalds err = -ENOMEM; 5041da177e4SLinus Torvalds goto err_unmap_qp; 5051da177e4SLinus Torvalds } 5061da177e4SLinus Torvalds 50708aeb14eSRoland Dreier mdev->qp_table.rdb_table = mthca_alloc_icm_table(mdev, init_hca->rdb_base, 50808aeb14eSRoland Dreier MTHCA_RDB_ENTRY_SIZE, 50908aeb14eSRoland Dreier mdev->limits.num_qps << 51008aeb14eSRoland Dreier mdev->qp_table.rdb_shift, 51108aeb14eSRoland Dreier 0, 0); 51208aeb14eSRoland Dreier if (!mdev->qp_table.rdb_table) { 51308aeb14eSRoland Dreier mthca_err(mdev, "Failed to map RDB context memory, aborting\n"); 51408aeb14eSRoland Dreier err = -ENOMEM; 51519272d43SRoland Dreier goto err_unmap_eqp; 51608aeb14eSRoland Dreier } 51708aeb14eSRoland Dreier 5181da177e4SLinus Torvalds mdev->cq_table.table = mthca_alloc_icm_table(mdev, init_hca->cqc_base, 5191da177e4SLinus Torvalds dev_lim->cqc_entry_sz, 5201da177e4SLinus Torvalds mdev->limits.num_cqs, 5211da177e4SLinus Torvalds mdev->limits.reserved_cqs, 0); 5221da177e4SLinus Torvalds if (!mdev->cq_table.table) { 5231da177e4SLinus Torvalds mthca_err(mdev, "Failed to map CQ context memory, aborting.\n"); 5241da177e4SLinus Torvalds err = -ENOMEM; 52508aeb14eSRoland Dreier goto err_unmap_rdb; 5261da177e4SLinus Torvalds } 5271da177e4SLinus Torvalds 528ec34a922SRoland Dreier if (mdev->mthca_flags & MTHCA_FLAG_SRQ) { 529ec34a922SRoland Dreier mdev->srq_table.table = 530ec34a922SRoland Dreier mthca_alloc_icm_table(mdev, init_hca->srqc_base, 531ec34a922SRoland Dreier dev_lim->srq_entry_sz, 532ec34a922SRoland Dreier mdev->limits.num_srqs, 533ec34a922SRoland Dreier mdev->limits.reserved_srqs, 0); 534ec34a922SRoland Dreier if (!mdev->srq_table.table) { 535ec34a922SRoland Dreier mthca_err(mdev, "Failed to map SRQ context memory, " 536ec34a922SRoland Dreier "aborting.\n"); 537ec34a922SRoland Dreier err = -ENOMEM; 538ec34a922SRoland Dreier goto err_unmap_cq; 539ec34a922SRoland Dreier } 540ec34a922SRoland Dreier } 541ec34a922SRoland Dreier 5421da177e4SLinus Torvalds /* 5431da177e4SLinus Torvalds * It's not strictly required, but for simplicity just map the 5441da177e4SLinus Torvalds * whole multicast group table now. The table isn't very big 5451da177e4SLinus Torvalds * and it's a lot easier than trying to track ref counts. 5461da177e4SLinus Torvalds */ 5471da177e4SLinus Torvalds mdev->mcg_table.table = mthca_alloc_icm_table(mdev, init_hca->mc_base, 5481da177e4SLinus Torvalds MTHCA_MGM_ENTRY_SIZE, 5491da177e4SLinus Torvalds mdev->limits.num_mgms + 5501da177e4SLinus Torvalds mdev->limits.num_amgms, 5511da177e4SLinus Torvalds mdev->limits.num_mgms + 5521da177e4SLinus Torvalds mdev->limits.num_amgms, 5531da177e4SLinus Torvalds 0); 5541da177e4SLinus Torvalds if (!mdev->mcg_table.table) { 5551da177e4SLinus Torvalds mthca_err(mdev, "Failed to map MCG context memory, aborting.\n"); 5561da177e4SLinus Torvalds err = -ENOMEM; 557ec34a922SRoland Dreier goto err_unmap_srq; 5581da177e4SLinus Torvalds } 5591da177e4SLinus Torvalds 5601da177e4SLinus Torvalds return 0; 5611da177e4SLinus Torvalds 562ec34a922SRoland Dreier err_unmap_srq: 563ec34a922SRoland Dreier if (mdev->mthca_flags & MTHCA_FLAG_SRQ) 564ec34a922SRoland Dreier mthca_free_icm_table(mdev, mdev->srq_table.table); 565ec34a922SRoland Dreier 5661da177e4SLinus Torvalds err_unmap_cq: 5671da177e4SLinus Torvalds mthca_free_icm_table(mdev, mdev->cq_table.table); 5681da177e4SLinus Torvalds 56908aeb14eSRoland Dreier err_unmap_rdb: 57008aeb14eSRoland Dreier mthca_free_icm_table(mdev, mdev->qp_table.rdb_table); 57108aeb14eSRoland Dreier 5721da177e4SLinus Torvalds err_unmap_eqp: 5731da177e4SLinus Torvalds mthca_free_icm_table(mdev, mdev->qp_table.eqp_table); 5741da177e4SLinus Torvalds 5751da177e4SLinus Torvalds err_unmap_qp: 5761da177e4SLinus Torvalds mthca_free_icm_table(mdev, mdev->qp_table.qp_table); 5771da177e4SLinus Torvalds 5781da177e4SLinus Torvalds err_unmap_mpt: 5791da177e4SLinus Torvalds mthca_free_icm_table(mdev, mdev->mr_table.mpt_table); 5801da177e4SLinus Torvalds 5811da177e4SLinus Torvalds err_unmap_mtt: 5821da177e4SLinus Torvalds mthca_free_icm_table(mdev, mdev->mr_table.mtt_table); 5831da177e4SLinus Torvalds 5841da177e4SLinus Torvalds err_unmap_eq: 5851da177e4SLinus Torvalds mthca_unmap_eq_icm(mdev); 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds err_unmap_aux: 5881da177e4SLinus Torvalds mthca_UNMAP_ICM_AUX(mdev, &status); 5891da177e4SLinus Torvalds 5901da177e4SLinus Torvalds err_free_aux: 5911da177e4SLinus Torvalds mthca_free_icm(mdev, mdev->fw.arbel.aux_icm); 5921da177e4SLinus Torvalds 5931da177e4SLinus Torvalds return err; 5941da177e4SLinus Torvalds } 5951da177e4SLinus Torvalds 596aba7a22fSMichael S. Tsirkin static void mthca_free_icms(struct mthca_dev *mdev) 597aba7a22fSMichael S. Tsirkin { 598aba7a22fSMichael S. Tsirkin u8 status; 599aba7a22fSMichael S. Tsirkin 600aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->mcg_table.table); 601aba7a22fSMichael S. Tsirkin if (mdev->mthca_flags & MTHCA_FLAG_SRQ) 602aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->srq_table.table); 603aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->cq_table.table); 604aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->qp_table.rdb_table); 605aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->qp_table.eqp_table); 606aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->qp_table.qp_table); 607aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->mr_table.mpt_table); 608aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->mr_table.mtt_table); 609aba7a22fSMichael S. Tsirkin mthca_unmap_eq_icm(mdev); 610aba7a22fSMichael S. Tsirkin 611aba7a22fSMichael S. Tsirkin mthca_UNMAP_ICM_AUX(mdev, &status); 612aba7a22fSMichael S. Tsirkin mthca_free_icm(mdev, mdev->fw.arbel.aux_icm); 613aba7a22fSMichael S. Tsirkin } 614aba7a22fSMichael S. Tsirkin 615f4f3d0f0SRoland Dreier static int mthca_init_arbel(struct mthca_dev *mdev) 6161da177e4SLinus Torvalds { 6171da177e4SLinus Torvalds struct mthca_dev_lim dev_lim; 6181da177e4SLinus Torvalds struct mthca_profile profile; 6191da177e4SLinus Torvalds struct mthca_init_hca_param init_hca; 6201da177e4SLinus Torvalds u64 icm_size; 6211da177e4SLinus Torvalds u8 status; 6221da177e4SLinus Torvalds int err; 6231da177e4SLinus Torvalds 6241da177e4SLinus Torvalds err = mthca_QUERY_FW(mdev, &status); 6251da177e4SLinus Torvalds if (err) { 6261da177e4SLinus Torvalds mthca_err(mdev, "QUERY_FW command failed, aborting.\n"); 6271da177e4SLinus Torvalds return err; 6281da177e4SLinus Torvalds } 6291da177e4SLinus Torvalds if (status) { 6301da177e4SLinus Torvalds mthca_err(mdev, "QUERY_FW returned status 0x%02x, " 6311da177e4SLinus Torvalds "aborting.\n", status); 6321da177e4SLinus Torvalds return -EINVAL; 6331da177e4SLinus Torvalds } 6341da177e4SLinus Torvalds 6351da177e4SLinus Torvalds err = mthca_ENABLE_LAM(mdev, &status); 6361da177e4SLinus Torvalds if (err) { 6371da177e4SLinus Torvalds mthca_err(mdev, "ENABLE_LAM command failed, aborting.\n"); 6381da177e4SLinus Torvalds return err; 6391da177e4SLinus Torvalds } 6401da177e4SLinus Torvalds if (status == MTHCA_CMD_STAT_LAM_NOT_PRE) { 6411da177e4SLinus Torvalds mthca_dbg(mdev, "No HCA-attached memory (running in MemFree mode)\n"); 6421da177e4SLinus Torvalds mdev->mthca_flags |= MTHCA_FLAG_NO_LAM; 6431da177e4SLinus Torvalds } else if (status) { 6441da177e4SLinus Torvalds mthca_err(mdev, "ENABLE_LAM returned status 0x%02x, " 6451da177e4SLinus Torvalds "aborting.\n", status); 6461da177e4SLinus Torvalds return -EINVAL; 6471da177e4SLinus Torvalds } 6481da177e4SLinus Torvalds 6491da177e4SLinus Torvalds err = mthca_load_fw(mdev); 6501da177e4SLinus Torvalds if (err) { 6511da177e4SLinus Torvalds mthca_err(mdev, "Failed to start FW, aborting.\n"); 6521da177e4SLinus Torvalds goto err_disable; 6531da177e4SLinus Torvalds } 6541da177e4SLinus Torvalds 6551da177e4SLinus Torvalds err = mthca_dev_lim(mdev, &dev_lim); 6561da177e4SLinus Torvalds if (err) { 6571da177e4SLinus Torvalds mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n"); 6581da177e4SLinus Torvalds goto err_stop_fw; 6591da177e4SLinus Torvalds } 6601da177e4SLinus Torvalds 66182da703eSLeonid Arsh profile = hca_profile; 6621da177e4SLinus Torvalds profile.num_uar = dev_lim.uar_size / PAGE_SIZE; 6631da177e4SLinus Torvalds profile.num_udav = 0; 664ec34a922SRoland Dreier if (mdev->mthca_flags & MTHCA_FLAG_SRQ) 665ec34a922SRoland Dreier profile.num_srq = dev_lim.max_srqs; 6661da177e4SLinus Torvalds 6671da177e4SLinus Torvalds icm_size = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca); 6681da177e4SLinus Torvalds if ((int) icm_size < 0) { 6691da177e4SLinus Torvalds err = icm_size; 6701da177e4SLinus Torvalds goto err_stop_fw; 6711da177e4SLinus Torvalds } 6721da177e4SLinus Torvalds 6731da177e4SLinus Torvalds err = mthca_init_icm(mdev, &dev_lim, &init_hca, icm_size); 6741da177e4SLinus Torvalds if (err) 6751da177e4SLinus Torvalds goto err_stop_fw; 6761da177e4SLinus Torvalds 6771da177e4SLinus Torvalds err = mthca_INIT_HCA(mdev, &init_hca, &status); 6781da177e4SLinus Torvalds if (err) { 6791da177e4SLinus Torvalds mthca_err(mdev, "INIT_HCA command failed, aborting.\n"); 6801da177e4SLinus Torvalds goto err_free_icm; 6811da177e4SLinus Torvalds } 6821da177e4SLinus Torvalds if (status) { 6831da177e4SLinus Torvalds mthca_err(mdev, "INIT_HCA returned status 0x%02x, " 6841da177e4SLinus Torvalds "aborting.\n", status); 6851da177e4SLinus Torvalds err = -EINVAL; 6861da177e4SLinus Torvalds goto err_free_icm; 6871da177e4SLinus Torvalds } 6881da177e4SLinus Torvalds 6891da177e4SLinus Torvalds return 0; 6901da177e4SLinus Torvalds 6911da177e4SLinus Torvalds err_free_icm: 692aba7a22fSMichael S. Tsirkin mthca_free_icms(mdev); 6931da177e4SLinus Torvalds 6941da177e4SLinus Torvalds err_stop_fw: 6951da177e4SLinus Torvalds mthca_UNMAP_FA(mdev, &status); 6961da177e4SLinus Torvalds mthca_free_icm(mdev, mdev->fw.arbel.fw_icm); 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds err_disable: 6991da177e4SLinus Torvalds if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM)) 7001da177e4SLinus Torvalds mthca_DISABLE_LAM(mdev, &status); 7011da177e4SLinus Torvalds 7021da177e4SLinus Torvalds return err; 7031da177e4SLinus Torvalds } 7041da177e4SLinus Torvalds 7052e8b981cSMichael S. Tsirkin static void mthca_close_hca(struct mthca_dev *mdev) 7062e8b981cSMichael S. Tsirkin { 7072e8b981cSMichael S. Tsirkin u8 status; 7082e8b981cSMichael S. Tsirkin 7092e8b981cSMichael S. Tsirkin mthca_CLOSE_HCA(mdev, 0, &status); 7102e8b981cSMichael S. Tsirkin 7112e8b981cSMichael S. Tsirkin if (mthca_is_memfree(mdev)) { 712aba7a22fSMichael S. Tsirkin mthca_free_icms(mdev); 7132e8b981cSMichael S. Tsirkin 7142e8b981cSMichael S. Tsirkin mthca_UNMAP_FA(mdev, &status); 7152e8b981cSMichael S. Tsirkin mthca_free_icm(mdev, mdev->fw.arbel.fw_icm); 7162e8b981cSMichael S. Tsirkin 7172e8b981cSMichael S. Tsirkin if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM)) 7182e8b981cSMichael S. Tsirkin mthca_DISABLE_LAM(mdev, &status); 7192e8b981cSMichael S. Tsirkin } else 7202e8b981cSMichael S. Tsirkin mthca_SYS_DIS(mdev, &status); 7212e8b981cSMichael S. Tsirkin } 7222e8b981cSMichael S. Tsirkin 723f4f3d0f0SRoland Dreier static int mthca_init_hca(struct mthca_dev *mdev) 7241da177e4SLinus Torvalds { 7252e8b981cSMichael S. Tsirkin u8 status; 7262e8b981cSMichael S. Tsirkin int err; 7272e8b981cSMichael S. Tsirkin struct mthca_adapter adapter; 7282e8b981cSMichael S. Tsirkin 729d10ddbf6SRoland Dreier if (mthca_is_memfree(mdev)) 7302e8b981cSMichael S. Tsirkin err = mthca_init_arbel(mdev); 7311da177e4SLinus Torvalds else 7322e8b981cSMichael S. Tsirkin err = mthca_init_tavor(mdev); 7332e8b981cSMichael S. Tsirkin 7342e8b981cSMichael S. Tsirkin if (err) 7352e8b981cSMichael S. Tsirkin return err; 7362e8b981cSMichael S. Tsirkin 7372e8b981cSMichael S. Tsirkin err = mthca_QUERY_ADAPTER(mdev, &adapter, &status); 7382e8b981cSMichael S. Tsirkin if (err) { 7392e8b981cSMichael S. Tsirkin mthca_err(mdev, "QUERY_ADAPTER command failed, aborting.\n"); 7402e8b981cSMichael S. Tsirkin goto err_close; 7412e8b981cSMichael S. Tsirkin } 7422e8b981cSMichael S. Tsirkin if (status) { 7432e8b981cSMichael S. Tsirkin mthca_err(mdev, "QUERY_ADAPTER returned status 0x%02x, " 7442e8b981cSMichael S. Tsirkin "aborting.\n", status); 7452e8b981cSMichael S. Tsirkin err = -EINVAL; 7462e8b981cSMichael S. Tsirkin goto err_close; 7472e8b981cSMichael S. Tsirkin } 7482e8b981cSMichael S. Tsirkin 7492e8b981cSMichael S. Tsirkin mdev->eq_table.inta_pin = adapter.inta_pin; 7502e8b981cSMichael S. Tsirkin mdev->rev_id = adapter.revision_id; 7512e8b981cSMichael S. Tsirkin memcpy(mdev->board_id, adapter.board_id, sizeof mdev->board_id); 7522e8b981cSMichael S. Tsirkin 7532e8b981cSMichael S. Tsirkin return 0; 7542e8b981cSMichael S. Tsirkin 7552e8b981cSMichael S. Tsirkin err_close: 7562e8b981cSMichael S. Tsirkin mthca_close_hca(mdev); 7572e8b981cSMichael S. Tsirkin return err; 7581da177e4SLinus Torvalds } 7591da177e4SLinus Torvalds 760f4f3d0f0SRoland Dreier static int mthca_setup_hca(struct mthca_dev *dev) 7611da177e4SLinus Torvalds { 7621da177e4SLinus Torvalds int err; 7631da177e4SLinus Torvalds u8 status; 7641da177e4SLinus Torvalds 7651da177e4SLinus Torvalds MTHCA_INIT_DOORBELL_LOCK(&dev->doorbell_lock); 7661da177e4SLinus Torvalds 7671da177e4SLinus Torvalds err = mthca_init_uar_table(dev); 7681da177e4SLinus Torvalds if (err) { 7691da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 7701da177e4SLinus Torvalds "user access region table, aborting.\n"); 7711da177e4SLinus Torvalds return err; 7721da177e4SLinus Torvalds } 7731da177e4SLinus Torvalds 7741da177e4SLinus Torvalds err = mthca_uar_alloc(dev, &dev->driver_uar); 7751da177e4SLinus Torvalds if (err) { 7761da177e4SLinus Torvalds mthca_err(dev, "Failed to allocate driver access region, " 7771da177e4SLinus Torvalds "aborting.\n"); 7781da177e4SLinus Torvalds goto err_uar_table_free; 7791da177e4SLinus Torvalds } 7801da177e4SLinus Torvalds 7811da177e4SLinus Torvalds dev->kar = ioremap(dev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE); 7821da177e4SLinus Torvalds if (!dev->kar) { 7831da177e4SLinus Torvalds mthca_err(dev, "Couldn't map kernel access region, " 7841da177e4SLinus Torvalds "aborting.\n"); 7851da177e4SLinus Torvalds err = -ENOMEM; 7861da177e4SLinus Torvalds goto err_uar_free; 7871da177e4SLinus Torvalds } 7881da177e4SLinus Torvalds 7891da177e4SLinus Torvalds err = mthca_init_pd_table(dev); 7901da177e4SLinus Torvalds if (err) { 7911da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 7921da177e4SLinus Torvalds "protection domain table, aborting.\n"); 7931da177e4SLinus Torvalds goto err_kar_unmap; 7941da177e4SLinus Torvalds } 7951da177e4SLinus Torvalds 7961da177e4SLinus Torvalds err = mthca_init_mr_table(dev); 7971da177e4SLinus Torvalds if (err) { 7981da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 7991da177e4SLinus Torvalds "memory region table, aborting.\n"); 8001da177e4SLinus Torvalds goto err_pd_table_free; 8011da177e4SLinus Torvalds } 8021da177e4SLinus Torvalds 80399264c1eSRoland Dreier err = mthca_pd_alloc(dev, 1, &dev->driver_pd); 8041da177e4SLinus Torvalds if (err) { 8051da177e4SLinus Torvalds mthca_err(dev, "Failed to create driver PD, " 8061da177e4SLinus Torvalds "aborting.\n"); 8071da177e4SLinus Torvalds goto err_mr_table_free; 8081da177e4SLinus Torvalds } 8091da177e4SLinus Torvalds 8101da177e4SLinus Torvalds err = mthca_init_eq_table(dev); 8111da177e4SLinus Torvalds if (err) { 8121da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 8131da177e4SLinus Torvalds "event queue table, aborting.\n"); 8141da177e4SLinus Torvalds goto err_pd_free; 8151da177e4SLinus Torvalds } 8161da177e4SLinus Torvalds 8171da177e4SLinus Torvalds err = mthca_cmd_use_events(dev); 8181da177e4SLinus Torvalds if (err) { 8191da177e4SLinus Torvalds mthca_err(dev, "Failed to switch to event-driven " 8201da177e4SLinus Torvalds "firmware commands, aborting.\n"); 8211da177e4SLinus Torvalds goto err_eq_table_free; 8221da177e4SLinus Torvalds } 8231da177e4SLinus Torvalds 8241da177e4SLinus Torvalds err = mthca_NOP(dev, &status); 8251da177e4SLinus Torvalds if (err || status) { 8264ad81174SRoland Dreier mthca_err(dev, "NOP command failed to generate interrupt (IRQ %d), aborting.\n", 8274ad81174SRoland Dreier dev->mthca_flags & MTHCA_FLAG_MSI_X ? 8284ad81174SRoland Dreier dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector : 8294ad81174SRoland Dreier dev->pdev->irq); 8301da177e4SLinus Torvalds if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)) 8311da177e4SLinus Torvalds mthca_err(dev, "Try again with MSI/MSI-X disabled.\n"); 8321da177e4SLinus Torvalds else 8331da177e4SLinus Torvalds mthca_err(dev, "BIOS or ACPI interrupt routing problem?\n"); 8341da177e4SLinus Torvalds 8351da177e4SLinus Torvalds goto err_cmd_poll; 8361da177e4SLinus Torvalds } 8371da177e4SLinus Torvalds 8381da177e4SLinus Torvalds mthca_dbg(dev, "NOP command IRQ test passed\n"); 8391da177e4SLinus Torvalds 8401da177e4SLinus Torvalds err = mthca_init_cq_table(dev); 8411da177e4SLinus Torvalds if (err) { 8421da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 8431da177e4SLinus Torvalds "completion queue table, aborting.\n"); 8441da177e4SLinus Torvalds goto err_cmd_poll; 8451da177e4SLinus Torvalds } 8461da177e4SLinus Torvalds 847ec34a922SRoland Dreier err = mthca_init_srq_table(dev); 848ec34a922SRoland Dreier if (err) { 849ec34a922SRoland Dreier mthca_err(dev, "Failed to initialize " 850ec34a922SRoland Dreier "shared receive queue table, aborting.\n"); 851ec34a922SRoland Dreier goto err_cq_table_free; 852ec34a922SRoland Dreier } 853ec34a922SRoland Dreier 8541da177e4SLinus Torvalds err = mthca_init_qp_table(dev); 8551da177e4SLinus Torvalds if (err) { 8561da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 8571da177e4SLinus Torvalds "queue pair table, aborting.\n"); 858ec34a922SRoland Dreier goto err_srq_table_free; 8591da177e4SLinus Torvalds } 8601da177e4SLinus Torvalds 8611da177e4SLinus Torvalds err = mthca_init_av_table(dev); 8621da177e4SLinus Torvalds if (err) { 8631da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 8641da177e4SLinus Torvalds "address vector table, aborting.\n"); 8651da177e4SLinus Torvalds goto err_qp_table_free; 8661da177e4SLinus Torvalds } 8671da177e4SLinus Torvalds 8681da177e4SLinus Torvalds err = mthca_init_mcg_table(dev); 8691da177e4SLinus Torvalds if (err) { 8701da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 8711da177e4SLinus Torvalds "multicast group table, aborting.\n"); 8721da177e4SLinus Torvalds goto err_av_table_free; 8731da177e4SLinus Torvalds } 8741da177e4SLinus Torvalds 8751da177e4SLinus Torvalds return 0; 8761da177e4SLinus Torvalds 8771da177e4SLinus Torvalds err_av_table_free: 8781da177e4SLinus Torvalds mthca_cleanup_av_table(dev); 8791da177e4SLinus Torvalds 8801da177e4SLinus Torvalds err_qp_table_free: 8811da177e4SLinus Torvalds mthca_cleanup_qp_table(dev); 8821da177e4SLinus Torvalds 883ec34a922SRoland Dreier err_srq_table_free: 884ec34a922SRoland Dreier mthca_cleanup_srq_table(dev); 885ec34a922SRoland Dreier 8861da177e4SLinus Torvalds err_cq_table_free: 8871da177e4SLinus Torvalds mthca_cleanup_cq_table(dev); 8881da177e4SLinus Torvalds 8891da177e4SLinus Torvalds err_cmd_poll: 8901da177e4SLinus Torvalds mthca_cmd_use_polling(dev); 8911da177e4SLinus Torvalds 8921da177e4SLinus Torvalds err_eq_table_free: 8931da177e4SLinus Torvalds mthca_cleanup_eq_table(dev); 8941da177e4SLinus Torvalds 8951da177e4SLinus Torvalds err_pd_free: 8961da177e4SLinus Torvalds mthca_pd_free(dev, &dev->driver_pd); 8971da177e4SLinus Torvalds 8981da177e4SLinus Torvalds err_mr_table_free: 8991da177e4SLinus Torvalds mthca_cleanup_mr_table(dev); 9001da177e4SLinus Torvalds 9011da177e4SLinus Torvalds err_pd_table_free: 9021da177e4SLinus Torvalds mthca_cleanup_pd_table(dev); 9031da177e4SLinus Torvalds 9041da177e4SLinus Torvalds err_kar_unmap: 9051da177e4SLinus Torvalds iounmap(dev->kar); 9061da177e4SLinus Torvalds 9071da177e4SLinus Torvalds err_uar_free: 9081da177e4SLinus Torvalds mthca_uar_free(dev, &dev->driver_uar); 9091da177e4SLinus Torvalds 9101da177e4SLinus Torvalds err_uar_table_free: 9111da177e4SLinus Torvalds mthca_cleanup_uar_table(dev); 9121da177e4SLinus Torvalds return err; 9131da177e4SLinus Torvalds } 9141da177e4SLinus Torvalds 915f4f3d0f0SRoland Dreier static int mthca_request_regions(struct pci_dev *pdev, int ddr_hidden) 9161da177e4SLinus Torvalds { 9171da177e4SLinus Torvalds int err; 9181da177e4SLinus Torvalds 9191da177e4SLinus Torvalds /* 9201da177e4SLinus Torvalds * We can't just use pci_request_regions() because the MSI-X 9211da177e4SLinus Torvalds * table is right in the middle of the first BAR. If we did 9221da177e4SLinus Torvalds * pci_request_region and grab all of the first BAR, then 9231da177e4SLinus Torvalds * setting up MSI-X would fail, since the PCI core wants to do 9241da177e4SLinus Torvalds * request_mem_region on the MSI-X vector table. 9251da177e4SLinus Torvalds * 9261da177e4SLinus Torvalds * So just request what we need right now, and request any 9271da177e4SLinus Torvalds * other regions we need when setting up EQs. 9281da177e4SLinus Torvalds */ 9291da177e4SLinus Torvalds if (!request_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE, 9301da177e4SLinus Torvalds MTHCA_HCR_SIZE, DRV_NAME)) 9311da177e4SLinus Torvalds return -EBUSY; 9321da177e4SLinus Torvalds 9331da177e4SLinus Torvalds err = pci_request_region(pdev, 2, DRV_NAME); 9341da177e4SLinus Torvalds if (err) 9351da177e4SLinus Torvalds goto err_bar2_failed; 9361da177e4SLinus Torvalds 9371da177e4SLinus Torvalds if (!ddr_hidden) { 9381da177e4SLinus Torvalds err = pci_request_region(pdev, 4, DRV_NAME); 9391da177e4SLinus Torvalds if (err) 9401da177e4SLinus Torvalds goto err_bar4_failed; 9411da177e4SLinus Torvalds } 9421da177e4SLinus Torvalds 9431da177e4SLinus Torvalds return 0; 9441da177e4SLinus Torvalds 9451da177e4SLinus Torvalds err_bar4_failed: 9461da177e4SLinus Torvalds pci_release_region(pdev, 2); 9471da177e4SLinus Torvalds 9481da177e4SLinus Torvalds err_bar2_failed: 9491da177e4SLinus Torvalds release_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE, 9501da177e4SLinus Torvalds MTHCA_HCR_SIZE); 9511da177e4SLinus Torvalds 9521da177e4SLinus Torvalds return err; 9531da177e4SLinus Torvalds } 9541da177e4SLinus Torvalds 9551da177e4SLinus Torvalds static void mthca_release_regions(struct pci_dev *pdev, 9561da177e4SLinus Torvalds int ddr_hidden) 9571da177e4SLinus Torvalds { 9581da177e4SLinus Torvalds if (!ddr_hidden) 9591da177e4SLinus Torvalds pci_release_region(pdev, 4); 9601da177e4SLinus Torvalds 9611da177e4SLinus Torvalds pci_release_region(pdev, 2); 9621da177e4SLinus Torvalds 9631da177e4SLinus Torvalds release_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE, 9641da177e4SLinus Torvalds MTHCA_HCR_SIZE); 9651da177e4SLinus Torvalds } 9661da177e4SLinus Torvalds 967f4f3d0f0SRoland Dreier static int mthca_enable_msi_x(struct mthca_dev *mdev) 9681da177e4SLinus Torvalds { 9691da177e4SLinus Torvalds struct msix_entry entries[3]; 9701da177e4SLinus Torvalds int err; 9711da177e4SLinus Torvalds 9721da177e4SLinus Torvalds entries[0].entry = 0; 9731da177e4SLinus Torvalds entries[1].entry = 1; 9741da177e4SLinus Torvalds entries[2].entry = 2; 9751da177e4SLinus Torvalds 9761da177e4SLinus Torvalds err = pci_enable_msix(mdev->pdev, entries, ARRAY_SIZE(entries)); 9771da177e4SLinus Torvalds if (err) { 9781da177e4SLinus Torvalds if (err > 0) 9791da177e4SLinus Torvalds mthca_info(mdev, "Only %d MSI-X vectors available, " 9801da177e4SLinus Torvalds "not using MSI-X\n", err); 9811da177e4SLinus Torvalds return err; 9821da177e4SLinus Torvalds } 9831da177e4SLinus Torvalds 9841da177e4SLinus Torvalds mdev->eq_table.eq[MTHCA_EQ_COMP ].msi_x_vector = entries[0].vector; 9851da177e4SLinus Torvalds mdev->eq_table.eq[MTHCA_EQ_ASYNC].msi_x_vector = entries[1].vector; 9861da177e4SLinus Torvalds mdev->eq_table.eq[MTHCA_EQ_CMD ].msi_x_vector = entries[2].vector; 9871da177e4SLinus Torvalds 9881da177e4SLinus Torvalds return 0; 9891da177e4SLinus Torvalds } 9901da177e4SLinus Torvalds 99168a3c212SRoland Dreier /* Types of supported HCA */ 99268a3c212SRoland Dreier enum { 99368a3c212SRoland Dreier TAVOR, /* MT23108 */ 99468a3c212SRoland Dreier ARBEL_COMPAT, /* MT25208 in Tavor compat mode */ 99568a3c212SRoland Dreier ARBEL_NATIVE, /* MT25208 with extended features */ 99668a3c212SRoland Dreier SINAI /* MT25204 */ 99768a3c212SRoland Dreier }; 99868a3c212SRoland Dreier 99968a3c212SRoland Dreier #define MTHCA_FW_VER(major, minor, subminor) \ 100068a3c212SRoland Dreier (((u64) (major) << 32) | ((u64) (minor) << 16) | (u64) (subminor)) 100168a3c212SRoland Dreier 100268a3c212SRoland Dreier static struct { 100368a3c212SRoland Dreier u64 latest_fw; 1004651eaac9SEli Cohen u32 flags; 100568a3c212SRoland Dreier } mthca_hca_table[] = { 10066226bb57SRoland Dreier [TAVOR] = { .latest_fw = MTHCA_FW_VER(3, 4, 0), 1007651eaac9SEli Cohen .flags = 0 }, 1008834ac73dSMichael S. Tsirkin [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 7, 600), 1009651eaac9SEli Cohen .flags = MTHCA_FLAG_PCIE }, 1010834ac73dSMichael S. Tsirkin [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 1, 400), 1011651eaac9SEli Cohen .flags = MTHCA_FLAG_MEMFREE | 1012651eaac9SEli Cohen MTHCA_FLAG_PCIE }, 1013834ac73dSMichael S. Tsirkin [SINAI] = { .latest_fw = MTHCA_FW_VER(1, 1, 0), 1014651eaac9SEli Cohen .flags = MTHCA_FLAG_MEMFREE | 1015651eaac9SEli Cohen MTHCA_FLAG_PCIE | 1016651eaac9SEli Cohen MTHCA_FLAG_SINAI_OPT } 101768a3c212SRoland Dreier }; 101868a3c212SRoland Dreier 1019b3b30f5eSJack Morgenstein static int __mthca_init_one(struct pci_dev *pdev, int hca_type) 10201da177e4SLinus Torvalds { 10211da177e4SLinus Torvalds int ddr_hidden = 0; 10221da177e4SLinus Torvalds int err; 10231da177e4SLinus Torvalds struct mthca_dev *mdev; 10241da177e4SLinus Torvalds 1025982245f0SAdrian Bunk printk(KERN_INFO PFX "Initializing %s\n", 1026982245f0SAdrian Bunk pci_name(pdev)); 10271da177e4SLinus Torvalds 10281da177e4SLinus Torvalds err = pci_enable_device(pdev); 10291da177e4SLinus Torvalds if (err) { 10301da177e4SLinus Torvalds dev_err(&pdev->dev, "Cannot enable PCI device, " 10311da177e4SLinus Torvalds "aborting.\n"); 10321da177e4SLinus Torvalds return err; 10331da177e4SLinus Torvalds } 10341da177e4SLinus Torvalds 10351da177e4SLinus Torvalds /* 10361da177e4SLinus Torvalds * Check for BARs. We expect 0: 1MB, 2: 8MB, 4: DDR (may not 10371da177e4SLinus Torvalds * be present) 10381da177e4SLinus Torvalds */ 10391da177e4SLinus Torvalds if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) || 10401da177e4SLinus Torvalds pci_resource_len(pdev, 0) != 1 << 20) { 1041177214afSBernhard Fischer dev_err(&pdev->dev, "Missing DCS, aborting.\n"); 10421da177e4SLinus Torvalds err = -ENODEV; 10431da177e4SLinus Torvalds goto err_disable_pdev; 10441da177e4SLinus Torvalds } 1045cbd2981aSMichael S. Tsirkin if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { 1046177214afSBernhard Fischer dev_err(&pdev->dev, "Missing UAR, aborting.\n"); 10471da177e4SLinus Torvalds err = -ENODEV; 10481da177e4SLinus Torvalds goto err_disable_pdev; 10491da177e4SLinus Torvalds } 10501da177e4SLinus Torvalds if (!(pci_resource_flags(pdev, 4) & IORESOURCE_MEM)) 10511da177e4SLinus Torvalds ddr_hidden = 1; 10521da177e4SLinus Torvalds 10531da177e4SLinus Torvalds err = mthca_request_regions(pdev, ddr_hidden); 10541da177e4SLinus Torvalds if (err) { 10551da177e4SLinus Torvalds dev_err(&pdev->dev, "Cannot obtain PCI resources, " 10561da177e4SLinus Torvalds "aborting.\n"); 10571da177e4SLinus Torvalds goto err_disable_pdev; 10581da177e4SLinus Torvalds } 10591da177e4SLinus Torvalds 10601da177e4SLinus Torvalds pci_set_master(pdev); 10611da177e4SLinus Torvalds 10621da177e4SLinus Torvalds err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); 10631da177e4SLinus Torvalds if (err) { 10641da177e4SLinus Torvalds dev_warn(&pdev->dev, "Warning: couldn't set 64-bit PCI DMA mask.\n"); 10651da177e4SLinus Torvalds err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); 10661da177e4SLinus Torvalds if (err) { 10671da177e4SLinus Torvalds dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting.\n"); 10681da177e4SLinus Torvalds goto err_free_res; 10691da177e4SLinus Torvalds } 10701da177e4SLinus Torvalds } 10711da177e4SLinus Torvalds err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); 10721da177e4SLinus Torvalds if (err) { 10731da177e4SLinus Torvalds dev_warn(&pdev->dev, "Warning: couldn't set 64-bit " 10741da177e4SLinus Torvalds "consistent PCI DMA mask.\n"); 10751da177e4SLinus Torvalds err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 10761da177e4SLinus Torvalds if (err) { 10771da177e4SLinus Torvalds dev_err(&pdev->dev, "Can't set consistent PCI DMA mask, " 10781da177e4SLinus Torvalds "aborting.\n"); 10791da177e4SLinus Torvalds goto err_free_res; 10801da177e4SLinus Torvalds } 10811da177e4SLinus Torvalds } 10821da177e4SLinus Torvalds 10831da177e4SLinus Torvalds mdev = (struct mthca_dev *) ib_alloc_device(sizeof *mdev); 10841da177e4SLinus Torvalds if (!mdev) { 10851da177e4SLinus Torvalds dev_err(&pdev->dev, "Device struct alloc failed, " 10861da177e4SLinus Torvalds "aborting.\n"); 10871da177e4SLinus Torvalds err = -ENOMEM; 10881da177e4SLinus Torvalds goto err_free_res; 10891da177e4SLinus Torvalds } 10901da177e4SLinus Torvalds 10911da177e4SLinus Torvalds mdev->pdev = pdev; 10921da177e4SLinus Torvalds 1093b3b30f5eSJack Morgenstein mdev->mthca_flags = mthca_hca_table[hca_type].flags; 10941da177e4SLinus Torvalds if (ddr_hidden) 10951da177e4SLinus Torvalds mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN; 10961da177e4SLinus Torvalds 10971da177e4SLinus Torvalds /* 10981da177e4SLinus Torvalds * Now reset the HCA before we touch the PCI capabilities or 10991da177e4SLinus Torvalds * attempt a firmware command, since a boot ROM may have left 11001da177e4SLinus Torvalds * the HCA in an undefined state. 11011da177e4SLinus Torvalds */ 11021da177e4SLinus Torvalds err = mthca_reset(mdev); 11031da177e4SLinus Torvalds if (err) { 11041da177e4SLinus Torvalds mthca_err(mdev, "Failed to reset HCA, aborting.\n"); 11051da177e4SLinus Torvalds goto err_free_dev; 11061da177e4SLinus Torvalds } 11071da177e4SLinus Torvalds 11081da177e4SLinus Torvalds if (msi_x && !mthca_enable_msi_x(mdev)) 11091da177e4SLinus Torvalds mdev->mthca_flags |= MTHCA_FLAG_MSI_X; 11101da177e4SLinus Torvalds if (msi && !(mdev->mthca_flags & MTHCA_FLAG_MSI_X) && 11111da177e4SLinus Torvalds !pci_enable_msi(pdev)) 11121da177e4SLinus Torvalds mdev->mthca_flags |= MTHCA_FLAG_MSI; 11131da177e4SLinus Torvalds 111480fd8238SRoland Dreier if (mthca_cmd_init(mdev)) { 111580fd8238SRoland Dreier mthca_err(mdev, "Failed to init command interface, aborting.\n"); 11161da177e4SLinus Torvalds goto err_free_dev; 11171da177e4SLinus Torvalds } 11181da177e4SLinus Torvalds 11191da177e4SLinus Torvalds err = mthca_tune_pci(mdev); 11201da177e4SLinus Torvalds if (err) 112180fd8238SRoland Dreier goto err_cmd; 11221da177e4SLinus Torvalds 11231da177e4SLinus Torvalds err = mthca_init_hca(mdev); 11241da177e4SLinus Torvalds if (err) 112580fd8238SRoland Dreier goto err_cmd; 11261da177e4SLinus Torvalds 1127b3b30f5eSJack Morgenstein if (mdev->fw_ver < mthca_hca_table[hca_type].latest_fw) { 112887cfe323SRoland Dreier mthca_warn(mdev, "HCA FW version %d.%d.%d is old (%d.%d.%d is current).\n", 112968a3c212SRoland Dreier (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff, 113068a3c212SRoland Dreier (int) (mdev->fw_ver & 0xffff), 1131b3b30f5eSJack Morgenstein (int) (mthca_hca_table[hca_type].latest_fw >> 32), 1132b3b30f5eSJack Morgenstein (int) (mthca_hca_table[hca_type].latest_fw >> 16) & 0xffff, 1133b3b30f5eSJack Morgenstein (int) (mthca_hca_table[hca_type].latest_fw & 0xffff)); 113468a3c212SRoland Dreier mthca_warn(mdev, "If you have problems, try updating your HCA FW.\n"); 113568a3c212SRoland Dreier } 113668a3c212SRoland Dreier 11371da177e4SLinus Torvalds err = mthca_setup_hca(mdev); 11381da177e4SLinus Torvalds if (err) 11391da177e4SLinus Torvalds goto err_close; 11401da177e4SLinus Torvalds 11411da177e4SLinus Torvalds err = mthca_register_device(mdev); 11421da177e4SLinus Torvalds if (err) 11431da177e4SLinus Torvalds goto err_cleanup; 11441da177e4SLinus Torvalds 11451da177e4SLinus Torvalds err = mthca_create_agents(mdev); 11461da177e4SLinus Torvalds if (err) 11471da177e4SLinus Torvalds goto err_unregister; 11481da177e4SLinus Torvalds 11491da177e4SLinus Torvalds pci_set_drvdata(pdev, mdev); 1150b3b30f5eSJack Morgenstein mdev->hca_type = hca_type; 11511da177e4SLinus Torvalds 11521da177e4SLinus Torvalds return 0; 11531da177e4SLinus Torvalds 11541da177e4SLinus Torvalds err_unregister: 11551da177e4SLinus Torvalds mthca_unregister_device(mdev); 11561da177e4SLinus Torvalds 11571da177e4SLinus Torvalds err_cleanup: 11581da177e4SLinus Torvalds mthca_cleanup_mcg_table(mdev); 11591da177e4SLinus Torvalds mthca_cleanup_av_table(mdev); 11601da177e4SLinus Torvalds mthca_cleanup_qp_table(mdev); 1161ec34a922SRoland Dreier mthca_cleanup_srq_table(mdev); 11621da177e4SLinus Torvalds mthca_cleanup_cq_table(mdev); 11631da177e4SLinus Torvalds mthca_cmd_use_polling(mdev); 11641da177e4SLinus Torvalds mthca_cleanup_eq_table(mdev); 11651da177e4SLinus Torvalds 11661da177e4SLinus Torvalds mthca_pd_free(mdev, &mdev->driver_pd); 11671da177e4SLinus Torvalds 11681da177e4SLinus Torvalds mthca_cleanup_mr_table(mdev); 11691da177e4SLinus Torvalds mthca_cleanup_pd_table(mdev); 11701da177e4SLinus Torvalds mthca_cleanup_uar_table(mdev); 11711da177e4SLinus Torvalds 11721da177e4SLinus Torvalds err_close: 11731da177e4SLinus Torvalds mthca_close_hca(mdev); 11741da177e4SLinus Torvalds 117580fd8238SRoland Dreier err_cmd: 117680fd8238SRoland Dreier mthca_cmd_cleanup(mdev); 11771da177e4SLinus Torvalds 11781da177e4SLinus Torvalds err_free_dev: 11791da177e4SLinus Torvalds if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) 11801da177e4SLinus Torvalds pci_disable_msix(pdev); 11811da177e4SLinus Torvalds if (mdev->mthca_flags & MTHCA_FLAG_MSI) 11821da177e4SLinus Torvalds pci_disable_msi(pdev); 11831da177e4SLinus Torvalds 11841da177e4SLinus Torvalds ib_dealloc_device(&mdev->ib_dev); 11851da177e4SLinus Torvalds 11861da177e4SLinus Torvalds err_free_res: 11871da177e4SLinus Torvalds mthca_release_regions(pdev, ddr_hidden); 11881da177e4SLinus Torvalds 11891da177e4SLinus Torvalds err_disable_pdev: 11901da177e4SLinus Torvalds pci_disable_device(pdev); 11911da177e4SLinus Torvalds pci_set_drvdata(pdev, NULL); 11921da177e4SLinus Torvalds return err; 11931da177e4SLinus Torvalds } 11941da177e4SLinus Torvalds 1195b3b30f5eSJack Morgenstein static void __mthca_remove_one(struct pci_dev *pdev) 11961da177e4SLinus Torvalds { 11971da177e4SLinus Torvalds struct mthca_dev *mdev = pci_get_drvdata(pdev); 11981da177e4SLinus Torvalds u8 status; 11991da177e4SLinus Torvalds int p; 12001da177e4SLinus Torvalds 12011da177e4SLinus Torvalds if (mdev) { 12021da177e4SLinus Torvalds mthca_free_agents(mdev); 12031da177e4SLinus Torvalds mthca_unregister_device(mdev); 12041da177e4SLinus Torvalds 12051da177e4SLinus Torvalds for (p = 1; p <= mdev->limits.num_ports; ++p) 12061da177e4SLinus Torvalds mthca_CLOSE_IB(mdev, p, &status); 12071da177e4SLinus Torvalds 12081da177e4SLinus Torvalds mthca_cleanup_mcg_table(mdev); 12091da177e4SLinus Torvalds mthca_cleanup_av_table(mdev); 12101da177e4SLinus Torvalds mthca_cleanup_qp_table(mdev); 1211ec34a922SRoland Dreier mthca_cleanup_srq_table(mdev); 12121da177e4SLinus Torvalds mthca_cleanup_cq_table(mdev); 12131da177e4SLinus Torvalds mthca_cmd_use_polling(mdev); 12141da177e4SLinus Torvalds mthca_cleanup_eq_table(mdev); 12151da177e4SLinus Torvalds 12161da177e4SLinus Torvalds mthca_pd_free(mdev, &mdev->driver_pd); 12171da177e4SLinus Torvalds 12181da177e4SLinus Torvalds mthca_cleanup_mr_table(mdev); 12191da177e4SLinus Torvalds mthca_cleanup_pd_table(mdev); 12201da177e4SLinus Torvalds 12211da177e4SLinus Torvalds iounmap(mdev->kar); 12221da177e4SLinus Torvalds mthca_uar_free(mdev, &mdev->driver_uar); 12231da177e4SLinus Torvalds mthca_cleanup_uar_table(mdev); 12241da177e4SLinus Torvalds mthca_close_hca(mdev); 122580fd8238SRoland Dreier mthca_cmd_cleanup(mdev); 12261da177e4SLinus Torvalds 12271da177e4SLinus Torvalds if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) 12281da177e4SLinus Torvalds pci_disable_msix(pdev); 12291da177e4SLinus Torvalds if (mdev->mthca_flags & MTHCA_FLAG_MSI) 12301da177e4SLinus Torvalds pci_disable_msi(pdev); 12311da177e4SLinus Torvalds 12321da177e4SLinus Torvalds ib_dealloc_device(&mdev->ib_dev); 12331da177e4SLinus Torvalds mthca_release_regions(pdev, mdev->mthca_flags & 12341da177e4SLinus Torvalds MTHCA_FLAG_DDR_HIDDEN); 12351da177e4SLinus Torvalds pci_disable_device(pdev); 12361da177e4SLinus Torvalds pci_set_drvdata(pdev, NULL); 12371da177e4SLinus Torvalds } 12381da177e4SLinus Torvalds } 12391da177e4SLinus Torvalds 1240b3b30f5eSJack Morgenstein int __mthca_restart_one(struct pci_dev *pdev) 1241b3b30f5eSJack Morgenstein { 1242b3b30f5eSJack Morgenstein struct mthca_dev *mdev; 1243b3b30f5eSJack Morgenstein 1244b3b30f5eSJack Morgenstein mdev = pci_get_drvdata(pdev); 1245b3b30f5eSJack Morgenstein if (!mdev) 1246b3b30f5eSJack Morgenstein return -ENODEV; 1247b3b30f5eSJack Morgenstein __mthca_remove_one(pdev); 1248b3b30f5eSJack Morgenstein return __mthca_init_one(pdev, mdev->hca_type); 1249b3b30f5eSJack Morgenstein } 1250b3b30f5eSJack Morgenstein 1251b3b30f5eSJack Morgenstein static int __devinit mthca_init_one(struct pci_dev *pdev, 1252b3b30f5eSJack Morgenstein const struct pci_device_id *id) 1253b3b30f5eSJack Morgenstein { 1254b3b30f5eSJack Morgenstein static int mthca_version_printed = 0; 1255b3b30f5eSJack Morgenstein int ret; 1256b3b30f5eSJack Morgenstein 1257b3b30f5eSJack Morgenstein mutex_lock(&mthca_device_mutex); 1258b3b30f5eSJack Morgenstein 1259b3b30f5eSJack Morgenstein if (!mthca_version_printed) { 1260b3b30f5eSJack Morgenstein printk(KERN_INFO "%s", mthca_version); 1261b3b30f5eSJack Morgenstein ++mthca_version_printed; 1262b3b30f5eSJack Morgenstein } 1263b3b30f5eSJack Morgenstein 1264b3b30f5eSJack Morgenstein if (id->driver_data >= ARRAY_SIZE(mthca_hca_table)) { 1265b3b30f5eSJack Morgenstein printk(KERN_ERR PFX "%s has invalid driver data %lx\n", 1266b3b30f5eSJack Morgenstein pci_name(pdev), id->driver_data); 1267b3b30f5eSJack Morgenstein mutex_unlock(&mthca_device_mutex); 1268b3b30f5eSJack Morgenstein return -ENODEV; 1269b3b30f5eSJack Morgenstein } 1270b3b30f5eSJack Morgenstein 1271b3b30f5eSJack Morgenstein ret = __mthca_init_one(pdev, id->driver_data); 1272b3b30f5eSJack Morgenstein 1273b3b30f5eSJack Morgenstein mutex_unlock(&mthca_device_mutex); 1274b3b30f5eSJack Morgenstein 1275b3b30f5eSJack Morgenstein return ret; 1276b3b30f5eSJack Morgenstein } 1277b3b30f5eSJack Morgenstein 1278b3b30f5eSJack Morgenstein static void __devexit mthca_remove_one(struct pci_dev *pdev) 1279b3b30f5eSJack Morgenstein { 1280b3b30f5eSJack Morgenstein mutex_lock(&mthca_device_mutex); 1281b3b30f5eSJack Morgenstein __mthca_remove_one(pdev); 1282b3b30f5eSJack Morgenstein mutex_unlock(&mthca_device_mutex); 1283b3b30f5eSJack Morgenstein } 1284b3b30f5eSJack Morgenstein 12851da177e4SLinus Torvalds static struct pci_device_id mthca_pci_table[] = { 12861da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_TAVOR), 12871da177e4SLinus Torvalds .driver_data = TAVOR }, 12881da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_TAVOR), 12891da177e4SLinus Torvalds .driver_data = TAVOR }, 12901da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT), 12911da177e4SLinus Torvalds .driver_data = ARBEL_COMPAT }, 12921da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT), 12931da177e4SLinus Torvalds .driver_data = ARBEL_COMPAT }, 12941da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_ARBEL), 12951da177e4SLinus Torvalds .driver_data = ARBEL_NATIVE }, 12961da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_ARBEL), 12971da177e4SLinus Torvalds .driver_data = ARBEL_NATIVE }, 129868a3c212SRoland Dreier { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_SINAI), 129968a3c212SRoland Dreier .driver_data = SINAI }, 130068a3c212SRoland Dreier { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_SINAI), 130168a3c212SRoland Dreier .driver_data = SINAI }, 130268a3c212SRoland Dreier { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_SINAI_OLD), 130368a3c212SRoland Dreier .driver_data = SINAI }, 130468a3c212SRoland Dreier { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_SINAI_OLD), 130568a3c212SRoland Dreier .driver_data = SINAI }, 13061da177e4SLinus Torvalds { 0, } 13071da177e4SLinus Torvalds }; 13081da177e4SLinus Torvalds 13091da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, mthca_pci_table); 13101da177e4SLinus Torvalds 13111da177e4SLinus Torvalds static struct pci_driver mthca_driver = { 1312177214afSBernhard Fischer .name = DRV_NAME, 13131da177e4SLinus Torvalds .id_table = mthca_pci_table, 13141da177e4SLinus Torvalds .probe = mthca_init_one, 13151da177e4SLinus Torvalds .remove = __devexit_p(mthca_remove_one) 13161da177e4SLinus Torvalds }; 13171da177e4SLinus Torvalds 131882da703eSLeonid Arsh static void __init __mthca_check_profile_val(const char *name, int *pval, 131982da703eSLeonid Arsh int pval_default) 132082da703eSLeonid Arsh { 132182da703eSLeonid Arsh /* value must be positive and power of 2 */ 132282da703eSLeonid Arsh int old_pval = *pval; 132382da703eSLeonid Arsh 132482da703eSLeonid Arsh if (old_pval <= 0) 132582da703eSLeonid Arsh *pval = pval_default; 132682da703eSLeonid Arsh else 132782da703eSLeonid Arsh *pval = roundup_pow_of_two(old_pval); 132882da703eSLeonid Arsh 132982da703eSLeonid Arsh if (old_pval != *pval) { 133082da703eSLeonid Arsh printk(KERN_WARNING PFX "Invalid value %d for %s in module parameter.\n", 133182da703eSLeonid Arsh old_pval, name); 133282da703eSLeonid Arsh printk(KERN_WARNING PFX "Corrected %s to %d.\n", name, *pval); 133382da703eSLeonid Arsh } 133482da703eSLeonid Arsh } 133582da703eSLeonid Arsh 133682da703eSLeonid Arsh #define mthca_check_profile_val(name, default) \ 133782da703eSLeonid Arsh __mthca_check_profile_val(#name, &hca_profile.name, default) 133882da703eSLeonid Arsh 133982da703eSLeonid Arsh static void __init mthca_validate_profile(void) 134082da703eSLeonid Arsh { 134182da703eSLeonid Arsh mthca_check_profile_val(num_qp, MTHCA_DEFAULT_NUM_QP); 134282da703eSLeonid Arsh mthca_check_profile_val(rdb_per_qp, MTHCA_DEFAULT_RDB_PER_QP); 134382da703eSLeonid Arsh mthca_check_profile_val(num_cq, MTHCA_DEFAULT_NUM_CQ); 134482da703eSLeonid Arsh mthca_check_profile_val(num_mcg, MTHCA_DEFAULT_NUM_MCG); 134582da703eSLeonid Arsh mthca_check_profile_val(num_mpt, MTHCA_DEFAULT_NUM_MPT); 134682da703eSLeonid Arsh mthca_check_profile_val(num_mtt, MTHCA_DEFAULT_NUM_MTT); 134782da703eSLeonid Arsh mthca_check_profile_val(num_udav, MTHCA_DEFAULT_NUM_UDAV); 134882da703eSLeonid Arsh mthca_check_profile_val(fmr_reserved_mtts, MTHCA_DEFAULT_NUM_RESERVED_MTTS); 134982da703eSLeonid Arsh 135082da703eSLeonid Arsh if (hca_profile.fmr_reserved_mtts >= hca_profile.num_mtt) { 135182da703eSLeonid Arsh printk(KERN_WARNING PFX "Invalid fmr_reserved_mtts module parameter %d.\n", 135282da703eSLeonid Arsh hca_profile.fmr_reserved_mtts); 135382da703eSLeonid Arsh printk(KERN_WARNING PFX "(Must be smaller than num_mtt %d)\n", 135482da703eSLeonid Arsh hca_profile.num_mtt); 135582da703eSLeonid Arsh hca_profile.fmr_reserved_mtts = hca_profile.num_mtt / 2; 135682da703eSLeonid Arsh printk(KERN_WARNING PFX "Corrected fmr_reserved_mtts to %d.\n", 135782da703eSLeonid Arsh hca_profile.fmr_reserved_mtts); 135882da703eSLeonid Arsh } 135982da703eSLeonid Arsh } 136082da703eSLeonid Arsh 13611da177e4SLinus Torvalds static int __init mthca_init(void) 13621da177e4SLinus Torvalds { 13631da177e4SLinus Torvalds int ret; 13641da177e4SLinus Torvalds 1365b3b30f5eSJack Morgenstein mutex_init(&mthca_device_mutex); 136682da703eSLeonid Arsh 136782da703eSLeonid Arsh mthca_validate_profile(); 136882da703eSLeonid Arsh 1369b3b30f5eSJack Morgenstein ret = mthca_catas_init(); 1370b3b30f5eSJack Morgenstein if (ret) 1371b3b30f5eSJack Morgenstein return ret; 1372b3b30f5eSJack Morgenstein 13731da177e4SLinus Torvalds ret = pci_register_driver(&mthca_driver); 1374b3b30f5eSJack Morgenstein if (ret < 0) { 1375b3b30f5eSJack Morgenstein mthca_catas_cleanup(); 1376b3b30f5eSJack Morgenstein return ret; 1377b3b30f5eSJack Morgenstein } 1378b3b30f5eSJack Morgenstein 1379b3b30f5eSJack Morgenstein return 0; 13801da177e4SLinus Torvalds } 13811da177e4SLinus Torvalds 13821da177e4SLinus Torvalds static void __exit mthca_cleanup(void) 13831da177e4SLinus Torvalds { 13841da177e4SLinus Torvalds pci_unregister_driver(&mthca_driver); 1385b3b30f5eSJack Morgenstein mthca_catas_cleanup(); 13861da177e4SLinus Torvalds } 13871da177e4SLinus Torvalds 13881da177e4SLinus Torvalds module_init(mthca_init); 13891da177e4SLinus Torvalds module_exit(mthca_cleanup); 1390