diff options
author | Jan Beulich <jbeulich@novell.com> | 2007-02-05 21:53:04 -0500 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2007-02-05 21:53:04 -0500 |
commit | 51099005ab8e09d68a13fea8d55bc739c1040ca6 (patch) | |
tree | 865519c98fada85e5ae2ba4f617dea27e63aee56 | |
parent | 563aaf064f3776623ff5e7aef511ac2eb7e5f0bb (diff) |
[IA64] swiotlb abstraction (e.g. for Xen)
Add abstraction so that the file can be used by environments other than IA64
and EM64T, namely for Xen.
Signed-off-by: Jan Beulich <jbeulich@novell.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Tony Luck <tony.luck@intel.com>
-rw-r--r-- | include/asm-ia64/swiotlb.h | 9 | ||||
-rw-r--r-- | include/asm-x86_64/swiotlb.h | 1 | ||||
-rw-r--r-- | lib/swiotlb.c | 184 |
3 files changed, 159 insertions, 35 deletions
diff --git a/include/asm-ia64/swiotlb.h b/include/asm-ia64/swiotlb.h new file mode 100644 index 000000000000..452c162dee4e --- /dev/null +++ b/include/asm-ia64/swiotlb.h | |||
@@ -0,0 +1,9 @@ | |||
1 | #ifndef _ASM_SWIOTLB_H | ||
2 | #define _ASM_SWIOTLB_H 1 | ||
3 | |||
4 | #include <asm/machvec.h> | ||
5 | |||
6 | #define SWIOTLB_ARCH_NEED_LATE_INIT | ||
7 | #define SWIOTLB_ARCH_NEED_ALLOC | ||
8 | |||
9 | #endif /* _ASM_SWIOTLB_H */ | ||
diff --git a/include/asm-x86_64/swiotlb.h b/include/asm-x86_64/swiotlb.h index f9c589539a82..ab913ffcad56 100644 --- a/include/asm-x86_64/swiotlb.h +++ b/include/asm-x86_64/swiotlb.h | |||
@@ -44,6 +44,7 @@ extern void swiotlb_init(void); | |||
44 | extern int swiotlb_force; | 44 | extern int swiotlb_force; |
45 | 45 | ||
46 | #ifdef CONFIG_SWIOTLB | 46 | #ifdef CONFIG_SWIOTLB |
47 | #define SWIOTLB_ARCH_NEED_ALLOC | ||
47 | extern int swiotlb; | 48 | extern int swiotlb; |
48 | #else | 49 | #else |
49 | #define swiotlb 0 | 50 | #define swiotlb 0 |
diff --git a/lib/swiotlb.c b/lib/swiotlb.c index 067eed5b2758..50a438010182 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <asm/io.h> | 28 | #include <asm/io.h> |
29 | #include <asm/dma.h> | 29 | #include <asm/dma.h> |
30 | #include <asm/scatterlist.h> | 30 | #include <asm/scatterlist.h> |
31 | #include <asm/swiotlb.h> | ||
31 | 32 | ||
32 | #include <linux/init.h> | 33 | #include <linux/init.h> |
33 | #include <linux/bootmem.h> | 34 | #include <linux/bootmem.h> |
@@ -35,8 +36,10 @@ | |||
35 | #define OFFSET(val,align) ((unsigned long) \ | 36 | #define OFFSET(val,align) ((unsigned long) \ |
36 | ( (val) & ( (align) - 1))) | 37 | ( (val) & ( (align) - 1))) |
37 | 38 | ||
39 | #ifndef SG_ENT_VIRT_ADDRESS | ||
38 | #define SG_ENT_VIRT_ADDRESS(sg) (page_address((sg)->page) + (sg)->offset) | 40 | #define SG_ENT_VIRT_ADDRESS(sg) (page_address((sg)->page) + (sg)->offset) |
39 | #define SG_ENT_PHYS_ADDRESS(sg) virt_to_bus(SG_ENT_VIRT_ADDRESS(sg)) | 41 | #define SG_ENT_PHYS_ADDRESS(sg) virt_to_bus(SG_ENT_VIRT_ADDRESS(sg)) |
42 | #endif | ||
40 | 43 | ||
41 | /* | 44 | /* |
42 | * Maximum allowable number of contiguous slabs to map, | 45 | * Maximum allowable number of contiguous slabs to map, |
@@ -101,13 +104,25 @@ static unsigned int io_tlb_index; | |||
101 | * We need to save away the original address corresponding to a mapped entry | 104 | * We need to save away the original address corresponding to a mapped entry |
102 | * for the sync operations. | 105 | * for the sync operations. |
103 | */ | 106 | */ |
104 | static unsigned char **io_tlb_orig_addr; | 107 | #ifndef SWIOTLB_ARCH_HAS_IO_TLB_ADDR_T |
108 | typedef char *io_tlb_addr_t; | ||
109 | #define swiotlb_orig_addr_null(buffer) (!(buffer)) | ||
110 | #define ptr_to_io_tlb_addr(ptr) (ptr) | ||
111 | #define page_to_io_tlb_addr(pg, off) (page_address(pg) + (off)) | ||
112 | #define sg_to_io_tlb_addr(sg) SG_ENT_VIRT_ADDRESS(sg) | ||
113 | #endif | ||
114 | static io_tlb_addr_t *io_tlb_orig_addr; | ||
105 | 115 | ||
106 | /* | 116 | /* |
107 | * Protect the above data structures in the map and unmap calls | 117 | * Protect the above data structures in the map and unmap calls |
108 | */ | 118 | */ |
109 | static DEFINE_SPINLOCK(io_tlb_lock); | 119 | static DEFINE_SPINLOCK(io_tlb_lock); |
110 | 120 | ||
121 | #ifdef SWIOTLB_EXTRA_VARIABLES | ||
122 | SWIOTLB_EXTRA_VARIABLES; | ||
123 | #endif | ||
124 | |||
125 | #ifndef SWIOTLB_ARCH_HAS_SETUP_IO_TLB_NPAGES | ||
111 | static int __init | 126 | static int __init |
112 | setup_io_tlb_npages(char *str) | 127 | setup_io_tlb_npages(char *str) |
113 | { | 128 | { |
@@ -122,9 +137,25 @@ setup_io_tlb_npages(char *str) | |||
122 | swiotlb_force = 1; | 137 | swiotlb_force = 1; |
123 | return 1; | 138 | return 1; |
124 | } | 139 | } |
140 | #endif | ||
125 | __setup("swiotlb=", setup_io_tlb_npages); | 141 | __setup("swiotlb=", setup_io_tlb_npages); |
126 | /* make io_tlb_overflow tunable too? */ | 142 | /* make io_tlb_overflow tunable too? */ |
127 | 143 | ||
144 | #ifndef swiotlb_adjust_size | ||
145 | #define swiotlb_adjust_size(size) ((void)0) | ||
146 | #endif | ||
147 | |||
148 | #ifndef swiotlb_adjust_seg | ||
149 | #define swiotlb_adjust_seg(start, size) ((void)0) | ||
150 | #endif | ||
151 | |||
152 | #ifndef swiotlb_print_info | ||
153 | #define swiotlb_print_info(bytes) \ | ||
154 | printk(KERN_INFO "Placing %luMB software IO TLB between 0x%lx - " \ | ||
155 | "0x%lx\n", bytes >> 20, \ | ||
156 | virt_to_bus(io_tlb_start), virt_to_bus(io_tlb_end)) | ||
157 | #endif | ||
158 | |||
128 | /* | 159 | /* |
129 | * Statically reserve bounce buffer space and initialize bounce buffer data | 160 | * Statically reserve bounce buffer space and initialize bounce buffer data |
130 | * structures for the software IO TLB used to implement the DMA API. | 161 | * structures for the software IO TLB used to implement the DMA API. |
@@ -138,6 +169,8 @@ swiotlb_init_with_default_size(size_t default_size) | |||
138 | io_tlb_nslabs = (default_size >> IO_TLB_SHIFT); | 169 | io_tlb_nslabs = (default_size >> IO_TLB_SHIFT); |
139 | io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE); | 170 | io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE); |
140 | } | 171 | } |
172 | swiotlb_adjust_size(io_tlb_nslabs); | ||
173 | swiotlb_adjust_size(io_tlb_overflow); | ||
141 | 174 | ||
142 | bytes = io_tlb_nslabs << IO_TLB_SHIFT; | 175 | bytes = io_tlb_nslabs << IO_TLB_SHIFT; |
143 | 176 | ||
@@ -155,10 +188,14 @@ swiotlb_init_with_default_size(size_t default_size) | |||
155 | * between io_tlb_start and io_tlb_end. | 188 | * between io_tlb_start and io_tlb_end. |
156 | */ | 189 | */ |
157 | io_tlb_list = alloc_bootmem(io_tlb_nslabs * sizeof(int)); | 190 | io_tlb_list = alloc_bootmem(io_tlb_nslabs * sizeof(int)); |
158 | for (i = 0; i < io_tlb_nslabs; i++) | 191 | for (i = 0; i < io_tlb_nslabs; i++) { |
192 | if ( !(i % IO_TLB_SEGSIZE) ) | ||
193 | swiotlb_adjust_seg(io_tlb_start + (i << IO_TLB_SHIFT), | ||
194 | IO_TLB_SEGSIZE << IO_TLB_SHIFT); | ||
159 | io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE); | 195 | io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE); |
196 | } | ||
160 | io_tlb_index = 0; | 197 | io_tlb_index = 0; |
161 | io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(char *)); | 198 | io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(io_tlb_addr_t)); |
162 | 199 | ||
163 | /* | 200 | /* |
164 | * Get the overflow emergency buffer | 201 | * Get the overflow emergency buffer |
@@ -166,17 +203,21 @@ swiotlb_init_with_default_size(size_t default_size) | |||
166 | io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow); | 203 | io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow); |
167 | if (!io_tlb_overflow_buffer) | 204 | if (!io_tlb_overflow_buffer) |
168 | panic("Cannot allocate SWIOTLB overflow buffer!\n"); | 205 | panic("Cannot allocate SWIOTLB overflow buffer!\n"); |
206 | swiotlb_adjust_seg(io_tlb_overflow_buffer, io_tlb_overflow); | ||
169 | 207 | ||
170 | printk(KERN_INFO "Placing software IO TLB between 0x%lx - 0x%lx\n", | 208 | swiotlb_print_info(bytes); |
171 | virt_to_bus(io_tlb_start), virt_to_bus(io_tlb_end)); | ||
172 | } | 209 | } |
210 | #ifndef __swiotlb_init_with_default_size | ||
211 | #define __swiotlb_init_with_default_size swiotlb_init_with_default_size | ||
212 | #endif | ||
173 | 213 | ||
174 | void __init | 214 | void __init |
175 | swiotlb_init(void) | 215 | swiotlb_init(void) |
176 | { | 216 | { |
177 | swiotlb_init_with_default_size(64 * (1<<20)); /* default to 64MB */ | 217 | __swiotlb_init_with_default_size(64 * (1<<20)); /* default to 64MB */ |
178 | } | 218 | } |
179 | 219 | ||
220 | #ifdef SWIOTLB_ARCH_NEED_LATE_INIT | ||
180 | /* | 221 | /* |
181 | * Systems with larger DMA zones (those that don't support ISA) can | 222 | * Systems with larger DMA zones (those that don't support ISA) can |
182 | * initialize the swiotlb later using the slab allocator if needed. | 223 | * initialize the swiotlb later using the slab allocator if needed. |
@@ -234,12 +275,12 @@ swiotlb_late_init_with_default_size(size_t default_size) | |||
234 | io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE); | 275 | io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE); |
235 | io_tlb_index = 0; | 276 | io_tlb_index = 0; |
236 | 277 | ||
237 | io_tlb_orig_addr = (unsigned char **)__get_free_pages(GFP_KERNEL, | 278 | io_tlb_orig_addr = (io_tlb_addr_t *)__get_free_pages(GFP_KERNEL, |
238 | get_order(io_tlb_nslabs * sizeof(char *))); | 279 | get_order(io_tlb_nslabs * sizeof(io_tlb_addr_t))); |
239 | if (!io_tlb_orig_addr) | 280 | if (!io_tlb_orig_addr) |
240 | goto cleanup3; | 281 | goto cleanup3; |
241 | 282 | ||
242 | memset(io_tlb_orig_addr, 0, io_tlb_nslabs * sizeof(char *)); | 283 | memset(io_tlb_orig_addr, 0, io_tlb_nslabs * sizeof(io_tlb_addr_t)); |
243 | 284 | ||
244 | /* | 285 | /* |
245 | * Get the overflow emergency buffer | 286 | * Get the overflow emergency buffer |
@@ -249,19 +290,17 @@ swiotlb_late_init_with_default_size(size_t default_size) | |||
249 | if (!io_tlb_overflow_buffer) | 290 | if (!io_tlb_overflow_buffer) |
250 | goto cleanup4; | 291 | goto cleanup4; |
251 | 292 | ||
252 | printk(KERN_INFO "Placing %luMB software IO TLB between 0x%lx - " | 293 | swiotlb_print_info(bytes); |
253 | "0x%lx\n", bytes >> 20, | ||
254 | virt_to_bus(io_tlb_start), virt_to_bus(io_tlb_end)); | ||
255 | 294 | ||
256 | return 0; | 295 | return 0; |
257 | 296 | ||
258 | cleanup4: | 297 | cleanup4: |
259 | free_pages((unsigned long)io_tlb_orig_addr, get_order(io_tlb_nslabs * | 298 | free_pages((unsigned long)io_tlb_orig_addr, |
260 | sizeof(char *))); | 299 | get_order(io_tlb_nslabs * sizeof(io_tlb_addr_t))); |
261 | io_tlb_orig_addr = NULL; | 300 | io_tlb_orig_addr = NULL; |
262 | cleanup3: | 301 | cleanup3: |
263 | free_pages((unsigned long)io_tlb_list, get_order(io_tlb_nslabs * | 302 | free_pages((unsigned long)io_tlb_list, |
264 | sizeof(int))); | 303 | get_order(io_tlb_nslabs * sizeof(int))); |
265 | io_tlb_list = NULL; | 304 | io_tlb_list = NULL; |
266 | cleanup2: | 305 | cleanup2: |
267 | io_tlb_end = NULL; | 306 | io_tlb_end = NULL; |
@@ -271,7 +310,9 @@ cleanup1: | |||
271 | io_tlb_nslabs = req_nslabs; | 310 | io_tlb_nslabs = req_nslabs; |
272 | return -ENOMEM; | 311 | return -ENOMEM; |
273 | } | 312 | } |
313 | #endif | ||
274 | 314 | ||
315 | #ifndef SWIOTLB_ARCH_HAS_NEEDS_MAPPING | ||
275 | static inline int | 316 | static inline int |
276 | address_needs_mapping(struct device *hwdev, dma_addr_t addr) | 317 | address_needs_mapping(struct device *hwdev, dma_addr_t addr) |
277 | { | 318 | { |
@@ -282,11 +323,35 @@ address_needs_mapping(struct device *hwdev, dma_addr_t addr) | |||
282 | return (addr & ~mask) != 0; | 323 | return (addr & ~mask) != 0; |
283 | } | 324 | } |
284 | 325 | ||
326 | static inline int range_needs_mapping(const void *ptr, size_t size) | ||
327 | { | ||
328 | return swiotlb_force; | ||
329 | } | ||
330 | |||
331 | static inline int order_needs_mapping(unsigned int order) | ||
332 | { | ||
333 | return 0; | ||
334 | } | ||
335 | #endif | ||
336 | |||
337 | static void | ||
338 | __sync_single(io_tlb_addr_t buffer, char *dma_addr, size_t size, int dir) | ||
339 | { | ||
340 | #ifndef SWIOTLB_ARCH_HAS_SYNC_SINGLE | ||
341 | if (dir == DMA_TO_DEVICE) | ||
342 | memcpy(dma_addr, buffer, size); | ||
343 | else | ||
344 | memcpy(buffer, dma_addr, size); | ||
345 | #else | ||
346 | __swiotlb_arch_sync_single(buffer, dma_addr, size, dir); | ||
347 | #endif | ||
348 | } | ||
349 | |||
285 | /* | 350 | /* |
286 | * Allocates bounce buffer and returns its kernel virtual address. | 351 | * Allocates bounce buffer and returns its kernel virtual address. |
287 | */ | 352 | */ |
288 | static void * | 353 | static void * |
289 | map_single(struct device *hwdev, char *buffer, size_t size, int dir) | 354 | map_single(struct device *hwdev, io_tlb_addr_t buffer, size_t size, int dir) |
290 | { | 355 | { |
291 | unsigned long flags; | 356 | unsigned long flags; |
292 | char *dma_addr; | 357 | char *dma_addr; |
@@ -359,7 +424,7 @@ map_single(struct device *hwdev, char *buffer, size_t size, int dir) | |||
359 | */ | 424 | */ |
360 | io_tlb_orig_addr[index] = buffer; | 425 | io_tlb_orig_addr[index] = buffer; |
361 | if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) | 426 | if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) |
362 | memcpy(dma_addr, buffer, size); | 427 | __sync_single(buffer, dma_addr, size, DMA_TO_DEVICE); |
363 | 428 | ||
364 | return dma_addr; | 429 | return dma_addr; |
365 | } | 430 | } |
@@ -373,17 +438,18 @@ unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir) | |||
373 | unsigned long flags; | 438 | unsigned long flags; |
374 | int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT; | 439 | int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT; |
375 | int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT; | 440 | int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT; |
376 | char *buffer = io_tlb_orig_addr[index]; | 441 | io_tlb_addr_t buffer = io_tlb_orig_addr[index]; |
377 | 442 | ||
378 | /* | 443 | /* |
379 | * First, sync the memory before unmapping the entry | 444 | * First, sync the memory before unmapping the entry |
380 | */ | 445 | */ |
381 | if (buffer && ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL))) | 446 | if (!swiotlb_orig_addr_null(buffer) |
447 | && ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL))) | ||
382 | /* | 448 | /* |
383 | * bounce... copy the data back into the original buffer * and | 449 | * bounce... copy the data back into the original buffer * and |
384 | * delete the bounce buffer. | 450 | * delete the bounce buffer. |
385 | */ | 451 | */ |
386 | memcpy(buffer, dma_addr, size); | 452 | __sync_single(buffer, dma_addr, size, DMA_FROM_DEVICE); |
387 | 453 | ||
388 | /* | 454 | /* |
389 | * Return the buffer to the free list by setting the corresponding | 455 | * Return the buffer to the free list by setting the corresponding |
@@ -416,18 +482,18 @@ sync_single(struct device *hwdev, char *dma_addr, size_t size, | |||
416 | int dir, int target) | 482 | int dir, int target) |
417 | { | 483 | { |
418 | int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT; | 484 | int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT; |
419 | char *buffer = io_tlb_orig_addr[index]; | 485 | io_tlb_addr_t buffer = io_tlb_orig_addr[index]; |
420 | 486 | ||
421 | switch (target) { | 487 | switch (target) { |
422 | case SYNC_FOR_CPU: | 488 | case SYNC_FOR_CPU: |
423 | if (likely(dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)) | 489 | if (likely(dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)) |
424 | memcpy(buffer, dma_addr, size); | 490 | __sync_single(buffer, dma_addr, size, DMA_FROM_DEVICE); |
425 | else | 491 | else |
426 | BUG_ON(dir != DMA_TO_DEVICE); | 492 | BUG_ON(dir != DMA_TO_DEVICE); |
427 | break; | 493 | break; |
428 | case SYNC_FOR_DEVICE: | 494 | case SYNC_FOR_DEVICE: |
429 | if (likely(dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)) | 495 | if (likely(dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)) |
430 | memcpy(dma_addr, buffer, size); | 496 | __sync_single(buffer, dma_addr, size, DMA_TO_DEVICE); |
431 | else | 497 | else |
432 | BUG_ON(dir != DMA_FROM_DEVICE); | 498 | BUG_ON(dir != DMA_FROM_DEVICE); |
433 | break; | 499 | break; |
@@ -436,6 +502,8 @@ sync_single(struct device *hwdev, char *dma_addr, size_t size, | |||
436 | } | 502 | } |
437 | } | 503 | } |
438 | 504 | ||
505 | #ifdef SWIOTLB_ARCH_NEED_ALLOC | ||
506 | |||
439 | void * | 507 | void * |
440 | swiotlb_alloc_coherent(struct device *hwdev, size_t size, | 508 | swiotlb_alloc_coherent(struct device *hwdev, size_t size, |
441 | dma_addr_t *dma_handle, gfp_t flags) | 509 | dma_addr_t *dma_handle, gfp_t flags) |
@@ -451,7 +519,10 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size, | |||
451 | */ | 519 | */ |
452 | flags |= GFP_DMA; | 520 | flags |= GFP_DMA; |
453 | 521 | ||
454 | ret = (void *)__get_free_pages(flags, order); | 522 | if (!order_needs_mapping(order)) |
523 | ret = (void *)__get_free_pages(flags, order); | ||
524 | else | ||
525 | ret = NULL; | ||
455 | if (ret && address_needs_mapping(hwdev, virt_to_bus(ret))) { | 526 | if (ret && address_needs_mapping(hwdev, virt_to_bus(ret))) { |
456 | /* | 527 | /* |
457 | * The allocated memory isn't reachable by the device. | 528 | * The allocated memory isn't reachable by the device. |
@@ -489,6 +560,7 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size, | |||
489 | *dma_handle = dev_addr; | 560 | *dma_handle = dev_addr; |
490 | return ret; | 561 | return ret; |
491 | } | 562 | } |
563 | EXPORT_SYMBOL(swiotlb_alloc_coherent); | ||
492 | 564 | ||
493 | void | 565 | void |
494 | swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr, | 566 | swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr, |
@@ -501,6 +573,9 @@ swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr, | |||
501 | /* DMA_TO_DEVICE to avoid memcpy in unmap_single */ | 573 | /* DMA_TO_DEVICE to avoid memcpy in unmap_single */ |
502 | swiotlb_unmap_single (hwdev, dma_handle, size, DMA_TO_DEVICE); | 574 | swiotlb_unmap_single (hwdev, dma_handle, size, DMA_TO_DEVICE); |
503 | } | 575 | } |
576 | EXPORT_SYMBOL(swiotlb_free_coherent); | ||
577 | |||
578 | #endif | ||
504 | 579 | ||
505 | static void | 580 | static void |
506 | swiotlb_full(struct device *dev, size_t size, int dir, int do_panic) | 581 | swiotlb_full(struct device *dev, size_t size, int dir, int do_panic) |
@@ -542,13 +617,14 @@ swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir) | |||
542 | * we can safely return the device addr and not worry about bounce | 617 | * we can safely return the device addr and not worry about bounce |
543 | * buffering it. | 618 | * buffering it. |
544 | */ | 619 | */ |
545 | if (!address_needs_mapping(hwdev, dev_addr) && !swiotlb_force) | 620 | if (!range_needs_mapping(ptr, size) |
621 | && !address_needs_mapping(hwdev, dev_addr)) | ||
546 | return dev_addr; | 622 | return dev_addr; |
547 | 623 | ||
548 | /* | 624 | /* |
549 | * Oh well, have to allocate and map a bounce buffer. | 625 | * Oh well, have to allocate and map a bounce buffer. |
550 | */ | 626 | */ |
551 | map = map_single(hwdev, ptr, size, dir); | 627 | map = map_single(hwdev, ptr_to_io_tlb_addr(ptr), size, dir); |
552 | if (!map) { | 628 | if (!map) { |
553 | swiotlb_full(hwdev, size, dir, 1); | 629 | swiotlb_full(hwdev, size, dir, 1); |
554 | map = io_tlb_overflow_buffer; | 630 | map = io_tlb_overflow_buffer; |
@@ -676,17 +752,16 @@ int | |||
676 | swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nelems, | 752 | swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nelems, |
677 | int dir) | 753 | int dir) |
678 | { | 754 | { |
679 | void *addr; | ||
680 | dma_addr_t dev_addr; | 755 | dma_addr_t dev_addr; |
681 | int i; | 756 | int i; |
682 | 757 | ||
683 | BUG_ON(dir == DMA_NONE); | 758 | BUG_ON(dir == DMA_NONE); |
684 | 759 | ||
685 | for (i = 0; i < nelems; i++, sg++) { | 760 | for (i = 0; i < nelems; i++, sg++) { |
686 | addr = SG_ENT_VIRT_ADDRESS(sg); | 761 | dev_addr = SG_ENT_PHYS_ADDRESS(sg); |
687 | dev_addr = virt_to_bus(addr); | 762 | if (range_needs_mapping(SG_ENT_VIRT_ADDRESS(sg), sg->length) |
688 | if (swiotlb_force || address_needs_mapping(hwdev, dev_addr)) { | 763 | || address_needs_mapping(hwdev, dev_addr)) { |
689 | void *map = map_single(hwdev, addr, sg->length, dir); | 764 | void *map = map_single(hwdev, sg_to_io_tlb_addr(sg), sg->length, dir); |
690 | if (!map) { | 765 | if (!map) { |
691 | /* Don't panic here, we expect map_sg users | 766 | /* Don't panic here, we expect map_sg users |
692 | to do proper error handling. */ | 767 | to do proper error handling. */ |
@@ -760,6 +835,44 @@ swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg, | |||
760 | swiotlb_sync_sg(hwdev, sg, nelems, dir, SYNC_FOR_DEVICE); | 835 | swiotlb_sync_sg(hwdev, sg, nelems, dir, SYNC_FOR_DEVICE); |
761 | } | 836 | } |
762 | 837 | ||
838 | #ifdef SWIOTLB_ARCH_NEED_MAP_PAGE | ||
839 | |||
840 | dma_addr_t | ||
841 | swiotlb_map_page(struct device *hwdev, struct page *page, | ||
842 | unsigned long offset, size_t size, | ||
843 | enum dma_data_direction direction) | ||
844 | { | ||
845 | dma_addr_t dev_addr; | ||
846 | char *map; | ||
847 | |||
848 | dev_addr = page_to_bus(page) + offset; | ||
849 | if (address_needs_mapping(hwdev, dev_addr)) { | ||
850 | map = map_single(hwdev, page_to_io_tlb_addr(page, offset), size, direction); | ||
851 | if (!map) { | ||
852 | swiotlb_full(hwdev, size, direction, 1); | ||
853 | map = io_tlb_overflow_buffer; | ||
854 | } | ||
855 | dev_addr = virt_to_bus(map); | ||
856 | } | ||
857 | |||
858 | return dev_addr; | ||
859 | } | ||
860 | |||
861 | void | ||
862 | swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr, | ||
863 | size_t size, enum dma_data_direction direction) | ||
864 | { | ||
865 | char *dma_addr = bus_to_virt(dev_addr); | ||
866 | |||
867 | BUG_ON(direction == DMA_NONE); | ||
868 | if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end) | ||
869 | unmap_single(hwdev, dma_addr, size, direction); | ||
870 | else if (direction == DMA_FROM_DEVICE) | ||
871 | dma_mark_clean(dma_addr, size); | ||
872 | } | ||
873 | |||
874 | #endif | ||
875 | |||
763 | int | 876 | int |
764 | swiotlb_dma_mapping_error(dma_addr_t dma_addr) | 877 | swiotlb_dma_mapping_error(dma_addr_t dma_addr) |
765 | { | 878 | { |
@@ -772,10 +885,13 @@ swiotlb_dma_mapping_error(dma_addr_t dma_addr) | |||
772 | * during bus mastering, then you would pass 0x00ffffff as the mask to | 885 | * during bus mastering, then you would pass 0x00ffffff as the mask to |
773 | * this function. | 886 | * this function. |
774 | */ | 887 | */ |
888 | #ifndef __swiotlb_dma_supported | ||
889 | #define __swiotlb_dma_supported(hwdev, mask) (virt_to_bus(io_tlb_end - 1) <= (mask)) | ||
890 | #endif | ||
775 | int | 891 | int |
776 | swiotlb_dma_supported(struct device *hwdev, u64 mask) | 892 | swiotlb_dma_supported(struct device *hwdev, u64 mask) |
777 | { | 893 | { |
778 | return virt_to_bus(io_tlb_end - 1) <= mask; | 894 | return __swiotlb_dma_supported(hwdev, mask); |
779 | } | 895 | } |
780 | 896 | ||
781 | EXPORT_SYMBOL(swiotlb_init); | 897 | EXPORT_SYMBOL(swiotlb_init); |
@@ -790,6 +906,4 @@ EXPORT_SYMBOL_GPL(swiotlb_sync_single_range_for_device); | |||
790 | EXPORT_SYMBOL(swiotlb_sync_sg_for_cpu); | 906 | EXPORT_SYMBOL(swiotlb_sync_sg_for_cpu); |
791 | EXPORT_SYMBOL(swiotlb_sync_sg_for_device); | 907 | EXPORT_SYMBOL(swiotlb_sync_sg_for_device); |
792 | EXPORT_SYMBOL(swiotlb_dma_mapping_error); | 908 | EXPORT_SYMBOL(swiotlb_dma_mapping_error); |
793 | EXPORT_SYMBOL(swiotlb_alloc_coherent); | ||
794 | EXPORT_SYMBOL(swiotlb_free_coherent); | ||
795 | EXPORT_SYMBOL(swiotlb_dma_supported); | 909 | EXPORT_SYMBOL(swiotlb_dma_supported); |