diff options
| -rw-r--r-- | arch/xtensa/kernel/pci-dma.c | 40 |
1 files changed, 30 insertions, 10 deletions
diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c index 623720a11143..732631ce250f 100644 --- a/arch/xtensa/kernel/pci-dma.c +++ b/arch/xtensa/kernel/pci-dma.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #include <linux/dma-contiguous.h> | 18 | #include <linux/dma-contiguous.h> |
| 19 | #include <linux/dma-direct.h> | ||
| 19 | #include <linux/gfp.h> | 20 | #include <linux/gfp.h> |
| 20 | #include <linux/highmem.h> | 21 | #include <linux/highmem.h> |
| 21 | #include <linux/mm.h> | 22 | #include <linux/mm.h> |
| @@ -123,7 +124,7 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size, | |||
| 123 | unsigned long attrs) | 124 | unsigned long attrs) |
| 124 | { | 125 | { |
| 125 | unsigned long ret; | 126 | unsigned long ret; |
| 126 | unsigned long uncached = 0; | 127 | unsigned long uncached; |
| 127 | unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; | 128 | unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; |
| 128 | struct page *page = NULL; | 129 | struct page *page = NULL; |
| 129 | 130 | ||
| @@ -144,15 +145,27 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size, | |||
| 144 | if (!page) | 145 | if (!page) |
| 145 | return NULL; | 146 | return NULL; |
| 146 | 147 | ||
| 147 | ret = (unsigned long)page_address(page); | 148 | *handle = phys_to_dma(dev, page_to_phys(page)); |
| 148 | 149 | ||
| 149 | /* We currently don't support coherent memory outside KSEG */ | 150 | #ifdef CONFIG_MMU |
| 151 | if (PageHighMem(page)) { | ||
| 152 | void *p; | ||
| 150 | 153 | ||
| 154 | p = dma_common_contiguous_remap(page, size, VM_MAP, | ||
| 155 | pgprot_noncached(PAGE_KERNEL), | ||
| 156 | __builtin_return_address(0)); | ||
| 157 | if (!p) { | ||
| 158 | if (!dma_release_from_contiguous(dev, page, count)) | ||
| 159 | __free_pages(page, get_order(size)); | ||
| 160 | } | ||
| 161 | return p; | ||
| 162 | } | ||
| 163 | #endif | ||
| 164 | ret = (unsigned long)page_address(page); | ||
| 151 | BUG_ON(ret < XCHAL_KSEG_CACHED_VADDR || | 165 | BUG_ON(ret < XCHAL_KSEG_CACHED_VADDR || |
| 152 | ret > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1); | 166 | ret > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1); |
| 153 | 167 | ||
| 154 | uncached = ret + XCHAL_KSEG_BYPASS_VADDR - XCHAL_KSEG_CACHED_VADDR; | 168 | uncached = ret + XCHAL_KSEG_BYPASS_VADDR - XCHAL_KSEG_CACHED_VADDR; |
| 155 | *handle = virt_to_bus((void *)ret); | ||
| 156 | __invalidate_dcache_range(ret, size); | 169 | __invalidate_dcache_range(ret, size); |
| 157 | 170 | ||
| 158 | return (void *)uncached; | 171 | return (void *)uncached; |
| @@ -161,13 +174,20 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size, | |||
| 161 | static void xtensa_dma_free(struct device *dev, size_t size, void *vaddr, | 174 | static void xtensa_dma_free(struct device *dev, size_t size, void *vaddr, |
| 162 | dma_addr_t dma_handle, unsigned long attrs) | 175 | dma_addr_t dma_handle, unsigned long attrs) |
| 163 | { | 176 | { |
| 164 | unsigned long addr = (unsigned long)vaddr + | ||
| 165 | XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_BYPASS_VADDR; | ||
| 166 | struct page *page = virt_to_page(addr); | ||
| 167 | unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; | 177 | unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; |
| 168 | 178 | unsigned long addr = (unsigned long)vaddr; | |
| 169 | BUG_ON(addr < XCHAL_KSEG_CACHED_VADDR || | 179 | struct page *page; |
| 170 | addr > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1); | 180 | |
| 181 | if (addr >= XCHAL_KSEG_BYPASS_VADDR && | ||
| 182 | addr - XCHAL_KSEG_BYPASS_VADDR < XCHAL_KSEG_SIZE) { | ||
| 183 | addr += XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_BYPASS_VADDR; | ||
| 184 | page = virt_to_page(addr); | ||
| 185 | } else { | ||
| 186 | #ifdef CONFIG_MMU | ||
| 187 | dma_common_free_remap(vaddr, size, VM_MAP); | ||
| 188 | #endif | ||
| 189 | page = pfn_to_page(PHYS_PFN(dma_to_phys(dev, dma_handle))); | ||
| 190 | } | ||
| 171 | 191 | ||
| 172 | if (!dma_release_from_contiguous(dev, page, count)) | 192 | if (!dma_release_from_contiguous(dev, page, count)) |
| 173 | __free_pages(page, get_order(size)); | 193 | __free_pages(page, get_order(size)); |
