• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18 
19 #include <linux/slab.h>
20 #include <linux/vmalloc.h>
21 #include <linux/module.h>
22 #include <linux/kernel.h>
23 #include <asm/io.h>
24 #include <linux/uaccess.h>
25 #include <linux/version.h>
26 #include <linux/mm.h>
27 #include <linux/memblock.h>
28 
29 #include "hi_osal.h"
30 #include "hi_module.h"
31 #include "securec.h"
32 
33 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)
34 #ifndef CONFIG_64BIT
35 #include <mach/io.h>
36 #endif
37 #endif
38 
39 unsigned int g_kmalloc_used[HI_ID_BUTT] = {0};
40 unsigned int g_vmalloc_used[HI_ID_BUTT] = {0};
41 
osal_get_kmalloc_used(unsigned int module_id)42 unsigned int osal_get_kmalloc_used(unsigned int module_id)
43 {
44     if (module_id >= HI_ID_BUTT) {
45         return 0;
46     }
47 
48     return g_kmalloc_used[module_id];
49 }
50 
osal_get_vmalloc_used(unsigned int module_id)51 unsigned int osal_get_vmalloc_used(unsigned int module_id)
52 {
53     if (module_id >= HI_ID_BUTT) {
54         return 0;
55     }
56 
57     return g_vmalloc_used[module_id];
58 }
59 
osal_convert_gfp_flag(unsigned int osal_gfp_flag)60 static unsigned int osal_convert_gfp_flag(unsigned int osal_gfp_flag)
61 {
62     unsigned int gfp_flag;
63 
64     switch (osal_gfp_flag) {
65         case OSAL_GFP_KERNEL:
66             gfp_flag = GFP_KERNEL;
67             break;
68 
69         case OSAL_GFP_ATOMIC:
70             gfp_flag = GFP_ATOMIC;
71             break;
72 
73         case OSAL_GFP_DMA:
74             gfp_flag = GFP_DMA;
75             break;
76 
77         default:
78             gfp_flag = GFP_KERNEL;
79             break;
80     }
81 
82     return gfp_flag;
83 }
84 
osal_kmalloc(unsigned int module_id,unsigned long size,unsigned int osal_gfp_flag)85 void *osal_kmalloc(unsigned int module_id, unsigned long size, unsigned int osal_gfp_flag)
86 {
87     unsigned int gfp_flag;
88 
89     if (module_id >= HI_ID_BUTT) {
90         printk("osal_kmalloc module id(%ud) is wrong\n", module_id);
91         osal_dump_stack();
92         return NULL;
93     }
94 
95     g_kmalloc_used[module_id]++;
96     gfp_flag = osal_convert_gfp_flag(osal_gfp_flag);
97     return kmalloc(size, gfp_flag);
98 }
99 EXPORT_SYMBOL(osal_kmalloc);
100 
osal_kfree(unsigned int module_id,const void * addr)101 void osal_kfree(unsigned int module_id, const void *addr)
102 {
103     if (module_id >= HI_ID_BUTT) {
104         printk("osal_kfree module id(%ud) is wrong\n", module_id);
105         osal_dump_stack();
106         return;
107     }
108 
109     if (addr != NULL) {
110         g_kmalloc_used[module_id]--;
111         kfree(addr);
112     }
113     return;
114 }
115 EXPORT_SYMBOL(osal_kfree);
116 
osal_vmalloc(unsigned int module_id,unsigned long size)117 void *osal_vmalloc(unsigned int module_id, unsigned long size)
118 {
119     if (module_id >= HI_ID_BUTT) {
120         printk("osal_vmalloc module id(%ud) is wrong\n", module_id);
121         osal_dump_stack();
122         return NULL;
123     }
124 
125     g_vmalloc_used[module_id]++;
126 
127     return vmalloc(size);
128 }
129 
130 EXPORT_SYMBOL(osal_vmalloc);
131 
osal_vfree(unsigned int module_id,const void * addr)132 void osal_vfree(unsigned int module_id, const void *addr)
133 {
134     if (module_id >= HI_ID_BUTT) {
135         printk("osal_vfree module id(%ud) is wrong\n", module_id);
136         osal_dump_stack();
137         return;
138     }
139 
140     if (addr != NULL) {
141         g_vmalloc_used[module_id]--;
142         vfree(addr);
143     }
144     return;
145 }
146 
147 EXPORT_SYMBOL(osal_vfree);
148 
osal_ioremap(unsigned long phys_addr,unsigned long size)149 void *osal_ioremap(unsigned long phys_addr, unsigned long size)
150 {
151     return ioremap(phys_addr, size);
152 }
153 EXPORT_SYMBOL(osal_ioremap);
154 
osal_ioremap_nocache(unsigned long phys_addr,unsigned long size)155 void *osal_ioremap_nocache(unsigned long phys_addr, unsigned long size)
156 {
157 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
158     return ioremap(phys_addr, size);
159 #else
160     return ioremap_nocache(phys_addr, size);
161 #endif
162 }
163 EXPORT_SYMBOL(osal_ioremap_nocache);
164 
osal_ioremap_cached(unsigned long phys_addr,unsigned long size)165 void *osal_ioremap_cached(unsigned long phys_addr, unsigned long size)
166 {
167 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
168     return ioremap_cached(phys_addr, size);
169 #else
170     return ioremap_cache(phys_addr, size);
171 #endif
172 }
173 EXPORT_SYMBOL(osal_ioremap_cached);
174 
osal_iounmap(volatile void * addr)175 void osal_iounmap(volatile void *addr)
176 {
177     iounmap(addr);
178 }
179 EXPORT_SYMBOL(osal_iounmap);
180 
osal_copy_from_user(void * to,const void * from,unsigned long n)181 unsigned long osal_copy_from_user(void *to, const void *from, unsigned long n)
182 {
183     return copy_from_user(to, from, n);
184 }
185 EXPORT_SYMBOL(osal_copy_from_user);
186 
osal_copy_to_user(void * to,const void * from,unsigned long n)187 unsigned long osal_copy_to_user(void *to, const void *from, unsigned long n)
188 {
189     return copy_to_user(to, from, n);
190 }
191 EXPORT_SYMBOL(osal_copy_to_user);
192 
osal_access_ok(int type,const void * addr,unsigned long size)193 int osal_access_ok(int type, const void *addr, unsigned long size)
194 {
195     uintptr_t uaddr = (uintptr_t)addr;
196 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
197     return access_ok(uaddr, size);
198 #else
199     return access_ok(type, uaddr, size);
200 #endif
201 }
202 EXPORT_SYMBOL(osal_access_ok);
203 
osal_phys_to_virt(unsigned long addr)204 void *osal_phys_to_virt(unsigned long addr)
205 {
206     return phys_to_virt(addr);
207 }
208 EXPORT_SYMBOL(osal_phys_to_virt);
209 
osal_virt_to_phys(const void * virt_addr)210 unsigned long osal_virt_to_phys(const void *virt_addr)
211 {
212     return virt_to_phys(virt_addr);
213 }
214 EXPORT_SYMBOL(osal_virt_to_phys);
215 
216 /*
217  * Maps @size from @phys_addr into contiguous kernel virtual space
218  * Note:this function only support VM_MAP with PAGE_KERNEL flag
219  * */
osal_blockmem_vmap(unsigned long phys_addr,unsigned long size)220 void *osal_blockmem_vmap(unsigned long phys_addr, unsigned long size)
221 {
222     int ret = 0;
223     unsigned int i = 0;
224     unsigned int page_count;
225     struct page **pages = NULL;
226     void *vaddr = NULL;
227 
228     if ((phys_addr == 0) || (size == 0)) {
229         printk("invalid vmap address: 0x%lX or size:%lu\n", phys_addr, size);
230         return NULL;
231     }
232 
233     page_count = (size + PAGE_SIZE - 1) / PAGE_SIZE;
234     pages = vmalloc(page_count * sizeof(struct page *));
235     if (!pages) {
236         printk("vmap malloc pages failed\n");
237         return NULL;
238     }
239 
240     ret = memset_s(pages, page_count * sizeof(struct page *), 0, page_count * sizeof(struct page *));
241     if (ret != 0) {
242         return NULL;
243     }
244 
245     for (i = 0; i < page_count; i++) {
246         pages[i] = phys_to_page(phys_addr + i * PAGE_SIZE);
247     }
248 
249     vaddr = vmap(pages, page_count, VM_MAP, PAGE_KERNEL);
250     if (!vaddr) {
251         printk("vmap failed phys_addr:0x%lX, size:%lu\n", phys_addr, size);
252     }
253 
254     vfree(pages);
255     pages = NULL;
256 
257     return vaddr;
258 }
259 EXPORT_SYMBOL(osal_blockmem_vmap);
260 
261 /*
262  * Free the virtually contiguous memory area starting at @virt_addr
263  * which was created from the phys_addr passed to osal_vunmap()
264  * Must not be called in interrupt context.
265  * */
osal_blockmem_vunmap(const void * virt_addr)266 void osal_blockmem_vunmap(const void *virt_addr)
267 {
268     if (!virt_addr) {
269         printk("vumap failed: virt_addr is NULL\n");
270         return;
271     }
272 
273     vunmap(virt_addr);
274 }
275 EXPORT_SYMBOL(osal_blockmem_vunmap);
276 
277 /*
278  * Free the reserved memory which has been defined in product
279  **/
osal_blockmem_free(unsigned long phys_addr,unsigned long size)280 void osal_blockmem_free(unsigned long phys_addr, unsigned long size)
281 {
282     unsigned int pfn_start;
283     unsigned int pfn_end;
284 
285     if ((phys_addr == 0) || (size == 0)) {
286         printk("Free block memory failed: phys_addr 0x%lX,size %lu\n",
287             phys_addr, size);
288         return;
289     }
290 
291     pfn_start = __phys_to_pfn(phys_addr);
292     pfn_end = __phys_to_pfn(phys_addr + size);
293 
294     for (; pfn_start < pfn_end; pfn_start++) {
295         struct page *page = pfn_to_page(pfn_start);
296         ClearPageReserved(page);
297         init_page_count(page);
298         __free_page(page);
299         adjust_managed_page_count(page, 1); /* 1 block mem page count */
300     }
301 
302 #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
303 #ifndef CONFIG_ARCH_DISCARD_MEMBLOCK
304     (void)memblock_free(phys_addr, size);
305 #endif
306 #endif
307     return;
308 }
309 EXPORT_SYMBOL(osal_blockmem_free);
310