diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2016-08-19 11:54:26 -0400 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2016-08-19 12:13:35 -0400 |
commit | cafaf14a5d8f152ed3c984ecd48dee6e824446bc (patch) | |
tree | 3053466d3791ede38d33e61f34b8541bae8d3a43 | |
parent | 8678fdaf396c3aa3732b3d98ce2241633dbc26ba (diff) |
io-mapping: Always create a struct to hold metadata about the io-mapping
Currently, we only allocate a structure to hold metadata if we need to
allocate an ioremap for every access, such as on x86-32. However, it
would be useful to store basic information about the io-mapping, such as
its page protection, on all platforms.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: linux-mm@kvack.org
Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20160819155428.1670-4-chris@chris-wilson.co.uk
-rw-r--r-- | include/linux/io-mapping.h | 92 |
1 files changed, 57 insertions, 35 deletions
diff --git a/include/linux/io-mapping.h b/include/linux/io-mapping.h index 645ad06b5d52..b4c4b5c4216d 100644 --- a/include/linux/io-mapping.h +++ b/include/linux/io-mapping.h | |||
@@ -31,16 +31,16 @@ | |||
31 | * See Documentation/io-mapping.txt | 31 | * See Documentation/io-mapping.txt |
32 | */ | 32 | */ |
33 | 33 | ||
34 | #ifdef CONFIG_HAVE_ATOMIC_IOMAP | ||
35 | |||
36 | #include <asm/iomap.h> | ||
37 | |||
38 | struct io_mapping { | 34 | struct io_mapping { |
39 | resource_size_t base; | 35 | resource_size_t base; |
40 | unsigned long size; | 36 | unsigned long size; |
41 | pgprot_t prot; | 37 | pgprot_t prot; |
38 | void __iomem *iomem; | ||
42 | }; | 39 | }; |
43 | 40 | ||
41 | #ifdef CONFIG_HAVE_ATOMIC_IOMAP | ||
42 | |||
43 | #include <asm/iomap.h> | ||
44 | /* | 44 | /* |
45 | * For small address space machines, mapping large objects | 45 | * For small address space machines, mapping large objects |
46 | * into the kernel virtual space isn't practical. Where | 46 | * into the kernel virtual space isn't practical. Where |
@@ -49,34 +49,25 @@ struct io_mapping { | |||
49 | */ | 49 | */ |
50 | 50 | ||
51 | static inline struct io_mapping * | 51 | static inline struct io_mapping * |
52 | io_mapping_create_wc(resource_size_t base, unsigned long size) | 52 | io_mapping_init_wc(struct io_mapping *iomap, |
53 | resource_size_t base, | ||
54 | unsigned long size) | ||
53 | { | 55 | { |
54 | struct io_mapping *iomap; | ||
55 | pgprot_t prot; | 56 | pgprot_t prot; |
56 | 57 | ||
57 | iomap = kmalloc(sizeof(*iomap), GFP_KERNEL); | ||
58 | if (!iomap) | ||
59 | goto out_err; | ||
60 | |||
61 | if (iomap_create_wc(base, size, &prot)) | 58 | if (iomap_create_wc(base, size, &prot)) |
62 | goto out_free; | 59 | return NULL; |
63 | 60 | ||
64 | iomap->base = base; | 61 | iomap->base = base; |
65 | iomap->size = size; | 62 | iomap->size = size; |
66 | iomap->prot = prot; | 63 | iomap->prot = prot; |
67 | return iomap; | 64 | return iomap; |
68 | |||
69 | out_free: | ||
70 | kfree(iomap); | ||
71 | out_err: | ||
72 | return NULL; | ||
73 | } | 65 | } |
74 | 66 | ||
75 | static inline void | 67 | static inline void |
76 | io_mapping_free(struct io_mapping *mapping) | 68 | io_mapping_fini(struct io_mapping *mapping) |
77 | { | 69 | { |
78 | iomap_free(mapping->base, mapping->size); | 70 | iomap_free(mapping->base, mapping->size); |
79 | kfree(mapping); | ||
80 | } | 71 | } |
81 | 72 | ||
82 | /* Atomic map/unmap */ | 73 | /* Atomic map/unmap */ |
@@ -121,21 +112,40 @@ io_mapping_unmap(void __iomem *vaddr) | |||
121 | #else | 112 | #else |
122 | 113 | ||
123 | #include <linux/uaccess.h> | 114 | #include <linux/uaccess.h> |
124 | 115 | #include <asm/pgtable_types.h> | |
125 | /* this struct isn't actually defined anywhere */ | ||
126 | struct io_mapping; | ||
127 | 116 | ||
128 | /* Create the io_mapping object*/ | 117 | /* Create the io_mapping object*/ |
129 | static inline struct io_mapping * | 118 | static inline struct io_mapping * |
130 | io_mapping_create_wc(resource_size_t base, unsigned long size) | 119 | io_mapping_init_wc(struct io_mapping *iomap, |
120 | resource_size_t base, | ||
121 | unsigned long size) | ||
122 | { | ||
123 | iomap->base = base; | ||
124 | iomap->size = size; | ||
125 | iomap->iomem = ioremap_wc(base, size); | ||
126 | iomap->prot = pgprot_writecombine(PAGE_KERNEL_IO); | ||
127 | |||
128 | return iomap; | ||
129 | } | ||
130 | |||
131 | static inline void | ||
132 | io_mapping_fini(struct io_mapping *mapping) | ||
133 | { | ||
134 | iounmap(mapping->iomem); | ||
135 | } | ||
136 | |||
137 | /* Non-atomic map/unmap */ | ||
138 | static inline void __iomem * | ||
139 | io_mapping_map_wc(struct io_mapping *mapping, | ||
140 | unsigned long offset, | ||
141 | unsigned long size) | ||
131 | { | 142 | { |
132 | return (struct io_mapping __force *) ioremap_wc(base, size); | 143 | return mapping->iomem + offset; |
133 | } | 144 | } |
134 | 145 | ||
135 | static inline void | 146 | static inline void |
136 | io_mapping_free(struct io_mapping *mapping) | 147 | io_mapping_unmap(void __iomem *vaddr) |
137 | { | 148 | { |
138 | iounmap((void __force __iomem *) mapping); | ||
139 | } | 149 | } |
140 | 150 | ||
141 | /* Atomic map/unmap */ | 151 | /* Atomic map/unmap */ |
@@ -145,30 +155,42 @@ io_mapping_map_atomic_wc(struct io_mapping *mapping, | |||
145 | { | 155 | { |
146 | preempt_disable(); | 156 | preempt_disable(); |
147 | pagefault_disable(); | 157 | pagefault_disable(); |
148 | return ((char __force __iomem *) mapping) + offset; | 158 | return io_mapping_map_wc(mapping, offset, PAGE_SIZE); |
149 | } | 159 | } |
150 | 160 | ||
151 | static inline void | 161 | static inline void |
152 | io_mapping_unmap_atomic(void __iomem *vaddr) | 162 | io_mapping_unmap_atomic(void __iomem *vaddr) |
153 | { | 163 | { |
164 | io_mapping_unmap(vaddr); | ||
154 | pagefault_enable(); | 165 | pagefault_enable(); |
155 | preempt_enable(); | 166 | preempt_enable(); |
156 | } | 167 | } |
157 | 168 | ||
158 | /* Non-atomic map/unmap */ | 169 | #endif /* HAVE_ATOMIC_IOMAP */ |
159 | static inline void __iomem * | 170 | |
160 | io_mapping_map_wc(struct io_mapping *mapping, | 171 | static inline struct io_mapping * |
161 | unsigned long offset, | 172 | io_mapping_create_wc(resource_size_t base, |
162 | unsigned long size) | 173 | unsigned long size) |
163 | { | 174 | { |
164 | return ((char __force __iomem *) mapping) + offset; | 175 | struct io_mapping *iomap; |
176 | |||
177 | iomap = kmalloc(sizeof(*iomap), GFP_KERNEL); | ||
178 | if (!iomap) | ||
179 | return NULL; | ||
180 | |||
181 | if (!io_mapping_init_wc(iomap, base, size)) { | ||
182 | kfree(iomap); | ||
183 | return NULL; | ||
184 | } | ||
185 | |||
186 | return iomap; | ||
165 | } | 187 | } |
166 | 188 | ||
167 | static inline void | 189 | static inline void |
168 | io_mapping_unmap(void __iomem *vaddr) | 190 | io_mapping_free(struct io_mapping *iomap) |
169 | { | 191 | { |
192 | io_mapping_fini(iomap); | ||
193 | kfree(iomap); | ||
170 | } | 194 | } |
171 | 195 | ||
172 | #endif /* HAVE_ATOMIC_IOMAP */ | ||
173 | |||
174 | #endif /* _LINUX_IO_MAPPING_H */ | 196 | #endif /* _LINUX_IO_MAPPING_H */ |