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