Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / arch / nds32 / mm / ioremap.c
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2005-2017 Andes Technology Corporation
3
4 #include <linux/vmalloc.h>
5 #include <linux/io.h>
6 #include <linux/mm.h>
7 #include <asm/pgtable.h>
8
9 void __iomem *ioremap(phys_addr_t phys_addr, size_t size);
10
11 static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size,
12                                       void *caller)
13 {
14         struct vm_struct *area;
15         unsigned long addr, offset, last_addr;
16         pgprot_t prot;
17
18         /* Don't allow wraparound or zero size */
19         last_addr = phys_addr + size - 1;
20         if (!size || last_addr < phys_addr)
21                 return NULL;
22
23         /*
24          * Mappings have to be page-aligned
25          */
26         offset = phys_addr & ~PAGE_MASK;
27         phys_addr &= PAGE_MASK;
28         size = PAGE_ALIGN(last_addr + 1) - phys_addr;
29
30         /*
31          * Ok, go for it..
32          */
33         area = get_vm_area_caller(size, VM_IOREMAP, caller);
34         if (!area)
35                 return NULL;
36
37         area->phys_addr = phys_addr;
38         addr = (unsigned long)area->addr;
39         prot = __pgprot(_PAGE_V | _PAGE_M_KRW | _PAGE_D |
40                         _PAGE_G | _PAGE_C_DEV);
41         if (ioremap_page_range(addr, addr + size, phys_addr, prot)) {
42                 vunmap((void *)addr);
43                 return NULL;
44         }
45         return (__force void __iomem *)(offset + (char *)addr);
46
47 }
48
49 void __iomem *ioremap(phys_addr_t phys_addr, size_t size)
50 {
51         return __ioremap_caller(phys_addr, size,
52                                 __builtin_return_address(0));
53 }
54
55 EXPORT_SYMBOL(ioremap);
56
57 void iounmap(volatile void __iomem * addr)
58 {
59         vunmap((void *)(PAGE_MASK & (unsigned long)addr));
60 }
61
62 EXPORT_SYMBOL(iounmap);