1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Re-map IO memory to kernel address space so that we can access it. |
4 | * This is needed for high PCI addresses that aren't mapped in the |
5 | * 640k-1MB IO memory area on PC's |
6 | * |
7 | * (C) Copyright 1995 1996 Linus Torvalds |
8 | */ |
9 | #include <linux/vmalloc.h> |
10 | #include <linux/mm.h> |
11 | #include <linux/io.h> |
12 | #include <linux/export.h> |
13 | #include <linux/ioremap.h> |
14 | |
15 | void __iomem *generic_ioremap_prot(phys_addr_t phys_addr, size_t size, |
16 | pgprot_t prot) |
17 | { |
18 | unsigned long offset, vaddr; |
19 | phys_addr_t last_addr; |
20 | struct vm_struct *area; |
21 | |
22 | /* An early platform driver might end up here */ |
23 | if (WARN_ON_ONCE(!slab_is_available())) |
24 | return NULL; |
25 | |
26 | /* Disallow wrap-around or zero size */ |
27 | last_addr = phys_addr + size - 1; |
28 | if (!size || last_addr < phys_addr) |
29 | return NULL; |
30 | |
31 | /* Page-align mappings */ |
32 | offset = phys_addr & (~PAGE_MASK); |
33 | phys_addr -= offset; |
34 | size = PAGE_ALIGN(size + offset); |
35 | |
36 | area = __get_vm_area_caller(size, VM_IOREMAP, IOREMAP_START, |
37 | IOREMAP_END, caller: __builtin_return_address(0)); |
38 | if (!area) |
39 | return NULL; |
40 | vaddr = (unsigned long)area->addr; |
41 | area->phys_addr = phys_addr; |
42 | |
43 | if (ioremap_page_range(addr: vaddr, end: vaddr + size, phys_addr, prot)) { |
44 | free_vm_area(area); |
45 | return NULL; |
46 | } |
47 | |
48 | return (void __iomem *)(vaddr + offset); |
49 | } |
50 | |
51 | #ifndef ioremap_prot |
52 | void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size, |
53 | unsigned long prot) |
54 | { |
55 | return generic_ioremap_prot(phys_addr, size, __pgprot(prot)); |
56 | } |
57 | EXPORT_SYMBOL(ioremap_prot); |
58 | #endif |
59 | |
60 | void generic_iounmap(volatile void __iomem *addr) |
61 | { |
62 | void *vaddr = (void *)((unsigned long)addr & PAGE_MASK); |
63 | |
64 | if (is_ioremap_addr(x: vaddr)) |
65 | vunmap(addr: vaddr); |
66 | } |
67 | |
68 | #ifndef iounmap |
69 | void iounmap(volatile void __iomem *addr) |
70 | { |
71 | generic_iounmap(addr); |
72 | } |
73 | EXPORT_SYMBOL(iounmap); |
74 | #endif |
75 | |