diff options
Diffstat (limited to 'arch/arm/mach-tegra/include/mach/iovmm.h')
-rw-r--r-- | arch/arm/mach-tegra/include/mach/iovmm.h | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/include/mach/iovmm.h b/arch/arm/mach-tegra/include/mach/iovmm.h new file mode 100644 index 00000000000..fd83a326e12 --- /dev/null +++ b/arch/arm/mach-tegra/include/mach/iovmm.h | |||
@@ -0,0 +1,323 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-tegra/include/mach/iovmm.h | ||
3 | * | ||
4 | * Copyright (c) 2010-2011, NVIDIA Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed i the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/list.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/miscdevice.h> | ||
24 | #include <linux/rbtree.h> | ||
25 | #include <linux/rwsem.h> | ||
26 | #include <linux/spinlock.h> | ||
27 | #include <linux/types.h> | ||
28 | |||
29 | #ifndef _MACH_TEGRA_IOVMM_H_ | ||
30 | #define _MACH_TEGRA_IOVMM_H_ | ||
31 | |||
32 | typedef u32 tegra_iovmm_addr_t; | ||
33 | |||
34 | struct tegra_iovmm_device_ops; | ||
35 | |||
36 | /* | ||
37 | * each I/O virtual memory manager unit should register a device with | ||
38 | * the iovmm system | ||
39 | */ | ||
40 | struct tegra_iovmm_device { | ||
41 | struct tegra_iovmm_device_ops *ops; | ||
42 | const char *name; | ||
43 | struct list_head list; | ||
44 | int pgsize_bits; | ||
45 | }; | ||
46 | |||
47 | /* | ||
48 | * tegra_iovmm_domain serves a purpose analagous to mm_struct as defined in | ||
49 | * <linux/mm_types.h> - it defines a virtual address space within which | ||
50 | * tegra_iovmm_areas can be created. | ||
51 | */ | ||
52 | struct tegra_iovmm_domain { | ||
53 | atomic_t clients; | ||
54 | atomic_t locks; | ||
55 | spinlock_t block_lock; /* RB-tree for iovmm_area blocks */ | ||
56 | unsigned long flags; | ||
57 | wait_queue_head_t delay_lock; /* when lock_client fails */ | ||
58 | struct rw_semaphore map_lock; | ||
59 | struct rb_root all_blocks; /* ordered by address */ | ||
60 | struct rb_root free_blocks; /* ordered by size */ | ||
61 | struct tegra_iovmm_device *dev; | ||
62 | }; | ||
63 | |||
64 | /* | ||
65 | * tegra_iovmm_client is analagous to an individual task in the task group | ||
66 | * which owns an mm_struct. | ||
67 | */ | ||
68 | |||
69 | struct iovmm_share_group; | ||
70 | |||
71 | struct tegra_iovmm_client { | ||
72 | const char *name; | ||
73 | unsigned long flags; | ||
74 | struct iovmm_share_group *group; | ||
75 | struct tegra_iovmm_domain *domain; | ||
76 | struct miscdevice *misc_dev; | ||
77 | struct list_head list; | ||
78 | }; | ||
79 | |||
80 | /* | ||
81 | * tegra_iovmm_area serves a purpose analagous to vm_area_struct as defined | ||
82 | * in <linux/mm_types.h> - it defines a virtual memory area which can be | ||
83 | * mapped to physical memory by a client-provided mapping function. */ | ||
84 | |||
85 | struct tegra_iovmm_area { | ||
86 | struct tegra_iovmm_domain *domain; | ||
87 | tegra_iovmm_addr_t iovm_start; | ||
88 | size_t iovm_length; | ||
89 | pgprot_t pgprot; | ||
90 | struct tegra_iovmm_area_ops *ops; | ||
91 | }; | ||
92 | |||
93 | struct tegra_iovmm_device_ops { | ||
94 | /* maps a VMA using the page residency functions provided by the VMA */ | ||
95 | int (*map)(struct tegra_iovmm_domain *domain, | ||
96 | struct tegra_iovmm_area *io_vma); | ||
97 | /* marks all PTEs in a VMA as invalid; decommits the virtual addres | ||
98 | * space (potentially freeing PDEs when decommit is true.) */ | ||
99 | void (*unmap)(struct tegra_iovmm_domain *domain, | ||
100 | struct tegra_iovmm_area *io_vma, bool decommit); | ||
101 | void (*map_pfn)(struct tegra_iovmm_domain *domain, | ||
102 | struct tegra_iovmm_area *io_vma, | ||
103 | unsigned long offs, unsigned long pfn); | ||
104 | /* | ||
105 | * ensures that a domain is resident in the hardware's mapping region | ||
106 | * so that it may be used by a client | ||
107 | */ | ||
108 | int (*lock_domain)(struct tegra_iovmm_domain *domain, | ||
109 | struct tegra_iovmm_client *client); | ||
110 | void (*unlock_domain)(struct tegra_iovmm_domain *domain, | ||
111 | struct tegra_iovmm_client *client); | ||
112 | /* | ||
113 | * allocates a vmm_domain for the specified client; may return the same | ||
114 | * domain for multiple clients | ||
115 | */ | ||
116 | struct tegra_iovmm_domain* (*alloc_domain)( | ||
117 | struct tegra_iovmm_device *dev, | ||
118 | struct tegra_iovmm_client *client); | ||
119 | void (*free_domain)(struct tegra_iovmm_domain *domain, | ||
120 | struct tegra_iovmm_client *client); | ||
121 | int (*suspend)(struct tegra_iovmm_device *dev); | ||
122 | void (*resume)(struct tegra_iovmm_device *dev); | ||
123 | }; | ||
124 | |||
125 | struct tegra_iovmm_area_ops { | ||
126 | /* | ||
127 | * ensures that the page of data starting at the specified offset | ||
128 | * from the start of the iovma is resident and pinned for use by | ||
129 | * DMA, returns the system pfn, or an invalid pfn if the | ||
130 | * operation fails. | ||
131 | */ | ||
132 | unsigned long (*lock_makeresident)(struct tegra_iovmm_area *area, | ||
133 | tegra_iovmm_addr_t offs); | ||
134 | /* called when the page is unmapped from the I/O VMA */ | ||
135 | void (*release)(struct tegra_iovmm_area *area, tegra_iovmm_addr_t offs); | ||
136 | }; | ||
137 | |||
138 | #ifdef CONFIG_TEGRA_IOVMM | ||
139 | /* | ||
140 | * called by clients to allocate an I/O VMM client mapping context which | ||
141 | * will be shared by all clients in the same share_group | ||
142 | */ | ||
143 | struct tegra_iovmm_client *tegra_iovmm_alloc_client(const char *name, | ||
144 | const char *share_group, struct miscdevice *misc_dev); | ||
145 | |||
146 | size_t tegra_iovmm_get_vm_size(struct tegra_iovmm_client *client); | ||
147 | |||
148 | void tegra_iovmm_free_client(struct tegra_iovmm_client *client); | ||
149 | |||
150 | /* | ||
151 | * called by clients to ensure that their mapping context is resident | ||
152 | * before performing any DMA operations addressing I/O VMM regions. | ||
153 | * client_lock may return -EINTR. | ||
154 | */ | ||
155 | int tegra_iovmm_client_lock(struct tegra_iovmm_client *client); | ||
156 | int tegra_iovmm_client_trylock(struct tegra_iovmm_client *client); | ||
157 | |||
158 | /* called by clients after DMA operations are complete */ | ||
159 | void tegra_iovmm_client_unlock(struct tegra_iovmm_client *client); | ||
160 | |||
161 | /* | ||
162 | * called by clients to allocate a new iovmm_area and reserve I/O virtual | ||
163 | * address space for it. if ops is NULL, clients should subsequently call | ||
164 | * tegra_iovmm_vm_map_pages and/or tegra_iovmm_vm_insert_pfn to explicitly | ||
165 | * map the I/O virtual address to an OS-allocated page or physical address, | ||
166 | * respectively. VM operations may be called before this call returns | ||
167 | */ | ||
168 | struct tegra_iovmm_area *tegra_iovmm_create_vm( | ||
169 | struct tegra_iovmm_client *client, struct tegra_iovmm_area_ops *ops, | ||
170 | size_t size, size_t align, pgprot_t pgprot, unsigned long iovm_start); | ||
171 | |||
172 | /* | ||
173 | * called by clients to "zap" an iovmm_area, and replace all mappings | ||
174 | * in it with invalid ones, without freeing the virtual address range | ||
175 | */ | ||
176 | void tegra_iovmm_zap_vm(struct tegra_iovmm_area *vm); | ||
177 | |||
178 | /* | ||
179 | * after zapping a demand-loaded iovmm_area, the client should unzap it | ||
180 | * to allow the VMM device to remap the page range. | ||
181 | */ | ||
182 | void tegra_iovmm_unzap_vm(struct tegra_iovmm_area *vm); | ||
183 | |||
184 | /* called by clients to return an iovmm_area to the free pool for the domain */ | ||
185 | void tegra_iovmm_free_vm(struct tegra_iovmm_area *vm); | ||
186 | |||
187 | /* returns size of largest free iovm block */ | ||
188 | size_t tegra_iovmm_get_max_free(struct tegra_iovmm_client *client); | ||
189 | |||
190 | /* | ||
191 | * called by client software to map the page-aligned I/O address vaddr to | ||
192 | * a specific physical address pfn. I/O VMA should have been created with | ||
193 | * a NULL tegra_iovmm_area_ops structure. | ||
194 | */ | ||
195 | void tegra_iovmm_vm_insert_pfn(struct tegra_iovmm_area *area, | ||
196 | tegra_iovmm_addr_t vaddr, unsigned long pfn); | ||
197 | |||
198 | /* | ||
199 | * called by clients to return the iovmm_area containing addr, or NULL if | ||
200 | * addr has not been allocated. caller should call tegra_iovmm_area_put when | ||
201 | * finished using the returned pointer | ||
202 | */ | ||
203 | struct tegra_iovmm_area *tegra_iovmm_find_area_get( | ||
204 | struct tegra_iovmm_client *client, tegra_iovmm_addr_t addr); | ||
205 | |||
206 | struct tegra_iovmm_area *tegra_iovmm_area_get(struct tegra_iovmm_area *vm); | ||
207 | void tegra_iovmm_area_put(struct tegra_iovmm_area *vm); | ||
208 | |||
209 | /* called by drivers to initialize a tegra_iovmm_domain structure */ | ||
210 | int tegra_iovmm_domain_init(struct tegra_iovmm_domain *domain, | ||
211 | struct tegra_iovmm_device *dev, tegra_iovmm_addr_t start, | ||
212 | tegra_iovmm_addr_t end); | ||
213 | |||
214 | /* called by drivers to register an I/O VMM device with the system */ | ||
215 | int tegra_iovmm_register(struct tegra_iovmm_device *dev); | ||
216 | |||
217 | /* called by drivers to remove an I/O VMM device from the system */ | ||
218 | int tegra_iovmm_unregister(struct tegra_iovmm_device *dev); | ||
219 | |||
220 | #else /* CONFIG_TEGRA_IOVMM */ | ||
221 | |||
222 | static inline struct tegra_iovmm_client *tegra_iovmm_alloc_client( | ||
223 | const char *name, const char *share_group, struct miscdevice *misc_dev) | ||
224 | { | ||
225 | return NULL; | ||
226 | } | ||
227 | |||
228 | static inline size_t tegra_iovmm_get_vm_size(struct tegra_iovmm_client *client) | ||
229 | { | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static inline void tegra_iovmm_free_client(struct tegra_iovmm_client *client) | ||
234 | { | ||
235 | } | ||
236 | |||
237 | static inline int tegra_iovmm_client_lock(struct tegra_iovmm_client *client) | ||
238 | { | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static inline int tegra_iovmm_client_trylock(struct tegra_iovmm_client *client) | ||
243 | { | ||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static inline void tegra_iovmm_client_unlock(struct tegra_iovmm_client *client) | ||
248 | { | ||
249 | } | ||
250 | |||
251 | static inline struct tegra_iovmm_area *tegra_iovmm_create_vm( | ||
252 | struct tegra_iovmm_client *client, struct tegra_iovmm_area_ops *ops, | ||
253 | size_t size, size_t align, pgprot_t pgprot, unsigned long iovm_start) | ||
254 | { | ||
255 | return NULL; | ||
256 | } | ||
257 | |||
258 | static inline void tegra_iovmm_zap_vm(struct tegra_iovmm_area *vm) | ||
259 | { | ||
260 | } | ||
261 | |||
262 | static inline void tegra_iovmm_unzap_vm(struct tegra_iovmm_area *vm) | ||
263 | { | ||
264 | } | ||
265 | |||
266 | static inline void tegra_iovmm_free_vm(struct tegra_iovmm_area *vm) | ||
267 | { | ||
268 | } | ||
269 | |||
270 | static inline size_t tegra_iovmm_get_max_free(struct tegra_iovmm_client *client) | ||
271 | { | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static inline void tegra_iovmm_vm_insert_pfn(struct tegra_iovmm_area *area, | ||
276 | tegra_iovmm_addr_t vaddr, unsigned long pfn) | ||
277 | { | ||
278 | } | ||
279 | |||
280 | static inline struct tegra_iovmm_area *tegra_iovmm_find_area_get( | ||
281 | struct tegra_iovmm_client *client, tegra_iovmm_addr_t addr) | ||
282 | { | ||
283 | return NULL; | ||
284 | } | ||
285 | |||
286 | static inline struct tegra_iovmm_area *tegra_iovmm_area_get( | ||
287 | struct tegra_iovmm_area *vm) | ||
288 | { | ||
289 | return NULL; | ||
290 | } | ||
291 | |||
292 | static inline void tegra_iovmm_area_put(struct tegra_iovmm_area *vm) | ||
293 | { | ||
294 | } | ||
295 | |||
296 | static inline int tegra_iovmm_domain_init(struct tegra_iovmm_domain *domain, | ||
297 | struct tegra_iovmm_device *dev, tegra_iovmm_addr_t start, | ||
298 | tegra_iovmm_addr_t end) | ||
299 | { | ||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static inline int tegra_iovmm_register(struct tegra_iovmm_device *dev) | ||
304 | { | ||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static inline int tegra_iovmm_unregister(struct tegra_iovmm_device *dev) | ||
309 | { | ||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | static inline int tegra_iovmm_suspend(void) | ||
314 | { | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static inline void tegra_iovmm_resume(void) | ||
319 | { | ||
320 | } | ||
321 | |||
322 | #endif /* CONFIG_TEGRA_IOVMM */ | ||
323 | #endif /* _MACH_TEGRA_IOVMM_H_*/ | ||