xref: /linux/drivers/infiniband/hw/ionic/ionic_pgtbl.c (revision f3bdbd42702c6b10ebe627828c76ef51c68e4355)
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