1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */ 3 4 #include <linux/mman.h> 5 #include <linux/dma-mapping.h> 6 7 #include "ionic_fw.h" 8 #include "ionic_ibdev.h" 9 10 int ionic_pgtbl_page(struct ionic_tbl_buf *buf, u64 dma) 11 { 12 if (unlikely(buf->tbl_pages == buf->tbl_limit)) 13 return -ENOMEM; 14 15 if (buf->tbl_buf) 16 buf->tbl_buf[buf->tbl_pages] = cpu_to_le64(dma); 17 else 18 buf->tbl_dma = dma; 19 20 ++buf->tbl_pages; 21 22 return 0; 23 } 24 25 static int ionic_tbl_buf_alloc(struct ionic_ibdev *dev, 26 struct ionic_tbl_buf *buf) 27 { 28 int rc; 29 30 buf->tbl_size = buf->tbl_limit * sizeof(*buf->tbl_buf); 31 buf->tbl_buf = kmalloc(buf->tbl_size, GFP_KERNEL); 32 if (!buf->tbl_buf) 33 return -ENOMEM; 34 35 buf->tbl_dma = dma_map_single(dev->lif_cfg.hwdev, buf->tbl_buf, 36 buf->tbl_size, DMA_TO_DEVICE); 37 rc = dma_mapping_error(dev->lif_cfg.hwdev, buf->tbl_dma); 38 if (rc) { 39 kfree(buf->tbl_buf); 40 return rc; 41 } 42 43 return 0; 44 } 45 46 static int ionic_pgtbl_umem(struct ionic_tbl_buf *buf, struct ib_umem *umem) 47 { 48 struct ib_block_iter biter; 49 u64 page_dma; 50 int rc; 51 52 rdma_umem_for_each_dma_block(umem, &biter, BIT_ULL(buf->page_size_log2)) { 53 page_dma = rdma_block_iter_dma_address(&biter); 54 rc = ionic_pgtbl_page(buf, page_dma); 55 if (rc) 56 return rc; 57 } 58 59 return 0; 60 } 61 62 void ionic_pgtbl_unbuf(struct ionic_ibdev *dev, struct ionic_tbl_buf *buf) 63 { 64 if (buf->tbl_buf) 65 dma_unmap_single(dev->lif_cfg.hwdev, buf->tbl_dma, 66 buf->tbl_size, DMA_TO_DEVICE); 67 68 kfree(buf->tbl_buf); 69 memset(buf, 0, sizeof(*buf)); 70 } 71 72 int ionic_pgtbl_init(struct ionic_ibdev *dev, 73 struct ionic_tbl_buf *buf, 74 struct ib_umem *umem, 75 dma_addr_t dma, 76 int limit, 77 u64 page_size) 78 { 79 int rc; 80 81 memset(buf, 0, sizeof(*buf)); 82 83 if (umem) { 84 limit = ib_umem_num_dma_blocks(umem, page_size); 85 buf->page_size_log2 = order_base_2(page_size); 86 } 87 88 if (limit < 1) 89 return -EINVAL; 90 91 buf->tbl_limit = limit; 92 93 /* skip pgtbl if contiguous / direct translation */ 94 if (limit > 1) { 95 rc = ionic_tbl_buf_alloc(dev, buf); 96 if (rc) 97 return rc; 98 } 99 100 if (umem) 101 rc = ionic_pgtbl_umem(buf, umem); 102 else 103 rc = ionic_pgtbl_page(buf, dma); 104 105 if (rc) 106 goto err_unbuf; 107 108 return 0; 109 110 err_unbuf: 111 ionic_pgtbl_unbuf(dev, buf); 112 return rc; 113 } 114