18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 38c2ecf20Sopenharmony_ci * Copyright (c) 2005 Mellanox Technologies. All rights reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 68c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 78c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 88c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 98c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 128c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 138c2ecf20Sopenharmony_ci * conditions are met: 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 168c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 178c2ecf20Sopenharmony_ci * disclaimer. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 208c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 218c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 228c2ecf20Sopenharmony_ci * provided with the distribution. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 258c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 268c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 278c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 288c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 298c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 308c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 318c2ecf20Sopenharmony_ci * SOFTWARE. 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <linux/module.h> 358c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 368c2ecf20Sopenharmony_ci#include <linux/string.h> 378c2ecf20Sopenharmony_ci#include <linux/slab.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include "mthca_profile.h" 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cienum { 428c2ecf20Sopenharmony_ci MTHCA_RES_QP, 438c2ecf20Sopenharmony_ci MTHCA_RES_EEC, 448c2ecf20Sopenharmony_ci MTHCA_RES_SRQ, 458c2ecf20Sopenharmony_ci MTHCA_RES_CQ, 468c2ecf20Sopenharmony_ci MTHCA_RES_EQP, 478c2ecf20Sopenharmony_ci MTHCA_RES_EEEC, 488c2ecf20Sopenharmony_ci MTHCA_RES_EQ, 498c2ecf20Sopenharmony_ci MTHCA_RES_RDB, 508c2ecf20Sopenharmony_ci MTHCA_RES_MCG, 518c2ecf20Sopenharmony_ci MTHCA_RES_MPT, 528c2ecf20Sopenharmony_ci MTHCA_RES_MTT, 538c2ecf20Sopenharmony_ci MTHCA_RES_UAR, 548c2ecf20Sopenharmony_ci MTHCA_RES_UDAV, 558c2ecf20Sopenharmony_ci MTHCA_RES_UARC, 568c2ecf20Sopenharmony_ci MTHCA_RES_NUM 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cienum { 608c2ecf20Sopenharmony_ci MTHCA_NUM_EQS = 32, 618c2ecf20Sopenharmony_ci MTHCA_NUM_PDS = 1 << 15 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cis64 mthca_make_profile(struct mthca_dev *dev, 658c2ecf20Sopenharmony_ci struct mthca_profile *request, 668c2ecf20Sopenharmony_ci struct mthca_dev_lim *dev_lim, 678c2ecf20Sopenharmony_ci struct mthca_init_hca_param *init_hca) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci struct mthca_resource { 708c2ecf20Sopenharmony_ci u64 size; 718c2ecf20Sopenharmony_ci u64 start; 728c2ecf20Sopenharmony_ci int type; 738c2ecf20Sopenharmony_ci int num; 748c2ecf20Sopenharmony_ci int log_num; 758c2ecf20Sopenharmony_ci }; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci u64 mem_base, mem_avail; 788c2ecf20Sopenharmony_ci s64 total_size = 0; 798c2ecf20Sopenharmony_ci struct mthca_resource *profile; 808c2ecf20Sopenharmony_ci int i, j; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci profile = kcalloc(MTHCA_RES_NUM, sizeof(*profile), GFP_KERNEL); 838c2ecf20Sopenharmony_ci if (!profile) 848c2ecf20Sopenharmony_ci return -ENOMEM; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci profile[MTHCA_RES_QP].size = dev_lim->qpc_entry_sz; 878c2ecf20Sopenharmony_ci profile[MTHCA_RES_EEC].size = dev_lim->eec_entry_sz; 888c2ecf20Sopenharmony_ci profile[MTHCA_RES_SRQ].size = dev_lim->srq_entry_sz; 898c2ecf20Sopenharmony_ci profile[MTHCA_RES_CQ].size = dev_lim->cqc_entry_sz; 908c2ecf20Sopenharmony_ci profile[MTHCA_RES_EQP].size = dev_lim->eqpc_entry_sz; 918c2ecf20Sopenharmony_ci profile[MTHCA_RES_EEEC].size = dev_lim->eeec_entry_sz; 928c2ecf20Sopenharmony_ci profile[MTHCA_RES_EQ].size = dev_lim->eqc_entry_sz; 938c2ecf20Sopenharmony_ci profile[MTHCA_RES_RDB].size = MTHCA_RDB_ENTRY_SIZE; 948c2ecf20Sopenharmony_ci profile[MTHCA_RES_MCG].size = MTHCA_MGM_ENTRY_SIZE; 958c2ecf20Sopenharmony_ci profile[MTHCA_RES_MPT].size = dev_lim->mpt_entry_sz; 968c2ecf20Sopenharmony_ci profile[MTHCA_RES_MTT].size = dev->limits.mtt_seg_size; 978c2ecf20Sopenharmony_ci profile[MTHCA_RES_UAR].size = dev_lim->uar_scratch_entry_sz; 988c2ecf20Sopenharmony_ci profile[MTHCA_RES_UDAV].size = MTHCA_AV_SIZE; 998c2ecf20Sopenharmony_ci profile[MTHCA_RES_UARC].size = request->uarc_size; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci profile[MTHCA_RES_QP].num = request->num_qp; 1028c2ecf20Sopenharmony_ci profile[MTHCA_RES_SRQ].num = request->num_srq; 1038c2ecf20Sopenharmony_ci profile[MTHCA_RES_EQP].num = request->num_qp; 1048c2ecf20Sopenharmony_ci profile[MTHCA_RES_RDB].num = request->num_qp * request->rdb_per_qp; 1058c2ecf20Sopenharmony_ci profile[MTHCA_RES_CQ].num = request->num_cq; 1068c2ecf20Sopenharmony_ci profile[MTHCA_RES_EQ].num = MTHCA_NUM_EQS; 1078c2ecf20Sopenharmony_ci profile[MTHCA_RES_MCG].num = request->num_mcg; 1088c2ecf20Sopenharmony_ci profile[MTHCA_RES_MPT].num = request->num_mpt; 1098c2ecf20Sopenharmony_ci profile[MTHCA_RES_MTT].num = request->num_mtt; 1108c2ecf20Sopenharmony_ci profile[MTHCA_RES_UAR].num = request->num_uar; 1118c2ecf20Sopenharmony_ci profile[MTHCA_RES_UARC].num = request->num_uar; 1128c2ecf20Sopenharmony_ci profile[MTHCA_RES_UDAV].num = request->num_udav; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci for (i = 0; i < MTHCA_RES_NUM; ++i) { 1158c2ecf20Sopenharmony_ci profile[i].type = i; 1168c2ecf20Sopenharmony_ci profile[i].log_num = max(ffs(profile[i].num) - 1, 0); 1178c2ecf20Sopenharmony_ci profile[i].size *= profile[i].num; 1188c2ecf20Sopenharmony_ci if (mthca_is_memfree(dev)) 1198c2ecf20Sopenharmony_ci profile[i].size = max(profile[i].size, (u64) PAGE_SIZE); 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (mthca_is_memfree(dev)) { 1238c2ecf20Sopenharmony_ci mem_base = 0; 1248c2ecf20Sopenharmony_ci mem_avail = dev_lim->hca.arbel.max_icm_sz; 1258c2ecf20Sopenharmony_ci } else { 1268c2ecf20Sopenharmony_ci mem_base = dev->ddr_start; 1278c2ecf20Sopenharmony_ci mem_avail = dev->fw.tavor.fw_start - dev->ddr_start; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* 1318c2ecf20Sopenharmony_ci * Sort the resources in decreasing order of size. Since they 1328c2ecf20Sopenharmony_ci * all have sizes that are powers of 2, we'll be able to keep 1338c2ecf20Sopenharmony_ci * resources aligned to their size and pack them without gaps 1348c2ecf20Sopenharmony_ci * using the sorted order. 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_ci for (i = MTHCA_RES_NUM; i > 0; --i) 1378c2ecf20Sopenharmony_ci for (j = 1; j < i; ++j) { 1388c2ecf20Sopenharmony_ci if (profile[j].size > profile[j - 1].size) 1398c2ecf20Sopenharmony_ci swap(profile[j], profile[j - 1]); 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci for (i = 0; i < MTHCA_RES_NUM; ++i) { 1438c2ecf20Sopenharmony_ci if (profile[i].size) { 1448c2ecf20Sopenharmony_ci profile[i].start = mem_base + total_size; 1458c2ecf20Sopenharmony_ci total_size += profile[i].size; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci if (total_size > mem_avail) { 1488c2ecf20Sopenharmony_ci mthca_err(dev, "Profile requires 0x%llx bytes; " 1498c2ecf20Sopenharmony_ci "won't fit in 0x%llx bytes of context memory.\n", 1508c2ecf20Sopenharmony_ci (unsigned long long) total_size, 1518c2ecf20Sopenharmony_ci (unsigned long long) mem_avail); 1528c2ecf20Sopenharmony_ci kfree(profile); 1538c2ecf20Sopenharmony_ci return -ENOMEM; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (profile[i].size) 1578c2ecf20Sopenharmony_ci mthca_dbg(dev, "profile[%2d]--%2d/%2d @ 0x%16llx " 1588c2ecf20Sopenharmony_ci "(size 0x%8llx)\n", 1598c2ecf20Sopenharmony_ci i, profile[i].type, profile[i].log_num, 1608c2ecf20Sopenharmony_ci (unsigned long long) profile[i].start, 1618c2ecf20Sopenharmony_ci (unsigned long long) profile[i].size); 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (mthca_is_memfree(dev)) 1658c2ecf20Sopenharmony_ci mthca_dbg(dev, "HCA context memory: reserving %d KB\n", 1668c2ecf20Sopenharmony_ci (int) (total_size >> 10)); 1678c2ecf20Sopenharmony_ci else 1688c2ecf20Sopenharmony_ci mthca_dbg(dev, "HCA memory: allocated %d KB/%d KB (%d KB free)\n", 1698c2ecf20Sopenharmony_ci (int) (total_size >> 10), (int) (mem_avail >> 10), 1708c2ecf20Sopenharmony_ci (int) ((mem_avail - total_size) >> 10)); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci for (i = 0; i < MTHCA_RES_NUM; ++i) { 1738c2ecf20Sopenharmony_ci switch (profile[i].type) { 1748c2ecf20Sopenharmony_ci case MTHCA_RES_QP: 1758c2ecf20Sopenharmony_ci dev->limits.num_qps = profile[i].num; 1768c2ecf20Sopenharmony_ci init_hca->qpc_base = profile[i].start; 1778c2ecf20Sopenharmony_ci init_hca->log_num_qps = profile[i].log_num; 1788c2ecf20Sopenharmony_ci break; 1798c2ecf20Sopenharmony_ci case MTHCA_RES_EEC: 1808c2ecf20Sopenharmony_ci dev->limits.num_eecs = profile[i].num; 1818c2ecf20Sopenharmony_ci init_hca->eec_base = profile[i].start; 1828c2ecf20Sopenharmony_ci init_hca->log_num_eecs = profile[i].log_num; 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci case MTHCA_RES_SRQ: 1858c2ecf20Sopenharmony_ci dev->limits.num_srqs = profile[i].num; 1868c2ecf20Sopenharmony_ci init_hca->srqc_base = profile[i].start; 1878c2ecf20Sopenharmony_ci init_hca->log_num_srqs = profile[i].log_num; 1888c2ecf20Sopenharmony_ci break; 1898c2ecf20Sopenharmony_ci case MTHCA_RES_CQ: 1908c2ecf20Sopenharmony_ci dev->limits.num_cqs = profile[i].num; 1918c2ecf20Sopenharmony_ci init_hca->cqc_base = profile[i].start; 1928c2ecf20Sopenharmony_ci init_hca->log_num_cqs = profile[i].log_num; 1938c2ecf20Sopenharmony_ci break; 1948c2ecf20Sopenharmony_ci case MTHCA_RES_EQP: 1958c2ecf20Sopenharmony_ci init_hca->eqpc_base = profile[i].start; 1968c2ecf20Sopenharmony_ci break; 1978c2ecf20Sopenharmony_ci case MTHCA_RES_EEEC: 1988c2ecf20Sopenharmony_ci init_hca->eeec_base = profile[i].start; 1998c2ecf20Sopenharmony_ci break; 2008c2ecf20Sopenharmony_ci case MTHCA_RES_EQ: 2018c2ecf20Sopenharmony_ci dev->limits.num_eqs = profile[i].num; 2028c2ecf20Sopenharmony_ci init_hca->eqc_base = profile[i].start; 2038c2ecf20Sopenharmony_ci init_hca->log_num_eqs = profile[i].log_num; 2048c2ecf20Sopenharmony_ci break; 2058c2ecf20Sopenharmony_ci case MTHCA_RES_RDB: 2068c2ecf20Sopenharmony_ci for (dev->qp_table.rdb_shift = 0; 2078c2ecf20Sopenharmony_ci request->num_qp << dev->qp_table.rdb_shift < profile[i].num; 2088c2ecf20Sopenharmony_ci ++dev->qp_table.rdb_shift) 2098c2ecf20Sopenharmony_ci ; /* nothing */ 2108c2ecf20Sopenharmony_ci dev->qp_table.rdb_base = (u32) profile[i].start; 2118c2ecf20Sopenharmony_ci init_hca->rdb_base = profile[i].start; 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci case MTHCA_RES_MCG: 2148c2ecf20Sopenharmony_ci dev->limits.num_mgms = profile[i].num >> 1; 2158c2ecf20Sopenharmony_ci dev->limits.num_amgms = profile[i].num >> 1; 2168c2ecf20Sopenharmony_ci init_hca->mc_base = profile[i].start; 2178c2ecf20Sopenharmony_ci init_hca->log_mc_entry_sz = ffs(MTHCA_MGM_ENTRY_SIZE) - 1; 2188c2ecf20Sopenharmony_ci init_hca->log_mc_table_sz = profile[i].log_num; 2198c2ecf20Sopenharmony_ci init_hca->mc_hash_sz = 1 << (profile[i].log_num - 1); 2208c2ecf20Sopenharmony_ci break; 2218c2ecf20Sopenharmony_ci case MTHCA_RES_MPT: 2228c2ecf20Sopenharmony_ci dev->limits.num_mpts = profile[i].num; 2238c2ecf20Sopenharmony_ci dev->mr_table.mpt_base = profile[i].start; 2248c2ecf20Sopenharmony_ci init_hca->mpt_base = profile[i].start; 2258c2ecf20Sopenharmony_ci init_hca->log_mpt_sz = profile[i].log_num; 2268c2ecf20Sopenharmony_ci break; 2278c2ecf20Sopenharmony_ci case MTHCA_RES_MTT: 2288c2ecf20Sopenharmony_ci dev->limits.num_mtt_segs = profile[i].num; 2298c2ecf20Sopenharmony_ci dev->mr_table.mtt_base = profile[i].start; 2308c2ecf20Sopenharmony_ci init_hca->mtt_base = profile[i].start; 2318c2ecf20Sopenharmony_ci init_hca->mtt_seg_sz = ffs(dev->limits.mtt_seg_size) - 7; 2328c2ecf20Sopenharmony_ci break; 2338c2ecf20Sopenharmony_ci case MTHCA_RES_UAR: 2348c2ecf20Sopenharmony_ci dev->limits.num_uars = profile[i].num; 2358c2ecf20Sopenharmony_ci init_hca->uar_scratch_base = profile[i].start; 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci case MTHCA_RES_UDAV: 2388c2ecf20Sopenharmony_ci dev->av_table.ddr_av_base = profile[i].start; 2398c2ecf20Sopenharmony_ci dev->av_table.num_ddr_avs = profile[i].num; 2408c2ecf20Sopenharmony_ci break; 2418c2ecf20Sopenharmony_ci case MTHCA_RES_UARC: 2428c2ecf20Sopenharmony_ci dev->uar_table.uarc_size = request->uarc_size; 2438c2ecf20Sopenharmony_ci dev->uar_table.uarc_base = profile[i].start; 2448c2ecf20Sopenharmony_ci init_hca->uarc_base = profile[i].start; 2458c2ecf20Sopenharmony_ci init_hca->log_uarc_sz = ffs(request->uarc_size) - 13; 2468c2ecf20Sopenharmony_ci init_hca->log_uar_sz = ffs(request->num_uar) - 1; 2478c2ecf20Sopenharmony_ci break; 2488c2ecf20Sopenharmony_ci default: 2498c2ecf20Sopenharmony_ci break; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* 2548c2ecf20Sopenharmony_ci * PDs don't take any HCA memory, but we assign them as part 2558c2ecf20Sopenharmony_ci * of the HCA profile anyway. 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_ci dev->limits.num_pds = MTHCA_NUM_PDS; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT && 2608c2ecf20Sopenharmony_ci init_hca->log_mpt_sz > 23) { 2618c2ecf20Sopenharmony_ci mthca_warn(dev, "MPT table too large (requested size 2^%d >= 2^24)\n", 2628c2ecf20Sopenharmony_ci init_hca->log_mpt_sz); 2638c2ecf20Sopenharmony_ci mthca_warn(dev, "Disabling memory key throughput optimization.\n"); 2648c2ecf20Sopenharmony_ci dev->mthca_flags &= ~MTHCA_FLAG_SINAI_OPT; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* 2688c2ecf20Sopenharmony_ci * For Tavor, FMRs use ioremapped PCI memory. For 32 bit 2698c2ecf20Sopenharmony_ci * systems it may use too much vmalloc space to map all MTT 2708c2ecf20Sopenharmony_ci * memory, so we reserve some MTTs for FMR access, taking them 2718c2ecf20Sopenharmony_ci * out of the MR pool. They don't use additional memory, but 2728c2ecf20Sopenharmony_ci * we assign them as part of the HCA profile anyway. 2738c2ecf20Sopenharmony_ci */ 2748c2ecf20Sopenharmony_ci if (mthca_is_memfree(dev) || BITS_PER_LONG == 64) 2758c2ecf20Sopenharmony_ci dev->limits.fmr_reserved_mtts = 0; 2768c2ecf20Sopenharmony_ci else 2778c2ecf20Sopenharmony_ci dev->limits.fmr_reserved_mtts = request->fmr_reserved_mtts; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci kfree(profile); 2808c2ecf20Sopenharmony_ci return total_size; 2818c2ecf20Sopenharmony_ci} 282