123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- /*
- * linux/arch/arm/mm/dma-mapping.c
- *
- * Copyright (C) 2000-2004 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * DMA uncached mapping support.
- */
- #include <linux/module.h>
- #include <linux/mm.h>
- #include <linux/gfp.h>
- #include <linux/errno.h>
- #include <linux/list.h>
- #include <linux/init.h>
- #include <linux/device.h>
- #include <linux/dma-mapping.h>
- #include <linux/dma-contiguous.h>
- #include <linux/highmem.h>
- #include <linux/memblock.h>
- #include <linux/slab.h>
- #include <linux/iommu.h>
- #include <linux/io.h>
- #include <linux/vmalloc.h>
- #include <linux/sizes.h>
- #include <asm/memory.h>
- #include <asm/highmem.h>
- #include <asm/cacheflush.h>
- #include <asm/tlbflush.h>
- #include <asm/mach/arch.h>
- #include <asm/dma-iommu.h>
- #include <asm/mach/map.h>
- #include <asm/system_info.h>
- #include <asm/dma-contiguous.h>
- #include "mm.h"
- /*
- * The DMA API is built upon the notion of "buffer ownership". A buffer
- * is either exclusively owned by the CPU (and therefore may be accessed
- * by it) or exclusively owned by the DMA device. These helper functions
- * represent the transitions between these two ownership states.
- *
- * Note, however, that on later ARMs, this notion does not work due to
- * speculative prefetches. We model our approach on the assumption that
- * the CPU does do speculative prefetches, which means we clean caches
- * before transfers and delay cache invalidation until transfer completion.
- *
- */
- static void __dma_page_cpu_to_dev(struct page *, unsigned long,
- size_t, enum dma_data_direction);
- static void __dma_page_dev_to_cpu(struct page *, unsigned long,
- size_t, enum dma_data_direction);
- /**
- * 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
- * @page: page that buffer resides in
- * @offset: offset into page for start of buffer
- * @size: size of buffer to map
- * @dir: DMA transfer direction
- *
- * Ensure that any data held in the cache is appropriately discarded
- * or written back.
- *
- * The device owns this memory once this call has completed. The CPU
- * can regain ownership by calling dma_unmap_page().
- */
- static dma_addr_t arm_dma_map_page(struct device *dev, struct page *page,
- unsigned long offset, size_t size, enum dma_data_direction dir,
- struct dma_attrs *attrs)
- {
- if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
- __dma_page_cpu_to_dev(page, offset, size, dir);
- return pfn_to_dma(dev, page_to_pfn(page)) + offset;
- }
- static dma_addr_t arm_coherent_dma_map_page(struct device *dev, struct page *page,
- unsigned long offset, size_t size, enum dma_data_direction dir,
- struct dma_attrs *attrs)
- {
- return pfn_to_dma(dev, page_to_pfn(page)) + offset;
- }
- /**
- * arm_dma_unmap_page - unmap a buffer previously mapped through dma_map_page()
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @handle: DMA address of buffer
- * @size: size of buffer (same as passed to dma_map_page)
- * @dir: DMA transfer direction (same as passed to dma_map_page)
- *
- * Unmap a page streaming mode DMA translation. The handle and size
- * must match what was provided in the previous dma_map_page() call.
- * All other usages are undefined.
- *
- * After this call, reads by the CPU to the buffer are guaranteed to see
- * whatever the device wrote there.
- */
- static void arm_dma_unmap_page(struct device *dev, dma_addr_t handle,
- size_t size, enum dma_data_direction dir,
- struct dma_attrs *attrs)
- {
- if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
- __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, handle)),
- handle & ~PAGE_MASK, size, dir);
- }
- static void arm_dma_sync_single_for_cpu(struct device *dev,
- dma_addr_t handle, size_t size, enum dma_data_direction dir)
- {
- unsigned int offset = handle & (PAGE_SIZE - 1);
- struct page *page = pfn_to_page(dma_to_pfn(dev, handle-offset));
- __dma_page_dev_to_cpu(page, offset, size, dir);
- }
- static void arm_dma_sync_single_for_device(struct device *dev,
- dma_addr_t handle, size_t size, enum dma_data_direction dir)
- {
- unsigned int offset = handle & (PAGE_SIZE - 1);
- struct page *page = pfn_to_page(dma_to_pfn(dev, handle-offset));
- __dma_page_cpu_to_dev(page, offset, size, dir);
- }
- struct dma_map_ops arm_dma_ops = {
- .alloc = arm_dma_alloc,
- .free = arm_dma_free,
- .mmap = arm_dma_mmap,
- .get_sgtable = arm_dma_get_sgtable,
- .map_page = arm_dma_map_page,
- .unmap_page = arm_dma_unmap_page,
- .map_sg = arm_dma_map_sg,
- .unmap_sg = arm_dma_unmap_sg,
- .sync_single_for_cpu = arm_dma_sync_single_for_cpu,
- .sync_single_for_device = arm_dma_sync_single_for_device,
- .sync_sg_for_cpu = arm_dma_sync_sg_for_cpu,
- .sync_sg_for_device = arm_dma_sync_sg_for_device,
- .set_dma_mask = arm_dma_set_mask,
- };
- EXPORT_SYMBOL(arm_dma_ops);
- static void *arm_coherent_dma_alloc(struct device *dev, size_t size,
- dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs);
- static void arm_coherent_dma_free(struct device *dev, size_t size, void *cpu_addr,
- dma_addr_t handle, struct dma_attrs *attrs);
- struct dma_map_ops arm_coherent_dma_ops = {
- .alloc = arm_coherent_dma_alloc,
- .free = arm_coherent_dma_free,
- .mmap = arm_dma_mmap,
- .get_sgtable = arm_dma_get_sgtable,
- .map_page = arm_coherent_dma_map_page,
- .map_sg = arm_dma_map_sg,
- .set_dma_mask = arm_dma_set_mask,
- };
- EXPORT_SYMBOL(arm_coherent_dma_ops);
- static u64 get_coherent_dma_mask(struct device *dev)
- {
- u64 mask = (u64)arm_dma_limit;
- if (dev) {
- mask = dev->coherent_dma_mask;
- /*
- * Sanity check the DMA mask - it must be non-zero, and
- * must be able to be satisfied by a DMA allocation.
- */
- if (mask == 0) {
- dev_warn(dev, "coherent DMA mask is unset\n");
- return 0;
- }
- if ((~mask) & (u64)arm_dma_limit) {
- dev_warn(dev, "coherent DMA mask %#llx is smaller "
- "than system GFP_DMA mask %#llx\n",
- mask, (u64)arm_dma_limit);
- return 0;
- }
- }
- return mask;
- }
- static void __dma_clear_buffer(struct page *page, size_t size)
- {
- void *ptr;
- /*
- * Ensure that the allocated pages are zeroed, and that any data
- * lurking in the kernel direct-mapped region is invalidated.
- */
- ptr = page_address(page);
- if (ptr) {
- memset(ptr, 0, size);
- dmac_flush_range(ptr, ptr + size);
- outer_flush_range(__pa(ptr), __pa(ptr) + size);
- }
- }
- /*
- * Allocate a DMA buffer for 'dev' of size 'size' using the
- * specified gfp mask. Note that 'size' must be page aligned.
- */
- static struct page *__dma_alloc_buffer(struct device *dev, size_t size, gfp_t gfp)
- {
- unsigned long order = get_order(size);
- struct page *page, *p, *e;
- page = alloc_pages(gfp, order);
- if (!page)
- return NULL;
- /*
- * Now split the huge page and free the excess pages
- */
- split_page(page, order);
- for (p = page + (size >> PAGE_SHIFT), e = page + (1 << order); p < e; p++)
- __free_page(p);
- __dma_clear_buffer(page, size);
- return page;
- }
- /*
- * Free a DMA buffer. 'size' must be page aligned.
- */
- static void __dma_free_buffer(struct page *page, size_t size)
- {
- struct page *e = page + (size >> PAGE_SHIFT);
- while (page < e) {
- __free_page(page);
- page++;
- }
- }
- #ifdef CONFIG_MMU
- #ifdef CONFIG_HUGETLB_PAGE
- #error ARM Coherent DMA allocator does not (yet) support huge TLB
- #endif
- static void *__alloc_from_contiguous(struct device *dev, size_t size,
- pgprot_t prot, struct page **ret_page);
- static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
- pgprot_t prot, struct page **ret_page,
- const void *caller);
- static void *
- __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
- const void *caller)
- {
- struct vm_struct *area;
- unsigned long addr;
- /*
- * DMA allocation can be mapped to user space, so lets
- * set VM_USERMAP flags too.
- */
- area = get_vm_area_caller(size, VM_ARM_DMA_CONSISTENT | VM_USERMAP,
- caller);
- if (!area)
- return NULL;
- addr = (unsigned long)area->addr;
- area->phys_addr = __pfn_to_phys(page_to_pfn(page));
- if (ioremap_page_range(addr, addr + size, area->phys_addr, prot)) {
- vunmap((void *)addr);
- return NULL;
- }
- return (void *)addr;
- }
- static void __dma_free_remap(void *cpu_addr, size_t size)
- {
- unsigned int flags = VM_ARM_DMA_CONSISTENT | VM_USERMAP;
|