18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2006, 2007 Cisco Systems, Inc. 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/errno.h> 358c2ecf20Sopenharmony_ci#include <linux/export.h> 368c2ecf20Sopenharmony_ci#include <linux/io-mapping.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include <asm/page.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include "mlx4.h" 418c2ecf20Sopenharmony_ci#include "icm.h" 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cienum { 448c2ecf20Sopenharmony_ci MLX4_NUM_RESERVED_UARS = 8 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ciint mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci *pdn = mlx4_bitmap_alloc(&priv->pd_bitmap); 528c2ecf20Sopenharmony_ci if (*pdn == -1) 538c2ecf20Sopenharmony_ci return -ENOMEM; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci return 0; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_pd_alloc); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_civoid mlx4_pd_free(struct mlx4_dev *dev, u32 pdn) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci mlx4_bitmap_free(&mlx4_priv(dev)->pd_bitmap, pdn, MLX4_USE_RR); 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_pd_free); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ciint __mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci *xrcdn = mlx4_bitmap_alloc(&priv->xrcd_bitmap); 708c2ecf20Sopenharmony_ci if (*xrcdn == -1) 718c2ecf20Sopenharmony_ci return -ENOMEM; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ciint mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci u64 out_param; 798c2ecf20Sopenharmony_ci int err; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (mlx4_is_mfunc(dev)) { 828c2ecf20Sopenharmony_ci err = mlx4_cmd_imm(dev, 0, &out_param, 838c2ecf20Sopenharmony_ci RES_XRCD, RES_OP_RESERVE, 848c2ecf20Sopenharmony_ci MLX4_CMD_ALLOC_RES, 858c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 868c2ecf20Sopenharmony_ci if (err) 878c2ecf20Sopenharmony_ci return err; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci *xrcdn = get_param_l(&out_param); 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci return __mlx4_xrcd_alloc(dev, xrcdn); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_xrcd_alloc); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_civoid __mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci mlx4_bitmap_free(&mlx4_priv(dev)->xrcd_bitmap, xrcdn, MLX4_USE_RR); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_civoid mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci u64 in_param = 0; 1048c2ecf20Sopenharmony_ci int err; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (mlx4_is_mfunc(dev)) { 1078c2ecf20Sopenharmony_ci set_param_l(&in_param, xrcdn); 1088c2ecf20Sopenharmony_ci err = mlx4_cmd(dev, in_param, RES_XRCD, 1098c2ecf20Sopenharmony_ci RES_OP_RESERVE, MLX4_CMD_FREE_RES, 1108c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 1118c2ecf20Sopenharmony_ci if (err) 1128c2ecf20Sopenharmony_ci mlx4_warn(dev, "Failed to release xrcdn %d\n", xrcdn); 1138c2ecf20Sopenharmony_ci } else 1148c2ecf20Sopenharmony_ci __mlx4_xrcd_free(dev, xrcdn); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_xrcd_free); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ciint mlx4_init_pd_table(struct mlx4_dev *dev) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return mlx4_bitmap_init(&priv->pd_bitmap, dev->caps.num_pds, 1238c2ecf20Sopenharmony_ci (1 << NOT_MASKED_PD_BITS) - 1, 1248c2ecf20Sopenharmony_ci dev->caps.reserved_pds, 0); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_civoid mlx4_cleanup_pd_table(struct mlx4_dev *dev) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci mlx4_bitmap_cleanup(&mlx4_priv(dev)->pd_bitmap); 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ciint mlx4_init_xrcd_table(struct mlx4_dev *dev) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return mlx4_bitmap_init(&priv->xrcd_bitmap, (1 << 16), 1378c2ecf20Sopenharmony_ci (1 << 16) - 1, dev->caps.reserved_xrcds + 1, 0); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_civoid mlx4_cleanup_xrcd_table(struct mlx4_dev *dev) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci mlx4_bitmap_cleanup(&mlx4_priv(dev)->xrcd_bitmap); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ciint mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci int offset; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci uar->index = mlx4_bitmap_alloc(&mlx4_priv(dev)->uar_table.bitmap); 1508c2ecf20Sopenharmony_ci if (uar->index == -1) 1518c2ecf20Sopenharmony_ci return -ENOMEM; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (mlx4_is_slave(dev)) 1548c2ecf20Sopenharmony_ci offset = uar->index % ((int)pci_resource_len(dev->persist->pdev, 1558c2ecf20Sopenharmony_ci 2) / 1568c2ecf20Sopenharmony_ci dev->caps.uar_page_size); 1578c2ecf20Sopenharmony_ci else 1588c2ecf20Sopenharmony_ci offset = uar->index; 1598c2ecf20Sopenharmony_ci uar->pfn = (pci_resource_start(dev->persist->pdev, 2) >> PAGE_SHIFT) 1608c2ecf20Sopenharmony_ci + offset; 1618c2ecf20Sopenharmony_ci uar->map = NULL; 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_uar_alloc); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_civoid mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci mlx4_bitmap_free(&mlx4_priv(dev)->uar_table.bitmap, uar->index, MLX4_USE_RR); 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_uar_free); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ciint mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf, int node) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 1758c2ecf20Sopenharmony_ci struct mlx4_uar *uar; 1768c2ecf20Sopenharmony_ci int err = 0; 1778c2ecf20Sopenharmony_ci int idx; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (!priv->bf_mapping) 1808c2ecf20Sopenharmony_ci return -ENOMEM; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci mutex_lock(&priv->bf_mutex); 1838c2ecf20Sopenharmony_ci if (!list_empty(&priv->bf_list)) 1848c2ecf20Sopenharmony_ci uar = list_entry(priv->bf_list.next, struct mlx4_uar, bf_list); 1858c2ecf20Sopenharmony_ci else { 1868c2ecf20Sopenharmony_ci if (mlx4_bitmap_avail(&priv->uar_table.bitmap) < MLX4_NUM_RESERVED_UARS) { 1878c2ecf20Sopenharmony_ci err = -ENOMEM; 1888c2ecf20Sopenharmony_ci goto out; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci uar = kmalloc_node(sizeof(*uar), GFP_KERNEL, node); 1918c2ecf20Sopenharmony_ci if (!uar) { 1928c2ecf20Sopenharmony_ci uar = kmalloc(sizeof(*uar), GFP_KERNEL); 1938c2ecf20Sopenharmony_ci if (!uar) { 1948c2ecf20Sopenharmony_ci err = -ENOMEM; 1958c2ecf20Sopenharmony_ci goto out; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci err = mlx4_uar_alloc(dev, uar); 1998c2ecf20Sopenharmony_ci if (err) 2008c2ecf20Sopenharmony_ci goto free_kmalloc; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci uar->map = ioremap(uar->pfn << PAGE_SHIFT, PAGE_SIZE); 2038c2ecf20Sopenharmony_ci if (!uar->map) { 2048c2ecf20Sopenharmony_ci err = -ENOMEM; 2058c2ecf20Sopenharmony_ci goto free_uar; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci uar->bf_map = io_mapping_map_wc(priv->bf_mapping, 2098c2ecf20Sopenharmony_ci uar->index << PAGE_SHIFT, 2108c2ecf20Sopenharmony_ci PAGE_SIZE); 2118c2ecf20Sopenharmony_ci if (!uar->bf_map) { 2128c2ecf20Sopenharmony_ci err = -ENOMEM; 2138c2ecf20Sopenharmony_ci goto unamp_uar; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci uar->free_bf_bmap = 0; 2168c2ecf20Sopenharmony_ci list_add(&uar->bf_list, &priv->bf_list); 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci idx = ffz(uar->free_bf_bmap); 2208c2ecf20Sopenharmony_ci uar->free_bf_bmap |= 1 << idx; 2218c2ecf20Sopenharmony_ci bf->uar = uar; 2228c2ecf20Sopenharmony_ci bf->offset = 0; 2238c2ecf20Sopenharmony_ci bf->buf_size = dev->caps.bf_reg_size / 2; 2248c2ecf20Sopenharmony_ci bf->reg = uar->bf_map + idx * dev->caps.bf_reg_size; 2258c2ecf20Sopenharmony_ci if (uar->free_bf_bmap == (1 << dev->caps.bf_regs_per_page) - 1) 2268c2ecf20Sopenharmony_ci list_del_init(&uar->bf_list); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci goto out; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ciunamp_uar: 2318c2ecf20Sopenharmony_ci bf->uar = NULL; 2328c2ecf20Sopenharmony_ci iounmap(uar->map); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cifree_uar: 2358c2ecf20Sopenharmony_ci mlx4_uar_free(dev, uar); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cifree_kmalloc: 2388c2ecf20Sopenharmony_ci kfree(uar); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ciout: 2418c2ecf20Sopenharmony_ci mutex_unlock(&priv->bf_mutex); 2428c2ecf20Sopenharmony_ci return err; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_bf_alloc); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_civoid mlx4_bf_free(struct mlx4_dev *dev, struct mlx4_bf *bf) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 2498c2ecf20Sopenharmony_ci int idx; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (!bf->uar || !bf->uar->bf_map) 2528c2ecf20Sopenharmony_ci return; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci mutex_lock(&priv->bf_mutex); 2558c2ecf20Sopenharmony_ci idx = (bf->reg - bf->uar->bf_map) / dev->caps.bf_reg_size; 2568c2ecf20Sopenharmony_ci bf->uar->free_bf_bmap &= ~(1 << idx); 2578c2ecf20Sopenharmony_ci if (!bf->uar->free_bf_bmap) { 2588c2ecf20Sopenharmony_ci if (!list_empty(&bf->uar->bf_list)) 2598c2ecf20Sopenharmony_ci list_del(&bf->uar->bf_list); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci io_mapping_unmap(bf->uar->bf_map); 2628c2ecf20Sopenharmony_ci iounmap(bf->uar->map); 2638c2ecf20Sopenharmony_ci mlx4_uar_free(dev, bf->uar); 2648c2ecf20Sopenharmony_ci kfree(bf->uar); 2658c2ecf20Sopenharmony_ci } else if (list_empty(&bf->uar->bf_list)) 2668c2ecf20Sopenharmony_ci list_add(&bf->uar->bf_list, &priv->bf_list); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci mutex_unlock(&priv->bf_mutex); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_bf_free); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ciint mlx4_init_uar_table(struct mlx4_dev *dev) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci int num_reserved_uar = mlx4_get_num_reserved_uar(dev); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci mlx4_dbg(dev, "uar_page_shift = %d", dev->uar_page_shift); 2778c2ecf20Sopenharmony_ci mlx4_dbg(dev, "Effective reserved_uars=%d", dev->caps.reserved_uars); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (dev->caps.num_uars <= num_reserved_uar) { 2808c2ecf20Sopenharmony_ci mlx4_err( 2818c2ecf20Sopenharmony_ci dev, "Only %d UAR pages (need more than %d)\n", 2828c2ecf20Sopenharmony_ci dev->caps.num_uars, num_reserved_uar); 2838c2ecf20Sopenharmony_ci mlx4_err(dev, "Increase firmware log2_uar_bar_megabytes?\n"); 2848c2ecf20Sopenharmony_ci return -ENODEV; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci return mlx4_bitmap_init(&mlx4_priv(dev)->uar_table.bitmap, 2888c2ecf20Sopenharmony_ci dev->caps.num_uars, dev->caps.num_uars - 1, 2898c2ecf20Sopenharmony_ci dev->caps.reserved_uars, 0); 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_civoid mlx4_cleanup_uar_table(struct mlx4_dev *dev) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci mlx4_bitmap_cleanup(&mlx4_priv(dev)->uar_table.bitmap); 2958c2ecf20Sopenharmony_ci} 296