Jan Beulich
2007-Jan-02 14:28 UTC
[Xen-devel] [PATCH] linux: Reduce restrictions on address width for DMA operations
Use address width needed by device rather than dma_bits in dma_alloc_coherent(). Probe supported address width in swiotlb initialization. Signed-off-by: Jan Beulich <jbeulich@novell.com> Index: sle10-sp1-2006-12-21/arch/i386/kernel/pci-dma-xen.c ==================================================================--- sle10-sp1-2006-12-21.orig/arch/i386/kernel/pci-dma-xen.c 2007-01-02 12:36:26.000000000 +0100 +++ sle10-sp1-2006-12-21/arch/i386/kernel/pci-dma-xen.c 2007-01-02 10:32:16.000000000 +0100 @@ -161,6 +161,8 @@ void *dma_alloc_coherent(struct device * struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; unsigned int order = get_order(size); unsigned long vstart; + u64 mask; + /* ignore region specifiers */ gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); @@ -183,9 +185,14 @@ void *dma_alloc_coherent(struct device * vstart = __get_free_pages(gfp, order); ret = (void *)vstart; + if (dev != NULL && dev->coherent_dma_mask) + mask = dev->coherent_dma_mask; + else + mask = 0xffffffff; + if (ret != NULL) { if (xen_create_contiguous_region(vstart, order, - dma_bits) != 0) { + fls64(mask)) != 0) { free_pages(vstart, order); return NULL; } Index: sle10-sp1-2006-12-21/arch/i386/kernel/swiotlb.c ==================================================================--- sle10-sp1-2006-12-21.orig/arch/i386/kernel/swiotlb.c 2007-01-02 12:36:26.000000000 +0100 +++ sle10-sp1-2006-12-21/arch/i386/kernel/swiotlb.c 2007-01-02 12:48:40.000000000 +0100 @@ -47,9 +47,6 @@ EXPORT_SYMBOL(swiotlb); */ #define IO_TLB_SHIFT 11 -/* Width of DMA addresses. 30 bits is a b44 limitation. */ -#define DEFAULT_DMA_BITS 30 - static int swiotlb_force; static char *iotlb_virt_start; static unsigned long iotlb_nslabs; @@ -98,11 +95,12 @@ static struct phys_addr { */ static DEFINE_SPINLOCK(io_tlb_lock); -unsigned int dma_bits = DEFAULT_DMA_BITS; +static unsigned int dma_bits; +static unsigned int __initdata max_dma_bits = 32; static int __init setup_dma_bits(char *str) { - dma_bits = simple_strtoul(str, NULL, 0); + max_dma_bits = simple_strtoul(str, NULL, 0); return 0; } __setup("dma_bits=", setup_dma_bits); @@ -143,6 +141,7 @@ void swiotlb_init_with_default_size (size_t default_size) { unsigned long i, bytes; + int rc; if (!iotlb_nslabs) { iotlb_nslabs = (default_size >> IO_TLB_SHIFT); @@ -159,16 +158,33 @@ swiotlb_init_with_default_size (size_t d */ iotlb_virt_start = alloc_bootmem_low_pages(bytes); if (!iotlb_virt_start) - panic("Cannot allocate SWIOTLB buffer!\n" - "Use dom0_mem Xen boot parameter to reserve\n" - "some DMA memory (e.g., dom0_mem=-128M).\n"); + panic("Cannot allocate SWIOTLB buffer!\n"); + dma_bits = get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT) + PAGE_SHIFT; for (i = 0; i < iotlb_nslabs; i += IO_TLB_SEGSIZE) { - int rc = xen_create_contiguous_region( - (unsigned long)iotlb_virt_start + (i << IO_TLB_SHIFT), - get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT), - dma_bits); - BUG_ON(rc); + do { + rc = xen_create_contiguous_region( + (unsigned long)iotlb_virt_start + (i << IO_TLB_SHIFT), + get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT), + dma_bits); + } while (rc && dma_bits++ < max_dma_bits); + if (rc) { + if (i == 0) + panic("No suitable physical memory available for SWIOTLB buffer!\n" + "Use dom0_mem Xen boot parameter to reserve\n" + "some DMA memory (e.g., dom0_mem=-128M).\n"); + iotlb_nslabs = i; + i <<= IO_TLB_SHIFT; + free_bootmem(__pa(iotlb_virt_start + i), bytes - i); + bytes = i; + for (dma_bits = 0; i > 0; i -= IO_TLB_SEGSIZE << IO_TLB_SHIFT) { + unsigned int bits = fls64(virt_to_bus(iotlb_virt_start + i - 1)); + + if (bits > dma_bits) + dma_bits = bits; + } + break; + } } /* @@ -186,17 +202,27 @@ swiotlb_init_with_default_size (size_t d * Get the overflow emergency buffer */ io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow); + if (!io_tlb_overflow_buffer) + panic("Cannot allocate SWIOTLB overflow buffer!\n"); + + do { + rc = xen_create_contiguous_region( + (unsigned long)io_tlb_overflow_buffer, + get_order(io_tlb_overflow), + dma_bits); + } while (rc && dma_bits++ < max_dma_bits); + if (rc) + panic("No suitable physical memory available for SWIOTLB overflow buffer!\n"); iotlb_pfn_start = __pa(iotlb_virt_start) >> PAGE_SHIFT; iotlb_pfn_end = iotlb_pfn_start + (bytes >> PAGE_SHIFT); printk(KERN_INFO "Software IO TLB enabled: \n" " Aperture: %lu megabytes\n" - " Kernel range: 0x%016lx - 0x%016lx\n" + " Kernel range: %p - %p\n" " Address size: %u bits\n", bytes >> 20, - (unsigned long)iotlb_virt_start, - (unsigned long)iotlb_virt_start + bytes, + iotlb_virt_start, iotlb_virt_start + bytes, dma_bits); } Index: sle10-sp1-2006-12-21/include/asm-i386/mach-xen/asm/swiotlb.h ==================================================================--- sle10-sp1-2006-12-21.orig/include/asm-i386/mach-xen/asm/swiotlb.h 2007-01-02 12:36:26.000000000 +0100 +++ sle10-sp1-2006-12-21/include/asm-i386/mach-xen/asm/swiotlb.h 2007-01-02 10:28:31.000000000 +0100 @@ -34,8 +34,6 @@ extern void swiotlb_unmap_page(struct de extern int swiotlb_dma_supported(struct device *hwdev, u64 mask); extern void swiotlb_init(void); -extern unsigned int dma_bits; - #ifdef CONFIG_SWIOTLB extern int swiotlb; #else _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel