aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/xtensa/kernel/pci-dma.c40
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,
161static void xtensa_dma_free(struct device *dev, size_t size, void *vaddr, 174static 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));