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