xref: /linux/drivers/net/ethernet/huawei/hinic3/hinic3_common.c (revision e78f70bad29c5ae1e1076698b690b15794e9b81e)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
3 
4 #include <linux/delay.h>
5 #include <linux/dma-mapping.h>
6 
7 #include "hinic3_common.h"
8 
9 int hinic3_dma_zalloc_coherent_align(struct device *dev, u32 size, u32 align,
10 				     gfp_t flag,
11 				     struct hinic3_dma_addr_align *mem_align)
12 {
13 	dma_addr_t paddr, align_paddr;
14 	void *vaddr, *align_vaddr;
15 	u32 real_size = size;
16 
17 	vaddr = dma_alloc_coherent(dev, real_size, &paddr, flag);
18 	if (!vaddr)
19 		return -ENOMEM;
20 
21 	align_paddr = ALIGN(paddr, align);
22 	if (align_paddr == paddr) {
23 		align_vaddr = vaddr;
24 		goto out;
25 	}
26 
27 	dma_free_coherent(dev, real_size, vaddr, paddr);
28 
29 	/* realloc memory for align */
30 	real_size = size + align;
31 	vaddr = dma_alloc_coherent(dev, real_size, &paddr, flag);
32 	if (!vaddr)
33 		return -ENOMEM;
34 
35 	align_paddr = ALIGN(paddr, align);
36 	align_vaddr = vaddr + (align_paddr - paddr);
37 
38 out:
39 	mem_align->real_size = real_size;
40 	mem_align->ori_vaddr = vaddr;
41 	mem_align->ori_paddr = paddr;
42 	mem_align->align_vaddr = align_vaddr;
43 	mem_align->align_paddr = align_paddr;
44 
45 	return 0;
46 }
47 
48 void hinic3_dma_free_coherent_align(struct device *dev,
49 				    struct hinic3_dma_addr_align *mem_align)
50 {
51 	dma_free_coherent(dev, mem_align->real_size,
52 			  mem_align->ori_vaddr, mem_align->ori_paddr);
53 }
54