diff options
Diffstat (limited to 'arch/xtensa/kernel/pci-dma.c')
-rw-r--r-- | arch/xtensa/kernel/pci-dma.c | 44 |
1 files changed, 32 insertions, 12 deletions
diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c index 6648fa9d9192..ca76f071666e 100644 --- a/arch/xtensa/kernel/pci-dma.c +++ b/arch/xtensa/kernel/pci-dma.c @@ -1,5 +1,5 @@ /* - * arch/xtensa/kernel/pci-dma.c + * arch/xtensa/pci-dma.c * * DMA coherent memory allocation. * @@ -29,28 +29,48 @@ */ void * -dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) +dma_alloc_coherent(struct device *dev,size_t size,dma_addr_t *handle,gfp_t flag) { - void *ret; + unsigned long ret; + unsigned long uncached = 0; /* ignore region speicifiers */ - gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); - if (dev == NULL || (*dev->dma_mask < 0xffffffff)) - gfp |= GFP_DMA; - ret = (void *)__get_free_pages(gfp, get_order(size)); + flag &= ~(__GFP_DMA | __GFP_HIGHMEM); - if (ret != NULL) { - memset(ret, 0, size); - *handle = virt_to_bus(ret); + if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) + flag |= GFP_DMA; + ret = (unsigned long)__get_free_pages(flag, get_order(size)); + + if (ret == 0) + return NULL; + + /* We currently don't support coherent memory outside KSEG */ + + if (ret < XCHAL_KSEG_CACHED_VADDR + || ret >= XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE) + BUG(); + + + if (ret != 0) { + memset((void*) ret, 0, size); + uncached = ret+XCHAL_KSEG_BYPASS_VADDR-XCHAL_KSEG_CACHED_VADDR; + *handle = virt_to_bus((void*)ret); + __flush_invalidate_dcache_range(ret, size); } - return (void*) BYPASS_ADDR((unsigned long)ret); + + return (void*)uncached; } void dma_free_coherent(struct device *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { - free_pages(CACHED_ADDR((unsigned long)vaddr), get_order(size)); + long addr=(long)vaddr+XCHAL_KSEG_CACHED_VADDR-XCHAL_KSEG_BYPASS_VADDR; + + if (addr < 0 || addr >= XCHAL_KSEG_SIZE) + BUG(); + + free_pages(addr, get_order(size)); } |