18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 38c2ecf20Sopenharmony_ci * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 48c2ecf20Sopenharmony_ci * Copyright (c) 2005 Mellanox Technologies. All rights reserved. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 78c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 88c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 98c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 108c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 138c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 148c2ecf20Sopenharmony_ci * conditions are met: 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 178c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 188c2ecf20Sopenharmony_ci * disclaimer. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 218c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 228c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 238c2ecf20Sopenharmony_ci * provided with the distribution. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 268c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 278c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 288c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 298c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 308c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 318c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 328c2ecf20Sopenharmony_ci * SOFTWARE. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include <linux/module.h> 368c2ecf20Sopenharmony_ci#include <linux/init.h> 378c2ecf20Sopenharmony_ci#include <linux/errno.h> 388c2ecf20Sopenharmony_ci#include <linux/pci.h> 398c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 408c2ecf20Sopenharmony_ci#include <linux/gfp.h> 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#include "mthca_dev.h" 438c2ecf20Sopenharmony_ci#include "mthca_config_reg.h" 448c2ecf20Sopenharmony_ci#include "mthca_cmd.h" 458c2ecf20Sopenharmony_ci#include "mthca_profile.h" 468c2ecf20Sopenharmony_ci#include "mthca_memfree.h" 478c2ecf20Sopenharmony_ci#include "mthca_wqe.h" 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ciMODULE_AUTHOR("Roland Dreier"); 508c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Mellanox InfiniBand HCA low-level driver"); 518c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#ifdef CONFIG_INFINIBAND_MTHCA_DEBUG 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ciint mthca_debug_level = 0; 568c2ecf20Sopenharmony_cimodule_param_named(debug_level, mthca_debug_level, int, 0644); 578c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#endif /* CONFIG_INFINIBAND_MTHCA_DEBUG */ 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_MSI 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic int msi_x = 1; 648c2ecf20Sopenharmony_cimodule_param(msi_x, int, 0444); 658c2ecf20Sopenharmony_ciMODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero"); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#else /* CONFIG_PCI_MSI */ 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define msi_x (0) 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI_MSI */ 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic int tune_pci = 0; 748c2ecf20Sopenharmony_cimodule_param(tune_pci, int, 0444); 758c2ecf20Sopenharmony_ciMODULE_PARM_DESC(tune_pci, "increase PCI burst from the default set by BIOS if nonzero"); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ciDEFINE_MUTEX(mthca_device_mutex); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#define MTHCA_DEFAULT_NUM_QP (1 << 16) 808c2ecf20Sopenharmony_ci#define MTHCA_DEFAULT_RDB_PER_QP (1 << 2) 818c2ecf20Sopenharmony_ci#define MTHCA_DEFAULT_NUM_CQ (1 << 16) 828c2ecf20Sopenharmony_ci#define MTHCA_DEFAULT_NUM_MCG (1 << 13) 838c2ecf20Sopenharmony_ci#define MTHCA_DEFAULT_NUM_MPT (1 << 17) 848c2ecf20Sopenharmony_ci#define MTHCA_DEFAULT_NUM_MTT (1 << 20) 858c2ecf20Sopenharmony_ci#define MTHCA_DEFAULT_NUM_UDAV (1 << 15) 868c2ecf20Sopenharmony_ci#define MTHCA_DEFAULT_NUM_RESERVED_MTTS (1 << 18) 878c2ecf20Sopenharmony_ci#define MTHCA_DEFAULT_NUM_UARC_SIZE (1 << 18) 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic struct mthca_profile hca_profile = { 908c2ecf20Sopenharmony_ci .num_qp = MTHCA_DEFAULT_NUM_QP, 918c2ecf20Sopenharmony_ci .rdb_per_qp = MTHCA_DEFAULT_RDB_PER_QP, 928c2ecf20Sopenharmony_ci .num_cq = MTHCA_DEFAULT_NUM_CQ, 938c2ecf20Sopenharmony_ci .num_mcg = MTHCA_DEFAULT_NUM_MCG, 948c2ecf20Sopenharmony_ci .num_mpt = MTHCA_DEFAULT_NUM_MPT, 958c2ecf20Sopenharmony_ci .num_mtt = MTHCA_DEFAULT_NUM_MTT, 968c2ecf20Sopenharmony_ci .num_udav = MTHCA_DEFAULT_NUM_UDAV, /* Tavor only */ 978c2ecf20Sopenharmony_ci .fmr_reserved_mtts = MTHCA_DEFAULT_NUM_RESERVED_MTTS, /* Tavor only */ 988c2ecf20Sopenharmony_ci .uarc_size = MTHCA_DEFAULT_NUM_UARC_SIZE, /* Arbel only */ 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cimodule_param_named(num_qp, hca_profile.num_qp, int, 0444); 1028c2ecf20Sopenharmony_ciMODULE_PARM_DESC(num_qp, "maximum number of QPs per HCA"); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cimodule_param_named(rdb_per_qp, hca_profile.rdb_per_qp, int, 0444); 1058c2ecf20Sopenharmony_ciMODULE_PARM_DESC(rdb_per_qp, "number of RDB buffers per QP"); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cimodule_param_named(num_cq, hca_profile.num_cq, int, 0444); 1088c2ecf20Sopenharmony_ciMODULE_PARM_DESC(num_cq, "maximum number of CQs per HCA"); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cimodule_param_named(num_mcg, hca_profile.num_mcg, int, 0444); 1118c2ecf20Sopenharmony_ciMODULE_PARM_DESC(num_mcg, "maximum number of multicast groups per HCA"); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cimodule_param_named(num_mpt, hca_profile.num_mpt, int, 0444); 1148c2ecf20Sopenharmony_ciMODULE_PARM_DESC(num_mpt, 1158c2ecf20Sopenharmony_ci "maximum number of memory protection table entries per HCA"); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cimodule_param_named(num_mtt, hca_profile.num_mtt, int, 0444); 1188c2ecf20Sopenharmony_ciMODULE_PARM_DESC(num_mtt, 1198c2ecf20Sopenharmony_ci "maximum number of memory translation table segments per HCA"); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cimodule_param_named(num_udav, hca_profile.num_udav, int, 0444); 1228c2ecf20Sopenharmony_ciMODULE_PARM_DESC(num_udav, "maximum number of UD address vectors per HCA"); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cimodule_param_named(fmr_reserved_mtts, hca_profile.fmr_reserved_mtts, int, 0444); 1258c2ecf20Sopenharmony_ciMODULE_PARM_DESC(fmr_reserved_mtts, 1268c2ecf20Sopenharmony_ci "number of memory translation table segments reserved for FMR"); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic int log_mtts_per_seg = ilog2(MTHCA_MTT_SEG_SIZE / 8); 1298c2ecf20Sopenharmony_cimodule_param_named(log_mtts_per_seg, log_mtts_per_seg, int, 0444); 1308c2ecf20Sopenharmony_ciMODULE_PARM_DESC(log_mtts_per_seg, "Log2 number of MTT entries per segment (1-5)"); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic char mthca_version[] = 1338c2ecf20Sopenharmony_ci DRV_NAME ": Mellanox InfiniBand HCA driver v" 1348c2ecf20Sopenharmony_ci DRV_VERSION " (" DRV_RELDATE ")\n"; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic int mthca_tune_pci(struct mthca_dev *mdev) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci if (!tune_pci) 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* First try to max out Read Byte Count */ 1428c2ecf20Sopenharmony_ci if (pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX)) { 1438c2ecf20Sopenharmony_ci if (pcix_set_mmrbc(mdev->pdev, pcix_get_max_mmrbc(mdev->pdev))) { 1448c2ecf20Sopenharmony_ci mthca_err(mdev, "Couldn't set PCI-X max read count, " 1458c2ecf20Sopenharmony_ci "aborting.\n"); 1468c2ecf20Sopenharmony_ci return -ENODEV; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci } else if (!(mdev->mthca_flags & MTHCA_FLAG_PCIE)) 1498c2ecf20Sopenharmony_ci mthca_info(mdev, "No PCI-X capability, not setting RBC.\n"); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (pci_is_pcie(mdev->pdev)) { 1528c2ecf20Sopenharmony_ci if (pcie_set_readrq(mdev->pdev, 4096)) { 1538c2ecf20Sopenharmony_ci mthca_err(mdev, "Couldn't write PCI Express read request, " 1548c2ecf20Sopenharmony_ci "aborting.\n"); 1558c2ecf20Sopenharmony_ci return -ENODEV; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci } else if (mdev->mthca_flags & MTHCA_FLAG_PCIE) 1588c2ecf20Sopenharmony_ci mthca_info(mdev, "No PCI Express capability, " 1598c2ecf20Sopenharmony_ci "not setting Max Read Request Size.\n"); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim *dev_lim) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci int err; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci mdev->limits.mtt_seg_size = (1 << log_mtts_per_seg) * 8; 1698c2ecf20Sopenharmony_ci err = mthca_QUERY_DEV_LIM(mdev, dev_lim); 1708c2ecf20Sopenharmony_ci if (err) { 1718c2ecf20Sopenharmony_ci mthca_err(mdev, "QUERY_DEV_LIM command returned %d" 1728c2ecf20Sopenharmony_ci ", aborting.\n", err); 1738c2ecf20Sopenharmony_ci return err; 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci if (dev_lim->min_page_sz > PAGE_SIZE) { 1768c2ecf20Sopenharmony_ci mthca_err(mdev, "HCA minimum page size of %d bigger than " 1778c2ecf20Sopenharmony_ci "kernel PAGE_SIZE of %ld, aborting.\n", 1788c2ecf20Sopenharmony_ci dev_lim->min_page_sz, PAGE_SIZE); 1798c2ecf20Sopenharmony_ci return -ENODEV; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci if (dev_lim->num_ports > MTHCA_MAX_PORTS) { 1828c2ecf20Sopenharmony_ci mthca_err(mdev, "HCA has %d ports, but we only support %d, " 1838c2ecf20Sopenharmony_ci "aborting.\n", 1848c2ecf20Sopenharmony_ci dev_lim->num_ports, MTHCA_MAX_PORTS); 1858c2ecf20Sopenharmony_ci return -ENODEV; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (dev_lim->uar_size > pci_resource_len(mdev->pdev, 2)) { 1898c2ecf20Sopenharmony_ci mthca_err(mdev, "HCA reported UAR size of 0x%x bigger than " 1908c2ecf20Sopenharmony_ci "PCI resource 2 size of 0x%llx, aborting.\n", 1918c2ecf20Sopenharmony_ci dev_lim->uar_size, 1928c2ecf20Sopenharmony_ci (unsigned long long)pci_resource_len(mdev->pdev, 2)); 1938c2ecf20Sopenharmony_ci return -ENODEV; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci mdev->limits.num_ports = dev_lim->num_ports; 1978c2ecf20Sopenharmony_ci mdev->limits.vl_cap = dev_lim->max_vl; 1988c2ecf20Sopenharmony_ci mdev->limits.mtu_cap = dev_lim->max_mtu; 1998c2ecf20Sopenharmony_ci mdev->limits.gid_table_len = dev_lim->max_gids; 2008c2ecf20Sopenharmony_ci mdev->limits.pkey_table_len = dev_lim->max_pkeys; 2018c2ecf20Sopenharmony_ci mdev->limits.local_ca_ack_delay = dev_lim->local_ca_ack_delay; 2028c2ecf20Sopenharmony_ci /* 2038c2ecf20Sopenharmony_ci * Need to allow for worst case send WQE overhead and check 2048c2ecf20Sopenharmony_ci * whether max_desc_sz imposes a lower limit than max_sg; UD 2058c2ecf20Sopenharmony_ci * send has the biggest overhead. 2068c2ecf20Sopenharmony_ci */ 2078c2ecf20Sopenharmony_ci mdev->limits.max_sg = min_t(int, dev_lim->max_sg, 2088c2ecf20Sopenharmony_ci (dev_lim->max_desc_sz - 2098c2ecf20Sopenharmony_ci sizeof (struct mthca_next_seg) - 2108c2ecf20Sopenharmony_ci (mthca_is_memfree(mdev) ? 2118c2ecf20Sopenharmony_ci sizeof (struct mthca_arbel_ud_seg) : 2128c2ecf20Sopenharmony_ci sizeof (struct mthca_tavor_ud_seg))) / 2138c2ecf20Sopenharmony_ci sizeof (struct mthca_data_seg)); 2148c2ecf20Sopenharmony_ci mdev->limits.max_wqes = dev_lim->max_qp_sz; 2158c2ecf20Sopenharmony_ci mdev->limits.max_qp_init_rdma = dev_lim->max_requester_per_qp; 2168c2ecf20Sopenharmony_ci mdev->limits.reserved_qps = dev_lim->reserved_qps; 2178c2ecf20Sopenharmony_ci mdev->limits.max_srq_wqes = dev_lim->max_srq_sz; 2188c2ecf20Sopenharmony_ci mdev->limits.reserved_srqs = dev_lim->reserved_srqs; 2198c2ecf20Sopenharmony_ci mdev->limits.reserved_eecs = dev_lim->reserved_eecs; 2208c2ecf20Sopenharmony_ci mdev->limits.max_desc_sz = dev_lim->max_desc_sz; 2218c2ecf20Sopenharmony_ci mdev->limits.max_srq_sge = mthca_max_srq_sge(mdev); 2228c2ecf20Sopenharmony_ci /* 2238c2ecf20Sopenharmony_ci * Subtract 1 from the limit because we need to allocate a 2248c2ecf20Sopenharmony_ci * spare CQE so the HCA HW can tell the difference between an 2258c2ecf20Sopenharmony_ci * empty CQ and a full CQ. 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_ci mdev->limits.max_cqes = dev_lim->max_cq_sz - 1; 2288c2ecf20Sopenharmony_ci mdev->limits.reserved_cqs = dev_lim->reserved_cqs; 2298c2ecf20Sopenharmony_ci mdev->limits.reserved_eqs = dev_lim->reserved_eqs; 2308c2ecf20Sopenharmony_ci mdev->limits.reserved_mtts = dev_lim->reserved_mtts; 2318c2ecf20Sopenharmony_ci mdev->limits.reserved_mrws = dev_lim->reserved_mrws; 2328c2ecf20Sopenharmony_ci mdev->limits.reserved_uars = dev_lim->reserved_uars; 2338c2ecf20Sopenharmony_ci mdev->limits.reserved_pds = dev_lim->reserved_pds; 2348c2ecf20Sopenharmony_ci mdev->limits.port_width_cap = dev_lim->max_port_width; 2358c2ecf20Sopenharmony_ci mdev->limits.page_size_cap = ~(u32) (dev_lim->min_page_sz - 1); 2368c2ecf20Sopenharmony_ci mdev->limits.flags = dev_lim->flags; 2378c2ecf20Sopenharmony_ci /* 2388c2ecf20Sopenharmony_ci * For old FW that doesn't return static rate support, use a 2398c2ecf20Sopenharmony_ci * value of 0x3 (only static rate values of 0 or 1 are handled), 2408c2ecf20Sopenharmony_ci * except on Sinai, where even old FW can handle static rate 2418c2ecf20Sopenharmony_ci * values of 2 and 3. 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_ci if (dev_lim->stat_rate_support) 2448c2ecf20Sopenharmony_ci mdev->limits.stat_rate_support = dev_lim->stat_rate_support; 2458c2ecf20Sopenharmony_ci else if (mdev->mthca_flags & MTHCA_FLAG_SINAI_OPT) 2468c2ecf20Sopenharmony_ci mdev->limits.stat_rate_support = 0xf; 2478c2ecf20Sopenharmony_ci else 2488c2ecf20Sopenharmony_ci mdev->limits.stat_rate_support = 0x3; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* IB_DEVICE_RESIZE_MAX_WR not supported by driver. 2518c2ecf20Sopenharmony_ci May be doable since hardware supports it for SRQ. 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci IB_DEVICE_N_NOTIFY_CQ is supported by hardware but not by driver. 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci IB_DEVICE_SRQ_RESIZE is supported by hardware but SRQ is not 2568c2ecf20Sopenharmony_ci supported by driver. */ 2578c2ecf20Sopenharmony_ci mdev->device_cap_flags = IB_DEVICE_CHANGE_PHY_PORT | 2588c2ecf20Sopenharmony_ci IB_DEVICE_PORT_ACTIVE_EVENT | 2598c2ecf20Sopenharmony_ci IB_DEVICE_SYS_IMAGE_GUID | 2608c2ecf20Sopenharmony_ci IB_DEVICE_RC_RNR_NAK_GEN; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (dev_lim->flags & DEV_LIM_FLAG_BAD_PKEY_CNTR) 2638c2ecf20Sopenharmony_ci mdev->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (dev_lim->flags & DEV_LIM_FLAG_BAD_QKEY_CNTR) 2668c2ecf20Sopenharmony_ci mdev->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (dev_lim->flags & DEV_LIM_FLAG_RAW_MULTI) 2698c2ecf20Sopenharmony_ci mdev->device_cap_flags |= IB_DEVICE_RAW_MULTI; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (dev_lim->flags & DEV_LIM_FLAG_AUTO_PATH_MIG) 2728c2ecf20Sopenharmony_ci mdev->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (dev_lim->flags & DEV_LIM_FLAG_UD_AV_PORT_ENFORCE) 2758c2ecf20Sopenharmony_ci mdev->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (dev_lim->flags & DEV_LIM_FLAG_SRQ) 2788c2ecf20Sopenharmony_ci mdev->mthca_flags |= MTHCA_FLAG_SRQ; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (mthca_is_memfree(mdev)) 2818c2ecf20Sopenharmony_ci if (dev_lim->flags & DEV_LIM_FLAG_IPOIB_CSUM) 2828c2ecf20Sopenharmony_ci mdev->device_cap_flags |= IB_DEVICE_UD_IP_CSUM; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci return 0; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic int mthca_init_tavor(struct mthca_dev *mdev) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci s64 size; 2908c2ecf20Sopenharmony_ci int err; 2918c2ecf20Sopenharmony_ci struct mthca_dev_lim dev_lim; 2928c2ecf20Sopenharmony_ci struct mthca_profile profile; 2938c2ecf20Sopenharmony_ci struct mthca_init_hca_param init_hca; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci err = mthca_SYS_EN(mdev); 2968c2ecf20Sopenharmony_ci if (err) { 2978c2ecf20Sopenharmony_ci mthca_err(mdev, "SYS_EN command returned %d, aborting.\n", err); 2988c2ecf20Sopenharmony_ci return err; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci err = mthca_QUERY_FW(mdev); 3028c2ecf20Sopenharmony_ci if (err) { 3038c2ecf20Sopenharmony_ci mthca_err(mdev, "QUERY_FW command returned %d," 3048c2ecf20Sopenharmony_ci " aborting.\n", err); 3058c2ecf20Sopenharmony_ci goto err_disable; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci err = mthca_QUERY_DDR(mdev); 3088c2ecf20Sopenharmony_ci if (err) { 3098c2ecf20Sopenharmony_ci mthca_err(mdev, "QUERY_DDR command returned %d, aborting.\n", err); 3108c2ecf20Sopenharmony_ci goto err_disable; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci err = mthca_dev_lim(mdev, &dev_lim); 3148c2ecf20Sopenharmony_ci if (err) { 3158c2ecf20Sopenharmony_ci mthca_err(mdev, "QUERY_DEV_LIM command returned %d, aborting.\n", err); 3168c2ecf20Sopenharmony_ci goto err_disable; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci profile = hca_profile; 3208c2ecf20Sopenharmony_ci profile.num_uar = dev_lim.uar_size / PAGE_SIZE; 3218c2ecf20Sopenharmony_ci profile.uarc_size = 0; 3228c2ecf20Sopenharmony_ci if (mdev->mthca_flags & MTHCA_FLAG_SRQ) 3238c2ecf20Sopenharmony_ci profile.num_srq = dev_lim.max_srqs; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci size = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca); 3268c2ecf20Sopenharmony_ci if (size < 0) { 3278c2ecf20Sopenharmony_ci err = size; 3288c2ecf20Sopenharmony_ci goto err_disable; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci err = mthca_INIT_HCA(mdev, &init_hca); 3328c2ecf20Sopenharmony_ci if (err) { 3338c2ecf20Sopenharmony_ci mthca_err(mdev, "INIT_HCA command returned %d, aborting.\n", err); 3348c2ecf20Sopenharmony_ci goto err_disable; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return 0; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cierr_disable: 3408c2ecf20Sopenharmony_ci mthca_SYS_DIS(mdev); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci return err; 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic int mthca_load_fw(struct mthca_dev *mdev) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci int err; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /* FIXME: use HCA-attached memory for FW if present */ 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci mdev->fw.arbel.fw_icm = 3528c2ecf20Sopenharmony_ci mthca_alloc_icm(mdev, mdev->fw.arbel.fw_pages, 3538c2ecf20Sopenharmony_ci GFP_HIGHUSER | __GFP_NOWARN, 0); 3548c2ecf20Sopenharmony_ci if (!mdev->fw.arbel.fw_icm) { 3558c2ecf20Sopenharmony_ci mthca_err(mdev, "Couldn't allocate FW area, aborting.\n"); 3568c2ecf20Sopenharmony_ci return -ENOMEM; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci err = mthca_MAP_FA(mdev, mdev->fw.arbel.fw_icm); 3608c2ecf20Sopenharmony_ci if (err) { 3618c2ecf20Sopenharmony_ci mthca_err(mdev, "MAP_FA command returned %d, aborting.\n", err); 3628c2ecf20Sopenharmony_ci goto err_free; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci err = mthca_RUN_FW(mdev); 3658c2ecf20Sopenharmony_ci if (err) { 3668c2ecf20Sopenharmony_ci mthca_err(mdev, "RUN_FW command returned %d, aborting.\n", err); 3678c2ecf20Sopenharmony_ci goto err_unmap_fa; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci return 0; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cierr_unmap_fa: 3738c2ecf20Sopenharmony_ci mthca_UNMAP_FA(mdev); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cierr_free: 3768c2ecf20Sopenharmony_ci mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0); 3778c2ecf20Sopenharmony_ci return err; 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic int mthca_init_icm(struct mthca_dev *mdev, 3818c2ecf20Sopenharmony_ci struct mthca_dev_lim *dev_lim, 3828c2ecf20Sopenharmony_ci struct mthca_init_hca_param *init_hca, 3838c2ecf20Sopenharmony_ci u64 icm_size) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci u64 aux_pages = 0; 3868c2ecf20Sopenharmony_ci int err; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci err = mthca_SET_ICM_SIZE(mdev, icm_size, &aux_pages); 3898c2ecf20Sopenharmony_ci if (err) { 3908c2ecf20Sopenharmony_ci mthca_err(mdev, "SET_ICM_SIZE command returned %d, aborting.\n", err); 3918c2ecf20Sopenharmony_ci return err; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci mthca_dbg(mdev, "%lld KB of HCA context requires %lld KB aux memory.\n", 3958c2ecf20Sopenharmony_ci (unsigned long long) icm_size >> 10, 3968c2ecf20Sopenharmony_ci (unsigned long long) aux_pages << 2); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci mdev->fw.arbel.aux_icm = mthca_alloc_icm(mdev, aux_pages, 3998c2ecf20Sopenharmony_ci GFP_HIGHUSER | __GFP_NOWARN, 0); 4008c2ecf20Sopenharmony_ci if (!mdev->fw.arbel.aux_icm) { 4018c2ecf20Sopenharmony_ci mthca_err(mdev, "Couldn't allocate aux memory, aborting.\n"); 4028c2ecf20Sopenharmony_ci return -ENOMEM; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci err = mthca_MAP_ICM_AUX(mdev, mdev->fw.arbel.aux_icm); 4068c2ecf20Sopenharmony_ci if (err) { 4078c2ecf20Sopenharmony_ci mthca_err(mdev, "MAP_ICM_AUX returned %d, aborting.\n", err); 4088c2ecf20Sopenharmony_ci goto err_free_aux; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci err = mthca_map_eq_icm(mdev, init_hca->eqc_base); 4128c2ecf20Sopenharmony_ci if (err) { 4138c2ecf20Sopenharmony_ci mthca_err(mdev, "Failed to map EQ context memory, aborting.\n"); 4148c2ecf20Sopenharmony_ci goto err_unmap_aux; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* CPU writes to non-reserved MTTs, while HCA might DMA to reserved mtts */ 4188c2ecf20Sopenharmony_ci mdev->limits.reserved_mtts = ALIGN(mdev->limits.reserved_mtts * mdev->limits.mtt_seg_size, 4198c2ecf20Sopenharmony_ci dma_get_cache_alignment()) / mdev->limits.mtt_seg_size; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci mdev->mr_table.mtt_table = mthca_alloc_icm_table(mdev, init_hca->mtt_base, 4228c2ecf20Sopenharmony_ci mdev->limits.mtt_seg_size, 4238c2ecf20Sopenharmony_ci mdev->limits.num_mtt_segs, 4248c2ecf20Sopenharmony_ci mdev->limits.reserved_mtts, 4258c2ecf20Sopenharmony_ci 1, 0); 4268c2ecf20Sopenharmony_ci if (!mdev->mr_table.mtt_table) { 4278c2ecf20Sopenharmony_ci mthca_err(mdev, "Failed to map MTT context memory, aborting.\n"); 4288c2ecf20Sopenharmony_ci err = -ENOMEM; 4298c2ecf20Sopenharmony_ci goto err_unmap_eq; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci mdev->mr_table.mpt_table = mthca_alloc_icm_table(mdev, init_hca->mpt_base, 4338c2ecf20Sopenharmony_ci dev_lim->mpt_entry_sz, 4348c2ecf20Sopenharmony_ci mdev->limits.num_mpts, 4358c2ecf20Sopenharmony_ci mdev->limits.reserved_mrws, 4368c2ecf20Sopenharmony_ci 1, 1); 4378c2ecf20Sopenharmony_ci if (!mdev->mr_table.mpt_table) { 4388c2ecf20Sopenharmony_ci mthca_err(mdev, "Failed to map MPT context memory, aborting.\n"); 4398c2ecf20Sopenharmony_ci err = -ENOMEM; 4408c2ecf20Sopenharmony_ci goto err_unmap_mtt; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci mdev->qp_table.qp_table = mthca_alloc_icm_table(mdev, init_hca->qpc_base, 4448c2ecf20Sopenharmony_ci dev_lim->qpc_entry_sz, 4458c2ecf20Sopenharmony_ci mdev->limits.num_qps, 4468c2ecf20Sopenharmony_ci mdev->limits.reserved_qps, 4478c2ecf20Sopenharmony_ci 0, 0); 4488c2ecf20Sopenharmony_ci if (!mdev->qp_table.qp_table) { 4498c2ecf20Sopenharmony_ci mthca_err(mdev, "Failed to map QP context memory, aborting.\n"); 4508c2ecf20Sopenharmony_ci err = -ENOMEM; 4518c2ecf20Sopenharmony_ci goto err_unmap_mpt; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci mdev->qp_table.eqp_table = mthca_alloc_icm_table(mdev, init_hca->eqpc_base, 4558c2ecf20Sopenharmony_ci dev_lim->eqpc_entry_sz, 4568c2ecf20Sopenharmony_ci mdev->limits.num_qps, 4578c2ecf20Sopenharmony_ci mdev->limits.reserved_qps, 4588c2ecf20Sopenharmony_ci 0, 0); 4598c2ecf20Sopenharmony_ci if (!mdev->qp_table.eqp_table) { 4608c2ecf20Sopenharmony_ci mthca_err(mdev, "Failed to map EQP context memory, aborting.\n"); 4618c2ecf20Sopenharmony_ci err = -ENOMEM; 4628c2ecf20Sopenharmony_ci goto err_unmap_qp; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci mdev->qp_table.rdb_table = mthca_alloc_icm_table(mdev, init_hca->rdb_base, 4668c2ecf20Sopenharmony_ci MTHCA_RDB_ENTRY_SIZE, 4678c2ecf20Sopenharmony_ci mdev->limits.num_qps << 4688c2ecf20Sopenharmony_ci mdev->qp_table.rdb_shift, 0, 4698c2ecf20Sopenharmony_ci 0, 0); 4708c2ecf20Sopenharmony_ci if (!mdev->qp_table.rdb_table) { 4718c2ecf20Sopenharmony_ci mthca_err(mdev, "Failed to map RDB context memory, aborting\n"); 4728c2ecf20Sopenharmony_ci err = -ENOMEM; 4738c2ecf20Sopenharmony_ci goto err_unmap_eqp; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci mdev->cq_table.table = mthca_alloc_icm_table(mdev, init_hca->cqc_base, 4778c2ecf20Sopenharmony_ci dev_lim->cqc_entry_sz, 4788c2ecf20Sopenharmony_ci mdev->limits.num_cqs, 4798c2ecf20Sopenharmony_ci mdev->limits.reserved_cqs, 4808c2ecf20Sopenharmony_ci 0, 0); 4818c2ecf20Sopenharmony_ci if (!mdev->cq_table.table) { 4828c2ecf20Sopenharmony_ci mthca_err(mdev, "Failed to map CQ context memory, aborting.\n"); 4838c2ecf20Sopenharmony_ci err = -ENOMEM; 4848c2ecf20Sopenharmony_ci goto err_unmap_rdb; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (mdev->mthca_flags & MTHCA_FLAG_SRQ) { 4888c2ecf20Sopenharmony_ci mdev->srq_table.table = 4898c2ecf20Sopenharmony_ci mthca_alloc_icm_table(mdev, init_hca->srqc_base, 4908c2ecf20Sopenharmony_ci dev_lim->srq_entry_sz, 4918c2ecf20Sopenharmony_ci mdev->limits.num_srqs, 4928c2ecf20Sopenharmony_ci mdev->limits.reserved_srqs, 4938c2ecf20Sopenharmony_ci 0, 0); 4948c2ecf20Sopenharmony_ci if (!mdev->srq_table.table) { 4958c2ecf20Sopenharmony_ci mthca_err(mdev, "Failed to map SRQ context memory, " 4968c2ecf20Sopenharmony_ci "aborting.\n"); 4978c2ecf20Sopenharmony_ci err = -ENOMEM; 4988c2ecf20Sopenharmony_ci goto err_unmap_cq; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* 5038c2ecf20Sopenharmony_ci * It's not strictly required, but for simplicity just map the 5048c2ecf20Sopenharmony_ci * whole multicast group table now. The table isn't very big 5058c2ecf20Sopenharmony_ci * and it's a lot easier than trying to track ref counts. 5068c2ecf20Sopenharmony_ci */ 5078c2ecf20Sopenharmony_ci mdev->mcg_table.table = mthca_alloc_icm_table(mdev, init_hca->mc_base, 5088c2ecf20Sopenharmony_ci MTHCA_MGM_ENTRY_SIZE, 5098c2ecf20Sopenharmony_ci mdev->limits.num_mgms + 5108c2ecf20Sopenharmony_ci mdev->limits.num_amgms, 5118c2ecf20Sopenharmony_ci mdev->limits.num_mgms + 5128c2ecf20Sopenharmony_ci mdev->limits.num_amgms, 5138c2ecf20Sopenharmony_ci 0, 0); 5148c2ecf20Sopenharmony_ci if (!mdev->mcg_table.table) { 5158c2ecf20Sopenharmony_ci mthca_err(mdev, "Failed to map MCG context memory, aborting.\n"); 5168c2ecf20Sopenharmony_ci err = -ENOMEM; 5178c2ecf20Sopenharmony_ci goto err_unmap_srq; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci return 0; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cierr_unmap_srq: 5238c2ecf20Sopenharmony_ci if (mdev->mthca_flags & MTHCA_FLAG_SRQ) 5248c2ecf20Sopenharmony_ci mthca_free_icm_table(mdev, mdev->srq_table.table); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cierr_unmap_cq: 5278c2ecf20Sopenharmony_ci mthca_free_icm_table(mdev, mdev->cq_table.table); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_cierr_unmap_rdb: 5308c2ecf20Sopenharmony_ci mthca_free_icm_table(mdev, mdev->qp_table.rdb_table); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cierr_unmap_eqp: 5338c2ecf20Sopenharmony_ci mthca_free_icm_table(mdev, mdev->qp_table.eqp_table); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cierr_unmap_qp: 5368c2ecf20Sopenharmony_ci mthca_free_icm_table(mdev, mdev->qp_table.qp_table); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cierr_unmap_mpt: 5398c2ecf20Sopenharmony_ci mthca_free_icm_table(mdev, mdev->mr_table.mpt_table); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cierr_unmap_mtt: 5428c2ecf20Sopenharmony_ci mthca_free_icm_table(mdev, mdev->mr_table.mtt_table); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cierr_unmap_eq: 5458c2ecf20Sopenharmony_ci mthca_unmap_eq_icm(mdev); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_cierr_unmap_aux: 5488c2ecf20Sopenharmony_ci mthca_UNMAP_ICM_AUX(mdev); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cierr_free_aux: 5518c2ecf20Sopenharmony_ci mthca_free_icm(mdev, mdev->fw.arbel.aux_icm, 0); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci return err; 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic void mthca_free_icms(struct mthca_dev *mdev) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci mthca_free_icm_table(mdev, mdev->mcg_table.table); 5608c2ecf20Sopenharmony_ci if (mdev->mthca_flags & MTHCA_FLAG_SRQ) 5618c2ecf20Sopenharmony_ci mthca_free_icm_table(mdev, mdev->srq_table.table); 5628c2ecf20Sopenharmony_ci mthca_free_icm_table(mdev, mdev->cq_table.table); 5638c2ecf20Sopenharmony_ci mthca_free_icm_table(mdev, mdev->qp_table.rdb_table); 5648c2ecf20Sopenharmony_ci mthca_free_icm_table(mdev, mdev->qp_table.eqp_table); 5658c2ecf20Sopenharmony_ci mthca_free_icm_table(mdev, mdev->qp_table.qp_table); 5668c2ecf20Sopenharmony_ci mthca_free_icm_table(mdev, mdev->mr_table.mpt_table); 5678c2ecf20Sopenharmony_ci mthca_free_icm_table(mdev, mdev->mr_table.mtt_table); 5688c2ecf20Sopenharmony_ci mthca_unmap_eq_icm(mdev); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci mthca_UNMAP_ICM_AUX(mdev); 5718c2ecf20Sopenharmony_ci mthca_free_icm(mdev, mdev->fw.arbel.aux_icm, 0); 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic int mthca_init_arbel(struct mthca_dev *mdev) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci struct mthca_dev_lim dev_lim; 5778c2ecf20Sopenharmony_ci struct mthca_profile profile; 5788c2ecf20Sopenharmony_ci struct mthca_init_hca_param init_hca; 5798c2ecf20Sopenharmony_ci s64 icm_size; 5808c2ecf20Sopenharmony_ci int err; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci err = mthca_QUERY_FW(mdev); 5838c2ecf20Sopenharmony_ci if (err) { 5848c2ecf20Sopenharmony_ci mthca_err(mdev, "QUERY_FW command failed %d, aborting.\n", err); 5858c2ecf20Sopenharmony_ci return err; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci err = mthca_ENABLE_LAM(mdev); 5898c2ecf20Sopenharmony_ci if (err == -EAGAIN) { 5908c2ecf20Sopenharmony_ci mthca_dbg(mdev, "No HCA-attached memory (running in MemFree mode)\n"); 5918c2ecf20Sopenharmony_ci mdev->mthca_flags |= MTHCA_FLAG_NO_LAM; 5928c2ecf20Sopenharmony_ci } else if (err) { 5938c2ecf20Sopenharmony_ci mthca_err(mdev, "ENABLE_LAM returned %d, aborting.\n", err); 5948c2ecf20Sopenharmony_ci return err; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci err = mthca_load_fw(mdev); 5988c2ecf20Sopenharmony_ci if (err) { 5998c2ecf20Sopenharmony_ci mthca_err(mdev, "Loading FW returned %d, aborting.\n", err); 6008c2ecf20Sopenharmony_ci goto err_disable; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci err = mthca_dev_lim(mdev, &dev_lim); 6048c2ecf20Sopenharmony_ci if (err) { 6058c2ecf20Sopenharmony_ci mthca_err(mdev, "QUERY_DEV_LIM returned %d, aborting.\n", err); 6068c2ecf20Sopenharmony_ci goto err_stop_fw; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci profile = hca_profile; 6108c2ecf20Sopenharmony_ci profile.num_uar = dev_lim.uar_size / PAGE_SIZE; 6118c2ecf20Sopenharmony_ci profile.num_udav = 0; 6128c2ecf20Sopenharmony_ci if (mdev->mthca_flags & MTHCA_FLAG_SRQ) 6138c2ecf20Sopenharmony_ci profile.num_srq = dev_lim.max_srqs; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci icm_size = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca); 6168c2ecf20Sopenharmony_ci if (icm_size < 0) { 6178c2ecf20Sopenharmony_ci err = icm_size; 6188c2ecf20Sopenharmony_ci goto err_stop_fw; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci err = mthca_init_icm(mdev, &dev_lim, &init_hca, icm_size); 6228c2ecf20Sopenharmony_ci if (err) 6238c2ecf20Sopenharmony_ci goto err_stop_fw; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci err = mthca_INIT_HCA(mdev, &init_hca); 6268c2ecf20Sopenharmony_ci if (err) { 6278c2ecf20Sopenharmony_ci mthca_err(mdev, "INIT_HCA command returned %d, aborting.\n", err); 6288c2ecf20Sopenharmony_ci goto err_free_icm; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci return 0; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cierr_free_icm: 6348c2ecf20Sopenharmony_ci mthca_free_icms(mdev); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cierr_stop_fw: 6378c2ecf20Sopenharmony_ci mthca_UNMAP_FA(mdev); 6388c2ecf20Sopenharmony_ci mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_cierr_disable: 6418c2ecf20Sopenharmony_ci if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM)) 6428c2ecf20Sopenharmony_ci mthca_DISABLE_LAM(mdev); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci return err; 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic void mthca_close_hca(struct mthca_dev *mdev) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci mthca_CLOSE_HCA(mdev, 0); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci if (mthca_is_memfree(mdev)) { 6528c2ecf20Sopenharmony_ci mthca_free_icms(mdev); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci mthca_UNMAP_FA(mdev); 6558c2ecf20Sopenharmony_ci mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM)) 6588c2ecf20Sopenharmony_ci mthca_DISABLE_LAM(mdev); 6598c2ecf20Sopenharmony_ci } else 6608c2ecf20Sopenharmony_ci mthca_SYS_DIS(mdev); 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic int mthca_init_hca(struct mthca_dev *mdev) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci int err; 6668c2ecf20Sopenharmony_ci struct mthca_adapter adapter; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci if (mthca_is_memfree(mdev)) 6698c2ecf20Sopenharmony_ci err = mthca_init_arbel(mdev); 6708c2ecf20Sopenharmony_ci else 6718c2ecf20Sopenharmony_ci err = mthca_init_tavor(mdev); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci if (err) 6748c2ecf20Sopenharmony_ci return err; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci err = mthca_QUERY_ADAPTER(mdev, &adapter); 6778c2ecf20Sopenharmony_ci if (err) { 6788c2ecf20Sopenharmony_ci mthca_err(mdev, "QUERY_ADAPTER command returned %d, aborting.\n", err); 6798c2ecf20Sopenharmony_ci goto err_close; 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci mdev->eq_table.inta_pin = adapter.inta_pin; 6838c2ecf20Sopenharmony_ci if (!mthca_is_memfree(mdev)) 6848c2ecf20Sopenharmony_ci mdev->rev_id = adapter.revision_id; 6858c2ecf20Sopenharmony_ci memcpy(mdev->board_id, adapter.board_id, sizeof mdev->board_id); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci return 0; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cierr_close: 6908c2ecf20Sopenharmony_ci mthca_close_hca(mdev); 6918c2ecf20Sopenharmony_ci return err; 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cistatic int mthca_setup_hca(struct mthca_dev *dev) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci int err; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci MTHCA_INIT_DOORBELL_LOCK(&dev->doorbell_lock); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci err = mthca_init_uar_table(dev); 7018c2ecf20Sopenharmony_ci if (err) { 7028c2ecf20Sopenharmony_ci mthca_err(dev, "Failed to initialize " 7038c2ecf20Sopenharmony_ci "user access region table, aborting.\n"); 7048c2ecf20Sopenharmony_ci return err; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci err = mthca_uar_alloc(dev, &dev->driver_uar); 7088c2ecf20Sopenharmony_ci if (err) { 7098c2ecf20Sopenharmony_ci mthca_err(dev, "Failed to allocate driver access region, " 7108c2ecf20Sopenharmony_ci "aborting.\n"); 7118c2ecf20Sopenharmony_ci goto err_uar_table_free; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci dev->kar = ioremap((phys_addr_t) dev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE); 7158c2ecf20Sopenharmony_ci if (!dev->kar) { 7168c2ecf20Sopenharmony_ci mthca_err(dev, "Couldn't map kernel access region, " 7178c2ecf20Sopenharmony_ci "aborting.\n"); 7188c2ecf20Sopenharmony_ci err = -ENOMEM; 7198c2ecf20Sopenharmony_ci goto err_uar_free; 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci err = mthca_init_pd_table(dev); 7238c2ecf20Sopenharmony_ci if (err) { 7248c2ecf20Sopenharmony_ci mthca_err(dev, "Failed to initialize " 7258c2ecf20Sopenharmony_ci "protection domain table, aborting.\n"); 7268c2ecf20Sopenharmony_ci goto err_kar_unmap; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci err = mthca_init_mr_table(dev); 7308c2ecf20Sopenharmony_ci if (err) { 7318c2ecf20Sopenharmony_ci mthca_err(dev, "Failed to initialize " 7328c2ecf20Sopenharmony_ci "memory region table, aborting.\n"); 7338c2ecf20Sopenharmony_ci goto err_pd_table_free; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci err = mthca_pd_alloc(dev, 1, &dev->driver_pd); 7378c2ecf20Sopenharmony_ci if (err) { 7388c2ecf20Sopenharmony_ci mthca_err(dev, "Failed to create driver PD, " 7398c2ecf20Sopenharmony_ci "aborting.\n"); 7408c2ecf20Sopenharmony_ci goto err_mr_table_free; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci err = mthca_init_eq_table(dev); 7448c2ecf20Sopenharmony_ci if (err) { 7458c2ecf20Sopenharmony_ci mthca_err(dev, "Failed to initialize " 7468c2ecf20Sopenharmony_ci "event queue table, aborting.\n"); 7478c2ecf20Sopenharmony_ci goto err_pd_free; 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci err = mthca_cmd_use_events(dev); 7518c2ecf20Sopenharmony_ci if (err) { 7528c2ecf20Sopenharmony_ci mthca_err(dev, "Failed to switch to event-driven " 7538c2ecf20Sopenharmony_ci "firmware commands, aborting.\n"); 7548c2ecf20Sopenharmony_ci goto err_eq_table_free; 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci err = mthca_NOP(dev); 7588c2ecf20Sopenharmony_ci if (err) { 7598c2ecf20Sopenharmony_ci if (dev->mthca_flags & MTHCA_FLAG_MSI_X) { 7608c2ecf20Sopenharmony_ci mthca_warn(dev, "NOP command failed to generate interrupt " 7618c2ecf20Sopenharmony_ci "(IRQ %d).\n", 7628c2ecf20Sopenharmony_ci dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector); 7638c2ecf20Sopenharmony_ci mthca_warn(dev, "Trying again with MSI-X disabled.\n"); 7648c2ecf20Sopenharmony_ci } else { 7658c2ecf20Sopenharmony_ci mthca_err(dev, "NOP command failed to generate interrupt " 7668c2ecf20Sopenharmony_ci "(IRQ %d), aborting.\n", 7678c2ecf20Sopenharmony_ci dev->pdev->irq); 7688c2ecf20Sopenharmony_ci mthca_err(dev, "BIOS or ACPI interrupt routing problem?\n"); 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci goto err_cmd_poll; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci mthca_dbg(dev, "NOP command IRQ test passed\n"); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci err = mthca_init_cq_table(dev); 7778c2ecf20Sopenharmony_ci if (err) { 7788c2ecf20Sopenharmony_ci mthca_err(dev, "Failed to initialize " 7798c2ecf20Sopenharmony_ci "completion queue table, aborting.\n"); 7808c2ecf20Sopenharmony_ci goto err_cmd_poll; 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci err = mthca_init_srq_table(dev); 7848c2ecf20Sopenharmony_ci if (err) { 7858c2ecf20Sopenharmony_ci mthca_err(dev, "Failed to initialize " 7868c2ecf20Sopenharmony_ci "shared receive queue table, aborting.\n"); 7878c2ecf20Sopenharmony_ci goto err_cq_table_free; 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci err = mthca_init_qp_table(dev); 7918c2ecf20Sopenharmony_ci if (err) { 7928c2ecf20Sopenharmony_ci mthca_err(dev, "Failed to initialize " 7938c2ecf20Sopenharmony_ci "queue pair table, aborting.\n"); 7948c2ecf20Sopenharmony_ci goto err_srq_table_free; 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci err = mthca_init_av_table(dev); 7988c2ecf20Sopenharmony_ci if (err) { 7998c2ecf20Sopenharmony_ci mthca_err(dev, "Failed to initialize " 8008c2ecf20Sopenharmony_ci "address vector table, aborting.\n"); 8018c2ecf20Sopenharmony_ci goto err_qp_table_free; 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci err = mthca_init_mcg_table(dev); 8058c2ecf20Sopenharmony_ci if (err) { 8068c2ecf20Sopenharmony_ci mthca_err(dev, "Failed to initialize " 8078c2ecf20Sopenharmony_ci "multicast group table, aborting.\n"); 8088c2ecf20Sopenharmony_ci goto err_av_table_free; 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci return 0; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cierr_av_table_free: 8148c2ecf20Sopenharmony_ci mthca_cleanup_av_table(dev); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_cierr_qp_table_free: 8178c2ecf20Sopenharmony_ci mthca_cleanup_qp_table(dev); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_cierr_srq_table_free: 8208c2ecf20Sopenharmony_ci mthca_cleanup_srq_table(dev); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cierr_cq_table_free: 8238c2ecf20Sopenharmony_ci mthca_cleanup_cq_table(dev); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_cierr_cmd_poll: 8268c2ecf20Sopenharmony_ci mthca_cmd_use_polling(dev); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_cierr_eq_table_free: 8298c2ecf20Sopenharmony_ci mthca_cleanup_eq_table(dev); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cierr_pd_free: 8328c2ecf20Sopenharmony_ci mthca_pd_free(dev, &dev->driver_pd); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_cierr_mr_table_free: 8358c2ecf20Sopenharmony_ci mthca_cleanup_mr_table(dev); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cierr_pd_table_free: 8388c2ecf20Sopenharmony_ci mthca_cleanup_pd_table(dev); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_cierr_kar_unmap: 8418c2ecf20Sopenharmony_ci iounmap(dev->kar); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cierr_uar_free: 8448c2ecf20Sopenharmony_ci mthca_uar_free(dev, &dev->driver_uar); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_cierr_uar_table_free: 8478c2ecf20Sopenharmony_ci mthca_cleanup_uar_table(dev); 8488c2ecf20Sopenharmony_ci return err; 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_cistatic int mthca_enable_msi_x(struct mthca_dev *mdev) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci int err; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci err = pci_alloc_irq_vectors(mdev->pdev, 3, 3, PCI_IRQ_MSIX); 8568c2ecf20Sopenharmony_ci if (err < 0) 8578c2ecf20Sopenharmony_ci return err; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci mdev->eq_table.eq[MTHCA_EQ_COMP ].msi_x_vector = 8608c2ecf20Sopenharmony_ci pci_irq_vector(mdev->pdev, 0); 8618c2ecf20Sopenharmony_ci mdev->eq_table.eq[MTHCA_EQ_ASYNC].msi_x_vector = 8628c2ecf20Sopenharmony_ci pci_irq_vector(mdev->pdev, 1); 8638c2ecf20Sopenharmony_ci mdev->eq_table.eq[MTHCA_EQ_CMD ].msi_x_vector = 8648c2ecf20Sopenharmony_ci pci_irq_vector(mdev->pdev, 2); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci return 0; 8678c2ecf20Sopenharmony_ci} 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci/* Types of supported HCA */ 8708c2ecf20Sopenharmony_cienum { 8718c2ecf20Sopenharmony_ci TAVOR, /* MT23108 */ 8728c2ecf20Sopenharmony_ci ARBEL_COMPAT, /* MT25208 in Tavor compat mode */ 8738c2ecf20Sopenharmony_ci ARBEL_NATIVE, /* MT25208 with extended features */ 8748c2ecf20Sopenharmony_ci SINAI /* MT25204 */ 8758c2ecf20Sopenharmony_ci}; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci#define MTHCA_FW_VER(major, minor, subminor) \ 8788c2ecf20Sopenharmony_ci (((u64) (major) << 32) | ((u64) (minor) << 16) | (u64) (subminor)) 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_cistatic struct { 8818c2ecf20Sopenharmony_ci u64 latest_fw; 8828c2ecf20Sopenharmony_ci u32 flags; 8838c2ecf20Sopenharmony_ci} mthca_hca_table[] = { 8848c2ecf20Sopenharmony_ci [TAVOR] = { .latest_fw = MTHCA_FW_VER(3, 5, 0), 8858c2ecf20Sopenharmony_ci .flags = 0 }, 8868c2ecf20Sopenharmony_ci [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 8, 200), 8878c2ecf20Sopenharmony_ci .flags = MTHCA_FLAG_PCIE }, 8888c2ecf20Sopenharmony_ci [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 3, 0), 8898c2ecf20Sopenharmony_ci .flags = MTHCA_FLAG_MEMFREE | 8908c2ecf20Sopenharmony_ci MTHCA_FLAG_PCIE }, 8918c2ecf20Sopenharmony_ci [SINAI] = { .latest_fw = MTHCA_FW_VER(1, 2, 0), 8928c2ecf20Sopenharmony_ci .flags = MTHCA_FLAG_MEMFREE | 8938c2ecf20Sopenharmony_ci MTHCA_FLAG_PCIE | 8948c2ecf20Sopenharmony_ci MTHCA_FLAG_SINAI_OPT } 8958c2ecf20Sopenharmony_ci}; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic int __mthca_init_one(struct pci_dev *pdev, int hca_type) 8988c2ecf20Sopenharmony_ci{ 8998c2ecf20Sopenharmony_ci int ddr_hidden = 0; 9008c2ecf20Sopenharmony_ci int err; 9018c2ecf20Sopenharmony_ci struct mthca_dev *mdev; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci printk(KERN_INFO PFX "Initializing %s\n", 9048c2ecf20Sopenharmony_ci pci_name(pdev)); 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci err = pci_enable_device(pdev); 9078c2ecf20Sopenharmony_ci if (err) { 9088c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Cannot enable PCI device, " 9098c2ecf20Sopenharmony_ci "aborting.\n"); 9108c2ecf20Sopenharmony_ci return err; 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci /* 9148c2ecf20Sopenharmony_ci * Check for BARs. We expect 0: 1MB, 2: 8MB, 4: DDR (may not 9158c2ecf20Sopenharmony_ci * be present) 9168c2ecf20Sopenharmony_ci */ 9178c2ecf20Sopenharmony_ci if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) || 9188c2ecf20Sopenharmony_ci pci_resource_len(pdev, 0) != 1 << 20) { 9198c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Missing DCS, aborting.\n"); 9208c2ecf20Sopenharmony_ci err = -ENODEV; 9218c2ecf20Sopenharmony_ci goto err_disable_pdev; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { 9248c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Missing UAR, aborting.\n"); 9258c2ecf20Sopenharmony_ci err = -ENODEV; 9268c2ecf20Sopenharmony_ci goto err_disable_pdev; 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci if (!(pci_resource_flags(pdev, 4) & IORESOURCE_MEM)) 9298c2ecf20Sopenharmony_ci ddr_hidden = 1; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci err = pci_request_regions(pdev, DRV_NAME); 9328c2ecf20Sopenharmony_ci if (err) { 9338c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Cannot obtain PCI resources, " 9348c2ecf20Sopenharmony_ci "aborting.\n"); 9358c2ecf20Sopenharmony_ci goto err_disable_pdev; 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci pci_set_master(pdev); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); 9418c2ecf20Sopenharmony_ci if (err) { 9428c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "Warning: couldn't set 64-bit PCI DMA mask.\n"); 9438c2ecf20Sopenharmony_ci err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 9448c2ecf20Sopenharmony_ci if (err) { 9458c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting.\n"); 9468c2ecf20Sopenharmony_ci goto err_free_res; 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); 9508c2ecf20Sopenharmony_ci if (err) { 9518c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "Warning: couldn't set 64-bit " 9528c2ecf20Sopenharmony_ci "consistent PCI DMA mask.\n"); 9538c2ecf20Sopenharmony_ci err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); 9548c2ecf20Sopenharmony_ci if (err) { 9558c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Can't set consistent PCI DMA mask, " 9568c2ecf20Sopenharmony_ci "aborting.\n"); 9578c2ecf20Sopenharmony_ci goto err_free_res; 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci /* We can handle large RDMA requests, so allow larger segments. */ 9628c2ecf20Sopenharmony_ci dma_set_max_seg_size(&pdev->dev, 1024 * 1024 * 1024); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci mdev = ib_alloc_device(mthca_dev, ib_dev); 9658c2ecf20Sopenharmony_ci if (!mdev) { 9668c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Device struct alloc failed, " 9678c2ecf20Sopenharmony_ci "aborting.\n"); 9688c2ecf20Sopenharmony_ci err = -ENOMEM; 9698c2ecf20Sopenharmony_ci goto err_free_res; 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci mdev->pdev = pdev; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci mdev->mthca_flags = mthca_hca_table[hca_type].flags; 9758c2ecf20Sopenharmony_ci if (ddr_hidden) 9768c2ecf20Sopenharmony_ci mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci /* 9798c2ecf20Sopenharmony_ci * Now reset the HCA before we touch the PCI capabilities or 9808c2ecf20Sopenharmony_ci * attempt a firmware command, since a boot ROM may have left 9818c2ecf20Sopenharmony_ci * the HCA in an undefined state. 9828c2ecf20Sopenharmony_ci */ 9838c2ecf20Sopenharmony_ci err = mthca_reset(mdev); 9848c2ecf20Sopenharmony_ci if (err) { 9858c2ecf20Sopenharmony_ci mthca_err(mdev, "Failed to reset HCA, aborting.\n"); 9868c2ecf20Sopenharmony_ci goto err_free_dev; 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci err = mthca_cmd_init(mdev); 9908c2ecf20Sopenharmony_ci if (err) { 9918c2ecf20Sopenharmony_ci mthca_err(mdev, "Failed to init command interface, aborting.\n"); 9928c2ecf20Sopenharmony_ci goto err_free_dev; 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci err = mthca_tune_pci(mdev); 9968c2ecf20Sopenharmony_ci if (err) 9978c2ecf20Sopenharmony_ci goto err_cmd; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci err = mthca_init_hca(mdev); 10008c2ecf20Sopenharmony_ci if (err) 10018c2ecf20Sopenharmony_ci goto err_cmd; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci if (mdev->fw_ver < mthca_hca_table[hca_type].latest_fw) { 10048c2ecf20Sopenharmony_ci mthca_warn(mdev, "HCA FW version %d.%d.%03d is old (%d.%d.%03d is current).\n", 10058c2ecf20Sopenharmony_ci (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff, 10068c2ecf20Sopenharmony_ci (int) (mdev->fw_ver & 0xffff), 10078c2ecf20Sopenharmony_ci (int) (mthca_hca_table[hca_type].latest_fw >> 32), 10088c2ecf20Sopenharmony_ci (int) (mthca_hca_table[hca_type].latest_fw >> 16) & 0xffff, 10098c2ecf20Sopenharmony_ci (int) (mthca_hca_table[hca_type].latest_fw & 0xffff)); 10108c2ecf20Sopenharmony_ci mthca_warn(mdev, "If you have problems, try updating your HCA FW.\n"); 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci if (msi_x && !mthca_enable_msi_x(mdev)) 10148c2ecf20Sopenharmony_ci mdev->mthca_flags |= MTHCA_FLAG_MSI_X; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci err = mthca_setup_hca(mdev); 10178c2ecf20Sopenharmony_ci if (err == -EBUSY && (mdev->mthca_flags & MTHCA_FLAG_MSI_X)) { 10188c2ecf20Sopenharmony_ci pci_free_irq_vectors(pdev); 10198c2ecf20Sopenharmony_ci mdev->mthca_flags &= ~MTHCA_FLAG_MSI_X; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci err = mthca_setup_hca(mdev); 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci if (err) 10258c2ecf20Sopenharmony_ci goto err_close; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci err = mthca_register_device(mdev); 10288c2ecf20Sopenharmony_ci if (err) 10298c2ecf20Sopenharmony_ci goto err_cleanup; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci err = mthca_create_agents(mdev); 10328c2ecf20Sopenharmony_ci if (err) 10338c2ecf20Sopenharmony_ci goto err_unregister; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, mdev); 10368c2ecf20Sopenharmony_ci mdev->hca_type = hca_type; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci mdev->active = true; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci return 0; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_cierr_unregister: 10438c2ecf20Sopenharmony_ci mthca_unregister_device(mdev); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cierr_cleanup: 10468c2ecf20Sopenharmony_ci mthca_cleanup_mcg_table(mdev); 10478c2ecf20Sopenharmony_ci mthca_cleanup_av_table(mdev); 10488c2ecf20Sopenharmony_ci mthca_cleanup_qp_table(mdev); 10498c2ecf20Sopenharmony_ci mthca_cleanup_srq_table(mdev); 10508c2ecf20Sopenharmony_ci mthca_cleanup_cq_table(mdev); 10518c2ecf20Sopenharmony_ci mthca_cmd_use_polling(mdev); 10528c2ecf20Sopenharmony_ci mthca_cleanup_eq_table(mdev); 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci mthca_pd_free(mdev, &mdev->driver_pd); 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci mthca_cleanup_mr_table(mdev); 10578c2ecf20Sopenharmony_ci mthca_cleanup_pd_table(mdev); 10588c2ecf20Sopenharmony_ci mthca_cleanup_uar_table(mdev); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_cierr_close: 10618c2ecf20Sopenharmony_ci if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) 10628c2ecf20Sopenharmony_ci pci_free_irq_vectors(pdev); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci mthca_close_hca(mdev); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_cierr_cmd: 10678c2ecf20Sopenharmony_ci mthca_cmd_cleanup(mdev); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_cierr_free_dev: 10708c2ecf20Sopenharmony_ci ib_dealloc_device(&mdev->ib_dev); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_cierr_free_res: 10738c2ecf20Sopenharmony_ci pci_release_regions(pdev); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_cierr_disable_pdev: 10768c2ecf20Sopenharmony_ci pci_disable_device(pdev); 10778c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 10788c2ecf20Sopenharmony_ci return err; 10798c2ecf20Sopenharmony_ci} 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_cistatic void __mthca_remove_one(struct pci_dev *pdev) 10828c2ecf20Sopenharmony_ci{ 10838c2ecf20Sopenharmony_ci struct mthca_dev *mdev = pci_get_drvdata(pdev); 10848c2ecf20Sopenharmony_ci int p; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci if (mdev) { 10878c2ecf20Sopenharmony_ci mthca_free_agents(mdev); 10888c2ecf20Sopenharmony_ci mthca_unregister_device(mdev); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci for (p = 1; p <= mdev->limits.num_ports; ++p) 10918c2ecf20Sopenharmony_ci mthca_CLOSE_IB(mdev, p); 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci mthca_cleanup_mcg_table(mdev); 10948c2ecf20Sopenharmony_ci mthca_cleanup_av_table(mdev); 10958c2ecf20Sopenharmony_ci mthca_cleanup_qp_table(mdev); 10968c2ecf20Sopenharmony_ci mthca_cleanup_srq_table(mdev); 10978c2ecf20Sopenharmony_ci mthca_cleanup_cq_table(mdev); 10988c2ecf20Sopenharmony_ci mthca_cmd_use_polling(mdev); 10998c2ecf20Sopenharmony_ci mthca_cleanup_eq_table(mdev); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci mthca_pd_free(mdev, &mdev->driver_pd); 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci mthca_cleanup_mr_table(mdev); 11048c2ecf20Sopenharmony_ci mthca_cleanup_pd_table(mdev); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci iounmap(mdev->kar); 11078c2ecf20Sopenharmony_ci mthca_uar_free(mdev, &mdev->driver_uar); 11088c2ecf20Sopenharmony_ci mthca_cleanup_uar_table(mdev); 11098c2ecf20Sopenharmony_ci mthca_close_hca(mdev); 11108c2ecf20Sopenharmony_ci mthca_cmd_cleanup(mdev); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) 11138c2ecf20Sopenharmony_ci pci_free_irq_vectors(pdev); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci ib_dealloc_device(&mdev->ib_dev); 11168c2ecf20Sopenharmony_ci pci_release_regions(pdev); 11178c2ecf20Sopenharmony_ci pci_disable_device(pdev); 11188c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci} 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ciint __mthca_restart_one(struct pci_dev *pdev) 11238c2ecf20Sopenharmony_ci{ 11248c2ecf20Sopenharmony_ci struct mthca_dev *mdev; 11258c2ecf20Sopenharmony_ci int hca_type; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci mdev = pci_get_drvdata(pdev); 11288c2ecf20Sopenharmony_ci if (!mdev) 11298c2ecf20Sopenharmony_ci return -ENODEV; 11308c2ecf20Sopenharmony_ci hca_type = mdev->hca_type; 11318c2ecf20Sopenharmony_ci __mthca_remove_one(pdev); 11328c2ecf20Sopenharmony_ci return __mthca_init_one(pdev, hca_type); 11338c2ecf20Sopenharmony_ci} 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_cistatic int mthca_init_one(struct pci_dev *pdev, const struct pci_device_id *id) 11368c2ecf20Sopenharmony_ci{ 11378c2ecf20Sopenharmony_ci int ret; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci mutex_lock(&mthca_device_mutex); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci printk_once(KERN_INFO "%s", mthca_version); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci if (id->driver_data >= ARRAY_SIZE(mthca_hca_table)) { 11448c2ecf20Sopenharmony_ci printk(KERN_ERR PFX "%s has invalid driver data %lx\n", 11458c2ecf20Sopenharmony_ci pci_name(pdev), id->driver_data); 11468c2ecf20Sopenharmony_ci mutex_unlock(&mthca_device_mutex); 11478c2ecf20Sopenharmony_ci return -ENODEV; 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci ret = __mthca_init_one(pdev, id->driver_data); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci mutex_unlock(&mthca_device_mutex); 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci return ret; 11558c2ecf20Sopenharmony_ci} 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_cistatic void mthca_remove_one(struct pci_dev *pdev) 11588c2ecf20Sopenharmony_ci{ 11598c2ecf20Sopenharmony_ci mutex_lock(&mthca_device_mutex); 11608c2ecf20Sopenharmony_ci __mthca_remove_one(pdev); 11618c2ecf20Sopenharmony_ci mutex_unlock(&mthca_device_mutex); 11628c2ecf20Sopenharmony_ci} 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_cistatic const struct pci_device_id mthca_pci_table[] = { 11658c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_TAVOR), 11668c2ecf20Sopenharmony_ci .driver_data = TAVOR }, 11678c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_TAVOR), 11688c2ecf20Sopenharmony_ci .driver_data = TAVOR }, 11698c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT), 11708c2ecf20Sopenharmony_ci .driver_data = ARBEL_COMPAT }, 11718c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT), 11728c2ecf20Sopenharmony_ci .driver_data = ARBEL_COMPAT }, 11738c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_ARBEL), 11748c2ecf20Sopenharmony_ci .driver_data = ARBEL_NATIVE }, 11758c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_ARBEL), 11768c2ecf20Sopenharmony_ci .driver_data = ARBEL_NATIVE }, 11778c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_SINAI), 11788c2ecf20Sopenharmony_ci .driver_data = SINAI }, 11798c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_SINAI), 11808c2ecf20Sopenharmony_ci .driver_data = SINAI }, 11818c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_SINAI_OLD), 11828c2ecf20Sopenharmony_ci .driver_data = SINAI }, 11838c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_SINAI_OLD), 11848c2ecf20Sopenharmony_ci .driver_data = SINAI }, 11858c2ecf20Sopenharmony_ci { 0, } 11868c2ecf20Sopenharmony_ci}; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mthca_pci_table); 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_cistatic struct pci_driver mthca_driver = { 11918c2ecf20Sopenharmony_ci .name = DRV_NAME, 11928c2ecf20Sopenharmony_ci .id_table = mthca_pci_table, 11938c2ecf20Sopenharmony_ci .probe = mthca_init_one, 11948c2ecf20Sopenharmony_ci .remove = mthca_remove_one, 11958c2ecf20Sopenharmony_ci}; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_cistatic void __init __mthca_check_profile_val(const char *name, int *pval, 11988c2ecf20Sopenharmony_ci int pval_default) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci /* value must be positive and power of 2 */ 12018c2ecf20Sopenharmony_ci int old_pval = *pval; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci if (old_pval <= 0) 12048c2ecf20Sopenharmony_ci *pval = pval_default; 12058c2ecf20Sopenharmony_ci else 12068c2ecf20Sopenharmony_ci *pval = roundup_pow_of_two(old_pval); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci if (old_pval != *pval) { 12098c2ecf20Sopenharmony_ci printk(KERN_WARNING PFX "Invalid value %d for %s in module parameter.\n", 12108c2ecf20Sopenharmony_ci old_pval, name); 12118c2ecf20Sopenharmony_ci printk(KERN_WARNING PFX "Corrected %s to %d.\n", name, *pval); 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci#define mthca_check_profile_val(name, default) \ 12168c2ecf20Sopenharmony_ci __mthca_check_profile_val(#name, &hca_profile.name, default) 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_cistatic void __init mthca_validate_profile(void) 12198c2ecf20Sopenharmony_ci{ 12208c2ecf20Sopenharmony_ci mthca_check_profile_val(num_qp, MTHCA_DEFAULT_NUM_QP); 12218c2ecf20Sopenharmony_ci mthca_check_profile_val(rdb_per_qp, MTHCA_DEFAULT_RDB_PER_QP); 12228c2ecf20Sopenharmony_ci mthca_check_profile_val(num_cq, MTHCA_DEFAULT_NUM_CQ); 12238c2ecf20Sopenharmony_ci mthca_check_profile_val(num_mcg, MTHCA_DEFAULT_NUM_MCG); 12248c2ecf20Sopenharmony_ci mthca_check_profile_val(num_mpt, MTHCA_DEFAULT_NUM_MPT); 12258c2ecf20Sopenharmony_ci mthca_check_profile_val(num_mtt, MTHCA_DEFAULT_NUM_MTT); 12268c2ecf20Sopenharmony_ci mthca_check_profile_val(num_udav, MTHCA_DEFAULT_NUM_UDAV); 12278c2ecf20Sopenharmony_ci mthca_check_profile_val(fmr_reserved_mtts, MTHCA_DEFAULT_NUM_RESERVED_MTTS); 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci if (hca_profile.fmr_reserved_mtts >= hca_profile.num_mtt) { 12308c2ecf20Sopenharmony_ci printk(KERN_WARNING PFX "Invalid fmr_reserved_mtts module parameter %d.\n", 12318c2ecf20Sopenharmony_ci hca_profile.fmr_reserved_mtts); 12328c2ecf20Sopenharmony_ci printk(KERN_WARNING PFX "(Must be smaller than num_mtt %d)\n", 12338c2ecf20Sopenharmony_ci hca_profile.num_mtt); 12348c2ecf20Sopenharmony_ci hca_profile.fmr_reserved_mtts = hca_profile.num_mtt / 2; 12358c2ecf20Sopenharmony_ci printk(KERN_WARNING PFX "Corrected fmr_reserved_mtts to %d.\n", 12368c2ecf20Sopenharmony_ci hca_profile.fmr_reserved_mtts); 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci if ((log_mtts_per_seg < 1) || (log_mtts_per_seg > 5)) { 12408c2ecf20Sopenharmony_ci printk(KERN_WARNING PFX "bad log_mtts_per_seg (%d). Using default - %d\n", 12418c2ecf20Sopenharmony_ci log_mtts_per_seg, ilog2(MTHCA_MTT_SEG_SIZE / 8)); 12428c2ecf20Sopenharmony_ci log_mtts_per_seg = ilog2(MTHCA_MTT_SEG_SIZE / 8); 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ci} 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_cistatic int __init mthca_init(void) 12478c2ecf20Sopenharmony_ci{ 12488c2ecf20Sopenharmony_ci int ret; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci mthca_validate_profile(); 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci ret = mthca_catas_init(); 12538c2ecf20Sopenharmony_ci if (ret) 12548c2ecf20Sopenharmony_ci return ret; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci ret = pci_register_driver(&mthca_driver); 12578c2ecf20Sopenharmony_ci if (ret < 0) { 12588c2ecf20Sopenharmony_ci mthca_catas_cleanup(); 12598c2ecf20Sopenharmony_ci return ret; 12608c2ecf20Sopenharmony_ci } 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci return 0; 12638c2ecf20Sopenharmony_ci} 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_cistatic void __exit mthca_cleanup(void) 12668c2ecf20Sopenharmony_ci{ 12678c2ecf20Sopenharmony_ci pci_unregister_driver(&mthca_driver); 12688c2ecf20Sopenharmony_ci mthca_catas_cleanup(); 12698c2ecf20Sopenharmony_ci} 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_cimodule_init(mthca_init); 12728c2ecf20Sopenharmony_cimodule_exit(mthca_cleanup); 1273