void __dma_direct_free_pages(struct device *dev, size_t size, struct page *page) { unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; if (!dma_release_from_contiguous(dev, page, count)) __free_pages(page, get_order(size)); }
static int __init atomic_pool_init(void) { pgprot_t prot = __pgprot(PROT_NORMAL_NC); unsigned long nr_pages = atomic_pool_size >> PAGE_SHIFT; struct page *page; void *addr; unsigned int pool_size_order = get_order(atomic_pool_size); if (dev_get_cma_area(NULL)) page = dma_alloc_from_contiguous(NULL, nr_pages, pool_size_order, false); else page = alloc_pages(GFP_DMA32, pool_size_order); if (page) { int ret; void *page_addr = page_address(page); memset(page_addr, 0, atomic_pool_size); __dma_flush_area(page_addr, atomic_pool_size); atomic_pool = gen_pool_create(PAGE_SHIFT, -1); if (!atomic_pool) goto free_page; addr = dma_common_contiguous_remap(page, atomic_pool_size, VM_USERMAP, prot, atomic_pool_init); if (!addr) goto destroy_genpool; ret = gen_pool_add_virt(atomic_pool, (unsigned long)addr, page_to_phys(page), atomic_pool_size, -1); if (ret) goto remove_mapping; gen_pool_set_algo(atomic_pool, gen_pool_first_fit_order_align, NULL); pr_info("DMA: preallocated %zu KiB pool for atomic allocations\n", atomic_pool_size / 1024); return 0; } goto out; remove_mapping: dma_common_free_remap(addr, atomic_pool_size, VM_USERMAP); destroy_genpool: gen_pool_destroy(atomic_pool); atomic_pool = NULL; free_page: if (!dma_release_from_contiguous(NULL, page, nr_pages)) __free_pages(page, pool_size_order); out: pr_err("DMA: failed to allocate %zu KiB pool for atomic coherent allocation\n", atomic_pool_size / 1024); return -ENOMEM; }
void dma_generic_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_addr, struct dma_attrs *attrs) { unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; struct page *page = virt_to_page(vaddr); if (!dma_release_from_contiguous(dev, page, count)) free_pages((unsigned long)vaddr, get_order(size)); }
static void __dma_free(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_addr, struct dma_attrs *attrs, bool is_coherent) { unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; struct page *page = virt_to_page(vaddr); if (is_coherent == false) set_pages_wb(page, count); if (!dma_release_from_contiguous(dev, page, count)) free_pages((unsigned long)vaddr, get_order(size)); }
void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t flag, unsigned long attrs) { unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; struct page *page = NULL; /* ignore region speicifiers */ flag &= ~(__GFP_DMA | __GFP_HIGHMEM); if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) flag |= GFP_DMA; if (gfpflags_allow_blocking(flag)) page = dma_alloc_from_contiguous(dev, count, get_order(size), flag & __GFP_NOWARN); if (!page) page = alloc_pages(flag, get_order(size)); if (!page) return NULL; *handle = phys_to_dma(dev, page_to_phys(page)); if (attrs & DMA_ATTR_NO_KERNEL_MAPPING) { return page; } #ifdef CONFIG_MMU if (PageHighMem(page)) { void *p; p = dma_common_contiguous_remap(page, size, VM_MAP, pgprot_noncached(PAGE_KERNEL), __builtin_return_address(0)); if (!p) { if (!dma_release_from_contiguous(dev, page, count)) __free_pages(page, get_order(size)); } return p; } #endif BUG_ON(!platform_vaddr_cached(page_address(page))); __invalidate_dcache_range((unsigned long)page_address(page), size); return platform_vaddr_to_uncached(page_address(page)); }
struct page *__dma_direct_alloc_pages(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs) { unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; int page_order = get_order(size); struct page *page = NULL; u64 phys_mask; if (attrs & DMA_ATTR_NO_WARN) gfp |= __GFP_NOWARN; /* we always manually zero the memory once we are done: */ gfp &= ~__GFP_ZERO; gfp |= __dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask, &phys_mask); again: /* CMA can be used only in the context which permits sleeping */ if (gfpflags_allow_blocking(gfp)) { page = dma_alloc_from_contiguous(dev, count, page_order, gfp & __GFP_NOWARN); if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) { dma_release_from_contiguous(dev, page, count); page = NULL; } } if (!page) page = alloc_pages_node(dev_to_node(dev), gfp, page_order); if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) { __free_pages(page, page_order); page = NULL; if (IS_ENABLED(CONFIG_ZONE_DMA32) && phys_mask < DMA_BIT_MASK(64) && !(gfp & (GFP_DMA32 | GFP_DMA))) { gfp |= GFP_DMA32; goto again; } if (IS_ENABLED(CONFIG_ZONE_DMA) && !(gfp & GFP_DMA)) { gfp = (gfp & ~GFP_DMA32) | GFP_DMA; goto again; } } return page; }
static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle, unsigned long attrs) { unsigned long addr = (unsigned long) vaddr; unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; struct page *page = NULL; plat_unmap_dma_mem(dev, dma_handle, size, DMA_BIDIRECTIONAL); if (!(attrs & DMA_ATTR_NON_CONSISTENT) && !plat_device_is_coherent(dev)) addr = CAC_ADDR(addr); page = virt_to_page((void *) addr); if (!dma_release_from_contiguous(dev, page, count)) __free_pages(page, get_order(size)); }
void *dma_generic_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr, gfp_t flag, struct dma_attrs *attrs) { unsigned long dma_mask; struct page *page; unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; dma_addr_t addr; dma_mask = dma_alloc_coherent_mask(dev, flag); flag &= ~__GFP_ZERO; again: page = NULL; /* CMA can be used only in the context which permits sleeping */ if (flag & __GFP_WAIT) { page = dma_alloc_from_contiguous(dev, count, get_order(size)); if (page && page_to_phys(page) + size > dma_mask) { dma_release_from_contiguous(dev, page, count); page = NULL; } } /* fallback */ if (!page) page = alloc_pages_node(dev_to_node(dev), flag, get_order(size)); if (!page) return NULL; addr = page_to_phys(page); if (addr + size > dma_mask) { __free_pages(page, get_order(size)); if (dma_mask < DMA_BIT_MASK(32) && !(flag & GFP_DMA)) { flag = (flag & ~GFP_DMA32) | GFP_DMA; goto again; } return NULL; } memset(page_address(page), 0, size); *dma_addr = addr; return page_address(page); }
void arch_dma_free(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle, unsigned long attrs) { unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; struct page *page; if (attrs & DMA_ATTR_NO_KERNEL_MAPPING) { page = vaddr; } else if (platform_vaddr_uncached(vaddr)) { page = virt_to_page(platform_vaddr_to_cached(vaddr)); } else { #ifdef CONFIG_MMU dma_common_free_remap(vaddr, size, VM_MAP); #endif page = pfn_to_page(PHYS_PFN(dma_to_phys(dev, dma_handle))); } if (!dma_release_from_contiguous(dev, page, count)) __free_pages(page, get_order(size)); }
void cma_free_phys(u32 phys_addr, size_t size) { struct page *pages; size_t count; if (unlikely(phys_addr < mem_start || phys_addr > mem_start + mem_size)) { pr_err("%s(%d) err: phys_addr 0x%x invalid!\n", __func__, __LINE__, phys_addr); return; } // BUG_ON(unlikely(!pfn_valid(__phys_to_pfn(phys_addr)))); size = PAGE_ALIGN(size); count = size >> PAGE_SHIFT; pages = phys_to_page((u32)phys_addr); if (!dma_release_from_contiguous(NULL, pages, count)) { pr_err("%s(%d) err: dma_release_from_contiguous failed!\n", __func__, __LINE__); return; } }
static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle, struct dma_attrs *attrs) { unsigned long addr = (unsigned long) vaddr; int order = get_order(size); unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; struct page *page = NULL; if (dma_release_from_coherent(dev, order, vaddr)) return; plat_unmap_dma_mem(dev, dma_handle, size, DMA_BIDIRECTIONAL); if (!plat_device_is_coherent(dev) && !hw_coherentio) addr = CAC_ADDR(addr); page = virt_to_page((void *) addr); if (!dma_release_from_contiguous(dev, page, count)) __free_pages(page, get_order(size)); }
void *removed_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs) { bool no_kernel_mapping = dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs); bool skip_zeroing = dma_get_attr(DMA_ATTR_SKIP_ZEROING, attrs); unsigned long pfn; unsigned long order = get_order(size); void *addr = NULL; size = PAGE_ALIGN(size); if (!(gfp & __GFP_WAIT)) return NULL; pfn = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT, order); if (pfn) { if (no_kernel_mapping && skip_zeroing) { *handle = __pfn_to_phys(pfn); return (void *)NO_KERNEL_MAPPING_DUMMY; } addr = ioremap(__pfn_to_phys(pfn), size); if (WARN_ON(!addr)) { dma_release_from_contiguous(dev, pfn, order); } else { if (!skip_zeroing) memset_io(addr, 0, size); if (no_kernel_mapping) { iounmap(addr); addr = (void *)NO_KERNEL_MAPPING_DUMMY; } *handle = __pfn_to_phys(pfn); } } return addr; }