]> git.ipfire.org Git - thirdparty/kernel/stable.git/blame - include/linux/io-mapping.h
treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 504
[thirdparty/kernel/stable.git] / include / linux / io-mapping.h
CommitLineData
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
22struct 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 39static inline struct io_mapping *
cafaf14a
CW
40io_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
55static inline void
cafaf14a 56io_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 62static inline void __iomem *
fca3ec01 63io_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
75static inline void
3e4d3af5 76io_mapping_unmap_atomic(void __iomem *vaddr)
9663f2e6 77{
3e4d3af5 78 iounmap_atomic(vaddr);
9663f2e6
KP
79}
80
29bc17ec 81static inline void __iomem *
d8dab00d
CW
82io_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
94static inline void
29bc17ec 95io_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 106static inline struct io_mapping *
cafaf14a
CW
107io_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
125static inline void
126io_mapping_fini(struct io_mapping *mapping)
127{
128 iounmap(mapping->iomem);
129}
130
131/* Non-atomic map/unmap */
132static inline void __iomem *
133io_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
140static inline void
cafaf14a 141io_mapping_unmap(void __iomem *vaddr)
9663f2e6
KP
142{
143}
144
145/* Atomic map/unmap */
29bc17ec 146static inline void __iomem *
fca3ec01 147io_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
155static inline void
3e4d3af5 156io_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
165static inline struct io_mapping *
166io_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
183static inline void
cafaf14a 184io_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 */