18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 58c2ecf20Sopenharmony_ci * modify it under the terms of EITHER the GNU General Public License 68c2ecf20Sopenharmony_ci * version 2 as published by the Free Software Foundation or the BSD 78c2ecf20Sopenharmony_ci * 2-Clause License. This program is distributed in the hope that it 88c2ecf20Sopenharmony_ci * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED 98c2ecf20Sopenharmony_ci * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 108c2ecf20Sopenharmony_ci * See the GNU General Public License version 2 for more details at 118c2ecf20Sopenharmony_ci * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License 148c2ecf20Sopenharmony_ci * along with this program available in the file COPYING in the main 158c2ecf20Sopenharmony_ci * directory of this source tree. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * The BSD 2-Clause License 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 208c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 218c2ecf20Sopenharmony_ci * conditions are met: 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 248c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 258c2ecf20Sopenharmony_ci * disclaimer. 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 288c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 298c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 308c2ecf20Sopenharmony_ci * provided with the distribution. 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 338c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 348c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 358c2ecf20Sopenharmony_ci * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 368c2ecf20Sopenharmony_ci * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 378c2ecf20Sopenharmony_ci * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 388c2ecf20Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 398c2ecf20Sopenharmony_ci * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 408c2ecf20Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 418c2ecf20Sopenharmony_ci * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 428c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 438c2ecf20Sopenharmony_ci * OF THE POSSIBILITY OF SUCH DAMAGE. 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#include <linux/errno.h> 478c2ecf20Sopenharmony_ci#include <linux/slab.h> 488c2ecf20Sopenharmony_ci#include <linux/bitmap.h> 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#include "pvrdma.h" 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ciint pvrdma_page_dir_init(struct pvrdma_dev *dev, struct pvrdma_page_dir *pdir, 538c2ecf20Sopenharmony_ci u64 npages, bool alloc_pages) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci u64 i; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (npages > PVRDMA_PAGE_DIR_MAX_PAGES) 588c2ecf20Sopenharmony_ci return -EINVAL; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci memset(pdir, 0, sizeof(*pdir)); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci pdir->dir = dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE, 638c2ecf20Sopenharmony_ci &pdir->dir_dma, GFP_KERNEL); 648c2ecf20Sopenharmony_ci if (!pdir->dir) 658c2ecf20Sopenharmony_ci goto err; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci pdir->ntables = PVRDMA_PAGE_DIR_TABLE(npages - 1) + 1; 688c2ecf20Sopenharmony_ci pdir->tables = kcalloc(pdir->ntables, sizeof(*pdir->tables), 698c2ecf20Sopenharmony_ci GFP_KERNEL); 708c2ecf20Sopenharmony_ci if (!pdir->tables) 718c2ecf20Sopenharmony_ci goto err; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci for (i = 0; i < pdir->ntables; i++) { 748c2ecf20Sopenharmony_ci pdir->tables[i] = dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE, 758c2ecf20Sopenharmony_ci (dma_addr_t *)&pdir->dir[i], 768c2ecf20Sopenharmony_ci GFP_KERNEL); 778c2ecf20Sopenharmony_ci if (!pdir->tables[i]) 788c2ecf20Sopenharmony_ci goto err; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci pdir->npages = npages; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (alloc_pages) { 848c2ecf20Sopenharmony_ci pdir->pages = kcalloc(npages, sizeof(*pdir->pages), 858c2ecf20Sopenharmony_ci GFP_KERNEL); 868c2ecf20Sopenharmony_ci if (!pdir->pages) 878c2ecf20Sopenharmony_ci goto err; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci for (i = 0; i < pdir->npages; i++) { 908c2ecf20Sopenharmony_ci dma_addr_t page_dma; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci pdir->pages[i] = dma_alloc_coherent(&dev->pdev->dev, 938c2ecf20Sopenharmony_ci PAGE_SIZE, 948c2ecf20Sopenharmony_ci &page_dma, 958c2ecf20Sopenharmony_ci GFP_KERNEL); 968c2ecf20Sopenharmony_ci if (!pdir->pages[i]) 978c2ecf20Sopenharmony_ci goto err; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci pvrdma_page_dir_insert_dma(pdir, i, page_dma); 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return 0; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cierr: 1068c2ecf20Sopenharmony_ci pvrdma_page_dir_cleanup(dev, pdir); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return -ENOMEM; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic u64 *pvrdma_page_dir_table(struct pvrdma_page_dir *pdir, u64 idx) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci return pdir->tables[PVRDMA_PAGE_DIR_TABLE(idx)]; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cidma_addr_t pvrdma_page_dir_get_dma(struct pvrdma_page_dir *pdir, u64 idx) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci return pvrdma_page_dir_table(pdir, idx)[PVRDMA_PAGE_DIR_PAGE(idx)]; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic void pvrdma_page_dir_cleanup_pages(struct pvrdma_dev *dev, 1228c2ecf20Sopenharmony_ci struct pvrdma_page_dir *pdir) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci if (pdir->pages) { 1258c2ecf20Sopenharmony_ci u64 i; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci for (i = 0; i < pdir->npages && pdir->pages[i]; i++) { 1288c2ecf20Sopenharmony_ci dma_addr_t page_dma = pvrdma_page_dir_get_dma(pdir, i); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, 1318c2ecf20Sopenharmony_ci pdir->pages[i], page_dma); 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci kfree(pdir->pages); 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic void pvrdma_page_dir_cleanup_tables(struct pvrdma_dev *dev, 1398c2ecf20Sopenharmony_ci struct pvrdma_page_dir *pdir) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci if (pdir->tables) { 1428c2ecf20Sopenharmony_ci int i; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci pvrdma_page_dir_cleanup_pages(dev, pdir); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci for (i = 0; i < pdir->ntables; i++) { 1478c2ecf20Sopenharmony_ci u64 *table = pdir->tables[i]; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (table) 1508c2ecf20Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, 1518c2ecf20Sopenharmony_ci table, pdir->dir[i]); 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci kfree(pdir->tables); 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_civoid pvrdma_page_dir_cleanup(struct pvrdma_dev *dev, 1598c2ecf20Sopenharmony_ci struct pvrdma_page_dir *pdir) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci if (pdir->dir) { 1628c2ecf20Sopenharmony_ci pvrdma_page_dir_cleanup_tables(dev, pdir); 1638c2ecf20Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, 1648c2ecf20Sopenharmony_ci pdir->dir, pdir->dir_dma); 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ciint pvrdma_page_dir_insert_dma(struct pvrdma_page_dir *pdir, u64 idx, 1698c2ecf20Sopenharmony_ci dma_addr_t daddr) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci u64 *table; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (idx >= pdir->npages) 1748c2ecf20Sopenharmony_ci return -EINVAL; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci table = pvrdma_page_dir_table(pdir, idx); 1778c2ecf20Sopenharmony_ci table[PVRDMA_PAGE_DIR_PAGE(idx)] = daddr; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci return 0; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ciint pvrdma_page_dir_insert_umem(struct pvrdma_page_dir *pdir, 1838c2ecf20Sopenharmony_ci struct ib_umem *umem, u64 offset) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci struct ib_block_iter biter; 1868c2ecf20Sopenharmony_ci u64 i = offset; 1878c2ecf20Sopenharmony_ci int ret = 0; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (offset >= pdir->npages) 1908c2ecf20Sopenharmony_ci return -EINVAL; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci rdma_umem_for_each_dma_block (umem, &biter, PAGE_SIZE) { 1938c2ecf20Sopenharmony_ci ret = pvrdma_page_dir_insert_dma( 1948c2ecf20Sopenharmony_ci pdir, i, rdma_block_iter_dma_address(&biter)); 1958c2ecf20Sopenharmony_ci if (ret) 1968c2ecf20Sopenharmony_ci goto exit; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci i++; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ciexit: 2028c2ecf20Sopenharmony_ci return ret; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ciint pvrdma_page_dir_insert_page_list(struct pvrdma_page_dir *pdir, 2068c2ecf20Sopenharmony_ci u64 *page_list, 2078c2ecf20Sopenharmony_ci int num_pages) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci int i; 2108c2ecf20Sopenharmony_ci int ret; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (num_pages > pdir->npages) 2138c2ecf20Sopenharmony_ci return -EINVAL; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci for (i = 0; i < num_pages; i++) { 2168c2ecf20Sopenharmony_ci ret = pvrdma_page_dir_insert_dma(pdir, i, page_list[i]); 2178c2ecf20Sopenharmony_ci if (ret) 2188c2ecf20Sopenharmony_ci return ret; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return 0; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_civoid pvrdma_qp_cap_to_ib(struct ib_qp_cap *dst, const struct pvrdma_qp_cap *src) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci dst->max_send_wr = src->max_send_wr; 2278c2ecf20Sopenharmony_ci dst->max_recv_wr = src->max_recv_wr; 2288c2ecf20Sopenharmony_ci dst->max_send_sge = src->max_send_sge; 2298c2ecf20Sopenharmony_ci dst->max_recv_sge = src->max_recv_sge; 2308c2ecf20Sopenharmony_ci dst->max_inline_data = src->max_inline_data; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_civoid ib_qp_cap_to_pvrdma(struct pvrdma_qp_cap *dst, const struct ib_qp_cap *src) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci dst->max_send_wr = src->max_send_wr; 2368c2ecf20Sopenharmony_ci dst->max_recv_wr = src->max_recv_wr; 2378c2ecf20Sopenharmony_ci dst->max_send_sge = src->max_send_sge; 2388c2ecf20Sopenharmony_ci dst->max_recv_sge = src->max_recv_sge; 2398c2ecf20Sopenharmony_ci dst->max_inline_data = src->max_inline_data; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_civoid pvrdma_gid_to_ib(union ib_gid *dst, const union pvrdma_gid *src) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(union pvrdma_gid) != sizeof(union ib_gid)); 2458c2ecf20Sopenharmony_ci memcpy(dst, src, sizeof(*src)); 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_civoid ib_gid_to_pvrdma(union pvrdma_gid *dst, const union ib_gid *src) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(union pvrdma_gid) != sizeof(union ib_gid)); 2518c2ecf20Sopenharmony_ci memcpy(dst, src, sizeof(*src)); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_civoid pvrdma_global_route_to_ib(struct ib_global_route *dst, 2558c2ecf20Sopenharmony_ci const struct pvrdma_global_route *src) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci pvrdma_gid_to_ib(&dst->dgid, &src->dgid); 2588c2ecf20Sopenharmony_ci dst->flow_label = src->flow_label; 2598c2ecf20Sopenharmony_ci dst->sgid_index = src->sgid_index; 2608c2ecf20Sopenharmony_ci dst->hop_limit = src->hop_limit; 2618c2ecf20Sopenharmony_ci dst->traffic_class = src->traffic_class; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_civoid ib_global_route_to_pvrdma(struct pvrdma_global_route *dst, 2658c2ecf20Sopenharmony_ci const struct ib_global_route *src) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci ib_gid_to_pvrdma(&dst->dgid, &src->dgid); 2688c2ecf20Sopenharmony_ci dst->flow_label = src->flow_label; 2698c2ecf20Sopenharmony_ci dst->sgid_index = src->sgid_index; 2708c2ecf20Sopenharmony_ci dst->hop_limit = src->hop_limit; 2718c2ecf20Sopenharmony_ci dst->traffic_class = src->traffic_class; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_civoid pvrdma_ah_attr_to_rdma(struct rdma_ah_attr *dst, 2758c2ecf20Sopenharmony_ci const struct pvrdma_ah_attr *src) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci dst->type = RDMA_AH_ATTR_TYPE_ROCE; 2788c2ecf20Sopenharmony_ci pvrdma_global_route_to_ib(rdma_ah_retrieve_grh(dst), &src->grh); 2798c2ecf20Sopenharmony_ci rdma_ah_set_dlid(dst, src->dlid); 2808c2ecf20Sopenharmony_ci rdma_ah_set_sl(dst, src->sl); 2818c2ecf20Sopenharmony_ci rdma_ah_set_path_bits(dst, src->src_path_bits); 2828c2ecf20Sopenharmony_ci rdma_ah_set_static_rate(dst, src->static_rate); 2838c2ecf20Sopenharmony_ci rdma_ah_set_ah_flags(dst, src->ah_flags); 2848c2ecf20Sopenharmony_ci rdma_ah_set_port_num(dst, src->port_num); 2858c2ecf20Sopenharmony_ci memcpy(dst->roce.dmac, &src->dmac, ETH_ALEN); 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_civoid rdma_ah_attr_to_pvrdma(struct pvrdma_ah_attr *dst, 2898c2ecf20Sopenharmony_ci const struct rdma_ah_attr *src) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci ib_global_route_to_pvrdma(&dst->grh, rdma_ah_read_grh(src)); 2928c2ecf20Sopenharmony_ci dst->dlid = rdma_ah_get_dlid(src); 2938c2ecf20Sopenharmony_ci dst->sl = rdma_ah_get_sl(src); 2948c2ecf20Sopenharmony_ci dst->src_path_bits = rdma_ah_get_path_bits(src); 2958c2ecf20Sopenharmony_ci dst->static_rate = rdma_ah_get_static_rate(src); 2968c2ecf20Sopenharmony_ci dst->ah_flags = rdma_ah_get_ah_flags(src); 2978c2ecf20Sopenharmony_ci dst->port_num = rdma_ah_get_port_num(src); 2988c2ecf20Sopenharmony_ci memcpy(&dst->dmac, src->roce.dmac, sizeof(dst->dmac)); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ciu8 ib_gid_type_to_pvrdma(enum ib_gid_type gid_type) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci return (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) ? 3048c2ecf20Sopenharmony_ci PVRDMA_GID_TYPE_FLAG_ROCE_V2 : 3058c2ecf20Sopenharmony_ci PVRDMA_GID_TYPE_FLAG_ROCE_V1; 3068c2ecf20Sopenharmony_ci} 307