diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-17 12:54:05 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-17 12:54:05 -0500 |
| commit | 0ea90b9e79cff66934119e6dd8fa8e9d0f7d005a (patch) | |
| tree | 33126618be3e6d8d0382a48f55b99fc2cb1c539c | |
| parent | 5f5425ef55b3fd2d395fb917edde3e6ae438c29a (diff) | |
| parent | 3a8e3265179b7e6394d7aab4d6df5651b49e7243 (diff) | |
Merge tag 'microblaze-3.19-rc1' of git://git.monstr.eu/linux-2.6-microblaze
Pull Microblaze fix from Michal Simek:
"Fix mmap for cache coherent memory"
* tag 'microblaze-3.19-rc1' of git://git.monstr.eu/linux-2.6-microblaze:
microblaze: Fix mmap for cache coherent memory
| -rw-r--r-- | arch/microblaze/include/asm/pgtable.h | 1 | ||||
| -rw-r--r-- | arch/microblaze/kernel/dma.c | 27 | ||||
| -rw-r--r-- | arch/microblaze/mm/consistent.c | 25 |
3 files changed, 48 insertions, 5 deletions
diff --git a/arch/microblaze/include/asm/pgtable.h b/arch/microblaze/include/asm/pgtable.h index 95cef0b5f836..df19d0c47be8 100644 --- a/arch/microblaze/include/asm/pgtable.h +++ b/arch/microblaze/include/asm/pgtable.h | |||
| @@ -565,6 +565,7 @@ void consistent_free(size_t size, void *vaddr); | |||
| 565 | void consistent_sync(void *vaddr, size_t size, int direction); | 565 | void consistent_sync(void *vaddr, size_t size, int direction); |
| 566 | void consistent_sync_page(struct page *page, unsigned long offset, | 566 | void consistent_sync_page(struct page *page, unsigned long offset, |
| 567 | size_t size, int direction); | 567 | size_t size, int direction); |
| 568 | unsigned long consistent_virt_to_pfn(void *vaddr); | ||
| 568 | 569 | ||
| 569 | void setup_memory(void); | 570 | void setup_memory(void); |
| 570 | #endif /* __ASSEMBLY__ */ | 571 | #endif /* __ASSEMBLY__ */ |
diff --git a/arch/microblaze/kernel/dma.c b/arch/microblaze/kernel/dma.c index 4633c36c1b32..ed7ba8a11822 100644 --- a/arch/microblaze/kernel/dma.c +++ b/arch/microblaze/kernel/dma.c | |||
| @@ -154,9 +154,36 @@ dma_direct_sync_sg_for_device(struct device *dev, | |||
| 154 | __dma_sync(sg->dma_address, sg->length, direction); | 154 | __dma_sync(sg->dma_address, sg->length, direction); |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | int dma_direct_mmap_coherent(struct device *dev, struct vm_area_struct *vma, | ||
| 158 | void *cpu_addr, dma_addr_t handle, size_t size, | ||
| 159 | struct dma_attrs *attrs) | ||
| 160 | { | ||
| 161 | #ifdef CONFIG_MMU | ||
| 162 | unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; | ||
| 163 | unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; | ||
| 164 | unsigned long off = vma->vm_pgoff; | ||
| 165 | unsigned long pfn; | ||
| 166 | |||
| 167 | if (off >= count || user_count > (count - off)) | ||
| 168 | return -ENXIO; | ||
| 169 | |||
| 170 | #ifdef NOT_COHERENT_CACHE | ||
| 171 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
| 172 | pfn = consistent_virt_to_pfn(cpu_addr); | ||
| 173 | #else | ||
| 174 | pfn = virt_to_pfn(cpu_addr); | ||
| 175 | #endif | ||
| 176 | return remap_pfn_range(vma, vma->vm_start, pfn + off, | ||
| 177 | vma->vm_end - vma->vm_start, vma->vm_page_prot); | ||
| 178 | #else | ||
| 179 | return -ENXIO; | ||
| 180 | #endif | ||
| 181 | } | ||
| 182 | |||
| 157 | struct dma_map_ops dma_direct_ops = { | 183 | struct dma_map_ops dma_direct_ops = { |
| 158 | .alloc = dma_direct_alloc_coherent, | 184 | .alloc = dma_direct_alloc_coherent, |
| 159 | .free = dma_direct_free_coherent, | 185 | .free = dma_direct_free_coherent, |
| 186 | .mmap = dma_direct_mmap_coherent, | ||
| 160 | .map_sg = dma_direct_map_sg, | 187 | .map_sg = dma_direct_map_sg, |
| 161 | .dma_supported = dma_direct_dma_supported, | 188 | .dma_supported = dma_direct_dma_supported, |
| 162 | .map_page = dma_direct_map_page, | 189 | .map_page = dma_direct_map_page, |
diff --git a/arch/microblaze/mm/consistent.c b/arch/microblaze/mm/consistent.c index e10ad930895e..b06c3a7faf20 100644 --- a/arch/microblaze/mm/consistent.c +++ b/arch/microblaze/mm/consistent.c | |||
| @@ -156,6 +156,25 @@ void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *dma_handle) | |||
| 156 | } | 156 | } |
| 157 | EXPORT_SYMBOL(consistent_alloc); | 157 | EXPORT_SYMBOL(consistent_alloc); |
| 158 | 158 | ||
| 159 | #ifdef CONFIG_MMU | ||
| 160 | static pte_t *consistent_virt_to_pte(void *vaddr) | ||
| 161 | { | ||
| 162 | unsigned long addr = (unsigned long)vaddr; | ||
| 163 | |||
| 164 | return pte_offset_kernel(pmd_offset(pgd_offset_k(addr), addr), addr); | ||
| 165 | } | ||
| 166 | |||
| 167 | unsigned long consistent_virt_to_pfn(void *vaddr) | ||
| 168 | { | ||
| 169 | pte_t *ptep = consistent_virt_to_pte(vaddr); | ||
| 170 | |||
| 171 | if (pte_none(*ptep) || !pte_present(*ptep)) | ||
| 172 | return 0; | ||
| 173 | |||
| 174 | return pte_pfn(*ptep); | ||
| 175 | } | ||
| 176 | #endif | ||
| 177 | |||
| 159 | /* | 178 | /* |
| 160 | * free page(s) as defined by the above mapping. | 179 | * free page(s) as defined by the above mapping. |
| 161 | */ | 180 | */ |
| @@ -181,13 +200,9 @@ void consistent_free(size_t size, void *vaddr) | |||
| 181 | } while (size -= PAGE_SIZE); | 200 | } while (size -= PAGE_SIZE); |
| 182 | #else | 201 | #else |
| 183 | do { | 202 | do { |
| 184 | pte_t *ptep; | 203 | pte_t *ptep = consistent_virt_to_pte(vaddr); |
| 185 | unsigned long pfn; | 204 | unsigned long pfn; |
| 186 | 205 | ||
| 187 | ptep = pte_offset_kernel(pmd_offset(pgd_offset_k( | ||
| 188 | (unsigned int)vaddr), | ||
| 189 | (unsigned int)vaddr), | ||
| 190 | (unsigned int)vaddr); | ||
| 191 | if (!pte_none(*ptep) && pte_present(*ptep)) { | 206 | if (!pte_none(*ptep) && pte_present(*ptep)) { |
| 192 | pfn = pte_pfn(*ptep); | 207 | pfn = pte_pfn(*ptep); |
| 193 | pte_clear(&init_mm, (unsigned int)vaddr, ptep); | 208 | pte_clear(&init_mm, (unsigned int)vaddr, ptep); |
