diff options
Diffstat (limited to 'lib/swiotlb.c')
-rw-r--r-- | lib/swiotlb.c | 53 |
1 files changed, 43 insertions, 10 deletions
diff --git a/lib/swiotlb.c b/lib/swiotlb.c index ac25cd28e807..5fddf720da73 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/types.h> | 28 | #include <linux/types.h> |
29 | #include <linux/ctype.h> | 29 | #include <linux/ctype.h> |
30 | #include <linux/highmem.h> | 30 | #include <linux/highmem.h> |
31 | #include <linux/gfp.h> | ||
31 | 32 | ||
32 | #include <asm/io.h> | 33 | #include <asm/io.h> |
33 | #include <asm/dma.h> | 34 | #include <asm/dma.h> |
@@ -97,6 +98,8 @@ static phys_addr_t *io_tlb_orig_addr; | |||
97 | */ | 98 | */ |
98 | static DEFINE_SPINLOCK(io_tlb_lock); | 99 | static DEFINE_SPINLOCK(io_tlb_lock); |
99 | 100 | ||
101 | static int late_alloc; | ||
102 | |||
100 | static int __init | 103 | static int __init |
101 | setup_io_tlb_npages(char *str) | 104 | setup_io_tlb_npages(char *str) |
102 | { | 105 | { |
@@ -109,6 +112,7 @@ setup_io_tlb_npages(char *str) | |||
109 | ++str; | 112 | ++str; |
110 | if (!strcmp(str, "force")) | 113 | if (!strcmp(str, "force")) |
111 | swiotlb_force = 1; | 114 | swiotlb_force = 1; |
115 | |||
112 | return 1; | 116 | return 1; |
113 | } | 117 | } |
114 | __setup("swiotlb=", setup_io_tlb_npages); | 118 | __setup("swiotlb=", setup_io_tlb_npages); |
@@ -121,8 +125,9 @@ static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev, | |||
121 | return phys_to_dma(hwdev, virt_to_phys(address)); | 125 | return phys_to_dma(hwdev, virt_to_phys(address)); |
122 | } | 126 | } |
123 | 127 | ||
124 | static void swiotlb_print_info(unsigned long bytes) | 128 | void swiotlb_print_info(void) |
125 | { | 129 | { |
130 | unsigned long bytes = io_tlb_nslabs << IO_TLB_SHIFT; | ||
126 | phys_addr_t pstart, pend; | 131 | phys_addr_t pstart, pend; |
127 | 132 | ||
128 | pstart = virt_to_phys(io_tlb_start); | 133 | pstart = virt_to_phys(io_tlb_start); |
@@ -140,7 +145,7 @@ static void swiotlb_print_info(unsigned long bytes) | |||
140 | * structures for the software IO TLB used to implement the DMA API. | 145 | * structures for the software IO TLB used to implement the DMA API. |
141 | */ | 146 | */ |
142 | void __init | 147 | void __init |
143 | swiotlb_init_with_default_size(size_t default_size) | 148 | swiotlb_init_with_default_size(size_t default_size, int verbose) |
144 | { | 149 | { |
145 | unsigned long i, bytes; | 150 | unsigned long i, bytes; |
146 | 151 | ||
@@ -176,14 +181,14 @@ swiotlb_init_with_default_size(size_t default_size) | |||
176 | io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow); | 181 | io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow); |
177 | if (!io_tlb_overflow_buffer) | 182 | if (!io_tlb_overflow_buffer) |
178 | panic("Cannot allocate SWIOTLB overflow buffer!\n"); | 183 | panic("Cannot allocate SWIOTLB overflow buffer!\n"); |
179 | 184 | if (verbose) | |
180 | swiotlb_print_info(bytes); | 185 | swiotlb_print_info(); |
181 | } | 186 | } |
182 | 187 | ||
183 | void __init | 188 | void __init |
184 | swiotlb_init(void) | 189 | swiotlb_init(int verbose) |
185 | { | 190 | { |
186 | swiotlb_init_with_default_size(64 * (1<<20)); /* default to 64MB */ | 191 | swiotlb_init_with_default_size(64 * (1<<20), verbose); /* default to 64MB */ |
187 | } | 192 | } |
188 | 193 | ||
189 | /* | 194 | /* |
@@ -260,7 +265,9 @@ swiotlb_late_init_with_default_size(size_t default_size) | |||
260 | if (!io_tlb_overflow_buffer) | 265 | if (!io_tlb_overflow_buffer) |
261 | goto cleanup4; | 266 | goto cleanup4; |
262 | 267 | ||
263 | swiotlb_print_info(bytes); | 268 | swiotlb_print_info(); |
269 | |||
270 | late_alloc = 1; | ||
264 | 271 | ||
265 | return 0; | 272 | return 0; |
266 | 273 | ||
@@ -281,6 +288,32 @@ cleanup1: | |||
281 | return -ENOMEM; | 288 | return -ENOMEM; |
282 | } | 289 | } |
283 | 290 | ||
291 | void __init swiotlb_free(void) | ||
292 | { | ||
293 | if (!io_tlb_overflow_buffer) | ||
294 | return; | ||
295 | |||
296 | if (late_alloc) { | ||
297 | free_pages((unsigned long)io_tlb_overflow_buffer, | ||
298 | get_order(io_tlb_overflow)); | ||
299 | free_pages((unsigned long)io_tlb_orig_addr, | ||
300 | get_order(io_tlb_nslabs * sizeof(phys_addr_t))); | ||
301 | free_pages((unsigned long)io_tlb_list, get_order(io_tlb_nslabs * | ||
302 | sizeof(int))); | ||
303 | free_pages((unsigned long)io_tlb_start, | ||
304 | get_order(io_tlb_nslabs << IO_TLB_SHIFT)); | ||
305 | } else { | ||
306 | free_bootmem_late(__pa(io_tlb_overflow_buffer), | ||
307 | io_tlb_overflow); | ||
308 | free_bootmem_late(__pa(io_tlb_orig_addr), | ||
309 | io_tlb_nslabs * sizeof(phys_addr_t)); | ||
310 | free_bootmem_late(__pa(io_tlb_list), | ||
311 | io_tlb_nslabs * sizeof(int)); | ||
312 | free_bootmem_late(__pa(io_tlb_start), | ||
313 | io_tlb_nslabs << IO_TLB_SHIFT); | ||
314 | } | ||
315 | } | ||
316 | |||
284 | static int is_swiotlb_buffer(phys_addr_t paddr) | 317 | static int is_swiotlb_buffer(phys_addr_t paddr) |
285 | { | 318 | { |
286 | return paddr >= virt_to_phys(io_tlb_start) && | 319 | return paddr >= virt_to_phys(io_tlb_start) && |
@@ -453,7 +486,7 @@ do_unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir) | |||
453 | 486 | ||
454 | /* | 487 | /* |
455 | * Return the buffer to the free list by setting the corresponding | 488 | * Return the buffer to the free list by setting the corresponding |
456 | * entries to indicate the number of contigous entries available. | 489 | * entries to indicate the number of contiguous entries available. |
457 | * While returning the entries to the free list, we merge the entries | 490 | * While returning the entries to the free list, we merge the entries |
458 | * with slots below and above the pool being returned. | 491 | * with slots below and above the pool being returned. |
459 | */ | 492 | */ |
@@ -517,7 +550,7 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size, | |||
517 | dma_mask = hwdev->coherent_dma_mask; | 550 | dma_mask = hwdev->coherent_dma_mask; |
518 | 551 | ||
519 | ret = (void *)__get_free_pages(flags, order); | 552 | ret = (void *)__get_free_pages(flags, order); |
520 | if (ret && swiotlb_virt_to_bus(hwdev, ret) + size > dma_mask) { | 553 | if (ret && swiotlb_virt_to_bus(hwdev, ret) + size - 1 > dma_mask) { |
521 | /* | 554 | /* |
522 | * The allocated memory isn't reachable by the device. | 555 | * The allocated memory isn't reachable by the device. |
523 | */ | 556 | */ |
@@ -539,7 +572,7 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size, | |||
539 | dev_addr = swiotlb_virt_to_bus(hwdev, ret); | 572 | dev_addr = swiotlb_virt_to_bus(hwdev, ret); |
540 | 573 | ||
541 | /* Confirm address can be DMA'd by device */ | 574 | /* Confirm address can be DMA'd by device */ |
542 | if (dev_addr + size > dma_mask) { | 575 | if (dev_addr + size - 1 > dma_mask) { |
543 | printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016Lx\n", | 576 | printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016Lx\n", |
544 | (unsigned long long)dma_mask, | 577 | (unsigned long long)dma_mask, |
545 | (unsigned long long)dev_addr); | 578 | (unsigned long long)dev_addr); |