Loading drivers/iommu/dma-mapping-fast.c +42 −11 Original line number Diff line number Diff line Loading @@ -31,12 +31,42 @@ static pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot, return prot; } static struct gen_pool *fast_atomic_pool __ro_after_init; static int __init fast_smmu_dma_init(void) { return dma_atomic_pool_init(); struct gen_pool *pool = __dma_atomic_pool_init(); if (!IS_ERR(pool)) { fast_atomic_pool = pool; return 0; } return PTR_ERR(pool); } arch_initcall(fast_smmu_dma_init); static bool fast_dma_in_atomic_pool(void *start, size_t size) { return __dma_in_atomic_pool(fast_atomic_pool, start, size); } static void *fast_dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags) { return __dma_alloc_from_pool(fast_atomic_pool, size, ret_page, flags); } static bool fast_dma_free_from_pool(void *start, size_t size) { return __dma_free_from_pool(fast_atomic_pool, start, size); } static phys_addr_t fast_dma_get_phys(void *addr) { return gen_pool_virt_to_phys(fast_atomic_pool, (unsigned long)addr); } static bool is_dma_coherent(struct device *dev, unsigned long attrs) { bool is_coherent; Loading Loading @@ -525,7 +555,7 @@ static void *fast_smmu_alloc_atomic(struct dma_fast_smmu_mapping *mapping, page = alloc_pages(gfp, get_order(size)); addr = page ? page_address(page) : NULL; } else addr = dma_alloc_from_pool(size, &page, gfp); addr = fast_dma_alloc_from_pool(size, &page, gfp); if (!addr) return NULL; Loading @@ -552,7 +582,7 @@ static void *fast_smmu_alloc_atomic(struct dma_fast_smmu_mapping *mapping, if (coherent) __free_pages(page, get_order(size)); else dma_free_from_pool(addr, size); fast_dma_free_from_pool(addr, size); return NULL; } Loading Loading @@ -701,7 +731,7 @@ static void fast_smmu_free(struct device *dev, size_t size, size = ALIGN(size, SZ_4K); if (dma_in_atomic_pool(vaddr, size) || !is_vmalloc_addr(vaddr)) if (fast_dma_in_atomic_pool(vaddr, size) || !is_vmalloc_addr(vaddr)) goto no_remap; area = find_vm_area(vaddr); Loading @@ -715,8 +745,8 @@ static void fast_smmu_free(struct device *dev, size_t size, av8l_fast_unmap_public(mapping->pgtbl_ops, dma_handle, size); __fast_smmu_free_iova(mapping, dma_handle, size); spin_unlock_irqrestore(&mapping->lock, flags); if (dma_in_atomic_pool(vaddr, size)) dma_free_from_pool(vaddr, size); if (fast_dma_in_atomic_pool(vaddr, size)) fast_dma_free_from_pool(vaddr, size); else if (is_vmalloc_addr(vaddr)) __fast_smmu_free_pages(pages, count); else Loading @@ -732,8 +762,8 @@ static int __vma_remap_range(struct vm_area_struct *vma, void *cpu_addr, unsigned long off = vma->vm_pgoff; unsigned long pfn; if (dma_in_atomic_pool(cpu_addr, size)) pfn = page_to_pfn(vmalloc_to_page(cpu_addr)); if (fast_dma_in_atomic_pool(cpu_addr, size)) pfn = fast_dma_get_phys(cpu_addr) >> PAGE_SHIFT; else pfn = page_to_pfn(virt_to_page(cpu_addr)); Loading @@ -759,7 +789,8 @@ static int fast_smmu_mmap_attrs(struct device *dev, struct vm_area_struct *vma, vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot, coherent); if (dma_in_atomic_pool(cpu_addr, size) || !is_vmalloc_addr(cpu_addr)) if (fast_dma_in_atomic_pool(cpu_addr, size) || !is_vmalloc_addr(cpu_addr)) return __vma_remap_range(vma, cpu_addr, size); area = find_vm_area(cpu_addr); Loading Loading @@ -793,8 +824,8 @@ static int fast_smmu_get_sgtable(struct device *dev, struct sg_table *sgt, size, GFP_KERNEL); else if (!is_vmalloc_addr(cpu_addr)) page = virt_to_page(cpu_addr); else if (dma_in_atomic_pool(cpu_addr, size)) page = vmalloc_to_page(cpu_addr); else if (fast_dma_in_atomic_pool(cpu_addr, size)) page = phys_to_page(fast_dma_get_phys(cpu_addr)); if (page) { ret = sg_alloc_table(sgt, 1, GFP_KERNEL); Loading include/linux/dma-mapping.h +6 −1 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ #include <linux/scatterlist.h> #include <linux/bug.h> #include <linux/mem_encrypt.h> #include <linux/genalloc.h> /** * List of possible attributes associated with a DMA mapping. The semantics Loading Loading @@ -675,9 +676,13 @@ void *dma_common_pages_remap(struct page **pages, size_t size, pgprot_t prot, const void *caller); void dma_common_free_remap(void *cpu_addr, size_t size); int __init dma_atomic_pool_init(void); struct gen_pool *__init __dma_atomic_pool_init(void); bool __dma_in_atomic_pool(struct gen_pool *pool, void *start, size_t size); bool dma_in_atomic_pool(void *start, size_t size); void *__dma_alloc_from_pool(struct gen_pool *pool, size_t size, struct page **ret_page, gfp_t flags); void *dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags); bool __dma_free_from_pool(struct gen_pool *pool, void *start, size_t size); bool dma_free_from_pool(void *start, size_t size); int Loading kernel/dma/remap.c +48 −19 Original line number Diff line number Diff line Loading @@ -120,11 +120,12 @@ static gfp_t dma_atomic_pool_gfp(void) return GFP_KERNEL; } int __init dma_atomic_pool_init(void) struct gen_pool *__init __dma_atomic_pool_init(void) { unsigned int pool_size_order = get_order(atomic_pool_size); unsigned long nr_pages = atomic_pool_size >> PAGE_SHIFT; struct page *page; struct gen_pool *pool; void *addr; int ret; Loading @@ -138,8 +139,8 @@ int __init dma_atomic_pool_init(void) arch_dma_prep_coherent(page, atomic_pool_size); atomic_pool = gen_pool_create(PAGE_SHIFT, -1); if (!atomic_pool) pool = gen_pool_create(PAGE_SHIFT, -1); if (!pool) goto free_page; addr = dma_common_contiguous_remap(page, atomic_pool_size, Loading @@ -148,52 +149,70 @@ int __init dma_atomic_pool_init(void) if (!addr) goto destroy_genpool; ret = gen_pool_add_virt(atomic_pool, (unsigned long)addr, ret = gen_pool_add_virt(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); gen_pool_set_algo(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; return pool; remove_mapping: dma_common_free_remap(addr, atomic_pool_size); destroy_genpool: gen_pool_destroy(atomic_pool); atomic_pool = NULL; gen_pool_destroy(pool); 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; return ERR_PTR(-ENOMEM); } static int __init dma_atomic_pool_init(void) { struct gen_pool *pool = __dma_atomic_pool_init(); if (!IS_ERR(pool)) { atomic_pool = pool; return 0; } return PTR_ERR(pool); } postcore_initcall(dma_atomic_pool_init); bool dma_in_atomic_pool(void *start, size_t size) bool __dma_in_atomic_pool(struct gen_pool *pool, void *start, size_t size) { if (unlikely(!atomic_pool)) if (unlikely(!pool)) return false; return addr_in_gen_pool(atomic_pool, (unsigned long)start, size); return addr_in_gen_pool(pool, (unsigned long)start, size); } void *dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags) bool dma_in_atomic_pool(void *start, size_t size) { return __dma_in_atomic_pool(atomic_pool, start, size); } void *__dma_alloc_from_pool(struct gen_pool *pool, size_t size, struct page **ret_page, gfp_t flags) { unsigned long val; void *ptr = NULL; if (!atomic_pool) { if (!pool) { WARN(1, "coherent pool not initialised!\n"); return NULL; } val = gen_pool_alloc(atomic_pool, size); val = gen_pool_alloc(pool, size); if (val) { phys_addr_t phys = gen_pool_virt_to_phys(atomic_pool, val); phys_addr_t phys = gen_pool_virt_to_phys(pool, val); *ret_page = pfn_to_page(__phys_to_pfn(phys)); ptr = (void *)val; Loading @@ -203,14 +222,24 @@ void *dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags) return ptr; } bool dma_free_from_pool(void *start, size_t size) void *dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags) { if (!dma_in_atomic_pool(start, size)) return __dma_alloc_from_pool(atomic_pool, size, ret_page, flags); } bool __dma_free_from_pool(struct gen_pool *pool, void *start, size_t size) { if (!__dma_in_atomic_pool(pool, start, size)) return false; gen_pool_free(atomic_pool, (unsigned long)start, size); gen_pool_free(pool, (unsigned long)start, size); return true; } bool dma_free_from_pool(void *start, size_t size) { return __dma_free_from_pool(atomic_pool, start, size); } void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flags, unsigned long attrs) { Loading Loading
drivers/iommu/dma-mapping-fast.c +42 −11 Original line number Diff line number Diff line Loading @@ -31,12 +31,42 @@ static pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot, return prot; } static struct gen_pool *fast_atomic_pool __ro_after_init; static int __init fast_smmu_dma_init(void) { return dma_atomic_pool_init(); struct gen_pool *pool = __dma_atomic_pool_init(); if (!IS_ERR(pool)) { fast_atomic_pool = pool; return 0; } return PTR_ERR(pool); } arch_initcall(fast_smmu_dma_init); static bool fast_dma_in_atomic_pool(void *start, size_t size) { return __dma_in_atomic_pool(fast_atomic_pool, start, size); } static void *fast_dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags) { return __dma_alloc_from_pool(fast_atomic_pool, size, ret_page, flags); } static bool fast_dma_free_from_pool(void *start, size_t size) { return __dma_free_from_pool(fast_atomic_pool, start, size); } static phys_addr_t fast_dma_get_phys(void *addr) { return gen_pool_virt_to_phys(fast_atomic_pool, (unsigned long)addr); } static bool is_dma_coherent(struct device *dev, unsigned long attrs) { bool is_coherent; Loading Loading @@ -525,7 +555,7 @@ static void *fast_smmu_alloc_atomic(struct dma_fast_smmu_mapping *mapping, page = alloc_pages(gfp, get_order(size)); addr = page ? page_address(page) : NULL; } else addr = dma_alloc_from_pool(size, &page, gfp); addr = fast_dma_alloc_from_pool(size, &page, gfp); if (!addr) return NULL; Loading @@ -552,7 +582,7 @@ static void *fast_smmu_alloc_atomic(struct dma_fast_smmu_mapping *mapping, if (coherent) __free_pages(page, get_order(size)); else dma_free_from_pool(addr, size); fast_dma_free_from_pool(addr, size); return NULL; } Loading Loading @@ -701,7 +731,7 @@ static void fast_smmu_free(struct device *dev, size_t size, size = ALIGN(size, SZ_4K); if (dma_in_atomic_pool(vaddr, size) || !is_vmalloc_addr(vaddr)) if (fast_dma_in_atomic_pool(vaddr, size) || !is_vmalloc_addr(vaddr)) goto no_remap; area = find_vm_area(vaddr); Loading @@ -715,8 +745,8 @@ static void fast_smmu_free(struct device *dev, size_t size, av8l_fast_unmap_public(mapping->pgtbl_ops, dma_handle, size); __fast_smmu_free_iova(mapping, dma_handle, size); spin_unlock_irqrestore(&mapping->lock, flags); if (dma_in_atomic_pool(vaddr, size)) dma_free_from_pool(vaddr, size); if (fast_dma_in_atomic_pool(vaddr, size)) fast_dma_free_from_pool(vaddr, size); else if (is_vmalloc_addr(vaddr)) __fast_smmu_free_pages(pages, count); else Loading @@ -732,8 +762,8 @@ static int __vma_remap_range(struct vm_area_struct *vma, void *cpu_addr, unsigned long off = vma->vm_pgoff; unsigned long pfn; if (dma_in_atomic_pool(cpu_addr, size)) pfn = page_to_pfn(vmalloc_to_page(cpu_addr)); if (fast_dma_in_atomic_pool(cpu_addr, size)) pfn = fast_dma_get_phys(cpu_addr) >> PAGE_SHIFT; else pfn = page_to_pfn(virt_to_page(cpu_addr)); Loading @@ -759,7 +789,8 @@ static int fast_smmu_mmap_attrs(struct device *dev, struct vm_area_struct *vma, vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot, coherent); if (dma_in_atomic_pool(cpu_addr, size) || !is_vmalloc_addr(cpu_addr)) if (fast_dma_in_atomic_pool(cpu_addr, size) || !is_vmalloc_addr(cpu_addr)) return __vma_remap_range(vma, cpu_addr, size); area = find_vm_area(cpu_addr); Loading Loading @@ -793,8 +824,8 @@ static int fast_smmu_get_sgtable(struct device *dev, struct sg_table *sgt, size, GFP_KERNEL); else if (!is_vmalloc_addr(cpu_addr)) page = virt_to_page(cpu_addr); else if (dma_in_atomic_pool(cpu_addr, size)) page = vmalloc_to_page(cpu_addr); else if (fast_dma_in_atomic_pool(cpu_addr, size)) page = phys_to_page(fast_dma_get_phys(cpu_addr)); if (page) { ret = sg_alloc_table(sgt, 1, GFP_KERNEL); Loading
include/linux/dma-mapping.h +6 −1 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ #include <linux/scatterlist.h> #include <linux/bug.h> #include <linux/mem_encrypt.h> #include <linux/genalloc.h> /** * List of possible attributes associated with a DMA mapping. The semantics Loading Loading @@ -675,9 +676,13 @@ void *dma_common_pages_remap(struct page **pages, size_t size, pgprot_t prot, const void *caller); void dma_common_free_remap(void *cpu_addr, size_t size); int __init dma_atomic_pool_init(void); struct gen_pool *__init __dma_atomic_pool_init(void); bool __dma_in_atomic_pool(struct gen_pool *pool, void *start, size_t size); bool dma_in_atomic_pool(void *start, size_t size); void *__dma_alloc_from_pool(struct gen_pool *pool, size_t size, struct page **ret_page, gfp_t flags); void *dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags); bool __dma_free_from_pool(struct gen_pool *pool, void *start, size_t size); bool dma_free_from_pool(void *start, size_t size); int Loading
kernel/dma/remap.c +48 −19 Original line number Diff line number Diff line Loading @@ -120,11 +120,12 @@ static gfp_t dma_atomic_pool_gfp(void) return GFP_KERNEL; } int __init dma_atomic_pool_init(void) struct gen_pool *__init __dma_atomic_pool_init(void) { unsigned int pool_size_order = get_order(atomic_pool_size); unsigned long nr_pages = atomic_pool_size >> PAGE_SHIFT; struct page *page; struct gen_pool *pool; void *addr; int ret; Loading @@ -138,8 +139,8 @@ int __init dma_atomic_pool_init(void) arch_dma_prep_coherent(page, atomic_pool_size); atomic_pool = gen_pool_create(PAGE_SHIFT, -1); if (!atomic_pool) pool = gen_pool_create(PAGE_SHIFT, -1); if (!pool) goto free_page; addr = dma_common_contiguous_remap(page, atomic_pool_size, Loading @@ -148,52 +149,70 @@ int __init dma_atomic_pool_init(void) if (!addr) goto destroy_genpool; ret = gen_pool_add_virt(atomic_pool, (unsigned long)addr, ret = gen_pool_add_virt(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); gen_pool_set_algo(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; return pool; remove_mapping: dma_common_free_remap(addr, atomic_pool_size); destroy_genpool: gen_pool_destroy(atomic_pool); atomic_pool = NULL; gen_pool_destroy(pool); 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; return ERR_PTR(-ENOMEM); } static int __init dma_atomic_pool_init(void) { struct gen_pool *pool = __dma_atomic_pool_init(); if (!IS_ERR(pool)) { atomic_pool = pool; return 0; } return PTR_ERR(pool); } postcore_initcall(dma_atomic_pool_init); bool dma_in_atomic_pool(void *start, size_t size) bool __dma_in_atomic_pool(struct gen_pool *pool, void *start, size_t size) { if (unlikely(!atomic_pool)) if (unlikely(!pool)) return false; return addr_in_gen_pool(atomic_pool, (unsigned long)start, size); return addr_in_gen_pool(pool, (unsigned long)start, size); } void *dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags) bool dma_in_atomic_pool(void *start, size_t size) { return __dma_in_atomic_pool(atomic_pool, start, size); } void *__dma_alloc_from_pool(struct gen_pool *pool, size_t size, struct page **ret_page, gfp_t flags) { unsigned long val; void *ptr = NULL; if (!atomic_pool) { if (!pool) { WARN(1, "coherent pool not initialised!\n"); return NULL; } val = gen_pool_alloc(atomic_pool, size); val = gen_pool_alloc(pool, size); if (val) { phys_addr_t phys = gen_pool_virt_to_phys(atomic_pool, val); phys_addr_t phys = gen_pool_virt_to_phys(pool, val); *ret_page = pfn_to_page(__phys_to_pfn(phys)); ptr = (void *)val; Loading @@ -203,14 +222,24 @@ void *dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags) return ptr; } bool dma_free_from_pool(void *start, size_t size) void *dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags) { if (!dma_in_atomic_pool(start, size)) return __dma_alloc_from_pool(atomic_pool, size, ret_page, flags); } bool __dma_free_from_pool(struct gen_pool *pool, void *start, size_t size) { if (!__dma_in_atomic_pool(pool, start, size)) return false; gen_pool_free(atomic_pool, (unsigned long)start, size); gen_pool_free(pool, (unsigned long)start, size); return true; } bool dma_free_from_pool(void *start, size_t size) { return __dma_free_from_pool(atomic_pool, start, size); } void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flags, unsigned long attrs) { Loading