129c8d9ebSAdit Ranadive /* 229c8d9ebSAdit Ranadive * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. 329c8d9ebSAdit Ranadive * 429c8d9ebSAdit Ranadive * This program is free software; you can redistribute it and/or 529c8d9ebSAdit Ranadive * modify it under the terms of EITHER the GNU General Public License 629c8d9ebSAdit Ranadive * version 2 as published by the Free Software Foundation or the BSD 729c8d9ebSAdit Ranadive * 2-Clause License. This program is distributed in the hope that it 829c8d9ebSAdit Ranadive * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED 929c8d9ebSAdit Ranadive * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 1029c8d9ebSAdit Ranadive * See the GNU General Public License version 2 for more details at 1129c8d9ebSAdit Ranadive * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. 1229c8d9ebSAdit Ranadive * 1329c8d9ebSAdit Ranadive * You should have received a copy of the GNU General Public License 1429c8d9ebSAdit Ranadive * along with this program available in the file COPYING in the main 1529c8d9ebSAdit Ranadive * directory of this source tree. 1629c8d9ebSAdit Ranadive * 1729c8d9ebSAdit Ranadive * The BSD 2-Clause License 1829c8d9ebSAdit Ranadive * 1929c8d9ebSAdit Ranadive * Redistribution and use in source and binary forms, with or 2029c8d9ebSAdit Ranadive * without modification, are permitted provided that the following 2129c8d9ebSAdit Ranadive * conditions are met: 2229c8d9ebSAdit Ranadive * 2329c8d9ebSAdit Ranadive * - Redistributions of source code must retain the above 2429c8d9ebSAdit Ranadive * copyright notice, this list of conditions and the following 2529c8d9ebSAdit Ranadive * disclaimer. 2629c8d9ebSAdit Ranadive * 2729c8d9ebSAdit Ranadive * - Redistributions in binary form must reproduce the above 2829c8d9ebSAdit Ranadive * copyright notice, this list of conditions and the following 2929c8d9ebSAdit Ranadive * disclaimer in the documentation and/or other materials 3029c8d9ebSAdit Ranadive * provided with the distribution. 3129c8d9ebSAdit Ranadive * 3229c8d9ebSAdit Ranadive * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3329c8d9ebSAdit Ranadive * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3429c8d9ebSAdit Ranadive * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 3529c8d9ebSAdit Ranadive * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 3629c8d9ebSAdit Ranadive * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 3729c8d9ebSAdit Ranadive * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 3829c8d9ebSAdit Ranadive * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 3929c8d9ebSAdit Ranadive * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4029c8d9ebSAdit Ranadive * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 4129c8d9ebSAdit Ranadive * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 4229c8d9ebSAdit Ranadive * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 4329c8d9ebSAdit Ranadive * OF THE POSSIBILITY OF SUCH DAMAGE. 4429c8d9ebSAdit Ranadive */ 4529c8d9ebSAdit Ranadive 4629c8d9ebSAdit Ranadive #include <linux/errno.h> 4729c8d9ebSAdit Ranadive #include <linux/slab.h> 4829c8d9ebSAdit Ranadive #include <linux/bitmap.h> 4929c8d9ebSAdit Ranadive 5029c8d9ebSAdit Ranadive #include "pvrdma.h" 5129c8d9ebSAdit Ranadive 5229c8d9ebSAdit Ranadive int pvrdma_page_dir_init(struct pvrdma_dev *dev, struct pvrdma_page_dir *pdir, 5329c8d9ebSAdit Ranadive u64 npages, bool alloc_pages) 5429c8d9ebSAdit Ranadive { 5529c8d9ebSAdit Ranadive u64 i; 5629c8d9ebSAdit Ranadive 5729c8d9ebSAdit Ranadive if (npages > PVRDMA_PAGE_DIR_MAX_PAGES) 5829c8d9ebSAdit Ranadive return -EINVAL; 5929c8d9ebSAdit Ranadive 6029c8d9ebSAdit Ranadive memset(pdir, 0, sizeof(*pdir)); 6129c8d9ebSAdit Ranadive 6229c8d9ebSAdit Ranadive pdir->dir = dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE, 6329c8d9ebSAdit Ranadive &pdir->dir_dma, GFP_KERNEL); 6429c8d9ebSAdit Ranadive if (!pdir->dir) 6529c8d9ebSAdit Ranadive goto err; 6629c8d9ebSAdit Ranadive 6729c8d9ebSAdit Ranadive pdir->ntables = PVRDMA_PAGE_DIR_TABLE(npages - 1) + 1; 6829c8d9ebSAdit Ranadive pdir->tables = kcalloc(pdir->ntables, sizeof(*pdir->tables), 6929c8d9ebSAdit Ranadive GFP_KERNEL); 7029c8d9ebSAdit Ranadive if (!pdir->tables) 7129c8d9ebSAdit Ranadive goto err; 7229c8d9ebSAdit Ranadive 7329c8d9ebSAdit Ranadive for (i = 0; i < pdir->ntables; i++) { 7429c8d9ebSAdit Ranadive pdir->tables[i] = dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE, 7529c8d9ebSAdit Ranadive (dma_addr_t *)&pdir->dir[i], 7629c8d9ebSAdit Ranadive GFP_KERNEL); 7729c8d9ebSAdit Ranadive if (!pdir->tables[i]) 7829c8d9ebSAdit Ranadive goto err; 7929c8d9ebSAdit Ranadive } 8029c8d9ebSAdit Ranadive 8129c8d9ebSAdit Ranadive pdir->npages = npages; 8229c8d9ebSAdit Ranadive 8329c8d9ebSAdit Ranadive if (alloc_pages) { 8429c8d9ebSAdit Ranadive pdir->pages = kcalloc(npages, sizeof(*pdir->pages), 8529c8d9ebSAdit Ranadive GFP_KERNEL); 8629c8d9ebSAdit Ranadive if (!pdir->pages) 8729c8d9ebSAdit Ranadive goto err; 8829c8d9ebSAdit Ranadive 8929c8d9ebSAdit Ranadive for (i = 0; i < pdir->npages; i++) { 9029c8d9ebSAdit Ranadive dma_addr_t page_dma; 9129c8d9ebSAdit Ranadive 9229c8d9ebSAdit Ranadive pdir->pages[i] = dma_alloc_coherent(&dev->pdev->dev, 9329c8d9ebSAdit Ranadive PAGE_SIZE, 9429c8d9ebSAdit Ranadive &page_dma, 9529c8d9ebSAdit Ranadive GFP_KERNEL); 9629c8d9ebSAdit Ranadive if (!pdir->pages[i]) 9729c8d9ebSAdit Ranadive goto err; 9829c8d9ebSAdit Ranadive 9929c8d9ebSAdit Ranadive pvrdma_page_dir_insert_dma(pdir, i, page_dma); 10029c8d9ebSAdit Ranadive } 10129c8d9ebSAdit Ranadive } 10229c8d9ebSAdit Ranadive 10329c8d9ebSAdit Ranadive return 0; 10429c8d9ebSAdit Ranadive 10529c8d9ebSAdit Ranadive err: 10629c8d9ebSAdit Ranadive pvrdma_page_dir_cleanup(dev, pdir); 10729c8d9ebSAdit Ranadive 10829c8d9ebSAdit Ranadive return -ENOMEM; 10929c8d9ebSAdit Ranadive } 11029c8d9ebSAdit Ranadive 11129c8d9ebSAdit Ranadive static u64 *pvrdma_page_dir_table(struct pvrdma_page_dir *pdir, u64 idx) 11229c8d9ebSAdit Ranadive { 11329c8d9ebSAdit Ranadive return pdir->tables[PVRDMA_PAGE_DIR_TABLE(idx)]; 11429c8d9ebSAdit Ranadive } 11529c8d9ebSAdit Ranadive 11629c8d9ebSAdit Ranadive dma_addr_t pvrdma_page_dir_get_dma(struct pvrdma_page_dir *pdir, u64 idx) 11729c8d9ebSAdit Ranadive { 11829c8d9ebSAdit Ranadive return pvrdma_page_dir_table(pdir, idx)[PVRDMA_PAGE_DIR_PAGE(idx)]; 11929c8d9ebSAdit Ranadive } 12029c8d9ebSAdit Ranadive 12129c8d9ebSAdit Ranadive static void pvrdma_page_dir_cleanup_pages(struct pvrdma_dev *dev, 12229c8d9ebSAdit Ranadive struct pvrdma_page_dir *pdir) 12329c8d9ebSAdit Ranadive { 12429c8d9ebSAdit Ranadive if (pdir->pages) { 12529c8d9ebSAdit Ranadive u64 i; 12629c8d9ebSAdit Ranadive 12729c8d9ebSAdit Ranadive for (i = 0; i < pdir->npages && pdir->pages[i]; i++) { 12829c8d9ebSAdit Ranadive dma_addr_t page_dma = pvrdma_page_dir_get_dma(pdir, i); 12929c8d9ebSAdit Ranadive 13029c8d9ebSAdit Ranadive dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, 13129c8d9ebSAdit Ranadive pdir->pages[i], page_dma); 13229c8d9ebSAdit Ranadive } 13329c8d9ebSAdit Ranadive 13429c8d9ebSAdit Ranadive kfree(pdir->pages); 13529c8d9ebSAdit Ranadive } 13629c8d9ebSAdit Ranadive } 13729c8d9ebSAdit Ranadive 13829c8d9ebSAdit Ranadive static void pvrdma_page_dir_cleanup_tables(struct pvrdma_dev *dev, 13929c8d9ebSAdit Ranadive struct pvrdma_page_dir *pdir) 14029c8d9ebSAdit Ranadive { 14129c8d9ebSAdit Ranadive if (pdir->tables) { 14229c8d9ebSAdit Ranadive int i; 14329c8d9ebSAdit Ranadive 14429c8d9ebSAdit Ranadive pvrdma_page_dir_cleanup_pages(dev, pdir); 14529c8d9ebSAdit Ranadive 14629c8d9ebSAdit Ranadive for (i = 0; i < pdir->ntables; i++) { 14729c8d9ebSAdit Ranadive u64 *table = pdir->tables[i]; 14829c8d9ebSAdit Ranadive 14929c8d9ebSAdit Ranadive if (table) 15029c8d9ebSAdit Ranadive dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, 15129c8d9ebSAdit Ranadive table, pdir->dir[i]); 15229c8d9ebSAdit Ranadive } 15329c8d9ebSAdit Ranadive 15429c8d9ebSAdit Ranadive kfree(pdir->tables); 15529c8d9ebSAdit Ranadive } 15629c8d9ebSAdit Ranadive } 15729c8d9ebSAdit Ranadive 15829c8d9ebSAdit Ranadive void pvrdma_page_dir_cleanup(struct pvrdma_dev *dev, 15929c8d9ebSAdit Ranadive struct pvrdma_page_dir *pdir) 16029c8d9ebSAdit Ranadive { 16129c8d9ebSAdit Ranadive if (pdir->dir) { 16229c8d9ebSAdit Ranadive pvrdma_page_dir_cleanup_tables(dev, pdir); 16329c8d9ebSAdit Ranadive dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, 16429c8d9ebSAdit Ranadive pdir->dir, pdir->dir_dma); 16529c8d9ebSAdit Ranadive } 16629c8d9ebSAdit Ranadive } 16729c8d9ebSAdit Ranadive 16829c8d9ebSAdit Ranadive int pvrdma_page_dir_insert_dma(struct pvrdma_page_dir *pdir, u64 idx, 16929c8d9ebSAdit Ranadive dma_addr_t daddr) 17029c8d9ebSAdit Ranadive { 17129c8d9ebSAdit Ranadive u64 *table; 17229c8d9ebSAdit Ranadive 17329c8d9ebSAdit Ranadive if (idx >= pdir->npages) 17429c8d9ebSAdit Ranadive return -EINVAL; 17529c8d9ebSAdit Ranadive 17629c8d9ebSAdit Ranadive table = pvrdma_page_dir_table(pdir, idx); 17729c8d9ebSAdit Ranadive table[PVRDMA_PAGE_DIR_PAGE(idx)] = daddr; 17829c8d9ebSAdit Ranadive 17929c8d9ebSAdit Ranadive return 0; 18029c8d9ebSAdit Ranadive } 18129c8d9ebSAdit Ranadive 18229c8d9ebSAdit Ranadive int pvrdma_page_dir_insert_umem(struct pvrdma_page_dir *pdir, 18329c8d9ebSAdit Ranadive struct ib_umem *umem, u64 offset) 18429c8d9ebSAdit Ranadive { 185*89603f7eSJason Gunthorpe struct ib_block_iter biter; 18629c8d9ebSAdit Ranadive u64 i = offset; 187f3e6d311SShiraz, Saleem int ret = 0; 18829c8d9ebSAdit Ranadive 18929c8d9ebSAdit Ranadive if (offset >= pdir->npages) 19029c8d9ebSAdit Ranadive return -EINVAL; 19129c8d9ebSAdit Ranadive 192*89603f7eSJason Gunthorpe rdma_umem_for_each_dma_block (umem, &biter, PAGE_SIZE) { 193*89603f7eSJason Gunthorpe ret = pvrdma_page_dir_insert_dma( 194*89603f7eSJason Gunthorpe pdir, i, rdma_block_iter_dma_address(&biter)); 19529c8d9ebSAdit Ranadive if (ret) 19629c8d9ebSAdit Ranadive goto exit; 19729c8d9ebSAdit Ranadive 19829c8d9ebSAdit Ranadive i++; 19929c8d9ebSAdit Ranadive } 20029c8d9ebSAdit Ranadive 20129c8d9ebSAdit Ranadive exit: 20229c8d9ebSAdit Ranadive return ret; 20329c8d9ebSAdit Ranadive } 20429c8d9ebSAdit Ranadive 20529c8d9ebSAdit Ranadive int pvrdma_page_dir_insert_page_list(struct pvrdma_page_dir *pdir, 20629c8d9ebSAdit Ranadive u64 *page_list, 20729c8d9ebSAdit Ranadive int num_pages) 20829c8d9ebSAdit Ranadive { 20929c8d9ebSAdit Ranadive int i; 21029c8d9ebSAdit Ranadive int ret; 21129c8d9ebSAdit Ranadive 21229c8d9ebSAdit Ranadive if (num_pages > pdir->npages) 21329c8d9ebSAdit Ranadive return -EINVAL; 21429c8d9ebSAdit Ranadive 21529c8d9ebSAdit Ranadive for (i = 0; i < num_pages; i++) { 21629c8d9ebSAdit Ranadive ret = pvrdma_page_dir_insert_dma(pdir, i, page_list[i]); 21729c8d9ebSAdit Ranadive if (ret) 21829c8d9ebSAdit Ranadive return ret; 21929c8d9ebSAdit Ranadive } 22029c8d9ebSAdit Ranadive 22129c8d9ebSAdit Ranadive return 0; 22229c8d9ebSAdit Ranadive } 22329c8d9ebSAdit Ranadive 22429c8d9ebSAdit Ranadive void pvrdma_qp_cap_to_ib(struct ib_qp_cap *dst, const struct pvrdma_qp_cap *src) 22529c8d9ebSAdit Ranadive { 22629c8d9ebSAdit Ranadive dst->max_send_wr = src->max_send_wr; 22729c8d9ebSAdit Ranadive dst->max_recv_wr = src->max_recv_wr; 22829c8d9ebSAdit Ranadive dst->max_send_sge = src->max_send_sge; 22929c8d9ebSAdit Ranadive dst->max_recv_sge = src->max_recv_sge; 23029c8d9ebSAdit Ranadive dst->max_inline_data = src->max_inline_data; 23129c8d9ebSAdit Ranadive } 23229c8d9ebSAdit Ranadive 23329c8d9ebSAdit Ranadive void ib_qp_cap_to_pvrdma(struct pvrdma_qp_cap *dst, const struct ib_qp_cap *src) 23429c8d9ebSAdit Ranadive { 23529c8d9ebSAdit Ranadive dst->max_send_wr = src->max_send_wr; 23629c8d9ebSAdit Ranadive dst->max_recv_wr = src->max_recv_wr; 23729c8d9ebSAdit Ranadive dst->max_send_sge = src->max_send_sge; 23829c8d9ebSAdit Ranadive dst->max_recv_sge = src->max_recv_sge; 23929c8d9ebSAdit Ranadive dst->max_inline_data = src->max_inline_data; 24029c8d9ebSAdit Ranadive } 24129c8d9ebSAdit Ranadive 24229c8d9ebSAdit Ranadive void pvrdma_gid_to_ib(union ib_gid *dst, const union pvrdma_gid *src) 24329c8d9ebSAdit Ranadive { 24429c8d9ebSAdit Ranadive BUILD_BUG_ON(sizeof(union pvrdma_gid) != sizeof(union ib_gid)); 24529c8d9ebSAdit Ranadive memcpy(dst, src, sizeof(*src)); 24629c8d9ebSAdit Ranadive } 24729c8d9ebSAdit Ranadive 24829c8d9ebSAdit Ranadive void ib_gid_to_pvrdma(union pvrdma_gid *dst, const union ib_gid *src) 24929c8d9ebSAdit Ranadive { 25029c8d9ebSAdit Ranadive BUILD_BUG_ON(sizeof(union pvrdma_gid) != sizeof(union ib_gid)); 25129c8d9ebSAdit Ranadive memcpy(dst, src, sizeof(*src)); 25229c8d9ebSAdit Ranadive } 25329c8d9ebSAdit Ranadive 25429c8d9ebSAdit Ranadive void pvrdma_global_route_to_ib(struct ib_global_route *dst, 25529c8d9ebSAdit Ranadive const struct pvrdma_global_route *src) 25629c8d9ebSAdit Ranadive { 25729c8d9ebSAdit Ranadive pvrdma_gid_to_ib(&dst->dgid, &src->dgid); 25829c8d9ebSAdit Ranadive dst->flow_label = src->flow_label; 25929c8d9ebSAdit Ranadive dst->sgid_index = src->sgid_index; 26029c8d9ebSAdit Ranadive dst->hop_limit = src->hop_limit; 26129c8d9ebSAdit Ranadive dst->traffic_class = src->traffic_class; 26229c8d9ebSAdit Ranadive } 26329c8d9ebSAdit Ranadive 26429c8d9ebSAdit Ranadive void ib_global_route_to_pvrdma(struct pvrdma_global_route *dst, 26529c8d9ebSAdit Ranadive const struct ib_global_route *src) 26629c8d9ebSAdit Ranadive { 26729c8d9ebSAdit Ranadive ib_gid_to_pvrdma(&dst->dgid, &src->dgid); 26829c8d9ebSAdit Ranadive dst->flow_label = src->flow_label; 26929c8d9ebSAdit Ranadive dst->sgid_index = src->sgid_index; 27029c8d9ebSAdit Ranadive dst->hop_limit = src->hop_limit; 27129c8d9ebSAdit Ranadive dst->traffic_class = src->traffic_class; 27229c8d9ebSAdit Ranadive } 27329c8d9ebSAdit Ranadive 274f988653aSDasaratharaman Chandramouli void pvrdma_ah_attr_to_rdma(struct rdma_ah_attr *dst, 27529c8d9ebSAdit Ranadive const struct pvrdma_ah_attr *src) 27629c8d9ebSAdit Ranadive { 27744c58487SDasaratharaman Chandramouli dst->type = RDMA_AH_ATTR_TYPE_ROCE; 278d8966fcdSDasaratharaman Chandramouli pvrdma_global_route_to_ib(rdma_ah_retrieve_grh(dst), &src->grh); 279d8966fcdSDasaratharaman Chandramouli rdma_ah_set_dlid(dst, src->dlid); 280d8966fcdSDasaratharaman Chandramouli rdma_ah_set_sl(dst, src->sl); 281d8966fcdSDasaratharaman Chandramouli rdma_ah_set_path_bits(dst, src->src_path_bits); 282d8966fcdSDasaratharaman Chandramouli rdma_ah_set_static_rate(dst, src->static_rate); 283d8966fcdSDasaratharaman Chandramouli rdma_ah_set_ah_flags(dst, src->ah_flags); 284d8966fcdSDasaratharaman Chandramouli rdma_ah_set_port_num(dst, src->port_num); 28544c58487SDasaratharaman Chandramouli memcpy(dst->roce.dmac, &src->dmac, ETH_ALEN); 28629c8d9ebSAdit Ranadive } 28729c8d9ebSAdit Ranadive 288f988653aSDasaratharaman Chandramouli void rdma_ah_attr_to_pvrdma(struct pvrdma_ah_attr *dst, 28990898850SDasaratharaman Chandramouli const struct rdma_ah_attr *src) 29029c8d9ebSAdit Ranadive { 291d8966fcdSDasaratharaman Chandramouli ib_global_route_to_pvrdma(&dst->grh, rdma_ah_read_grh(src)); 292d8966fcdSDasaratharaman Chandramouli dst->dlid = rdma_ah_get_dlid(src); 293d8966fcdSDasaratharaman Chandramouli dst->sl = rdma_ah_get_sl(src); 294d8966fcdSDasaratharaman Chandramouli dst->src_path_bits = rdma_ah_get_path_bits(src); 295d8966fcdSDasaratharaman Chandramouli dst->static_rate = rdma_ah_get_static_rate(src); 296d8966fcdSDasaratharaman Chandramouli dst->ah_flags = rdma_ah_get_ah_flags(src); 297d8966fcdSDasaratharaman Chandramouli dst->port_num = rdma_ah_get_port_num(src); 29844c58487SDasaratharaman Chandramouli memcpy(&dst->dmac, src->roce.dmac, sizeof(dst->dmac)); 29929c8d9ebSAdit Ranadive } 30005297b66SBryan Tan 30105297b66SBryan Tan u8 ib_gid_type_to_pvrdma(enum ib_gid_type gid_type) 30205297b66SBryan Tan { 30305297b66SBryan Tan return (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) ? 30405297b66SBryan Tan PVRDMA_GID_TYPE_FLAG_ROCE_V2 : 30505297b66SBryan Tan PVRDMA_GID_TYPE_FLAG_ROCE_V1; 30605297b66SBryan Tan } 307