Release 4.14 arch/arm64/mm/dma-mapping.c
/*
* SWIOTLB-based DMA API implementation
*
* Copyright (C) 2012 ARM Ltd.
* Author: Catalin Marinas <catalin.marinas@arm.com>
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/gfp.h>
#include <linux/acpi.h>
#include <linux/bootmem.h>
#include <linux/cache.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/genalloc.h>
#include <linux/dma-mapping.h>
#include <linux/dma-contiguous.h>
#include <linux/vmalloc.h>
#include <linux/swiotlb.h>
#include <linux/pci.h>
#include <asm/cacheflush.h>
static int swiotlb __ro_after_init;
static pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot,
bool coherent)
{
if (!coherent || (attrs & DMA_ATTR_WRITE_COMBINE))
return pgprot_writecombine(prot);
return prot;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Laura Abbott | 27 | 75.00% | 1 | 33.33% |
Krzysztof Kozlowski | 6 | 16.67% | 1 | 33.33% |
Catalin Marinas | 3 | 8.33% | 1 | 33.33% |
Total | 36 | 100.00% | 3 | 100.00% |
static struct gen_pool *atomic_pool __ro_after_init;
#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K
static size_t atomic_pool_size __initdata = DEFAULT_DMA_COHERENT_POOL_SIZE;
static int __init early_coherent_pool(char *p)
{
atomic_pool_size = memparse(p, &p);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Laura Abbott | 24 | 100.00% | 1 | 100.00% |
Total | 24 | 100.00% | 1 | 100.00% |
early_param("coherent_pool", early_coherent_pool);
static void *__alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags)
{
unsigned long val;
void *ptr = NULL;
if (!atomic_pool) {
WARN(1, "coherent pool not initialised!\n");
return NULL;
}
val = gen_pool_alloc(atomic_pool, size);
if (val) {
phys_addr_t phys = gen_pool_virt_to_phys(atomic_pool, val);
*ret_page = phys_to_page(phys);
ptr = (void *)val;
memset(ptr, 0, size);
}
return ptr;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Laura Abbott | 87 | 87.88% | 1 | 50.00% |
Suzuki K. Poulose | 12 | 12.12% | 1 | 50.00% |
Total | 99 | 100.00% | 2 | 100.00% |
static bool __in_atomic_pool(void *start, size_t size)
{
return addr_in_gen_pool(atomic_pool, (unsigned long)start, size);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Laura Abbott | 27 | 100.00% | 1 | 100.00% |
Total | 27 | 100.00% | 1 | 100.00% |
static int __free_from_pool(void *start, size_t size)
{
if (!__in_atomic_pool(start, size))
return 0;
gen_pool_free(atomic_pool, (unsigned long)start, size);
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Laura Abbott | 42 | 100.00% | 1 | 100.00% |
Total | 42 | 100.00% | 1 | 100.00% |
static void *__dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flags,
unsigned long attrs)
{
if (IS_ENABLED(CONFIG_ZONE_DMA) &&
dev->coherent_dma_mask <= DMA_BIT_MASK(32))
flags |= GFP_DMA;
if (dev_get_cma_area(dev) && gfpflags_allow_blocking(flags)) {
struct page *page;
void *addr;
page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT,
get_order(size), flags);
if (!page)
return NULL;
*dma_handle = phys_to_dma(dev, page_to_phys(page));
addr = page_address(page);
memset(addr, 0, size);
return addr;
} else {
return swiotlb_alloc_coherent(dev, size, dma_handle, flags);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Laura Abbott | 59 | 41.55% | 2 | 20.00% |
Catalin Marinas | 55 | 38.73% | 2 | 20.00% |
Suzuki K. Poulose | 18 | 12.68% | 1 | 10.00% |
Mel Gorman | 3 | 2.11% | 1 | 10.00% |
Krzysztof Kozlowski | 2 | 1.41% | 1 | 10.00% |
Lucas Stach | 2 | 1.41% | 1 | 10.00% |
JiSheng Zhang | 2 | 1.41% | 1 | 10.00% |
Ritesh Harjani | 1 | 0.70% | 1 | 10.00% |
Total | 142 | 100.00% | 10 | 100.00% |
static void __dma_free_coherent(struct device *dev, size_t size,
void *vaddr, dma_addr_t dma_handle,
unsigned long attrs)
{
bool freed;
phys_addr_t paddr = dma_to_phys(dev, dma_handle);
freed = dma_release_from_contiguous(dev,
phys_to_page(paddr),
size >> PAGE_SHIFT);
if (!freed)
swiotlb_free_coherent(dev, size, vaddr, dma_handle);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Laura Abbott | 34 | 48.57% | 2 | 40.00% |
Catalin Marinas | 33 | 47.14% | 1 | 20.00% |
Krzysztof Kozlowski | 2 | 2.86% | 1 | 20.00% |
Ritesh Harjani | 1 | 1.43% | 1 | 20.00% |
Total | 70 | 100.00% | 5 | 100.00% |
static void *__dma_alloc(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flags,
unsigned long attrs)
{
struct page *page;
void *ptr, *coherent_ptr;
bool coherent = is_device_dma_coherent(dev);
pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL, false);
size = PAGE_ALIGN(size);
if (!coherent && !gfpflags_allow_blocking(flags)) {
struct page *page = NULL;
void *addr = __alloc_from_pool(size, &page, flags);
if (addr)
*dma_handle = phys_to_dma(dev, page_to_phys(page));
return addr;
}
ptr = __dma_alloc_coherent(dev, size, dma_handle, flags, attrs);
if (!ptr)
goto no_mem;
/* no need for non-cacheable mapping if coherent */
if (coherent)
return ptr;
/* remove any dirty cache lines on the kernel alias */
__dma_flush_area(ptr, size);
/* create a coherent mapping */
page = virt_to_page(ptr);
coherent_ptr = dma_common_contiguous_remap(page, size, VM_USERMAP,
prot, NULL);
if (!coherent_ptr)
goto no_map;
return coherent_ptr;
no_map:
__dma_free_coherent(dev, size, ptr, *dma_handle, attrs);
no_mem:
return NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Catalin Marinas | 140 | 65.73% | 2 | 25.00% |
Laura Abbott | 52 | 24.41% | 1 | 12.50% |
Robin Murphy | 13 | 6.10% | 1 | 12.50% |
Mel Gorman | 3 | 1.41% | 1 | 12.50% |
Suzuki K. Poulose | 2 | 0.94% | 1 | 12.50% |
Krzysztof Kozlowski | 2 | 0.94% | 1 | 12.50% |
Kwangwoo Lee | 1 | 0.47% | 1 | 12.50% |
Total | 213 | 100.00% | 8 | 100.00% |
static void __dma_free(struct device *dev, size_t size,
void *vaddr, dma_addr_t dma_handle,
unsigned long attrs)
{
void *swiotlb_addr = phys_to_virt(dma_to_phys(dev, dma_handle));
size = PAGE_ALIGN(size);
if (!is_device_dma_coherent(dev)) {
if (__free_from_pool(vaddr, size))
return;
vunmap(vaddr);
}
__dma_free_coherent(dev, size, swiotlb_addr, dma_handle, attrs);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Catalin Marinas | 65 | 77.38% | 2 | 40.00% |
Laura Abbott | 10 | 11.90% | 1 | 20.00% |
Dean Nelson | 7 | 8.33% | 1 | 20.00% |
Krzysztof Kozlowski | 2 | 2.38% | 1 | 20.00% |
Total | 84 | 100.00% | 5 | 100.00% |
static dma_addr_t __swiotlb_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size,
enum dma_data_direction dir,
unsigned long attrs)
{
dma_addr_t dev_addr;
dev_addr = swiotlb_map_page(dev, page, offset, size, dir, attrs);
if (!is_device_dma_coherent(dev) &&
(attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
__dma_map_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir);
return dev_addr;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Catalin Marinas | 77 | 88.51% | 2 | 50.00% |
Takeshi Kihara | 8 | 9.20% | 1 | 25.00% |
Krzysztof Kozlowski | 2 | 2.30% | 1 | 25.00% |
Total | 87 | 100.00% | 4 | 100.00% |
static void __swiotlb_unmap_page(struct device *dev, dma_addr_t dev_addr,
size_t size, enum dma_data_direction dir,
unsigned long attrs)
{
if (!is_device_dma_coherent(dev) &&
(attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
__dma_unmap_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir);
swiotlb_unmap_page(dev, dev_addr, size, dir, attrs);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Catalin Marinas | 61 | 85.92% | 2 | 50.00% |
Takeshi Kihara | 8 | 11.27% | 1 | 25.00% |
Krzysztof Kozlowski | 2 | 2.82% | 1 | 25.00% |
Total | 71 | 100.00% | 4 | 100.00% |
static int __swiotlb_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
int nelems, enum dma_data_direction dir,
unsigned long attrs)
{
struct scatterlist *sg;
int i, ret;
ret = swiotlb_map_sg_attrs(dev, sgl, nelems, dir, attrs);
if (!is_device_dma_coherent(dev) &&
(attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
for_each_sg(sgl, sg, ret, i)
__dma_map_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)),
sg->length, dir);
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Catalin Marinas | 92 | 90.20% | 2 | 50.00% |
Takeshi Kihara | 8 | 7.84% | 1 | 25.00% |
Krzysztof Kozlowski | 2 | 1.96% | 1 | 25.00% |
Total | 102 | 100.00% | 4 | 100.00% |
static void __swiotlb_unmap_sg_attrs(struct device *dev,
struct scatterlist *sgl, int nelems,
enum dma_data_direction dir,
unsigned long attrs)
{
struct scatterlist *sg;
int i;
if (!is_device_dma_coherent(dev) &&
(attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
for_each_sg(sgl, sg, nelems, i)
__dma_unmap_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)),
sg->length, dir);
swiotlb_unmap_sg_attrs(dev, sgl, nelems, dir, attrs);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Catalin Marinas | 85 | 89.47% | 2 | 50.00% |
Takeshi Kihara | 8 | 8.42% | 1 | 25.00% |
Krzysztof Kozlowski | 2 | 2.11% | 1 | 25.00% |
Total | 95 | 100.00% | 4 | 100.00% |
static void __swiotlb_sync_single_for_cpu(struct device *dev,
dma_addr_t dev_addr, size_t size,
enum dma_data_direction dir)
{
if (!is_device_dma_coherent(dev))
__dma_unmap_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir);
swiotlb_sync_single_for_cpu(dev, dev_addr, size, dir);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Catalin Marinas | 57 | 100.00% | 2 | 100.00% |
Total | 57 | 100.00% | 2 | 100.00% |
static void __swiotlb_sync_single_for_device(struct device *dev,
dma_addr_t dev_addr, size_t size,
enum dma_data_direction dir)
{
swiotlb_sync_single_for_device(dev, dev_addr, size, dir);
if (!is_device_dma_coherent(dev))
__dma_map_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Catalin Marinas | 57 | 100.00% | 2 | 100.00% |
Total | 57 | 100.00% | 2 | 100.00% |
static void __swiotlb_sync_sg_for_cpu(struct device *dev,
struct scatterlist *sgl, int nelems,
enum dma_data_direction dir)
{
struct scatterlist *sg;
int i;
if (!is_device_dma_coherent(dev))
for_each_sg(sgl, sg, nelems, i)
__dma_unmap_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)),
sg->length, dir);
swiotlb_sync_sg_for_cpu(dev, sgl, nelems, dir);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Catalin Marinas | 81 | 100.00% | 2 | 100.00% |
Total | 81 | 100.00% | 2 | 100.00% |
static void __swiotlb_sync_sg_for_device(struct device *dev,
struct scatterlist *sgl, int nelems,
enum dma_data_direction dir)
{
struct scatterlist *sg;
int i;
swiotlb_sync_sg_for_device(dev, sgl, nelems, dir);
if (!is_device_dma_coherent(dev))
for_each_sg(sgl, sg, nelems, i)
__dma_map_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)),
sg->length, dir);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Catalin Marinas | 81 | 100.00% | 2 | 100.00% |
Total | 81 | 100.00% | 2 | 100.00% |
static int __swiotlb_mmap_pfn(struct vm_area_struct *vma,
unsigned long pfn, size_t size)
{
int ret = -ENXIO;
unsigned long nr_vma_pages = (vma->vm_end - vma->vm_start) >>
PAGE_SHIFT;
unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
unsigned long off = vma->vm_pgoff;
if (off < nr_pages && nr_vma_pages <= (nr_pages - off)) {
ret = remap_pfn_range(vma, vma->vm_start,
pfn + off,
vma->vm_end - vma->vm_start,
vma->vm_page_prot);
}
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Laura Abbott | 101 | 96.19% | 1 | 50.00% |
Catalin Marinas | 4 | 3.81% | 1 | 50.00% |
Total | 105 | 100.00% | 2 | 100.00% |
static int __swiotlb_mmap(struct device *dev,
struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size,
unsigned long attrs)
{
int ret;
unsigned long pfn = dma_to_phys(dev, dma_addr) >> PAGE_SHIFT;
vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot,
is_device_dma_coherent(dev));
if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
return ret;
return __swiotlb_mmap_pfn(vma, pfn, size);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Catalin Marinas | 65 | 69.89% | 1 | 25.00% |
Robin Murphy | 25 | 26.88% | 1 | 25.00% |
Krzysztof Kozlowski | 2 | 2.15% | 1 | 25.00% |
Vladimir Murzin | 1 | 1.08% | 1 | 25.00% |
Total | 93 | 100.00% | 4 | 100.00% |
static int __swiotlb_get_sgtable_page(struct sg_table *sgt,
struct page *page, size_t size)
{
int ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
if (!ret)
sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Catalin Marinas | 34 | 61.82% | 1 | 50.00% |
Robin Murphy | 21 | 38.18% | 1 | 50.00% |
Total | 55 | 100.00% | 2 | 100.00% |
static int __swiotlb_get_sgtable(struct device *dev, struct sg_table *sgt,
void *cpu_addr, dma_addr_t handle, size_t size,
unsigned long attrs)
{
struct page *page = phys_to_page(dma_to_phys(dev, handle));
return __swiotlb_get_sgtable_page(sgt, page, size);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Catalin Marinas | 41 | 74.55% | 1 | 50.00% |
Robin Murphy | 14 | 25.45% | 1 | 50.00% |
Total | 55 | 100.00% | 2 | 100.00% |
static int __swiotlb_dma_supported(struct device *hwdev, u64 mask)
{
if (swiotlb)
return swiotlb_dma_supported(hwdev, mask);
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
JiSheng Zhang | 29 | 100.00% | 1 | 100.00% |
Total | 29 | 100.00% | 1 | 100.00% |
static int __swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t addr)
{
if (swiotlb)
return swiotlb_dma_mapping_error(hwdev, addr);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robin Murphy | 29 | 100.00% | 1 | 100.00% |
Total | 29 | 100.00% | 1 | 100.00% |
static const struct dma_map_ops swiotlb_dma_ops = {
.alloc = __dma_alloc,
.free = __dma_free,
.mmap = __swiotlb_mmap,
.get_sgtable = __swiotlb_get_sgtable,
.map_page = __swiotlb_map_page,
.unmap_page = __swiotlb_unmap_page,
.map_sg = __swiotlb_map_sg_attrs,
.unmap_sg = __swiotlb_unmap_sg_attrs,
.sync_single_for_cpu = __swiotlb_sync_single_for_cpu,
.sync_single_for_device = __swiotlb_sync_single_for_device,
.sync_sg_for_cpu = __swiotlb_sync_sg_for_cpu,
.sync_sg_for_device = __swiotlb_sync_sg_for_device,
.dma_supported = __swiotlb_dma_supported,
.mapping_error = __swiotlb_dma_mapping_error,
};
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, GFP_KERNEL);
else
page = alloc_pages(GFP_DMA, 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;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Laura Abbott | 256 | 98.46% | 1 | 25.00% |
Lucas Stach | 2 | 0.77% | 1 | 25.00% |
Kwangwoo Lee | 1 | 0.38% | 1 | 25.00% |
Vladimir Murzin | 1 | 0.38% | 1 | 25.00% |
Total | 260 | 100.00% | 4 | 100.00% |
/********************************************
* The following APIs are for dummy DMA ops *
********************************************/
static void *__dummy_alloc(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flags,
unsigned long attrs)
{
return NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Suravee Suthikulpanit | 27 | 93.10% | 1 | 50.00% |
Krzysztof Kozlowski | 2 | 6.90% | 1 | 50.00% |
Total | 29 | 100.00% | 2 | 100.00% |
static void __dummy_free(struct device *dev, size_t size,
void *vaddr, dma_addr_t dma_handle,
unsigned long attrs)
{
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Suravee Suthikulpanit | 22 | 91.67% | 1 | 50.00% |
Krzysztof Kozlowski | 2 | 8.33% | 1 | 50.00% |
Total | 24 | 100.00% | 2 | 100.00% |
static int __dummy_mmap(struct device *dev,
struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size,
unsigned long attrs)
{
return -ENXIO;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Suravee Suthikulpanit | 32 | 94.12% | 1 | 50.00% |
Krzysztof Kozlowski | 2 | 5.88% | 1 | 50.00% |
Total | 34 | 100.00% | 2 | 100.00% |
static dma_addr_t __dummy_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size,
enum dma_data_direction dir,
unsigned long attrs)
{
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Suravee Suthikulpanit | 31 | 91.18% | 1 | 33.33% |
Krzysztof Kozlowski | 2 | 5.88% | 1 | 33.33% |
Christoph Hellwig | 1 | 2.94% | 1 | 33.33% |
Total | 34 | 100.00% | 3 | 100.00% |
static void __dummy_unmap_page(struct device *dev, dma_addr_t dev_addr,
size_t size, enum dma_data_direction dir,
unsigned long attrs)
{
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Suravee Suthikulpanit | 22 | 91.67% | 1 | 50.00% |
Krzysztof Kozlowski | 2 | 8.33% | 1 | 50.00% |
Total | 24 | 100.00% | 2 | 100.00% |
static int __dummy_map_sg(struct device *dev, struct scatterlist *sgl,
int nelems, enum dma_data_direction dir,
unsigned long attrs)
{
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Suravee Suthikulpanit | 28 | 93.33% | 1 | 50.00% |
Krzysztof Kozlowski | 2 | 6.67% | 1 | 50.00% |
Total | 30 | 100.00% | 2 | 100.00% |
static void __dummy_unmap_sg(struct device *dev,
struct scatterlist *sgl, int nelems,
enum dma_data_direction dir,
unsigned long attrs)
{
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Suravee Suthikulpanit | 24 | 92.31% | 1 | 50.00% |
Krzysztof Kozlowski | 2 | 7.69% | 1 | 50.00% |
Total | 26 | 100.00% | 2 | 100.00% |
static void __dummy_sync_single(struct device *dev,
dma_addr_t dev_addr, size_t size,
enum dma_data_direction dir)
{
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Suravee Suthikulpanit | 20 | 100.00% | 1 | 100.00% |
Total | 20 | 100.00% | 1 | 100.00% |
static void __dummy_sync_sg(struct device *dev,
struct scatterlist *sgl, int nelems,
enum dma_data_direction dir)
{
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Suravee Suthikulpanit | 22 | 100.00% | 1 | 100.00% |
Total | 22 | 100.00% | 1 | 100.00% |
static int __dummy_mapping_error(struct device *hwdev, dma_addr_t dma_addr)
{
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Suravee Suthikulpanit | 17 | 100.00% | 1 | 100.00% |
Total | 17 | 100.00% | 1 | 100.00% |
static int __dummy_dma_supported(struct device *hwdev, u64 mask)
{
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Suravee Suthikulpanit | 17 | 100.00% | 1 | 100.00% |
Total | 17 | 100.00% | 1 | 100.00% |
const struct dma_map_ops dummy_dma_ops = {
.alloc = __dummy_alloc,
.free = __dummy_free,
.mmap = __dummy_mmap,
.map_page = __dummy_map_page,
.unmap_page = __dummy_unmap_page,
.map_sg = __dummy_map_sg,
.unmap_sg = __dummy_unmap_sg,
.sync_single_for_cpu = __dummy_sync_single,
.sync_single_for_device = __dummy_sync_single,
.sync_sg_for_cpu = __dummy_sync_sg,
.sync_sg_for_device = __dummy_sync_sg,
.mapping_error = __dummy_mapping_error,
.dma_supported = __dummy_dma_supported,
};
EXPORT_SYMBOL(dummy_dma_ops);
static int __init arm64_dma_init(void)
{
if (swiotlb_force == SWIOTLB_FORCE ||
max_pfn > (arm64_dma_phys_limit >> PAGE_SHIFT))
swiotlb = 1;
return atomic_pool_init();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
JiSheng Zhang | 16 | 51.61% | 1 | 25.00% |
Laura Abbott | 12 | 38.71% | 1 | 25.00% |
Geert Uytterhoeven | 2 | 6.45% | 1 | 25.00% |
Arnd Bergmann | 1 | 3.23% | 1 | 25.00% |
Total | 31 | 100.00% | 4 | 100.00% |
arch_initcall(arm64_dma_init);
#define PREALLOC_DMA_DEBUG_ENTRIES 4096
static int __init dma_debug_do_init(void)
{
dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Catalin Marinas | 17 | 100.00% | 1 | 100.00% |
Total | 17 | 100.00% | 1 | 100.00% |
fs_initcall(dma_debug_do_init);
#ifdef CONFIG_IOMMU_DMA
#include <linux/dma-iommu.h>
#include <linux/platform_device.h>
#include <linux/amba/bus.h>
/* Thankfully, all cache ops are by VA so we can ignore phys here */
static void flush_page(struct device *dev, const void *virt, phys_addr_t phys)
{
__dma_flush_area(virt, PAGE_SIZE);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robin Murphy | 25 | 96.15% | 1 | 50.00% |
Kwangwoo Lee | 1 | 3.85% | 1 | 50.00% |
Total | 26 | 100.00% | 2 | 100.00% |
static void *__iommu_alloc_attrs(struct device *dev, size_t size,
dma_addr_t *handle, gfp_t gfp,
unsigned long attrs)
{
bool coherent = is_device_dma_coherent(dev);
int ioprot = dma_info_to_prot(DMA_BIDIRECTIONAL, coherent, attrs);
size_t iosize = size;
void *addr;
if (WARN(!dev, "cannot create IOMMU mapping for unknown device\n"))
return NULL;
size = PAGE_ALIGN(size);
/*
* Some drivers rely on this, and we probably don't want the
* possibility of stale kernel data being read by devices anyway.
*/
gfp |= __GFP_ZERO;
if (!gfpflags_allow_blocking(gfp)) {
struct page *page;
/*
* In atomic context we can't remap anything, so we'll only
* get the virtually contiguous buffer we need by way of a
* physically contiguous allocation.
*/
if (coherent) {
page = alloc_pages(gfp, get_order(size));
addr = page ? page_address(page) : NULL;
} else {
addr = __alloc_from_pool(size, &page, gfp);
}
if (!addr)
return NULL;
*handle = iommu_dma_map_page(dev, page, 0, iosize, ioprot);
if (iommu_dma_mapping_error(dev, *handle)) {
if (coherent)
__free_pages(page, get_order(size));
else
__free_from_pool(addr, size);
addr = NULL;
}
} else if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) {
pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL, coherent);
struct page *page;
page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT,
get_order(size), gfp);
if (!page)
return NULL;
*handle = iommu_dma_map_page(dev, page, 0, iosize, ioprot);
if (iommu_dma_mapping_error(dev, *handle)) {
dma_release_from_contiguous(dev, page,
size >> PAGE_SHIFT);
return NULL;
}
if (!coherent)
__dma_flush_area(page_to_virt(page), iosize);
addr = dma_common_contiguous_remap(page, size, VM_USERMAP,
prot,
__builtin_return_address(0));
if (!addr) {
iommu_dma_unmap_page(dev, *handle, iosize, 0, attrs);
dma_release_from_contiguous(dev, page,
size >> PAGE_SHIFT);
}
} else {
pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL, coherent);
struct page **pages;
pages = iommu_dma_alloc(dev, iosize, gfp, attrs, ioprot,
handle, flush_page);
if (!pages)
return NULL;
addr = dma_common_pages_remap(pages, size, VM_USERMAP, prot,
__builtin_return_address(0));
if (!addr)
iommu_dma_free(dev, pages, iosize, handle);
}
return addr;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Geert Uytterhoeven | 231 | 51.79% | 1 | 16.67% |
Robin Murphy | 207 | 46.41% | 2 | 33.33% |
Andrew Morton | 3 | 0.67% | 1 | 16.67% |
Mitchel Humpherys | 3 | 0.67% | 1 | 16.67% |
Krzysztof Kozlowski | 2 | 0.45% | 1 | 16.67% |
Total | 446 | 100.00% | 6 | 100.00% |
static void __iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
dma_addr_t handle, unsigned long attrs)
{
size_t iosize = size;
size = PAGE_ALIGN(size);
/*
* @cpu_addr will be one of 4 things depending on how it was allocated:
* - A remapped array of pages for contiguous allocations.
* - A remapped array of pages from iommu_dma_alloc(), for all
* non-atomic allocations.
* - A non-cacheable alias from the atomic pool, for atomic
* allocations by non-coherent devices.
* - A normal lowmem address, for atomic allocations by
* coherent devices.
* Hence how dodgy the below logic looks...
*/
if (__in_atomic_pool(cpu_addr, size)) {
iommu_dma_unmap_page(dev, handle, iosize, 0, 0);
__free_from_pool(cpu_addr, size);
} else if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) {
struct page *page = vmalloc_to_page(cpu_addr);
iommu_dma_unmap_page(dev, handle, iosize, 0, attrs);
dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT);
dma_common_free_remap(cpu_addr, size, VM_USERMAP);
} else if (is_vmalloc_addr(cpu_addr)){
struct vm_struct *area = find_vm_area(cpu_addr);
if (WARN_ON(!area || !area->pages))
return;
iommu_dma_free(dev, area->pages, iosize, &handle);
dma_common_free_remap(cpu_addr, size, VM_USERMAP);
} else {
iommu_dma_unmap_page(dev, handle, iosize, 0, 0);
__free_pages(virt_to_page(cpu_addr), get_order(size));
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robin Murphy | 150 | 72.46% | 2 | 50.00% |
Geert Uytterhoeven | 53 | 25.60% | 1 | 25.00% |
Krzysztof Kozlowski | 4 | 1.93% | 1 | 25.00% |
Total | 207 | 100.00% | 4 | 100.00% |
static int __iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size,
unsigned long attrs)
{
struct vm_struct *area;
int ret;
vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot,
is_device_dma_coherent(dev));
if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret))
return ret;
if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) {
/*
* DMA_ATTR_FORCE_CONTIGUOUS allocations are always remapped,
* hence in the vmalloc space.
*/
unsigned long pfn = vmalloc_to_pfn(cpu_addr);
return __swiotlb_mmap_pfn(vma, pfn, size);
}
area = find_vm_area(cpu_addr);
if (WARN_ON(!area || !area->pages))
return -ENXIO;
return iommu_dma_mmap(area->pages, size, vma);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robin Murphy | 108 | 77.70% | 1 | 25.00% |
Catalin Marinas | 28 | 20.14% | 1 | 25.00% |
Krzysztof Kozlowski | 2 | 1.44% | 1 | 25.00% |
Vladimir Murzin | 1 | 0.72% | 1 | 25.00% |
Total | 139 | 100.00% | 4 | 100.00% |
static int __iommu_get_sgtable(struct device *dev, struct sg_table *sgt,
void *cpu_addr, dma_addr_t dma_addr,
size_t size, unsigned long attrs)
{
unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
struct vm_struct *area = find_vm_area(cpu_addr);
if (attrs & DMA_ATTR_FORCE_CONTIGUOUS) {
/*
* DMA_ATTR_FORCE_CONTIGUOUS allocations are always remapped,
* hence in the vmalloc space.
*/
struct page *page = vmalloc_to_page(cpu_addr);
return __swiotlb_get_sgtable_page(sgt, page, size);
}
if (WARN_ON(!area || !area->pages))
return -ENXIO;
return sg_alloc_table_from_pages(sgt, area->pages, count, 0, size,
GFP_KERNEL);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robin Murphy | 84 | 73.04% | 1 | 33.33% |
Catalin Marinas | 29 | 25.22% | 1 | 33.33% |
Krzysztof Kozlowski | 2 | 1.74% | 1 | 33.33% |
Total | 115 | 100.00% | 3 | 100.00% |
static void __iommu_sync_single_for_cpu(struct device *dev,
dma_addr_t dev_addr, size_t size,
enum dma_data_direction dir)
{
phys_addr_t phys;
if (is_device_dma_coherent(dev))
return;
phys = iommu_iova_to_phys(iommu_get_domain_for_dev(dev), dev_addr);
__dma_unmap_area(phys_to_virt(phys), size, dir);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robin Murphy | 56 | 100.00% | 1 | 100.00% |
Total | 56 | 100.00% | 1 | 100.00% |
static void __iommu_sync_single_for_device(struct device *dev,
dma_addr_t dev_addr, size_t size,
enum dma_data_direction dir)
{
phys_addr_t phys;
if (is_device_dma_coherent(dev))
return;
phys = iommu_iova_to_phys(iommu_get_domain_for_dev(dev), dev_addr);
__dma_map_area(phys_to_virt(phys), size, dir);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robin Murphy | 56 | 100.00% | 1 | 100.00% |
Total | 56 | 100.00% | 1 | 100.00% |
static dma_addr_t __iommu_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size,
enum dma_data_direction dir,
unsigned long attrs)
{
bool coherent = is_device_dma_coherent(dev);
int prot = dma_info_to_prot(dir, coherent, attrs);
dma_addr_t dev_addr = iommu_dma_map_page(dev, page, offset, size, prot);
if (!iommu_dma_mapping_error(dev, dev_addr) &&
(attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
__iommu_sync_single_for_device(dev, dev_addr, size, dir);
return dev_addr;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robin Murphy | 88 | 88.89% | 1 | 33.33% |
Krzysztof Kozlowski | 8 | 8.08% | 1 | 33.33% |
Mitchel Humpherys | 3 | 3.03% | 1 | 33.33% |
Total | 99 | 100.00% | 3 | 100.00% |
static void __iommu_unmap_page(struct device *dev, dma_addr_t dev_addr,
size_t size, enum dma_data_direction dir,
unsigned long attrs)
{
if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
__iommu_sync_single_for_cpu(dev, dev_addr, size, dir);
iommu_dma_unmap_page(dev, dev_addr, size, dir, attrs);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robin Murphy | 51 | 86.44% | 1 | 50.00% |
Krzysztof Kozlowski | 8 | 13.56% | 1 | 50.00% |
Total | 59 | 100.00% | 2 | 100.00% |
static void __iommu_sync_sg_for_cpu(struct device *dev,
struct scatterlist *sgl, int nelems,
enum dma_data_direction dir)
{
struct scatterlist *sg;
int i;
if (is_device_dma_coherent(dev))
return;
for_each_sg(sgl, sg, nelems, i)
__dma_unmap_area(sg_virt(sg), sg->length, dir);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robin Murphy | 63 | 100.00% | 1 | 100.00% |
Total | 63 | 100.00% | 1 | 100.00% |
static void __iommu_sync_sg_for_device(struct device *dev,
struct scatterlist *sgl, int nelems,
enum dma_data_direction dir)
{
struct scatterlist *sg;
int i;
if (is_device_dma_coherent(dev))
return;
for_each_sg(sgl, sg, nelems, i)
__dma_map_area(sg_virt(sg), sg->length, dir);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robin Murphy | 63 | 100.00% | 1 | 100.00% |
Total | 63 | 100.00% | 1 | 100.00% |
static int __iommu_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
int nelems, enum dma_data_direction dir,
unsigned long attrs)
{
bool coherent = is_device_dma_coherent(dev);
if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
__iommu_sync_sg_for_device(dev, sgl, nelems, dir);
return iommu_dma_map_sg(dev, sgl, nelems,
dma_info_to_prot(dir, coherent, attrs));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robin Murphy | 64 | 85.33% | 1 | 33.33% |
Krzysztof Kozlowski | 8 | 10.67% | 1 | 33.33% |
Mitchel Humpherys | 3 | 4.00% | 1 | 33.33% |
Total | 75 | 100.00% | 3 | 100.00% |
static void __iommu_unmap_sg_attrs(struct device *dev,
struct scatterlist *sgl, int nelems,
enum dma_data_direction dir,
unsigned long attrs)
{
if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
__iommu_sync_sg_for_cpu(dev, sgl, nelems, dir);
iommu_dma_unmap_sg(dev, sgl, nelems, dir, attrs);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robin Murphy | 53 | 86.89% | 1 | 50.00% |
Krzysztof Kozlowski | 8 | 13.11% | 1 | 50.00% |
Total | 61 | 100.00% | 2 | 100.00% |
static const struct dma_map_ops iommu_dma_ops = {
.alloc = __iommu_alloc_attrs,
.free = __iommu_free_attrs,
.mmap = __iommu_mmap_attrs,
.get_sgtable = __iommu_get_sgtable,
.map_page = __iommu_map_page,
.unmap_page = __iommu_unmap_page,
.map_sg = __iommu_map_sg_attrs,
.unmap_sg = __iommu_unmap_sg_attrs,
.sync_single_for_cpu = __iommu_sync_single_for_cpu,
.sync_single_for_device = __iommu_sync_single_for_device,
.sync_sg_for_cpu = __iommu_sync_sg_for_cpu,
.sync_sg_for_device = __iommu_sync_sg_for_device,
.map_resource = iommu_dma_map_resource,
.unmap_resource = iommu_dma_unmap_resource,
.mapping_error = iommu_dma_mapping_error,
};
static int __init __iommu_dma_init(void)
{
return iommu_dma_init();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
R Sricharan | 11 | 84.62% | 1 | 50.00% |
Robin Murphy | 2 | 15.38% | 1 | 50.00% |
Total | 13 | 100.00% | 2 | 100.00% |
arch_initcall(__iommu_dma_init);
static void __iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
const struct iommu_ops *ops)
{
struct iommu_domain *domain;
if (!ops)
return;
/*
* The IOMMU core code allocates the default DMA domain, which the
* underlying IOMMU driver needs to support via the dma-iommu layer.
*/
domain = iommu_get_domain_for_dev(dev);
if (!domain)
goto out_err;
if (domain->type == IOMMU_DOMAIN_DMA) {
if (iommu_dma_init_domain(domain, dma_base, size, dev))
goto out_err;
dev->dma_ops = &iommu_dma_ops;
}
return;
out_err:
pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
dev_name(dev));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robin Murphy | 48 | 50.00% | 2 | 50.00% |
Will Deacon | 28 | 29.17% | 1 | 25.00% |
R Sricharan | 20 | 20.83% | 1 | 25.00% |
Total | 96 | 100.00% | 4 | 100.00% |
void arch_teardown_dma_ops(struct device *dev)
{
dev->dma_ops = NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robin Murphy | 16 | 100.00% | 1 | 100.00% |
Total | 16 | 100.00% | 1 | 100.00% |
#else
static void __iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
const struct iommu_ops *iommu)
{ }
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robin Murphy | 22 | 100.00% | 2 | 100.00% |
Total | 22 | 100.00% | 2 | 100.00% |
#endif /* CONFIG_IOMMU_DMA */
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
const struct iommu_ops *iommu, bool coherent)
{
if (!dev->dma_ops)
dev->dma_ops = &swiotlb_dma_ops;
dev->archdata.dma_coherent = coherent;
__iommu_setup_dma_ops(dev, dma_base, size, iommu);
#ifdef CONFIG_XEN
if (xen_initial_domain()) {
dev->archdata.dev_dma_ops = dev->dma_ops;
dev->dma_ops = xen_dma_ops;
}
#endif
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robin Murphy | 56 | 65.12% | 2 | 50.00% |
Stefano Stabellini | 28 | 32.56% | 1 | 25.00% |
Arnd Bergmann | 2 | 2.33% | 1 | 25.00% |
Total | 86 | 100.00% | 4 | 100.00% |
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robin Murphy | 1423 | 32.62% | 9 | 18.75% |
Catalin Marinas | 1206 | 27.64% | 8 | 16.67% |
Laura Abbott | 765 | 17.53% | 4 | 8.33% |
Suravee Suthikulpanit | 339 | 7.77% | 1 | 2.08% |
Geert Uytterhoeven | 286 | 6.56% | 2 | 4.17% |
Krzysztof Kozlowski | 80 | 1.83% | 1 | 2.08% |
JiSheng Zhang | 60 | 1.38% | 4 | 8.33% |
R Sricharan | 33 | 0.76% | 1 | 2.08% |
Suzuki K. Poulose | 32 | 0.73% | 1 | 2.08% |
Takeshi Kihara | 32 | 0.73% | 1 | 2.08% |
Will Deacon | 28 | 0.64% | 1 | 2.08% |
Stefano Stabellini | 28 | 0.64% | 1 | 2.08% |
Mitchel Humpherys | 9 | 0.21% | 1 | 2.08% |
Dean Nelson | 7 | 0.16% | 1 | 2.08% |
Arnd Bergmann | 6 | 0.14% | 1 | 2.08% |
Mel Gorman | 6 | 0.14% | 1 | 2.08% |
Lucas Stach | 4 | 0.09% | 1 | 2.08% |
Vladimir Murzin | 4 | 0.09% | 3 | 6.25% |
Joerg Roedel | 3 | 0.07% | 1 | 2.08% |
Kwangwoo Lee | 3 | 0.07% | 1 | 2.08% |
Andrew Morton | 3 | 0.07% | 1 | 2.08% |
Bart Van Assche | 3 | 0.07% | 1 | 2.08% |
Ritesh Harjani | 2 | 0.05% | 1 | 2.08% |
Christoph Hellwig | 1 | 0.02% | 1 | 2.08% |
Total | 4363 | 100.00% | 48 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.