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 830b0df6f2SRoland Dreier DEFINE_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, 382391e4deaSMichael S. Tsirkin GFP_HIGHUSER | __GFP_NOWARN, 0); 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: 415391e4deaSMichael S. Tsirkin mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0); 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, 444391e4deaSMichael S. Tsirkin GFP_HIGHUSER | __GFP_NOWARN, 0); 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 4671d1f19cfSMichael S. Tsirkin /* CPU writes to non-reserved MTTs, while HCA might DMA to reserved mtts */ 4681d1f19cfSMichael S. Tsirkin mdev->limits.reserved_mtts = ALIGN(mdev->limits.reserved_mtts * MTHCA_MTT_SEG_SIZE, 4691d1f19cfSMichael S. Tsirkin dma_get_cache_alignment()) / MTHCA_MTT_SEG_SIZE; 4701d1f19cfSMichael S. Tsirkin 4711da177e4SLinus Torvalds mdev->mr_table.mtt_table = mthca_alloc_icm_table(mdev, init_hca->mtt_base, 47244ea6687SRoland Dreier MTHCA_MTT_SEG_SIZE, 4731da177e4SLinus Torvalds mdev->limits.num_mtt_segs, 474391e4deaSMichael S. Tsirkin mdev->limits.reserved_mtts, 475391e4deaSMichael S. Tsirkin 1, 0); 4761da177e4SLinus Torvalds if (!mdev->mr_table.mtt_table) { 4771da177e4SLinus Torvalds mthca_err(mdev, "Failed to map MTT context memory, aborting.\n"); 4781da177e4SLinus Torvalds err = -ENOMEM; 4791da177e4SLinus Torvalds goto err_unmap_eq; 4801da177e4SLinus Torvalds } 4811da177e4SLinus Torvalds 4821da177e4SLinus Torvalds mdev->mr_table.mpt_table = mthca_alloc_icm_table(mdev, init_hca->mpt_base, 4831da177e4SLinus Torvalds dev_lim->mpt_entry_sz, 4841da177e4SLinus Torvalds mdev->limits.num_mpts, 485391e4deaSMichael S. Tsirkin mdev->limits.reserved_mrws, 486391e4deaSMichael S. Tsirkin 1, 1); 4871da177e4SLinus Torvalds if (!mdev->mr_table.mpt_table) { 4881da177e4SLinus Torvalds mthca_err(mdev, "Failed to map MPT context memory, aborting.\n"); 4891da177e4SLinus Torvalds err = -ENOMEM; 4901da177e4SLinus Torvalds goto err_unmap_mtt; 4911da177e4SLinus Torvalds } 4921da177e4SLinus Torvalds 4931da177e4SLinus Torvalds mdev->qp_table.qp_table = mthca_alloc_icm_table(mdev, init_hca->qpc_base, 4941da177e4SLinus Torvalds dev_lim->qpc_entry_sz, 4951da177e4SLinus Torvalds mdev->limits.num_qps, 496391e4deaSMichael S. Tsirkin mdev->limits.reserved_qps, 497391e4deaSMichael S. Tsirkin 0, 0); 4981da177e4SLinus Torvalds if (!mdev->qp_table.qp_table) { 4991da177e4SLinus Torvalds mthca_err(mdev, "Failed to map QP context memory, aborting.\n"); 5001da177e4SLinus Torvalds err = -ENOMEM; 5011da177e4SLinus Torvalds goto err_unmap_mpt; 5021da177e4SLinus Torvalds } 5031da177e4SLinus Torvalds 5041da177e4SLinus Torvalds mdev->qp_table.eqp_table = mthca_alloc_icm_table(mdev, init_hca->eqpc_base, 5051da177e4SLinus Torvalds dev_lim->eqpc_entry_sz, 5061da177e4SLinus Torvalds mdev->limits.num_qps, 507391e4deaSMichael S. Tsirkin mdev->limits.reserved_qps, 508391e4deaSMichael S. Tsirkin 0, 0); 5091da177e4SLinus Torvalds if (!mdev->qp_table.eqp_table) { 5101da177e4SLinus Torvalds mthca_err(mdev, "Failed to map EQP context memory, aborting.\n"); 5111da177e4SLinus Torvalds err = -ENOMEM; 5121da177e4SLinus Torvalds goto err_unmap_qp; 5131da177e4SLinus Torvalds } 5141da177e4SLinus Torvalds 51508aeb14eSRoland Dreier mdev->qp_table.rdb_table = mthca_alloc_icm_table(mdev, init_hca->rdb_base, 51608aeb14eSRoland Dreier MTHCA_RDB_ENTRY_SIZE, 51708aeb14eSRoland Dreier mdev->limits.num_qps << 518391e4deaSMichael S. Tsirkin mdev->qp_table.rdb_shift, 0, 51908aeb14eSRoland Dreier 0, 0); 52008aeb14eSRoland Dreier if (!mdev->qp_table.rdb_table) { 52108aeb14eSRoland Dreier mthca_err(mdev, "Failed to map RDB context memory, aborting\n"); 52208aeb14eSRoland Dreier err = -ENOMEM; 52319272d43SRoland Dreier goto err_unmap_eqp; 52408aeb14eSRoland Dreier } 52508aeb14eSRoland Dreier 5261da177e4SLinus Torvalds mdev->cq_table.table = mthca_alloc_icm_table(mdev, init_hca->cqc_base, 5271da177e4SLinus Torvalds dev_lim->cqc_entry_sz, 5281da177e4SLinus Torvalds mdev->limits.num_cqs, 529391e4deaSMichael S. Tsirkin mdev->limits.reserved_cqs, 530391e4deaSMichael S. Tsirkin 0, 0); 5311da177e4SLinus Torvalds if (!mdev->cq_table.table) { 5321da177e4SLinus Torvalds mthca_err(mdev, "Failed to map CQ context memory, aborting.\n"); 5331da177e4SLinus Torvalds err = -ENOMEM; 53408aeb14eSRoland Dreier goto err_unmap_rdb; 5351da177e4SLinus Torvalds } 5361da177e4SLinus Torvalds 537ec34a922SRoland Dreier if (mdev->mthca_flags & MTHCA_FLAG_SRQ) { 538ec34a922SRoland Dreier mdev->srq_table.table = 539ec34a922SRoland Dreier mthca_alloc_icm_table(mdev, init_hca->srqc_base, 540ec34a922SRoland Dreier dev_lim->srq_entry_sz, 541ec34a922SRoland Dreier mdev->limits.num_srqs, 542391e4deaSMichael S. Tsirkin mdev->limits.reserved_srqs, 543391e4deaSMichael S. Tsirkin 0, 0); 544ec34a922SRoland Dreier if (!mdev->srq_table.table) { 545ec34a922SRoland Dreier mthca_err(mdev, "Failed to map SRQ context memory, " 546ec34a922SRoland Dreier "aborting.\n"); 547ec34a922SRoland Dreier err = -ENOMEM; 548ec34a922SRoland Dreier goto err_unmap_cq; 549ec34a922SRoland Dreier } 550ec34a922SRoland Dreier } 551ec34a922SRoland Dreier 5521da177e4SLinus Torvalds /* 5531da177e4SLinus Torvalds * It's not strictly required, but for simplicity just map the 5541da177e4SLinus Torvalds * whole multicast group table now. The table isn't very big 5551da177e4SLinus Torvalds * and it's a lot easier than trying to track ref counts. 5561da177e4SLinus Torvalds */ 5571da177e4SLinus Torvalds mdev->mcg_table.table = mthca_alloc_icm_table(mdev, init_hca->mc_base, 5581da177e4SLinus Torvalds MTHCA_MGM_ENTRY_SIZE, 5591da177e4SLinus Torvalds mdev->limits.num_mgms + 5601da177e4SLinus Torvalds mdev->limits.num_amgms, 5611da177e4SLinus Torvalds mdev->limits.num_mgms + 5621da177e4SLinus Torvalds mdev->limits.num_amgms, 563391e4deaSMichael S. Tsirkin 0, 0); 5641da177e4SLinus Torvalds if (!mdev->mcg_table.table) { 5651da177e4SLinus Torvalds mthca_err(mdev, "Failed to map MCG context memory, aborting.\n"); 5661da177e4SLinus Torvalds err = -ENOMEM; 567ec34a922SRoland Dreier goto err_unmap_srq; 5681da177e4SLinus Torvalds } 5691da177e4SLinus Torvalds 5701da177e4SLinus Torvalds return 0; 5711da177e4SLinus Torvalds 572ec34a922SRoland Dreier err_unmap_srq: 573ec34a922SRoland Dreier if (mdev->mthca_flags & MTHCA_FLAG_SRQ) 574ec34a922SRoland Dreier mthca_free_icm_table(mdev, mdev->srq_table.table); 575ec34a922SRoland Dreier 5761da177e4SLinus Torvalds err_unmap_cq: 5771da177e4SLinus Torvalds mthca_free_icm_table(mdev, mdev->cq_table.table); 5781da177e4SLinus Torvalds 57908aeb14eSRoland Dreier err_unmap_rdb: 58008aeb14eSRoland Dreier mthca_free_icm_table(mdev, mdev->qp_table.rdb_table); 58108aeb14eSRoland Dreier 5821da177e4SLinus Torvalds err_unmap_eqp: 5831da177e4SLinus Torvalds mthca_free_icm_table(mdev, mdev->qp_table.eqp_table); 5841da177e4SLinus Torvalds 5851da177e4SLinus Torvalds err_unmap_qp: 5861da177e4SLinus Torvalds mthca_free_icm_table(mdev, mdev->qp_table.qp_table); 5871da177e4SLinus Torvalds 5881da177e4SLinus Torvalds err_unmap_mpt: 5891da177e4SLinus Torvalds mthca_free_icm_table(mdev, mdev->mr_table.mpt_table); 5901da177e4SLinus Torvalds 5911da177e4SLinus Torvalds err_unmap_mtt: 5921da177e4SLinus Torvalds mthca_free_icm_table(mdev, mdev->mr_table.mtt_table); 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds err_unmap_eq: 5951da177e4SLinus Torvalds mthca_unmap_eq_icm(mdev); 5961da177e4SLinus Torvalds 5971da177e4SLinus Torvalds err_unmap_aux: 5981da177e4SLinus Torvalds mthca_UNMAP_ICM_AUX(mdev, &status); 5991da177e4SLinus Torvalds 6001da177e4SLinus Torvalds err_free_aux: 601391e4deaSMichael S. Tsirkin mthca_free_icm(mdev, mdev->fw.arbel.aux_icm, 0); 6021da177e4SLinus Torvalds 6031da177e4SLinus Torvalds return err; 6041da177e4SLinus Torvalds } 6051da177e4SLinus Torvalds 606aba7a22fSMichael S. Tsirkin static void mthca_free_icms(struct mthca_dev *mdev) 607aba7a22fSMichael S. Tsirkin { 608aba7a22fSMichael S. Tsirkin u8 status; 609aba7a22fSMichael S. Tsirkin 610aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->mcg_table.table); 611aba7a22fSMichael S. Tsirkin if (mdev->mthca_flags & MTHCA_FLAG_SRQ) 612aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->srq_table.table); 613aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->cq_table.table); 614aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->qp_table.rdb_table); 615aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->qp_table.eqp_table); 616aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->qp_table.qp_table); 617aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->mr_table.mpt_table); 618aba7a22fSMichael S. Tsirkin mthca_free_icm_table(mdev, mdev->mr_table.mtt_table); 619aba7a22fSMichael S. Tsirkin mthca_unmap_eq_icm(mdev); 620aba7a22fSMichael S. Tsirkin 621aba7a22fSMichael S. Tsirkin mthca_UNMAP_ICM_AUX(mdev, &status); 622391e4deaSMichael S. Tsirkin mthca_free_icm(mdev, mdev->fw.arbel.aux_icm, 0); 623aba7a22fSMichael S. Tsirkin } 624aba7a22fSMichael S. Tsirkin 625f4f3d0f0SRoland Dreier static int mthca_init_arbel(struct mthca_dev *mdev) 6261da177e4SLinus Torvalds { 6271da177e4SLinus Torvalds struct mthca_dev_lim dev_lim; 6281da177e4SLinus Torvalds struct mthca_profile profile; 6291da177e4SLinus Torvalds struct mthca_init_hca_param init_hca; 6301da177e4SLinus Torvalds u64 icm_size; 6311da177e4SLinus Torvalds u8 status; 6321da177e4SLinus Torvalds int err; 6331da177e4SLinus Torvalds 6341da177e4SLinus Torvalds err = mthca_QUERY_FW(mdev, &status); 6351da177e4SLinus Torvalds if (err) { 6361da177e4SLinus Torvalds mthca_err(mdev, "QUERY_FW command failed, aborting.\n"); 6371da177e4SLinus Torvalds return err; 6381da177e4SLinus Torvalds } 6391da177e4SLinus Torvalds if (status) { 6401da177e4SLinus Torvalds mthca_err(mdev, "QUERY_FW returned status 0x%02x, " 6411da177e4SLinus Torvalds "aborting.\n", status); 6421da177e4SLinus Torvalds return -EINVAL; 6431da177e4SLinus Torvalds } 6441da177e4SLinus Torvalds 6451da177e4SLinus Torvalds err = mthca_ENABLE_LAM(mdev, &status); 6461da177e4SLinus Torvalds if (err) { 6471da177e4SLinus Torvalds mthca_err(mdev, "ENABLE_LAM command failed, aborting.\n"); 6481da177e4SLinus Torvalds return err; 6491da177e4SLinus Torvalds } 6501da177e4SLinus Torvalds if (status == MTHCA_CMD_STAT_LAM_NOT_PRE) { 6511da177e4SLinus Torvalds mthca_dbg(mdev, "No HCA-attached memory (running in MemFree mode)\n"); 6521da177e4SLinus Torvalds mdev->mthca_flags |= MTHCA_FLAG_NO_LAM; 6531da177e4SLinus Torvalds } else if (status) { 6541da177e4SLinus Torvalds mthca_err(mdev, "ENABLE_LAM returned status 0x%02x, " 6551da177e4SLinus Torvalds "aborting.\n", status); 6561da177e4SLinus Torvalds return -EINVAL; 6571da177e4SLinus Torvalds } 6581da177e4SLinus Torvalds 6591da177e4SLinus Torvalds err = mthca_load_fw(mdev); 6601da177e4SLinus Torvalds if (err) { 6611da177e4SLinus Torvalds mthca_err(mdev, "Failed to start FW, aborting.\n"); 6621da177e4SLinus Torvalds goto err_disable; 6631da177e4SLinus Torvalds } 6641da177e4SLinus Torvalds 6651da177e4SLinus Torvalds err = mthca_dev_lim(mdev, &dev_lim); 6661da177e4SLinus Torvalds if (err) { 6671da177e4SLinus Torvalds mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n"); 6681da177e4SLinus Torvalds goto err_stop_fw; 6691da177e4SLinus Torvalds } 6701da177e4SLinus Torvalds 67182da703eSLeonid Arsh profile = hca_profile; 6721da177e4SLinus Torvalds profile.num_uar = dev_lim.uar_size / PAGE_SIZE; 6731da177e4SLinus Torvalds profile.num_udav = 0; 674ec34a922SRoland Dreier if (mdev->mthca_flags & MTHCA_FLAG_SRQ) 675ec34a922SRoland Dreier profile.num_srq = dev_lim.max_srqs; 6761da177e4SLinus Torvalds 6771da177e4SLinus Torvalds icm_size = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca); 6781da177e4SLinus Torvalds if ((int) icm_size < 0) { 6791da177e4SLinus Torvalds err = icm_size; 6801da177e4SLinus Torvalds goto err_stop_fw; 6811da177e4SLinus Torvalds } 6821da177e4SLinus Torvalds 6831da177e4SLinus Torvalds err = mthca_init_icm(mdev, &dev_lim, &init_hca, icm_size); 6841da177e4SLinus Torvalds if (err) 6851da177e4SLinus Torvalds goto err_stop_fw; 6861da177e4SLinus Torvalds 6871da177e4SLinus Torvalds err = mthca_INIT_HCA(mdev, &init_hca, &status); 6881da177e4SLinus Torvalds if (err) { 6891da177e4SLinus Torvalds mthca_err(mdev, "INIT_HCA command failed, aborting.\n"); 6901da177e4SLinus Torvalds goto err_free_icm; 6911da177e4SLinus Torvalds } 6921da177e4SLinus Torvalds if (status) { 6931da177e4SLinus Torvalds mthca_err(mdev, "INIT_HCA returned status 0x%02x, " 6941da177e4SLinus Torvalds "aborting.\n", status); 6951da177e4SLinus Torvalds err = -EINVAL; 6961da177e4SLinus Torvalds goto err_free_icm; 6971da177e4SLinus Torvalds } 6981da177e4SLinus Torvalds 6991da177e4SLinus Torvalds return 0; 7001da177e4SLinus Torvalds 7011da177e4SLinus Torvalds err_free_icm: 702aba7a22fSMichael S. Tsirkin mthca_free_icms(mdev); 7031da177e4SLinus Torvalds 7041da177e4SLinus Torvalds err_stop_fw: 7051da177e4SLinus Torvalds mthca_UNMAP_FA(mdev, &status); 706391e4deaSMichael S. Tsirkin mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0); 7071da177e4SLinus Torvalds 7081da177e4SLinus Torvalds err_disable: 7091da177e4SLinus Torvalds if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM)) 7101da177e4SLinus Torvalds mthca_DISABLE_LAM(mdev, &status); 7111da177e4SLinus Torvalds 7121da177e4SLinus Torvalds return err; 7131da177e4SLinus Torvalds } 7141da177e4SLinus Torvalds 7152e8b981cSMichael S. Tsirkin static void mthca_close_hca(struct mthca_dev *mdev) 7162e8b981cSMichael S. Tsirkin { 7172e8b981cSMichael S. Tsirkin u8 status; 7182e8b981cSMichael S. Tsirkin 7192e8b981cSMichael S. Tsirkin mthca_CLOSE_HCA(mdev, 0, &status); 7202e8b981cSMichael S. Tsirkin 7212e8b981cSMichael S. Tsirkin if (mthca_is_memfree(mdev)) { 722aba7a22fSMichael S. Tsirkin mthca_free_icms(mdev); 7232e8b981cSMichael S. Tsirkin 7242e8b981cSMichael S. Tsirkin mthca_UNMAP_FA(mdev, &status); 725391e4deaSMichael S. Tsirkin mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0); 7262e8b981cSMichael S. Tsirkin 7272e8b981cSMichael S. Tsirkin if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM)) 7282e8b981cSMichael S. Tsirkin mthca_DISABLE_LAM(mdev, &status); 7292e8b981cSMichael S. Tsirkin } else 7302e8b981cSMichael S. Tsirkin mthca_SYS_DIS(mdev, &status); 7312e8b981cSMichael S. Tsirkin } 7322e8b981cSMichael S. Tsirkin 733f4f3d0f0SRoland Dreier static int mthca_init_hca(struct mthca_dev *mdev) 7341da177e4SLinus Torvalds { 7352e8b981cSMichael S. Tsirkin u8 status; 7362e8b981cSMichael S. Tsirkin int err; 7372e8b981cSMichael S. Tsirkin struct mthca_adapter adapter; 7382e8b981cSMichael S. Tsirkin 739d10ddbf6SRoland Dreier if (mthca_is_memfree(mdev)) 7402e8b981cSMichael S. Tsirkin err = mthca_init_arbel(mdev); 7411da177e4SLinus Torvalds else 7422e8b981cSMichael S. Tsirkin err = mthca_init_tavor(mdev); 7432e8b981cSMichael S. Tsirkin 7442e8b981cSMichael S. Tsirkin if (err) 7452e8b981cSMichael S. Tsirkin return err; 7462e8b981cSMichael S. Tsirkin 7472e8b981cSMichael S. Tsirkin err = mthca_QUERY_ADAPTER(mdev, &adapter, &status); 7482e8b981cSMichael S. Tsirkin if (err) { 7492e8b981cSMichael S. Tsirkin mthca_err(mdev, "QUERY_ADAPTER command failed, aborting.\n"); 7502e8b981cSMichael S. Tsirkin goto err_close; 7512e8b981cSMichael S. Tsirkin } 7522e8b981cSMichael S. Tsirkin if (status) { 7532e8b981cSMichael S. Tsirkin mthca_err(mdev, "QUERY_ADAPTER returned status 0x%02x, " 7542e8b981cSMichael S. Tsirkin "aborting.\n", status); 7552e8b981cSMichael S. Tsirkin err = -EINVAL; 7562e8b981cSMichael S. Tsirkin goto err_close; 7572e8b981cSMichael S. Tsirkin } 7582e8b981cSMichael S. Tsirkin 7592e8b981cSMichael S. Tsirkin mdev->eq_table.inta_pin = adapter.inta_pin; 7602e8b981cSMichael S. Tsirkin mdev->rev_id = adapter.revision_id; 7612e8b981cSMichael S. Tsirkin memcpy(mdev->board_id, adapter.board_id, sizeof mdev->board_id); 7622e8b981cSMichael S. Tsirkin 7632e8b981cSMichael S. Tsirkin return 0; 7642e8b981cSMichael S. Tsirkin 7652e8b981cSMichael S. Tsirkin err_close: 7662e8b981cSMichael S. Tsirkin mthca_close_hca(mdev); 7672e8b981cSMichael S. Tsirkin return err; 7681da177e4SLinus Torvalds } 7691da177e4SLinus Torvalds 770f4f3d0f0SRoland Dreier static int mthca_setup_hca(struct mthca_dev *dev) 7711da177e4SLinus Torvalds { 7721da177e4SLinus Torvalds int err; 7731da177e4SLinus Torvalds u8 status; 7741da177e4SLinus Torvalds 7751da177e4SLinus Torvalds MTHCA_INIT_DOORBELL_LOCK(&dev->doorbell_lock); 7761da177e4SLinus Torvalds 7771da177e4SLinus Torvalds err = mthca_init_uar_table(dev); 7781da177e4SLinus Torvalds if (err) { 7791da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 7801da177e4SLinus Torvalds "user access region table, aborting.\n"); 7811da177e4SLinus Torvalds return err; 7821da177e4SLinus Torvalds } 7831da177e4SLinus Torvalds 7841da177e4SLinus Torvalds err = mthca_uar_alloc(dev, &dev->driver_uar); 7851da177e4SLinus Torvalds if (err) { 7861da177e4SLinus Torvalds mthca_err(dev, "Failed to allocate driver access region, " 7871da177e4SLinus Torvalds "aborting.\n"); 7881da177e4SLinus Torvalds goto err_uar_table_free; 7891da177e4SLinus Torvalds } 7901da177e4SLinus Torvalds 7911da177e4SLinus Torvalds dev->kar = ioremap(dev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE); 7921da177e4SLinus Torvalds if (!dev->kar) { 7931da177e4SLinus Torvalds mthca_err(dev, "Couldn't map kernel access region, " 7941da177e4SLinus Torvalds "aborting.\n"); 7951da177e4SLinus Torvalds err = -ENOMEM; 7961da177e4SLinus Torvalds goto err_uar_free; 7971da177e4SLinus Torvalds } 7981da177e4SLinus Torvalds 7991da177e4SLinus Torvalds err = mthca_init_pd_table(dev); 8001da177e4SLinus Torvalds if (err) { 8011da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 8021da177e4SLinus Torvalds "protection domain table, aborting.\n"); 8031da177e4SLinus Torvalds goto err_kar_unmap; 8041da177e4SLinus Torvalds } 8051da177e4SLinus Torvalds 8061da177e4SLinus Torvalds err = mthca_init_mr_table(dev); 8071da177e4SLinus Torvalds if (err) { 8081da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 8091da177e4SLinus Torvalds "memory region table, aborting.\n"); 8101da177e4SLinus Torvalds goto err_pd_table_free; 8111da177e4SLinus Torvalds } 8121da177e4SLinus Torvalds 81399264c1eSRoland Dreier err = mthca_pd_alloc(dev, 1, &dev->driver_pd); 8141da177e4SLinus Torvalds if (err) { 8151da177e4SLinus Torvalds mthca_err(dev, "Failed to create driver PD, " 8161da177e4SLinus Torvalds "aborting.\n"); 8171da177e4SLinus Torvalds goto err_mr_table_free; 8181da177e4SLinus Torvalds } 8191da177e4SLinus Torvalds 8201da177e4SLinus Torvalds err = mthca_init_eq_table(dev); 8211da177e4SLinus Torvalds if (err) { 8221da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 8231da177e4SLinus Torvalds "event queue table, aborting.\n"); 8241da177e4SLinus Torvalds goto err_pd_free; 8251da177e4SLinus Torvalds } 8261da177e4SLinus Torvalds 8271da177e4SLinus Torvalds err = mthca_cmd_use_events(dev); 8281da177e4SLinus Torvalds if (err) { 8291da177e4SLinus Torvalds mthca_err(dev, "Failed to switch to event-driven " 8301da177e4SLinus Torvalds "firmware commands, aborting.\n"); 8311da177e4SLinus Torvalds goto err_eq_table_free; 8321da177e4SLinus Torvalds } 8331da177e4SLinus Torvalds 8341da177e4SLinus Torvalds err = mthca_NOP(dev, &status); 8351da177e4SLinus Torvalds if (err || status) { 8364ad81174SRoland Dreier mthca_err(dev, "NOP command failed to generate interrupt (IRQ %d), aborting.\n", 8374ad81174SRoland Dreier dev->mthca_flags & MTHCA_FLAG_MSI_X ? 8384ad81174SRoland Dreier dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector : 8394ad81174SRoland Dreier dev->pdev->irq); 8401da177e4SLinus Torvalds if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)) 8411da177e4SLinus Torvalds mthca_err(dev, "Try again with MSI/MSI-X disabled.\n"); 8421da177e4SLinus Torvalds else 8431da177e4SLinus Torvalds mthca_err(dev, "BIOS or ACPI interrupt routing problem?\n"); 8441da177e4SLinus Torvalds 8451da177e4SLinus Torvalds goto err_cmd_poll; 8461da177e4SLinus Torvalds } 8471da177e4SLinus Torvalds 8481da177e4SLinus Torvalds mthca_dbg(dev, "NOP command IRQ test passed\n"); 8491da177e4SLinus Torvalds 8501da177e4SLinus Torvalds err = mthca_init_cq_table(dev); 8511da177e4SLinus Torvalds if (err) { 8521da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 8531da177e4SLinus Torvalds "completion queue table, aborting.\n"); 8541da177e4SLinus Torvalds goto err_cmd_poll; 8551da177e4SLinus Torvalds } 8561da177e4SLinus Torvalds 857ec34a922SRoland Dreier err = mthca_init_srq_table(dev); 858ec34a922SRoland Dreier if (err) { 859ec34a922SRoland Dreier mthca_err(dev, "Failed to initialize " 860ec34a922SRoland Dreier "shared receive queue table, aborting.\n"); 861ec34a922SRoland Dreier goto err_cq_table_free; 862ec34a922SRoland Dreier } 863ec34a922SRoland Dreier 8641da177e4SLinus Torvalds err = mthca_init_qp_table(dev); 8651da177e4SLinus Torvalds if (err) { 8661da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 8671da177e4SLinus Torvalds "queue pair table, aborting.\n"); 868ec34a922SRoland Dreier goto err_srq_table_free; 8691da177e4SLinus Torvalds } 8701da177e4SLinus Torvalds 8711da177e4SLinus Torvalds err = mthca_init_av_table(dev); 8721da177e4SLinus Torvalds if (err) { 8731da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 8741da177e4SLinus Torvalds "address vector table, aborting.\n"); 8751da177e4SLinus Torvalds goto err_qp_table_free; 8761da177e4SLinus Torvalds } 8771da177e4SLinus Torvalds 8781da177e4SLinus Torvalds err = mthca_init_mcg_table(dev); 8791da177e4SLinus Torvalds if (err) { 8801da177e4SLinus Torvalds mthca_err(dev, "Failed to initialize " 8811da177e4SLinus Torvalds "multicast group table, aborting.\n"); 8821da177e4SLinus Torvalds goto err_av_table_free; 8831da177e4SLinus Torvalds } 8841da177e4SLinus Torvalds 8851da177e4SLinus Torvalds return 0; 8861da177e4SLinus Torvalds 8871da177e4SLinus Torvalds err_av_table_free: 8881da177e4SLinus Torvalds mthca_cleanup_av_table(dev); 8891da177e4SLinus Torvalds 8901da177e4SLinus Torvalds err_qp_table_free: 8911da177e4SLinus Torvalds mthca_cleanup_qp_table(dev); 8921da177e4SLinus Torvalds 893ec34a922SRoland Dreier err_srq_table_free: 894ec34a922SRoland Dreier mthca_cleanup_srq_table(dev); 895ec34a922SRoland Dreier 8961da177e4SLinus Torvalds err_cq_table_free: 8971da177e4SLinus Torvalds mthca_cleanup_cq_table(dev); 8981da177e4SLinus Torvalds 8991da177e4SLinus Torvalds err_cmd_poll: 9001da177e4SLinus Torvalds mthca_cmd_use_polling(dev); 9011da177e4SLinus Torvalds 9021da177e4SLinus Torvalds err_eq_table_free: 9031da177e4SLinus Torvalds mthca_cleanup_eq_table(dev); 9041da177e4SLinus Torvalds 9051da177e4SLinus Torvalds err_pd_free: 9061da177e4SLinus Torvalds mthca_pd_free(dev, &dev->driver_pd); 9071da177e4SLinus Torvalds 9081da177e4SLinus Torvalds err_mr_table_free: 9091da177e4SLinus Torvalds mthca_cleanup_mr_table(dev); 9101da177e4SLinus Torvalds 9111da177e4SLinus Torvalds err_pd_table_free: 9121da177e4SLinus Torvalds mthca_cleanup_pd_table(dev); 9131da177e4SLinus Torvalds 9141da177e4SLinus Torvalds err_kar_unmap: 9151da177e4SLinus Torvalds iounmap(dev->kar); 9161da177e4SLinus Torvalds 9171da177e4SLinus Torvalds err_uar_free: 9181da177e4SLinus Torvalds mthca_uar_free(dev, &dev->driver_uar); 9191da177e4SLinus Torvalds 9201da177e4SLinus Torvalds err_uar_table_free: 9211da177e4SLinus Torvalds mthca_cleanup_uar_table(dev); 9221da177e4SLinus Torvalds return err; 9231da177e4SLinus Torvalds } 9241da177e4SLinus Torvalds 925f4f3d0f0SRoland Dreier static int mthca_request_regions(struct pci_dev *pdev, int ddr_hidden) 9261da177e4SLinus Torvalds { 9271da177e4SLinus Torvalds int err; 9281da177e4SLinus Torvalds 9291da177e4SLinus Torvalds /* 9301da177e4SLinus Torvalds * We can't just use pci_request_regions() because the MSI-X 9311da177e4SLinus Torvalds * table is right in the middle of the first BAR. If we did 9321da177e4SLinus Torvalds * pci_request_region and grab all of the first BAR, then 9331da177e4SLinus Torvalds * setting up MSI-X would fail, since the PCI core wants to do 9341da177e4SLinus Torvalds * request_mem_region on the MSI-X vector table. 9351da177e4SLinus Torvalds * 9361da177e4SLinus Torvalds * So just request what we need right now, and request any 9371da177e4SLinus Torvalds * other regions we need when setting up EQs. 9381da177e4SLinus Torvalds */ 9391da177e4SLinus Torvalds if (!request_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE, 9401da177e4SLinus Torvalds MTHCA_HCR_SIZE, DRV_NAME)) 9411da177e4SLinus Torvalds return -EBUSY; 9421da177e4SLinus Torvalds 9431da177e4SLinus Torvalds err = pci_request_region(pdev, 2, DRV_NAME); 9441da177e4SLinus Torvalds if (err) 9451da177e4SLinus Torvalds goto err_bar2_failed; 9461da177e4SLinus Torvalds 9471da177e4SLinus Torvalds if (!ddr_hidden) { 9481da177e4SLinus Torvalds err = pci_request_region(pdev, 4, DRV_NAME); 9491da177e4SLinus Torvalds if (err) 9501da177e4SLinus Torvalds goto err_bar4_failed; 9511da177e4SLinus Torvalds } 9521da177e4SLinus Torvalds 9531da177e4SLinus Torvalds return 0; 9541da177e4SLinus Torvalds 9551da177e4SLinus Torvalds err_bar4_failed: 9561da177e4SLinus Torvalds pci_release_region(pdev, 2); 9571da177e4SLinus Torvalds 9581da177e4SLinus Torvalds err_bar2_failed: 9591da177e4SLinus Torvalds release_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE, 9601da177e4SLinus Torvalds MTHCA_HCR_SIZE); 9611da177e4SLinus Torvalds 9621da177e4SLinus Torvalds return err; 9631da177e4SLinus Torvalds } 9641da177e4SLinus Torvalds 9651da177e4SLinus Torvalds static void mthca_release_regions(struct pci_dev *pdev, 9661da177e4SLinus Torvalds int ddr_hidden) 9671da177e4SLinus Torvalds { 9681da177e4SLinus Torvalds if (!ddr_hidden) 9691da177e4SLinus Torvalds pci_release_region(pdev, 4); 9701da177e4SLinus Torvalds 9711da177e4SLinus Torvalds pci_release_region(pdev, 2); 9721da177e4SLinus Torvalds 9731da177e4SLinus Torvalds release_mem_region(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE, 9741da177e4SLinus Torvalds MTHCA_HCR_SIZE); 9751da177e4SLinus Torvalds } 9761da177e4SLinus Torvalds 977f4f3d0f0SRoland Dreier static int mthca_enable_msi_x(struct mthca_dev *mdev) 9781da177e4SLinus Torvalds { 9791da177e4SLinus Torvalds struct msix_entry entries[3]; 9801da177e4SLinus Torvalds int err; 9811da177e4SLinus Torvalds 9821da177e4SLinus Torvalds entries[0].entry = 0; 9831da177e4SLinus Torvalds entries[1].entry = 1; 9841da177e4SLinus Torvalds entries[2].entry = 2; 9851da177e4SLinus Torvalds 9861da177e4SLinus Torvalds err = pci_enable_msix(mdev->pdev, entries, ARRAY_SIZE(entries)); 9871da177e4SLinus Torvalds if (err) { 9881da177e4SLinus Torvalds if (err > 0) 9891da177e4SLinus Torvalds mthca_info(mdev, "Only %d MSI-X vectors available, " 9901da177e4SLinus Torvalds "not using MSI-X\n", err); 9911da177e4SLinus Torvalds return err; 9921da177e4SLinus Torvalds } 9931da177e4SLinus Torvalds 9941da177e4SLinus Torvalds mdev->eq_table.eq[MTHCA_EQ_COMP ].msi_x_vector = entries[0].vector; 9951da177e4SLinus Torvalds mdev->eq_table.eq[MTHCA_EQ_ASYNC].msi_x_vector = entries[1].vector; 9961da177e4SLinus Torvalds mdev->eq_table.eq[MTHCA_EQ_CMD ].msi_x_vector = entries[2].vector; 9971da177e4SLinus Torvalds 9981da177e4SLinus Torvalds return 0; 9991da177e4SLinus Torvalds } 10001da177e4SLinus Torvalds 100168a3c212SRoland Dreier /* Types of supported HCA */ 100268a3c212SRoland Dreier enum { 100368a3c212SRoland Dreier TAVOR, /* MT23108 */ 100468a3c212SRoland Dreier ARBEL_COMPAT, /* MT25208 in Tavor compat mode */ 100568a3c212SRoland Dreier ARBEL_NATIVE, /* MT25208 with extended features */ 100668a3c212SRoland Dreier SINAI /* MT25204 */ 100768a3c212SRoland Dreier }; 100868a3c212SRoland Dreier 100968a3c212SRoland Dreier #define MTHCA_FW_VER(major, minor, subminor) \ 101068a3c212SRoland Dreier (((u64) (major) << 32) | ((u64) (minor) << 16) | (u64) (subminor)) 101168a3c212SRoland Dreier 101268a3c212SRoland Dreier static struct { 101368a3c212SRoland Dreier u64 latest_fw; 1014651eaac9SEli Cohen u32 flags; 101568a3c212SRoland Dreier } mthca_hca_table[] = { 10163f114853SRoland Dreier [TAVOR] = { .latest_fw = MTHCA_FW_VER(3, 5, 0), 1017651eaac9SEli Cohen .flags = 0 }, 10183f114853SRoland Dreier [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 8, 200), 1019651eaac9SEli Cohen .flags = MTHCA_FLAG_PCIE }, 10203f114853SRoland Dreier [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 2, 0), 1021651eaac9SEli Cohen .flags = MTHCA_FLAG_MEMFREE | 1022651eaac9SEli Cohen MTHCA_FLAG_PCIE }, 10233f114853SRoland Dreier [SINAI] = { .latest_fw = MTHCA_FW_VER(1, 2, 0), 1024651eaac9SEli Cohen .flags = MTHCA_FLAG_MEMFREE | 1025651eaac9SEli Cohen MTHCA_FLAG_PCIE | 1026651eaac9SEli Cohen MTHCA_FLAG_SINAI_OPT } 102768a3c212SRoland Dreier }; 102868a3c212SRoland Dreier 1029b3b30f5eSJack Morgenstein static int __mthca_init_one(struct pci_dev *pdev, int hca_type) 10301da177e4SLinus Torvalds { 10311da177e4SLinus Torvalds int ddr_hidden = 0; 10321da177e4SLinus Torvalds int err; 10331da177e4SLinus Torvalds struct mthca_dev *mdev; 10341da177e4SLinus Torvalds 1035982245f0SAdrian Bunk printk(KERN_INFO PFX "Initializing %s\n", 1036982245f0SAdrian Bunk pci_name(pdev)); 10371da177e4SLinus Torvalds 10381da177e4SLinus Torvalds err = pci_enable_device(pdev); 10391da177e4SLinus Torvalds if (err) { 10401da177e4SLinus Torvalds dev_err(&pdev->dev, "Cannot enable PCI device, " 10411da177e4SLinus Torvalds "aborting.\n"); 10421da177e4SLinus Torvalds return err; 10431da177e4SLinus Torvalds } 10441da177e4SLinus Torvalds 10451da177e4SLinus Torvalds /* 10461da177e4SLinus Torvalds * Check for BARs. We expect 0: 1MB, 2: 8MB, 4: DDR (may not 10471da177e4SLinus Torvalds * be present) 10481da177e4SLinus Torvalds */ 10491da177e4SLinus Torvalds if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) || 10501da177e4SLinus Torvalds pci_resource_len(pdev, 0) != 1 << 20) { 1051177214afSBernhard Fischer dev_err(&pdev->dev, "Missing DCS, aborting.\n"); 10521da177e4SLinus Torvalds err = -ENODEV; 10531da177e4SLinus Torvalds goto err_disable_pdev; 10541da177e4SLinus Torvalds } 1055cbd2981aSMichael S. Tsirkin if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { 1056177214afSBernhard Fischer dev_err(&pdev->dev, "Missing UAR, aborting.\n"); 10571da177e4SLinus Torvalds err = -ENODEV; 10581da177e4SLinus Torvalds goto err_disable_pdev; 10591da177e4SLinus Torvalds } 10601da177e4SLinus Torvalds if (!(pci_resource_flags(pdev, 4) & IORESOURCE_MEM)) 10611da177e4SLinus Torvalds ddr_hidden = 1; 10621da177e4SLinus Torvalds 10631da177e4SLinus Torvalds err = mthca_request_regions(pdev, ddr_hidden); 10641da177e4SLinus Torvalds if (err) { 10651da177e4SLinus Torvalds dev_err(&pdev->dev, "Cannot obtain PCI resources, " 10661da177e4SLinus Torvalds "aborting.\n"); 10671da177e4SLinus Torvalds goto err_disable_pdev; 10681da177e4SLinus Torvalds } 10691da177e4SLinus Torvalds 10701da177e4SLinus Torvalds pci_set_master(pdev); 10711da177e4SLinus Torvalds 10721da177e4SLinus Torvalds err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); 10731da177e4SLinus Torvalds if (err) { 10741da177e4SLinus Torvalds dev_warn(&pdev->dev, "Warning: couldn't set 64-bit PCI DMA mask.\n"); 10751da177e4SLinus Torvalds err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); 10761da177e4SLinus Torvalds if (err) { 10771da177e4SLinus Torvalds dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting.\n"); 10781da177e4SLinus Torvalds goto err_free_res; 10791da177e4SLinus Torvalds } 10801da177e4SLinus Torvalds } 10811da177e4SLinus Torvalds err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); 10821da177e4SLinus Torvalds if (err) { 10831da177e4SLinus Torvalds dev_warn(&pdev->dev, "Warning: couldn't set 64-bit " 10841da177e4SLinus Torvalds "consistent PCI DMA mask.\n"); 10851da177e4SLinus Torvalds err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 10861da177e4SLinus Torvalds if (err) { 10871da177e4SLinus Torvalds dev_err(&pdev->dev, "Can't set consistent PCI DMA mask, " 10881da177e4SLinus Torvalds "aborting.\n"); 10891da177e4SLinus Torvalds goto err_free_res; 10901da177e4SLinus Torvalds } 10911da177e4SLinus Torvalds } 10921da177e4SLinus Torvalds 10931da177e4SLinus Torvalds mdev = (struct mthca_dev *) ib_alloc_device(sizeof *mdev); 10941da177e4SLinus Torvalds if (!mdev) { 10951da177e4SLinus Torvalds dev_err(&pdev->dev, "Device struct alloc failed, " 10961da177e4SLinus Torvalds "aborting.\n"); 10971da177e4SLinus Torvalds err = -ENOMEM; 10981da177e4SLinus Torvalds goto err_free_res; 10991da177e4SLinus Torvalds } 11001da177e4SLinus Torvalds 11011da177e4SLinus Torvalds mdev->pdev = pdev; 11021da177e4SLinus Torvalds 1103b3b30f5eSJack Morgenstein mdev->mthca_flags = mthca_hca_table[hca_type].flags; 11041da177e4SLinus Torvalds if (ddr_hidden) 11051da177e4SLinus Torvalds mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN; 11061da177e4SLinus Torvalds 11071da177e4SLinus Torvalds /* 11081da177e4SLinus Torvalds * Now reset the HCA before we touch the PCI capabilities or 11091da177e4SLinus Torvalds * attempt a firmware command, since a boot ROM may have left 11101da177e4SLinus Torvalds * the HCA in an undefined state. 11111da177e4SLinus Torvalds */ 11121da177e4SLinus Torvalds err = mthca_reset(mdev); 11131da177e4SLinus Torvalds if (err) { 11141da177e4SLinus Torvalds mthca_err(mdev, "Failed to reset HCA, aborting.\n"); 11151da177e4SLinus Torvalds goto err_free_dev; 11161da177e4SLinus Torvalds } 11171da177e4SLinus Torvalds 11181da177e4SLinus Torvalds if (msi_x && !mthca_enable_msi_x(mdev)) 11191da177e4SLinus Torvalds mdev->mthca_flags |= MTHCA_FLAG_MSI_X; 11201da177e4SLinus Torvalds if (msi && !(mdev->mthca_flags & MTHCA_FLAG_MSI_X) && 11211da177e4SLinus Torvalds !pci_enable_msi(pdev)) 11221da177e4SLinus Torvalds mdev->mthca_flags |= MTHCA_FLAG_MSI; 11231da177e4SLinus Torvalds 112480fd8238SRoland Dreier if (mthca_cmd_init(mdev)) { 112580fd8238SRoland Dreier mthca_err(mdev, "Failed to init command interface, aborting.\n"); 11261da177e4SLinus Torvalds goto err_free_dev; 11271da177e4SLinus Torvalds } 11281da177e4SLinus Torvalds 11291da177e4SLinus Torvalds err = mthca_tune_pci(mdev); 11301da177e4SLinus Torvalds if (err) 113180fd8238SRoland Dreier goto err_cmd; 11321da177e4SLinus Torvalds 11331da177e4SLinus Torvalds err = mthca_init_hca(mdev); 11341da177e4SLinus Torvalds if (err) 113580fd8238SRoland Dreier goto err_cmd; 11361da177e4SLinus Torvalds 1137b3b30f5eSJack Morgenstein if (mdev->fw_ver < mthca_hca_table[hca_type].latest_fw) { 11383f114853SRoland Dreier mthca_warn(mdev, "HCA FW version %d.%d.%3d is old (%d.%d.%3d is current).\n", 113968a3c212SRoland Dreier (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff, 114068a3c212SRoland Dreier (int) (mdev->fw_ver & 0xffff), 1141b3b30f5eSJack Morgenstein (int) (mthca_hca_table[hca_type].latest_fw >> 32), 1142b3b30f5eSJack Morgenstein (int) (mthca_hca_table[hca_type].latest_fw >> 16) & 0xffff, 1143b3b30f5eSJack Morgenstein (int) (mthca_hca_table[hca_type].latest_fw & 0xffff)); 114468a3c212SRoland Dreier mthca_warn(mdev, "If you have problems, try updating your HCA FW.\n"); 114568a3c212SRoland Dreier } 114668a3c212SRoland Dreier 11471da177e4SLinus Torvalds err = mthca_setup_hca(mdev); 11481da177e4SLinus Torvalds if (err) 11491da177e4SLinus Torvalds goto err_close; 11501da177e4SLinus Torvalds 11511da177e4SLinus Torvalds err = mthca_register_device(mdev); 11521da177e4SLinus Torvalds if (err) 11531da177e4SLinus Torvalds goto err_cleanup; 11541da177e4SLinus Torvalds 11551da177e4SLinus Torvalds err = mthca_create_agents(mdev); 11561da177e4SLinus Torvalds if (err) 11571da177e4SLinus Torvalds goto err_unregister; 11581da177e4SLinus Torvalds 11591da177e4SLinus Torvalds pci_set_drvdata(pdev, mdev); 1160b3b30f5eSJack Morgenstein mdev->hca_type = hca_type; 11611da177e4SLinus Torvalds 11621da177e4SLinus Torvalds return 0; 11631da177e4SLinus Torvalds 11641da177e4SLinus Torvalds err_unregister: 11651da177e4SLinus Torvalds mthca_unregister_device(mdev); 11661da177e4SLinus Torvalds 11671da177e4SLinus Torvalds err_cleanup: 11681da177e4SLinus Torvalds mthca_cleanup_mcg_table(mdev); 11691da177e4SLinus Torvalds mthca_cleanup_av_table(mdev); 11701da177e4SLinus Torvalds mthca_cleanup_qp_table(mdev); 1171ec34a922SRoland Dreier mthca_cleanup_srq_table(mdev); 11721da177e4SLinus Torvalds mthca_cleanup_cq_table(mdev); 11731da177e4SLinus Torvalds mthca_cmd_use_polling(mdev); 11741da177e4SLinus Torvalds mthca_cleanup_eq_table(mdev); 11751da177e4SLinus Torvalds 11761da177e4SLinus Torvalds mthca_pd_free(mdev, &mdev->driver_pd); 11771da177e4SLinus Torvalds 11781da177e4SLinus Torvalds mthca_cleanup_mr_table(mdev); 11791da177e4SLinus Torvalds mthca_cleanup_pd_table(mdev); 11801da177e4SLinus Torvalds mthca_cleanup_uar_table(mdev); 11811da177e4SLinus Torvalds 11821da177e4SLinus Torvalds err_close: 11831da177e4SLinus Torvalds mthca_close_hca(mdev); 11841da177e4SLinus Torvalds 118580fd8238SRoland Dreier err_cmd: 118680fd8238SRoland Dreier mthca_cmd_cleanup(mdev); 11871da177e4SLinus Torvalds 11881da177e4SLinus Torvalds err_free_dev: 11891da177e4SLinus Torvalds if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) 11901da177e4SLinus Torvalds pci_disable_msix(pdev); 11911da177e4SLinus Torvalds if (mdev->mthca_flags & MTHCA_FLAG_MSI) 11921da177e4SLinus Torvalds pci_disable_msi(pdev); 11931da177e4SLinus Torvalds 11941da177e4SLinus Torvalds ib_dealloc_device(&mdev->ib_dev); 11951da177e4SLinus Torvalds 11961da177e4SLinus Torvalds err_free_res: 11971da177e4SLinus Torvalds mthca_release_regions(pdev, ddr_hidden); 11981da177e4SLinus Torvalds 11991da177e4SLinus Torvalds err_disable_pdev: 12001da177e4SLinus Torvalds pci_disable_device(pdev); 12011da177e4SLinus Torvalds pci_set_drvdata(pdev, NULL); 12021da177e4SLinus Torvalds return err; 12031da177e4SLinus Torvalds } 12041da177e4SLinus Torvalds 1205b3b30f5eSJack Morgenstein static void __mthca_remove_one(struct pci_dev *pdev) 12061da177e4SLinus Torvalds { 12071da177e4SLinus Torvalds struct mthca_dev *mdev = pci_get_drvdata(pdev); 12081da177e4SLinus Torvalds u8 status; 12091da177e4SLinus Torvalds int p; 12101da177e4SLinus Torvalds 12111da177e4SLinus Torvalds if (mdev) { 12121da177e4SLinus Torvalds mthca_free_agents(mdev); 12131da177e4SLinus Torvalds mthca_unregister_device(mdev); 12141da177e4SLinus Torvalds 12151da177e4SLinus Torvalds for (p = 1; p <= mdev->limits.num_ports; ++p) 12161da177e4SLinus Torvalds mthca_CLOSE_IB(mdev, p, &status); 12171da177e4SLinus Torvalds 12181da177e4SLinus Torvalds mthca_cleanup_mcg_table(mdev); 12191da177e4SLinus Torvalds mthca_cleanup_av_table(mdev); 12201da177e4SLinus Torvalds mthca_cleanup_qp_table(mdev); 1221ec34a922SRoland Dreier mthca_cleanup_srq_table(mdev); 12221da177e4SLinus Torvalds mthca_cleanup_cq_table(mdev); 12231da177e4SLinus Torvalds mthca_cmd_use_polling(mdev); 12241da177e4SLinus Torvalds mthca_cleanup_eq_table(mdev); 12251da177e4SLinus Torvalds 12261da177e4SLinus Torvalds mthca_pd_free(mdev, &mdev->driver_pd); 12271da177e4SLinus Torvalds 12281da177e4SLinus Torvalds mthca_cleanup_mr_table(mdev); 12291da177e4SLinus Torvalds mthca_cleanup_pd_table(mdev); 12301da177e4SLinus Torvalds 12311da177e4SLinus Torvalds iounmap(mdev->kar); 12321da177e4SLinus Torvalds mthca_uar_free(mdev, &mdev->driver_uar); 12331da177e4SLinus Torvalds mthca_cleanup_uar_table(mdev); 12341da177e4SLinus Torvalds mthca_close_hca(mdev); 123580fd8238SRoland Dreier mthca_cmd_cleanup(mdev); 12361da177e4SLinus Torvalds 12371da177e4SLinus Torvalds if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) 12381da177e4SLinus Torvalds pci_disable_msix(pdev); 12391da177e4SLinus Torvalds if (mdev->mthca_flags & MTHCA_FLAG_MSI) 12401da177e4SLinus Torvalds pci_disable_msi(pdev); 12411da177e4SLinus Torvalds 12421da177e4SLinus Torvalds ib_dealloc_device(&mdev->ib_dev); 12431da177e4SLinus Torvalds mthca_release_regions(pdev, mdev->mthca_flags & 12441da177e4SLinus Torvalds MTHCA_FLAG_DDR_HIDDEN); 12451da177e4SLinus Torvalds pci_disable_device(pdev); 12461da177e4SLinus Torvalds pci_set_drvdata(pdev, NULL); 12471da177e4SLinus Torvalds } 12481da177e4SLinus Torvalds } 12491da177e4SLinus Torvalds 1250b3b30f5eSJack Morgenstein int __mthca_restart_one(struct pci_dev *pdev) 1251b3b30f5eSJack Morgenstein { 1252b3b30f5eSJack Morgenstein struct mthca_dev *mdev; 1253b3b30f5eSJack Morgenstein 1254b3b30f5eSJack Morgenstein mdev = pci_get_drvdata(pdev); 1255b3b30f5eSJack Morgenstein if (!mdev) 1256b3b30f5eSJack Morgenstein return -ENODEV; 1257b3b30f5eSJack Morgenstein __mthca_remove_one(pdev); 1258b3b30f5eSJack Morgenstein return __mthca_init_one(pdev, mdev->hca_type); 1259b3b30f5eSJack Morgenstein } 1260b3b30f5eSJack Morgenstein 1261b3b30f5eSJack Morgenstein static int __devinit mthca_init_one(struct pci_dev *pdev, 1262b3b30f5eSJack Morgenstein const struct pci_device_id *id) 1263b3b30f5eSJack Morgenstein { 1264b3b30f5eSJack Morgenstein static int mthca_version_printed = 0; 1265b3b30f5eSJack Morgenstein int ret; 1266b3b30f5eSJack Morgenstein 1267b3b30f5eSJack Morgenstein mutex_lock(&mthca_device_mutex); 1268b3b30f5eSJack Morgenstein 1269b3b30f5eSJack Morgenstein if (!mthca_version_printed) { 1270b3b30f5eSJack Morgenstein printk(KERN_INFO "%s", mthca_version); 1271b3b30f5eSJack Morgenstein ++mthca_version_printed; 1272b3b30f5eSJack Morgenstein } 1273b3b30f5eSJack Morgenstein 1274b3b30f5eSJack Morgenstein if (id->driver_data >= ARRAY_SIZE(mthca_hca_table)) { 1275b3b30f5eSJack Morgenstein printk(KERN_ERR PFX "%s has invalid driver data %lx\n", 1276b3b30f5eSJack Morgenstein pci_name(pdev), id->driver_data); 1277b3b30f5eSJack Morgenstein mutex_unlock(&mthca_device_mutex); 1278b3b30f5eSJack Morgenstein return -ENODEV; 1279b3b30f5eSJack Morgenstein } 1280b3b30f5eSJack Morgenstein 1281b3b30f5eSJack Morgenstein ret = __mthca_init_one(pdev, id->driver_data); 1282b3b30f5eSJack Morgenstein 1283b3b30f5eSJack Morgenstein mutex_unlock(&mthca_device_mutex); 1284b3b30f5eSJack Morgenstein 1285b3b30f5eSJack Morgenstein return ret; 1286b3b30f5eSJack Morgenstein } 1287b3b30f5eSJack Morgenstein 1288b3b30f5eSJack Morgenstein static void __devexit mthca_remove_one(struct pci_dev *pdev) 1289b3b30f5eSJack Morgenstein { 1290b3b30f5eSJack Morgenstein mutex_lock(&mthca_device_mutex); 1291b3b30f5eSJack Morgenstein __mthca_remove_one(pdev); 1292b3b30f5eSJack Morgenstein mutex_unlock(&mthca_device_mutex); 1293b3b30f5eSJack Morgenstein } 1294b3b30f5eSJack Morgenstein 12951da177e4SLinus Torvalds static struct pci_device_id mthca_pci_table[] = { 12961da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_TAVOR), 12971da177e4SLinus Torvalds .driver_data = TAVOR }, 12981da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_TAVOR), 12991da177e4SLinus Torvalds .driver_data = TAVOR }, 13001da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT), 13011da177e4SLinus Torvalds .driver_data = ARBEL_COMPAT }, 13021da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT), 13031da177e4SLinus Torvalds .driver_data = ARBEL_COMPAT }, 13041da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_ARBEL), 13051da177e4SLinus Torvalds .driver_data = ARBEL_NATIVE }, 13061da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_ARBEL), 13071da177e4SLinus Torvalds .driver_data = ARBEL_NATIVE }, 130868a3c212SRoland Dreier { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_SINAI), 130968a3c212SRoland Dreier .driver_data = SINAI }, 131068a3c212SRoland Dreier { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_SINAI), 131168a3c212SRoland Dreier .driver_data = SINAI }, 131268a3c212SRoland Dreier { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_SINAI_OLD), 131368a3c212SRoland Dreier .driver_data = SINAI }, 131468a3c212SRoland Dreier { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_SINAI_OLD), 131568a3c212SRoland Dreier .driver_data = SINAI }, 13161da177e4SLinus Torvalds { 0, } 13171da177e4SLinus Torvalds }; 13181da177e4SLinus Torvalds 13191da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, mthca_pci_table); 13201da177e4SLinus Torvalds 13211da177e4SLinus Torvalds static struct pci_driver mthca_driver = { 1322177214afSBernhard Fischer .name = DRV_NAME, 13231da177e4SLinus Torvalds .id_table = mthca_pci_table, 13241da177e4SLinus Torvalds .probe = mthca_init_one, 13251da177e4SLinus Torvalds .remove = __devexit_p(mthca_remove_one) 13261da177e4SLinus Torvalds }; 13271da177e4SLinus Torvalds 132882da703eSLeonid Arsh static void __init __mthca_check_profile_val(const char *name, int *pval, 132982da703eSLeonid Arsh int pval_default) 133082da703eSLeonid Arsh { 133182da703eSLeonid Arsh /* value must be positive and power of 2 */ 133282da703eSLeonid Arsh int old_pval = *pval; 133382da703eSLeonid Arsh 133482da703eSLeonid Arsh if (old_pval <= 0) 133582da703eSLeonid Arsh *pval = pval_default; 133682da703eSLeonid Arsh else 133782da703eSLeonid Arsh *pval = roundup_pow_of_two(old_pval); 133882da703eSLeonid Arsh 133982da703eSLeonid Arsh if (old_pval != *pval) { 134082da703eSLeonid Arsh printk(KERN_WARNING PFX "Invalid value %d for %s in module parameter.\n", 134182da703eSLeonid Arsh old_pval, name); 134282da703eSLeonid Arsh printk(KERN_WARNING PFX "Corrected %s to %d.\n", name, *pval); 134382da703eSLeonid Arsh } 134482da703eSLeonid Arsh } 134582da703eSLeonid Arsh 134682da703eSLeonid Arsh #define mthca_check_profile_val(name, default) \ 134782da703eSLeonid Arsh __mthca_check_profile_val(#name, &hca_profile.name, default) 134882da703eSLeonid Arsh 134982da703eSLeonid Arsh static void __init mthca_validate_profile(void) 135082da703eSLeonid Arsh { 135182da703eSLeonid Arsh mthca_check_profile_val(num_qp, MTHCA_DEFAULT_NUM_QP); 135282da703eSLeonid Arsh mthca_check_profile_val(rdb_per_qp, MTHCA_DEFAULT_RDB_PER_QP); 135382da703eSLeonid Arsh mthca_check_profile_val(num_cq, MTHCA_DEFAULT_NUM_CQ); 135482da703eSLeonid Arsh mthca_check_profile_val(num_mcg, MTHCA_DEFAULT_NUM_MCG); 135582da703eSLeonid Arsh mthca_check_profile_val(num_mpt, MTHCA_DEFAULT_NUM_MPT); 135682da703eSLeonid Arsh mthca_check_profile_val(num_mtt, MTHCA_DEFAULT_NUM_MTT); 135782da703eSLeonid Arsh mthca_check_profile_val(num_udav, MTHCA_DEFAULT_NUM_UDAV); 135882da703eSLeonid Arsh mthca_check_profile_val(fmr_reserved_mtts, MTHCA_DEFAULT_NUM_RESERVED_MTTS); 135982da703eSLeonid Arsh 136082da703eSLeonid Arsh if (hca_profile.fmr_reserved_mtts >= hca_profile.num_mtt) { 136182da703eSLeonid Arsh printk(KERN_WARNING PFX "Invalid fmr_reserved_mtts module parameter %d.\n", 136282da703eSLeonid Arsh hca_profile.fmr_reserved_mtts); 136382da703eSLeonid Arsh printk(KERN_WARNING PFX "(Must be smaller than num_mtt %d)\n", 136482da703eSLeonid Arsh hca_profile.num_mtt); 136582da703eSLeonid Arsh hca_profile.fmr_reserved_mtts = hca_profile.num_mtt / 2; 136682da703eSLeonid Arsh printk(KERN_WARNING PFX "Corrected fmr_reserved_mtts to %d.\n", 136782da703eSLeonid Arsh hca_profile.fmr_reserved_mtts); 136882da703eSLeonid Arsh } 136982da703eSLeonid Arsh } 137082da703eSLeonid Arsh 13711da177e4SLinus Torvalds static int __init mthca_init(void) 13721da177e4SLinus Torvalds { 13731da177e4SLinus Torvalds int ret; 13741da177e4SLinus Torvalds 137582da703eSLeonid Arsh mthca_validate_profile(); 137682da703eSLeonid Arsh 1377b3b30f5eSJack Morgenstein ret = mthca_catas_init(); 1378b3b30f5eSJack Morgenstein if (ret) 1379b3b30f5eSJack Morgenstein return ret; 1380b3b30f5eSJack Morgenstein 13811da177e4SLinus Torvalds ret = pci_register_driver(&mthca_driver); 1382b3b30f5eSJack Morgenstein if (ret < 0) { 1383b3b30f5eSJack Morgenstein mthca_catas_cleanup(); 1384b3b30f5eSJack Morgenstein return ret; 1385b3b30f5eSJack Morgenstein } 1386b3b30f5eSJack Morgenstein 1387b3b30f5eSJack Morgenstein return 0; 13881da177e4SLinus Torvalds } 13891da177e4SLinus Torvalds 13901da177e4SLinus Torvalds static void __exit mthca_cleanup(void) 13911da177e4SLinus Torvalds { 13921da177e4SLinus Torvalds pci_unregister_driver(&mthca_driver); 1393b3b30f5eSJack Morgenstein mthca_catas_cleanup(); 13941da177e4SLinus Torvalds } 13951da177e4SLinus Torvalds 13961da177e4SLinus Torvalds module_init(mthca_init); 13971da177e4SLinus Torvalds module_exit(mthca_cleanup); 1398