diff options
Diffstat (limited to 'lib/swiotlb.c')
| -rw-r--r-- | lib/swiotlb.c | 429 | 
1 files changed, 250 insertions, 179 deletions
diff --git a/lib/swiotlb.c b/lib/swiotlb.c index 7c06ee51a29..4abda074ea4 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -20,7 +20,7 @@  #include <linux/cache.h>  #include <linux/dma-mapping.h>  #include <linux/mm.h> -#include <linux/module.h> +#include <linux/export.h>  #include <linux/spinlock.h>  #include <linux/string.h>  #include <linux/swiotlb.h> @@ -38,6 +38,9 @@  #include <linux/bootmem.h>  #include <linux/iommu-helper.h> +#define CREATE_TRACE_POINTS +#include <trace/events/swiotlb.h> +  #define OFFSET(val,align) ((unsigned long)	\  	                   ( (val) & ( (align) - 1))) @@ -57,10 +60,10 @@ int swiotlb_force;   * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this   * API.   */ -static char *io_tlb_start, *io_tlb_end; +static phys_addr_t io_tlb_start, io_tlb_end;  /* - * The number of IO TLB blocks (in groups of 64) betweeen io_tlb_start and + * The number of IO TLB blocks (in groups of 64) between io_tlb_start and   * io_tlb_end.  This is command line adjustable via setup_io_tlb_npages.   */  static unsigned long io_tlb_nslabs; @@ -70,7 +73,7 @@ static unsigned long io_tlb_nslabs;   */  static unsigned long io_tlb_overflow = 32*1024; -static void *io_tlb_overflow_buffer; +static phys_addr_t io_tlb_overflow_buffer;  /*   * This is a free list describing the number of free entries available from @@ -83,6 +86,7 @@ static unsigned int io_tlb_index;   * We need to save away the original address corresponding to a mapped entry   * for the sync operations.   */ +#define INVALID_PHYS_ADDR (~(phys_addr_t)0)  static phys_addr_t *io_tlb_orig_addr;  /* @@ -105,11 +109,28 @@ setup_io_tlb_npages(char *str)  	if (!strcmp(str, "force"))  		swiotlb_force = 1; -	return 1; +	return 0;  } -__setup("swiotlb=", setup_io_tlb_npages); +early_param("swiotlb", setup_io_tlb_npages);  /* make io_tlb_overflow tunable too? */ +unsigned long swiotlb_nr_tbl(void) +{ +	return io_tlb_nslabs; +} +EXPORT_SYMBOL_GPL(swiotlb_nr_tbl); + +/* default to 64MB */ +#define IO_TLB_DEFAULT_SIZE (64UL<<20) +unsigned long swiotlb_size_or_default(void) +{ +	unsigned long size; + +	size = io_tlb_nslabs << IO_TLB_SHIFT; + +	return size ? size : (IO_TLB_DEFAULT_SIZE); +} +  /* Note that this doesn't work with highmem page */  static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev,  				      volatile void *address) @@ -117,59 +138,81 @@ static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev,  	return phys_to_dma(hwdev, virt_to_phys(address));  } +static bool no_iotlb_memory; +  void swiotlb_print_info(void)  {  	unsigned long bytes = io_tlb_nslabs << IO_TLB_SHIFT; -	phys_addr_t pstart, pend; +	unsigned char *vstart, *vend; -	pstart = virt_to_phys(io_tlb_start); -	pend = virt_to_phys(io_tlb_end); +	if (no_iotlb_memory) { +		pr_warn("software IO TLB: No low mem\n"); +		return; +	} + +	vstart = phys_to_virt(io_tlb_start); +	vend = phys_to_virt(io_tlb_end); -	printk(KERN_INFO "Placing %luMB software IO TLB between %p - %p\n", -	       bytes >> 20, io_tlb_start, io_tlb_end); -	printk(KERN_INFO "software IO TLB at phys %#llx - %#llx\n", -	       (unsigned long long)pstart, -	       (unsigned long long)pend); +	printk(KERN_INFO "software IO TLB [mem %#010llx-%#010llx] (%luMB) mapped at [%p-%p]\n", +	       (unsigned long long)io_tlb_start, +	       (unsigned long long)io_tlb_end, +	       bytes >> 20, vstart, vend - 1);  } -void __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose) +int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)  { +	void *v_overflow_buffer;  	unsigned long i, bytes;  	bytes = nslabs << IO_TLB_SHIFT;  	io_tlb_nslabs = nslabs; -	io_tlb_start = tlb; +	io_tlb_start = __pa(tlb);  	io_tlb_end = io_tlb_start + bytes;  	/* +	 * Get the overflow emergency buffer +	 */ +	v_overflow_buffer = memblock_virt_alloc_low_nopanic( +						PAGE_ALIGN(io_tlb_overflow), +						PAGE_SIZE); +	if (!v_overflow_buffer) +		return -ENOMEM; + +	io_tlb_overflow_buffer = __pa(v_overflow_buffer); + +	/*  	 * Allocate and initialize the free list array.  This array is used  	 * to find contiguous free memory regions of size up to IO_TLB_SEGSIZE  	 * between io_tlb_start and io_tlb_end.  	 */ -	io_tlb_list = alloc_bootmem_pages(PAGE_ALIGN(io_tlb_nslabs * sizeof(int))); -	for (i = 0; i < io_tlb_nslabs; i++) - 		io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE); +	io_tlb_list = memblock_virt_alloc( +				PAGE_ALIGN(io_tlb_nslabs * sizeof(int)), +				PAGE_SIZE); +	io_tlb_orig_addr = memblock_virt_alloc( +				PAGE_ALIGN(io_tlb_nslabs * sizeof(phys_addr_t)), +				PAGE_SIZE); +	for (i = 0; i < io_tlb_nslabs; i++) { +		io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE); +		io_tlb_orig_addr[i] = INVALID_PHYS_ADDR; +	}  	io_tlb_index = 0; -	io_tlb_orig_addr = alloc_bootmem_pages(PAGE_ALIGN(io_tlb_nslabs * sizeof(phys_addr_t))); -	/* -	 * Get the overflow emergency buffer -	 */ -	io_tlb_overflow_buffer = alloc_bootmem_low_pages(PAGE_ALIGN(io_tlb_overflow)); -	if (!io_tlb_overflow_buffer) -		panic("Cannot allocate SWIOTLB overflow buffer!\n");  	if (verbose)  		swiotlb_print_info(); + +	return 0;  }  /*   * Statically reserve bounce buffer space and initialize bounce buffer data   * structures for the software IO TLB used to implement the DMA API.   */ -void __init -swiotlb_init_with_default_size(size_t default_size, int verbose) +void  __init +swiotlb_init(int verbose)  { +	size_t default_size = IO_TLB_DEFAULT_SIZE; +	unsigned char *vstart;  	unsigned long bytes;  	if (!io_tlb_nslabs) { @@ -179,20 +222,16 @@ swiotlb_init_with_default_size(size_t default_size, int verbose)  	bytes = io_tlb_nslabs << IO_TLB_SHIFT; -	/* -	 * Get IO TLB memory from the low pages -	 */ -	io_tlb_start = alloc_bootmem_low_pages(PAGE_ALIGN(bytes)); -	if (!io_tlb_start) -		panic("Cannot allocate SWIOTLB buffer"); - -	swiotlb_init_with_tbl(io_tlb_start, io_tlb_nslabs, verbose); -} +	/* Get IO TLB memory from the low pages */ +	vstart = memblock_virt_alloc_low_nopanic(PAGE_ALIGN(bytes), PAGE_SIZE); +	if (vstart && !swiotlb_init_with_tbl(vstart, io_tlb_nslabs, verbose)) +		return; -void __init -swiotlb_init(int verbose) -{ -	swiotlb_init_with_default_size(64 * (1<<20), verbose);	/* default to 64MB */ +	if (io_tlb_start) +		memblock_free_early(io_tlb_start, +				    PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT)); +	pr_warn("Cannot allocate SWIOTLB buffer"); +	no_iotlb_memory = true;  }  /* @@ -203,8 +242,10 @@ swiotlb_init(int verbose)  int  swiotlb_late_init_with_default_size(size_t default_size)  { -	unsigned long i, bytes, req_nslabs = io_tlb_nslabs; +	unsigned long bytes, req_nslabs = io_tlb_nslabs; +	unsigned char *vstart = NULL;  	unsigned int order; +	int rc = 0;  	if (!io_tlb_nslabs) {  		io_tlb_nslabs = (default_size >> IO_TLB_SHIFT); @@ -219,24 +260,51 @@ swiotlb_late_init_with_default_size(size_t default_size)  	bytes = io_tlb_nslabs << IO_TLB_SHIFT;  	while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) { -		io_tlb_start = (void *)__get_free_pages(GFP_DMA | __GFP_NOWARN, -							order); -		if (io_tlb_start) +		vstart = (void *)__get_free_pages(GFP_DMA | __GFP_NOWARN, +						  order); +		if (vstart)  			break;  		order--;  	} -	if (!io_tlb_start) -		goto cleanup1; - +	if (!vstart) { +		io_tlb_nslabs = req_nslabs; +		return -ENOMEM; +	}  	if (order != get_order(bytes)) {  		printk(KERN_WARNING "Warning: only able to allocate %ld MB "  		       "for software IO TLB\n", (PAGE_SIZE << order) >> 20);  		io_tlb_nslabs = SLABS_PER_PAGE << order; -		bytes = io_tlb_nslabs << IO_TLB_SHIFT;  	} +	rc = swiotlb_late_init_with_tbl(vstart, io_tlb_nslabs); +	if (rc) +		free_pages((unsigned long)vstart, order); +	return rc; +} + +int +swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs) +{ +	unsigned long i, bytes; +	unsigned char *v_overflow_buffer; + +	bytes = nslabs << IO_TLB_SHIFT; + +	io_tlb_nslabs = nslabs; +	io_tlb_start = virt_to_phys(tlb);  	io_tlb_end = io_tlb_start + bytes; -	memset(io_tlb_start, 0, bytes); + +	memset(tlb, 0, bytes); + +	/* +	 * Get the overflow emergency buffer +	 */ +	v_overflow_buffer = (void *)__get_free_pages(GFP_DMA, +						     get_order(io_tlb_overflow)); +	if (!v_overflow_buffer) +		goto cleanup2; + +	io_tlb_overflow_buffer = virt_to_phys(v_overflow_buffer);  	/*  	 * Allocate and initialize the free list array.  This array is used @@ -246,29 +314,21 @@ swiotlb_late_init_with_default_size(size_t default_size)  	io_tlb_list = (unsigned int *)__get_free_pages(GFP_KERNEL,  	                              get_order(io_tlb_nslabs * sizeof(int)));  	if (!io_tlb_list) -		goto cleanup2; - -	for (i = 0; i < io_tlb_nslabs; i++) - 		io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE); -	io_tlb_index = 0; +		goto cleanup3;  	io_tlb_orig_addr = (phys_addr_t *)  		__get_free_pages(GFP_KERNEL,  				 get_order(io_tlb_nslabs *  					   sizeof(phys_addr_t)));  	if (!io_tlb_orig_addr) -		goto cleanup3; - -	memset(io_tlb_orig_addr, 0, io_tlb_nslabs * sizeof(phys_addr_t)); - -	/* -	 * Get the overflow emergency buffer -	 */ -	io_tlb_overflow_buffer = (void *)__get_free_pages(GFP_DMA, -	                                          get_order(io_tlb_overflow)); -	if (!io_tlb_overflow_buffer)  		goto cleanup4; +	for (i = 0; i < io_tlb_nslabs; i++) { +		io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE); +		io_tlb_orig_addr[i] = INVALID_PHYS_ADDR; +	} +	io_tlb_index = 0; +  	swiotlb_print_info();  	late_alloc = 1; @@ -276,65 +336,64 @@ swiotlb_late_init_with_default_size(size_t default_size)  	return 0;  cleanup4: -	free_pages((unsigned long)io_tlb_orig_addr, -		   get_order(io_tlb_nslabs * sizeof(phys_addr_t))); -	io_tlb_orig_addr = NULL; -cleanup3:  	free_pages((unsigned long)io_tlb_list, get_order(io_tlb_nslabs *  	                                                 sizeof(int)));  	io_tlb_list = NULL; +cleanup3: +	free_pages((unsigned long)v_overflow_buffer, +		   get_order(io_tlb_overflow)); +	io_tlb_overflow_buffer = 0;  cleanup2: -	io_tlb_end = NULL; -	free_pages((unsigned long)io_tlb_start, order); -	io_tlb_start = NULL; -cleanup1: -	io_tlb_nslabs = req_nslabs; +	io_tlb_end = 0; +	io_tlb_start = 0; +	io_tlb_nslabs = 0;  	return -ENOMEM;  }  void __init swiotlb_free(void)  { -	if (!io_tlb_overflow_buffer) +	if (!io_tlb_orig_addr)  		return;  	if (late_alloc) { -		free_pages((unsigned long)io_tlb_overflow_buffer, +		free_pages((unsigned long)phys_to_virt(io_tlb_overflow_buffer),  			   get_order(io_tlb_overflow));  		free_pages((unsigned long)io_tlb_orig_addr,  			   get_order(io_tlb_nslabs * sizeof(phys_addr_t)));  		free_pages((unsigned long)io_tlb_list, get_order(io_tlb_nslabs *  								 sizeof(int))); -		free_pages((unsigned long)io_tlb_start, +		free_pages((unsigned long)phys_to_virt(io_tlb_start),  			   get_order(io_tlb_nslabs << IO_TLB_SHIFT));  	} else { -		free_bootmem_late(__pa(io_tlb_overflow_buffer), -				  PAGE_ALIGN(io_tlb_overflow)); -		free_bootmem_late(__pa(io_tlb_orig_addr), -				  PAGE_ALIGN(io_tlb_nslabs * sizeof(phys_addr_t))); -		free_bootmem_late(__pa(io_tlb_list), -				  PAGE_ALIGN(io_tlb_nslabs * sizeof(int))); -		free_bootmem_late(__pa(io_tlb_start), -				  PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT)); +		memblock_free_late(io_tlb_overflow_buffer, +				   PAGE_ALIGN(io_tlb_overflow)); +		memblock_free_late(__pa(io_tlb_orig_addr), +				   PAGE_ALIGN(io_tlb_nslabs * sizeof(phys_addr_t))); +		memblock_free_late(__pa(io_tlb_list), +				   PAGE_ALIGN(io_tlb_nslabs * sizeof(int))); +		memblock_free_late(io_tlb_start, +				   PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT));  	} +	io_tlb_nslabs = 0;  } -static int is_swiotlb_buffer(phys_addr_t paddr) +int is_swiotlb_buffer(phys_addr_t paddr)  { -	return paddr >= virt_to_phys(io_tlb_start) && -		paddr < virt_to_phys(io_tlb_end); +	return paddr >= io_tlb_start && paddr < io_tlb_end;  }  /*   * Bounce: copy the swiotlb buffer back to the original dma location   */ -void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size, -		    enum dma_data_direction dir) +static void swiotlb_bounce(phys_addr_t orig_addr, phys_addr_t tlb_addr, +			   size_t size, enum dma_data_direction dir)  { -	unsigned long pfn = PFN_DOWN(phys); +	unsigned long pfn = PFN_DOWN(orig_addr); +	unsigned char *vaddr = phys_to_virt(tlb_addr);  	if (PageHighMem(pfn_to_page(pfn))) {  		/* The buffer does not have a mapping.  Map it in and copy */ -		unsigned int offset = phys & ~PAGE_MASK; +		unsigned int offset = orig_addr & ~PAGE_MASK;  		char *buffer;  		unsigned int sz = 0;  		unsigned long flags; @@ -343,41 +402,42 @@ void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,  			sz = min_t(size_t, PAGE_SIZE - offset, size);  			local_irq_save(flags); -			buffer = kmap_atomic(pfn_to_page(pfn), -					     KM_BOUNCE_READ); +			buffer = kmap_atomic(pfn_to_page(pfn));  			if (dir == DMA_TO_DEVICE) -				memcpy(dma_addr, buffer + offset, sz); +				memcpy(vaddr, buffer + offset, sz);  			else -				memcpy(buffer + offset, dma_addr, sz); -			kunmap_atomic(buffer, KM_BOUNCE_READ); +				memcpy(buffer + offset, vaddr, sz); +			kunmap_atomic(buffer);  			local_irq_restore(flags);  			size -= sz;  			pfn++; -			dma_addr += sz; +			vaddr += sz;  			offset = 0;  		} +	} else if (dir == DMA_TO_DEVICE) { +		memcpy(vaddr, phys_to_virt(orig_addr), size);  	} else { -		if (dir == DMA_TO_DEVICE) -			memcpy(dma_addr, phys_to_virt(phys), size); -		else -			memcpy(phys_to_virt(phys), dma_addr, size); +		memcpy(phys_to_virt(orig_addr), vaddr, size);  	}  } -EXPORT_SYMBOL_GPL(swiotlb_bounce); -void *swiotlb_tbl_map_single(struct device *hwdev, dma_addr_t tbl_dma_addr, -			     phys_addr_t phys, size_t size, -			     enum dma_data_direction dir) +phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, +				   dma_addr_t tbl_dma_addr, +				   phys_addr_t orig_addr, size_t size, +				   enum dma_data_direction dir)  {  	unsigned long flags; -	char *dma_addr; +	phys_addr_t tlb_addr;  	unsigned int nslots, stride, index, wrap;  	int i;  	unsigned long mask;  	unsigned long offset_slots;  	unsigned long max_slots; +	if (no_iotlb_memory) +		panic("Can not allocate SWIOTLB buffer earlier and can't now provide you with the DMA bounce buffer"); +  	mask = dma_get_seg_boundary(hwdev);  	tbl_dma_addr &= mask; @@ -435,7 +495,7 @@ void *swiotlb_tbl_map_single(struct device *hwdev, dma_addr_t tbl_dma_addr,  				io_tlb_list[i] = 0;  			for (i = index - 1; (OFFSET(i, IO_TLB_SEGSIZE) != IO_TLB_SEGSIZE - 1) && io_tlb_list[i]; i--)  				io_tlb_list[i] = ++count; -			dma_addr = io_tlb_start + (index << IO_TLB_SHIFT); +			tlb_addr = io_tlb_start + (index << IO_TLB_SHIFT);  			/*  			 * Update the indices to avoid searching in the next @@ -453,7 +513,9 @@ void *swiotlb_tbl_map_single(struct device *hwdev, dma_addr_t tbl_dma_addr,  not_found:  	spin_unlock_irqrestore(&io_tlb_lock, flags); -	return NULL; +	if (printk_ratelimit()) +		dev_warn(hwdev, "swiotlb buffer is full (sz: %zd bytes)\n", size); +	return SWIOTLB_MAP_ERROR;  found:  	spin_unlock_irqrestore(&io_tlb_lock, flags); @@ -463,11 +525,11 @@ found:  	 * needed.  	 */  	for (i = 0; i < nslots; i++) -		io_tlb_orig_addr[index+i] = phys + (i << IO_TLB_SHIFT); +		io_tlb_orig_addr[index+i] = orig_addr + (i << IO_TLB_SHIFT);  	if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) -		swiotlb_bounce(phys, dma_addr, size, DMA_TO_DEVICE); +		swiotlb_bounce(orig_addr, tlb_addr, size, DMA_TO_DEVICE); -	return dma_addr; +	return tlb_addr;  }  EXPORT_SYMBOL_GPL(swiotlb_tbl_map_single); @@ -475,11 +537,10 @@ EXPORT_SYMBOL_GPL(swiotlb_tbl_map_single);   * Allocates bounce buffer and returns its kernel virtual address.   */ -static void * -map_single(struct device *hwdev, phys_addr_t phys, size_t size, -	   enum dma_data_direction dir) +phys_addr_t map_single(struct device *hwdev, phys_addr_t phys, size_t size, +		       enum dma_data_direction dir)  { -	dma_addr_t start_dma_addr = swiotlb_virt_to_bus(hwdev, io_tlb_start); +	dma_addr_t start_dma_addr = phys_to_dma(hwdev, io_tlb_start);  	return swiotlb_tbl_map_single(hwdev, start_dma_addr, phys, size, dir);  } @@ -487,20 +548,20 @@ map_single(struct device *hwdev, phys_addr_t phys, size_t size,  /*   * dma_addr is the kernel virtual address of the bounce buffer to unmap.   */ -void -swiotlb_tbl_unmap_single(struct device *hwdev, char *dma_addr, size_t size, -			enum dma_data_direction dir) +void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr, +			      size_t size, enum dma_data_direction dir)  {  	unsigned long flags;  	int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT; -	int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT; -	phys_addr_t phys = io_tlb_orig_addr[index]; +	int index = (tlb_addr - io_tlb_start) >> IO_TLB_SHIFT; +	phys_addr_t orig_addr = io_tlb_orig_addr[index];  	/*  	 * First, sync the memory before unmapping the entry  	 */ -	if (phys && ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL))) -		swiotlb_bounce(phys, dma_addr, size, DMA_FROM_DEVICE); +	if (orig_addr != INVALID_PHYS_ADDR && +	    ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL))) +		swiotlb_bounce(orig_addr, tlb_addr, size, DMA_FROM_DEVICE);  	/*  	 * Return the buffer to the free list by setting the corresponding @@ -516,8 +577,10 @@ swiotlb_tbl_unmap_single(struct device *hwdev, char *dma_addr, size_t size,  		 * Step 1: return the slots to the free list, merging the  		 * slots with superceeding slots  		 */ -		for (i = index + nslots - 1; i >= index; i--) +		for (i = index + nslots - 1; i >= index; i--) {  			io_tlb_list[i] = ++count; +			io_tlb_orig_addr[i] = INVALID_PHYS_ADDR; +		}  		/*  		 * Step 2: merge the returned slots with the preceding slots,  		 * if available (non zero) @@ -529,26 +592,29 @@ swiotlb_tbl_unmap_single(struct device *hwdev, char *dma_addr, size_t size,  }  EXPORT_SYMBOL_GPL(swiotlb_tbl_unmap_single); -void -swiotlb_tbl_sync_single(struct device *hwdev, char *dma_addr, size_t size, -			enum dma_data_direction dir, -			enum dma_sync_target target) +void swiotlb_tbl_sync_single(struct device *hwdev, phys_addr_t tlb_addr, +			     size_t size, enum dma_data_direction dir, +			     enum dma_sync_target target)  { -	int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT; -	phys_addr_t phys = io_tlb_orig_addr[index]; +	int index = (tlb_addr - io_tlb_start) >> IO_TLB_SHIFT; +	phys_addr_t orig_addr = io_tlb_orig_addr[index]; -	phys += ((unsigned long)dma_addr & ((1 << IO_TLB_SHIFT) - 1)); +	if (orig_addr == INVALID_PHYS_ADDR) +		return; +	orig_addr += (unsigned long)tlb_addr & ((1 << IO_TLB_SHIFT) - 1);  	switch (target) {  	case SYNC_FOR_CPU:  		if (likely(dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)) -			swiotlb_bounce(phys, dma_addr, size, DMA_FROM_DEVICE); +			swiotlb_bounce(orig_addr, tlb_addr, +				       size, DMA_FROM_DEVICE);  		else  			BUG_ON(dir != DMA_TO_DEVICE);  		break;  	case SYNC_FOR_DEVICE:  		if (likely(dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)) -			swiotlb_bounce(phys, dma_addr, size, DMA_TO_DEVICE); +			swiotlb_bounce(orig_addr, tlb_addr, +				       size, DMA_TO_DEVICE);  		else  			BUG_ON(dir != DMA_FROM_DEVICE);  		break; @@ -571,12 +637,15 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,  		dma_mask = hwdev->coherent_dma_mask;  	ret = (void *)__get_free_pages(flags, order); -	if (ret && swiotlb_virt_to_bus(hwdev, ret) + size - 1 > dma_mask) { -		/* -		 * The allocated memory isn't reachable by the device. -		 */ -		free_pages((unsigned long) ret, order); -		ret = NULL; +	if (ret) { +		dev_addr = swiotlb_virt_to_bus(hwdev, ret); +		if (dev_addr + size - 1 > dma_mask) { +			/* +			 * The allocated memory isn't reachable by the device. +			 */ +			free_pages((unsigned long) ret, order); +			ret = NULL; +		}  	}  	if (!ret) {  		/* @@ -584,25 +653,29 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,  		 * GFP_DMA memory; fall back on map_single(), which  		 * will grab memory from the lowest available address range.  		 */ -		ret = map_single(hwdev, 0, size, DMA_FROM_DEVICE); -		if (!ret) +		phys_addr_t paddr = map_single(hwdev, 0, size, DMA_FROM_DEVICE); +		if (paddr == SWIOTLB_MAP_ERROR)  			return NULL; -	} -	memset(ret, 0, size); -	dev_addr = swiotlb_virt_to_bus(hwdev, ret); +		ret = phys_to_virt(paddr); +		dev_addr = phys_to_dma(hwdev, paddr); -	/* Confirm address can be DMA'd by device */ -	if (dev_addr + size - 1 > dma_mask) { -		printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016Lx\n", -		       (unsigned long long)dma_mask, -		       (unsigned long long)dev_addr); +		/* Confirm address can be DMA'd by device */ +		if (dev_addr + size - 1 > dma_mask) { +			printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016Lx\n", +			       (unsigned long long)dma_mask, +			       (unsigned long long)dev_addr); -		/* DMA_TO_DEVICE to avoid memcpy in unmap_single */ -		swiotlb_tbl_unmap_single(hwdev, ret, size, DMA_TO_DEVICE); -		return NULL; +			/* DMA_TO_DEVICE to avoid memcpy in unmap_single */ +			swiotlb_tbl_unmap_single(hwdev, paddr, +						 size, DMA_TO_DEVICE); +			return NULL; +		}  	} +  	*dma_handle = dev_addr; +	memset(ret, 0, size); +  	return ret;  }  EXPORT_SYMBOL(swiotlb_alloc_coherent); @@ -618,7 +691,7 @@ swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,  		free_pages((unsigned long)vaddr, get_order(size));  	else  		/* DMA_TO_DEVICE to avoid memcpy in swiotlb_tbl_unmap_single */ -		swiotlb_tbl_unmap_single(hwdev, vaddr, size, DMA_TO_DEVICE); +		swiotlb_tbl_unmap_single(hwdev, paddr, size, DMA_TO_DEVICE);  }  EXPORT_SYMBOL(swiotlb_free_coherent); @@ -659,9 +732,8 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,  			    enum dma_data_direction dir,  			    struct dma_attrs *attrs)  { -	phys_addr_t phys = page_to_phys(page) + offset; +	phys_addr_t map, phys = page_to_phys(page) + offset;  	dma_addr_t dev_addr = phys_to_dma(dev, phys); -	void *map;  	BUG_ON(dir == DMA_NONE);  	/* @@ -672,22 +744,22 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,  	if (dma_capable(dev, dev_addr, size) && !swiotlb_force)  		return dev_addr; -	/* -	 * Oh well, have to allocate and map a bounce buffer. -	 */ +	trace_swiotlb_bounced(dev, dev_addr, size, swiotlb_force); + +	/* Oh well, have to allocate and map a bounce buffer. */  	map = map_single(dev, phys, size, dir); -	if (!map) { +	if (map == SWIOTLB_MAP_ERROR) {  		swiotlb_full(dev, size, dir, 1); -		map = io_tlb_overflow_buffer; +		return phys_to_dma(dev, io_tlb_overflow_buffer);  	} -	dev_addr = swiotlb_virt_to_bus(dev, map); +	dev_addr = phys_to_dma(dev, map); -	/* -	 * Ensure that the address returned is DMA'ble -	 */ -	if (!dma_capable(dev, dev_addr, size)) -		panic("map_single: bounce buffer is not DMA'ble"); +	/* Ensure that the address returned is DMA'ble */ +	if (!dma_capable(dev, dev_addr, size)) { +		swiotlb_tbl_unmap_single(dev, map, size, dir); +		return phys_to_dma(dev, io_tlb_overflow_buffer); +	}  	return dev_addr;  } @@ -709,7 +781,7 @@ static void unmap_single(struct device *hwdev, dma_addr_t dev_addr,  	BUG_ON(dir == DMA_NONE);  	if (is_swiotlb_buffer(paddr)) { -		swiotlb_tbl_unmap_single(hwdev, phys_to_virt(paddr), size, dir); +		swiotlb_tbl_unmap_single(hwdev, paddr, size, dir);  		return;  	} @@ -753,8 +825,7 @@ swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr,  	BUG_ON(dir == DMA_NONE);  	if (is_swiotlb_buffer(paddr)) { -		swiotlb_tbl_sync_single(hwdev, phys_to_virt(paddr), size, dir, -				       target); +		swiotlb_tbl_sync_single(hwdev, paddr, size, dir, target);  		return;  	} @@ -811,21 +882,21 @@ swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,  		if (swiotlb_force ||  		    !dma_capable(hwdev, dev_addr, sg->length)) { -			void *map = map_single(hwdev, sg_phys(sg), -					       sg->length, dir); -			if (!map) { +			phys_addr_t map = map_single(hwdev, sg_phys(sg), +						     sg->length, dir); +			if (map == SWIOTLB_MAP_ERROR) {  				/* Don't panic here, we expect map_sg users  				   to do proper error handling. */  				swiotlb_full(hwdev, sg->length, dir, 0);  				swiotlb_unmap_sg_attrs(hwdev, sgl, i, dir,  						       attrs); -				sgl[0].dma_length = 0; +				sg_dma_len(sgl) = 0;  				return 0;  			} -			sg->dma_address = swiotlb_virt_to_bus(hwdev, map); +			sg->dma_address = phys_to_dma(hwdev, map);  		} else  			sg->dma_address = dev_addr; -		sg->dma_length = sg->length; +		sg_dma_len(sg) = sg->length;  	}  	return nelems;  } @@ -853,7 +924,7 @@ swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl,  	BUG_ON(dir == DMA_NONE);  	for_each_sg(sgl, sg, nelems, i) -		unmap_single(hwdev, sg->dma_address, sg->dma_length, dir); +		unmap_single(hwdev, sg->dma_address, sg_dma_len(sg), dir);  }  EXPORT_SYMBOL(swiotlb_unmap_sg_attrs); @@ -883,7 +954,7 @@ swiotlb_sync_sg(struct device *hwdev, struct scatterlist *sgl,  	for_each_sg(sgl, sg, nelems, i)  		swiotlb_sync_single(hwdev, sg->dma_address, -				    sg->dma_length, dir, target); +				    sg_dma_len(sg), dir, target);  }  void @@ -905,7 +976,7 @@ EXPORT_SYMBOL(swiotlb_sync_sg_for_device);  int  swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr)  { -	return (dma_addr == swiotlb_virt_to_bus(hwdev, io_tlb_overflow_buffer)); +	return (dma_addr == phys_to_dma(hwdev, io_tlb_overflow_buffer));  }  EXPORT_SYMBOL(swiotlb_dma_mapping_error); @@ -918,6 +989,6 @@ EXPORT_SYMBOL(swiotlb_dma_mapping_error);  int  swiotlb_dma_supported(struct device *hwdev, u64 mask)  { -	return swiotlb_virt_to_bus(hwdev, io_tlb_end - 1) <= mask; +	return phys_to_dma(hwdev, io_tlb_end - 1) <= mask;  }  EXPORT_SYMBOL(swiotlb_dma_supported);  | 
