Commit | Line | Data |
---|---|---|
775c8a3d | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
9663f2e6 KP |
2 | /* |
3 | * Copyright © 2008 Keith Packard <keithp@keithp.com> | |
9663f2e6 KP |
4 | */ |
5 | ||
6 | #ifndef _LINUX_IO_MAPPING_H | |
7 | #define _LINUX_IO_MAPPING_H | |
8 | ||
9 | #include <linux/types.h> | |
5a0e3ad6 | 10 | #include <linux/slab.h> |
187f1882 | 11 | #include <linux/bug.h> |
2584cf83 | 12 | #include <linux/io.h> |
9663f2e6 | 13 | #include <asm/page.h> |
9663f2e6 KP |
14 | |
15 | /* | |
16 | * The io_mapping mechanism provides an abstraction for mapping | |
17 | * individual pages from an io device to the CPU in an efficient fashion. | |
18 | * | |
395cf969 | 19 | * See Documentation/io-mapping.txt |
9663f2e6 KP |
20 | */ |
21 | ||
4ab0d47d VP |
22 | struct io_mapping { |
23 | resource_size_t base; | |
24 | unsigned long size; | |
25 | pgprot_t prot; | |
cafaf14a | 26 | void __iomem *iomem; |
4ab0d47d VP |
27 | }; |
28 | ||
cafaf14a CW |
29 | #ifdef CONFIG_HAVE_ATOMIC_IOMAP |
30 | ||
31 | #include <asm/iomap.h> | |
e5beae16 KP |
32 | /* |
33 | * For small address space machines, mapping large objects | |
34 | * into the kernel virtual space isn't practical. Where | |
35 | * available, use fixmap support to dynamically map pages | |
36 | * of the object at run time. | |
37 | */ | |
9663f2e6 | 38 | |
9663f2e6 | 39 | static inline struct io_mapping * |
cafaf14a CW |
40 | io_mapping_init_wc(struct io_mapping *iomap, |
41 | resource_size_t base, | |
42 | unsigned long size) | |
9663f2e6 | 43 | { |
9e36fda0 | 44 | pgprot_t prot; |
4ab0d47d | 45 | |
9e36fda0 | 46 | if (iomap_create_wc(base, size, &prot)) |
cafaf14a | 47 | return NULL; |
4ab0d47d VP |
48 | |
49 | iomap->base = base; | |
50 | iomap->size = size; | |
9e36fda0 | 51 | iomap->prot = prot; |
4ab0d47d | 52 | return iomap; |
9663f2e6 KP |
53 | } |
54 | ||
55 | static inline void | |
cafaf14a | 56 | io_mapping_fini(struct io_mapping *mapping) |
9663f2e6 | 57 | { |
9e36fda0 | 58 | iomap_free(mapping->base, mapping->size); |
9663f2e6 KP |
59 | } |
60 | ||
61 | /* Atomic map/unmap */ | |
29bc17ec | 62 | static inline void __iomem * |
fca3ec01 | 63 | io_mapping_map_atomic_wc(struct io_mapping *mapping, |
3e4d3af5 | 64 | unsigned long offset) |
9663f2e6 | 65 | { |
4ab0d47d VP |
66 | resource_size_t phys_addr; |
67 | unsigned long pfn; | |
68 | ||
69 | BUG_ON(offset >= mapping->size); | |
70 | phys_addr = mapping->base + offset; | |
71 | pfn = (unsigned long) (phys_addr >> PAGE_SHIFT); | |
3e4d3af5 | 72 | return iomap_atomic_prot_pfn(pfn, mapping->prot); |
9663f2e6 KP |
73 | } |
74 | ||
75 | static inline void | |
3e4d3af5 | 76 | io_mapping_unmap_atomic(void __iomem *vaddr) |
9663f2e6 | 77 | { |
3e4d3af5 | 78 | iounmap_atomic(vaddr); |
9663f2e6 KP |
79 | } |
80 | ||
29bc17ec | 81 | static inline void __iomem * |
d8dab00d CW |
82 | io_mapping_map_wc(struct io_mapping *mapping, |
83 | unsigned long offset, | |
84 | unsigned long size) | |
9663f2e6 | 85 | { |
5ce04e3d PV |
86 | resource_size_t phys_addr; |
87 | ||
4ab0d47d | 88 | BUG_ON(offset >= mapping->size); |
5ce04e3d PV |
89 | phys_addr = mapping->base + offset; |
90 | ||
d8dab00d | 91 | return ioremap_wc(phys_addr, size); |
9663f2e6 KP |
92 | } |
93 | ||
94 | static inline void | |
29bc17ec | 95 | io_mapping_unmap(void __iomem *vaddr) |
9663f2e6 | 96 | { |
e5beae16 | 97 | iounmap(vaddr); |
9663f2e6 KP |
98 | } |
99 | ||
e5beae16 | 100 | #else |
9663f2e6 | 101 | |
24dd85ff | 102 | #include <linux/uaccess.h> |
bcaaa0c4 | 103 | #include <asm/pgtable.h> |
4ab0d47d | 104 | |
e5beae16 | 105 | /* Create the io_mapping object*/ |
9663f2e6 | 106 | static inline struct io_mapping * |
cafaf14a CW |
107 | io_mapping_init_wc(struct io_mapping *iomap, |
108 | resource_size_t base, | |
109 | unsigned long size) | |
110 | { | |
111 | iomap->base = base; | |
112 | iomap->size = size; | |
113 | iomap->iomem = ioremap_wc(base, size); | |
35124389 DV |
114 | #if defined(pgprot_noncached_wc) /* archs can't agree on a name ... */ |
115 | iomap->prot = pgprot_noncached_wc(PAGE_KERNEL); | |
116 | #elif defined(pgprot_writecombine) | |
bcaaa0c4 | 117 | iomap->prot = pgprot_writecombine(PAGE_KERNEL); |
35124389 DV |
118 | #else |
119 | iomap->prot = pgprot_noncached(PAGE_KERNEL); | |
120 | #endif | |
cafaf14a CW |
121 | |
122 | return iomap; | |
123 | } | |
124 | ||
125 | static inline void | |
126 | io_mapping_fini(struct io_mapping *mapping) | |
127 | { | |
128 | iounmap(mapping->iomem); | |
129 | } | |
130 | ||
131 | /* Non-atomic map/unmap */ | |
132 | static inline void __iomem * | |
133 | io_mapping_map_wc(struct io_mapping *mapping, | |
134 | unsigned long offset, | |
135 | unsigned long size) | |
9663f2e6 | 136 | { |
cafaf14a | 137 | return mapping->iomem + offset; |
9663f2e6 KP |
138 | } |
139 | ||
140 | static inline void | |
cafaf14a | 141 | io_mapping_unmap(void __iomem *vaddr) |
9663f2e6 KP |
142 | { |
143 | } | |
144 | ||
145 | /* Atomic map/unmap */ | |
29bc17ec | 146 | static inline void __iomem * |
fca3ec01 | 147 | io_mapping_map_atomic_wc(struct io_mapping *mapping, |
3e4d3af5 | 148 | unsigned long offset) |
9663f2e6 | 149 | { |
2cb7c9cb | 150 | preempt_disable(); |
24dd85ff | 151 | pagefault_disable(); |
cafaf14a | 152 | return io_mapping_map_wc(mapping, offset, PAGE_SIZE); |
9663f2e6 KP |
153 | } |
154 | ||
155 | static inline void | |
3e4d3af5 | 156 | io_mapping_unmap_atomic(void __iomem *vaddr) |
9663f2e6 | 157 | { |
cafaf14a | 158 | io_mapping_unmap(vaddr); |
24dd85ff | 159 | pagefault_enable(); |
2cb7c9cb | 160 | preempt_enable(); |
9663f2e6 KP |
161 | } |
162 | ||
cafaf14a CW |
163 | #endif /* HAVE_ATOMIC_IOMAP */ |
164 | ||
165 | static inline struct io_mapping * | |
166 | io_mapping_create_wc(resource_size_t base, | |
167 | unsigned long size) | |
9663f2e6 | 168 | { |
cafaf14a CW |
169 | struct io_mapping *iomap; |
170 | ||
171 | iomap = kmalloc(sizeof(*iomap), GFP_KERNEL); | |
172 | if (!iomap) | |
173 | return NULL; | |
174 | ||
175 | if (!io_mapping_init_wc(iomap, base, size)) { | |
176 | kfree(iomap); | |
177 | return NULL; | |
178 | } | |
179 | ||
180 | return iomap; | |
9663f2e6 KP |
181 | } |
182 | ||
183 | static inline void | |
cafaf14a | 184 | io_mapping_free(struct io_mapping *iomap) |
9663f2e6 | 185 | { |
cafaf14a CW |
186 | io_mapping_fini(iomap); |
187 | kfree(iomap); | |
9663f2e6 | 188 | } |
e5beae16 | 189 | |
9663f2e6 | 190 | #endif /* _LINUX_IO_MAPPING_H */ |