Loading arch/arm/mm/dma-mapping.c +75 −13 Original line number Diff line number Diff line Loading @@ -112,6 +112,21 @@ static void __dma_page_cpu_to_dev(struct page *, unsigned long, static void __dma_page_dev_to_cpu(struct page *, unsigned long, size_t, enum dma_data_direction); static void * __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot, const void *caller); static void __dma_free_remap(void *cpu_addr, size_t size); static inline pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot); static void *arm_dma_remap(struct device *dev, void *cpu_addr, dma_addr_t handle, size_t size, unsigned long attrs); static void arm_dma_unremap(struct device *dev, void *remapped_addr, size_t size); /** * arm_dma_map_page - map a portion of a page for streaming DMA * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices Loading Loading @@ -200,6 +215,8 @@ const struct dma_map_ops arm_dma_ops = { .sync_sg_for_device = arm_dma_sync_sg_for_device, .mapping_error = arm_dma_mapping_error, .dma_supported = arm_dma_supported, .remap = arm_dma_remap, .unremap = arm_dma_unremap, }; EXPORT_SYMBOL(arm_dma_ops); Loading Loading @@ -541,12 +558,28 @@ static int __dma_update_pte(pte_t *pte, pgtable_t token, unsigned long addr, return 0; } static void __dma_remap(struct page *page, size_t size, pgprot_t prot) static int __dma_clear_pte(pte_t *pte, pgtable_t token, unsigned long addr, void *data) { pte_clear(&init_mm, addr, pte); return 0; } static void __dma_remap(struct page *page, size_t size, pgprot_t prot, bool want_vaddr) { unsigned long start = (unsigned long) page_address(page); unsigned end = start + size; int (*func)(pte_t *pte, pgtable_t token, unsigned long addr, void *data); if (!want_vaddr) func = __dma_clear_pte; else func = __dma_update_pte; apply_to_page_range(&init_mm, start, size, __dma_update_pte, &prot); apply_to_page_range(&init_mm, start, size, func, &prot); mb(); /*Ensure pte's are updated */ flush_tlb_kernel_range(start, end); } Loading Loading @@ -629,9 +662,6 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size, __dma_clear_buffer(page, size, coherent_flag); if (!want_vaddr) goto out; if (PageHighMem(page)) { ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot, caller); if (!ptr) { Loading @@ -639,11 +669,10 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size, return NULL; } } else { __dma_remap(page, size, prot); __dma_remap(page, size, prot, want_vaddr); ptr = page_address(page); } out: *ret_page = page; return ptr; } Loading @@ -651,12 +680,10 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size, static void __free_from_contiguous(struct device *dev, struct page *page, void *cpu_addr, size_t size, bool want_vaddr) { if (want_vaddr) { if (PageHighMem(page)) __dma_free_remap(cpu_addr, size); else __dma_remap(page, size, PAGE_KERNEL); } __dma_remap(page, size, PAGE_KERNEL, true); dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT); } Loading Loading @@ -883,6 +910,41 @@ static int __arm_dma_mmap(struct device *dev, struct vm_area_struct *vma, return ret; } static void *arm_dma_remap(struct device *dev, void *cpu_addr, dma_addr_t handle, size_t size, unsigned long attrs) { void *ptr; struct page *page = pfn_to_page(dma_to_pfn(dev, handle)); pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL); unsigned long offset = handle & ~PAGE_MASK; size = PAGE_ALIGN(size + offset); ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot, __builtin_return_address(0)); return ptr ? ptr + offset : ptr; } static void arm_dma_unremap(struct device *dev, void *remapped_addr, size_t size) { unsigned int flags = VM_ARM_DMA_CONSISTENT | VM_USERMAP; struct vm_struct *area; size = PAGE_ALIGN(size); remapped_addr = (void *)((unsigned long)remapped_addr & PAGE_MASK); area = find_vm_area(remapped_addr); if (!area || (area->flags & flags) != flags) { WARN(1, "trying to free invalid coherent area: %p\n", remapped_addr); return; } vunmap(remapped_addr); flush_tlb_kernel_range((unsigned long)remapped_addr, (unsigned long)(remapped_addr + size)); } /* * Create userspace mapping for the DMA-coherent memory. */ Loading drivers/base/dma-mapping.c +1 −1 Original line number Diff line number Diff line Loading @@ -294,7 +294,7 @@ void *dma_common_contiguous_remap(struct page *page, size_t size, unsigned long vm_flags, pgprot_t prot, const void *caller) { int i; unsigned long i; struct page **pages; struct vm_struct *area; Loading Loading
arch/arm/mm/dma-mapping.c +75 −13 Original line number Diff line number Diff line Loading @@ -112,6 +112,21 @@ static void __dma_page_cpu_to_dev(struct page *, unsigned long, static void __dma_page_dev_to_cpu(struct page *, unsigned long, size_t, enum dma_data_direction); static void * __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot, const void *caller); static void __dma_free_remap(void *cpu_addr, size_t size); static inline pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot); static void *arm_dma_remap(struct device *dev, void *cpu_addr, dma_addr_t handle, size_t size, unsigned long attrs); static void arm_dma_unremap(struct device *dev, void *remapped_addr, size_t size); /** * arm_dma_map_page - map a portion of a page for streaming DMA * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices Loading Loading @@ -200,6 +215,8 @@ const struct dma_map_ops arm_dma_ops = { .sync_sg_for_device = arm_dma_sync_sg_for_device, .mapping_error = arm_dma_mapping_error, .dma_supported = arm_dma_supported, .remap = arm_dma_remap, .unremap = arm_dma_unremap, }; EXPORT_SYMBOL(arm_dma_ops); Loading Loading @@ -541,12 +558,28 @@ static int __dma_update_pte(pte_t *pte, pgtable_t token, unsigned long addr, return 0; } static void __dma_remap(struct page *page, size_t size, pgprot_t prot) static int __dma_clear_pte(pte_t *pte, pgtable_t token, unsigned long addr, void *data) { pte_clear(&init_mm, addr, pte); return 0; } static void __dma_remap(struct page *page, size_t size, pgprot_t prot, bool want_vaddr) { unsigned long start = (unsigned long) page_address(page); unsigned end = start + size; int (*func)(pte_t *pte, pgtable_t token, unsigned long addr, void *data); if (!want_vaddr) func = __dma_clear_pte; else func = __dma_update_pte; apply_to_page_range(&init_mm, start, size, __dma_update_pte, &prot); apply_to_page_range(&init_mm, start, size, func, &prot); mb(); /*Ensure pte's are updated */ flush_tlb_kernel_range(start, end); } Loading Loading @@ -629,9 +662,6 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size, __dma_clear_buffer(page, size, coherent_flag); if (!want_vaddr) goto out; if (PageHighMem(page)) { ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot, caller); if (!ptr) { Loading @@ -639,11 +669,10 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size, return NULL; } } else { __dma_remap(page, size, prot); __dma_remap(page, size, prot, want_vaddr); ptr = page_address(page); } out: *ret_page = page; return ptr; } Loading @@ -651,12 +680,10 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size, static void __free_from_contiguous(struct device *dev, struct page *page, void *cpu_addr, size_t size, bool want_vaddr) { if (want_vaddr) { if (PageHighMem(page)) __dma_free_remap(cpu_addr, size); else __dma_remap(page, size, PAGE_KERNEL); } __dma_remap(page, size, PAGE_KERNEL, true); dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT); } Loading Loading @@ -883,6 +910,41 @@ static int __arm_dma_mmap(struct device *dev, struct vm_area_struct *vma, return ret; } static void *arm_dma_remap(struct device *dev, void *cpu_addr, dma_addr_t handle, size_t size, unsigned long attrs) { void *ptr; struct page *page = pfn_to_page(dma_to_pfn(dev, handle)); pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL); unsigned long offset = handle & ~PAGE_MASK; size = PAGE_ALIGN(size + offset); ptr = __dma_alloc_remap(page, size, GFP_KERNEL, prot, __builtin_return_address(0)); return ptr ? ptr + offset : ptr; } static void arm_dma_unremap(struct device *dev, void *remapped_addr, size_t size) { unsigned int flags = VM_ARM_DMA_CONSISTENT | VM_USERMAP; struct vm_struct *area; size = PAGE_ALIGN(size); remapped_addr = (void *)((unsigned long)remapped_addr & PAGE_MASK); area = find_vm_area(remapped_addr); if (!area || (area->flags & flags) != flags) { WARN(1, "trying to free invalid coherent area: %p\n", remapped_addr); return; } vunmap(remapped_addr); flush_tlb_kernel_range((unsigned long)remapped_addr, (unsigned long)(remapped_addr + size)); } /* * Create userspace mapping for the DMA-coherent memory. */ Loading
drivers/base/dma-mapping.c +1 −1 Original line number Diff line number Diff line Loading @@ -294,7 +294,7 @@ void *dma_common_contiguous_remap(struct page *page, size_t size, unsigned long vm_flags, pgprot_t prot, const void *caller) { int i; unsigned long i; struct page **pages; struct vm_struct *area; Loading