cregit-Linux how code gets into the kernel

Release 4.11 drivers/base/dma-coherent.c

Directory: drivers/base
/*
 * Coherent per-device memory handling.
 * Borrowed from i386
 */
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>


struct dma_coherent_mem {
	
void		*virt_base;
	
dma_addr_t	device_base;
	
unsigned long	pfn_base;
	
int		size;
	
int		flags;
	
unsigned long	*bitmap;
	
spinlock_t	spinlock;
};


static bool dma_init_coherent_memory( phys_addr_t phys_addr, dma_addr_t device_addr, size_t size, int flags, struct dma_coherent_mem **mem) { struct dma_coherent_mem *dma_mem = NULL; void __iomem *mem_base = NULL; int pages = size >> PAGE_SHIFT; int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0) goto out; if (!size) goto out; if (flags & DMA_MEMORY_MAP) mem_base = memremap(phys_addr, size, MEMREMAP_WC); else mem_base = ioremap(phys_addr, size); if (!mem_base) goto out; dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); if (!dma_mem) goto out; dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); if (!dma_mem->bitmap) goto out; dma_mem->virt_base = mem_base; dma_mem->device_base = device_addr; dma_mem->pfn_base = PFN_DOWN(phys_addr); dma_mem->size = pages; dma_mem->flags = flags; spin_lock_init(&dma_mem->spinlock); *mem = dma_mem; return true; out: kfree(dma_mem); if (mem_base) { if (flags & DMA_MEMORY_MAP) memunmap(mem_base); else iounmap(mem_base); } return false; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Baryshkov16568.18%116.67%
Marek Szyprowski3815.70%233.33%
Brian Starkey3213.22%116.67%
Björn Helgaas41.65%116.67%
Michal Nazarewicz31.24%116.67%
Total242100.00%6100.00%


static void dma_release_coherent_memory(struct dma_coherent_mem *mem) { if (!mem) return; if (mem->flags & DMA_MEMORY_MAP) memunmap(mem->virt_base); else iounmap(mem->virt_base); kfree(mem->bitmap); kfree(mem); }

Contributors

PersonTokensPropCommitsCommitProp
Marek Szyprowski3669.23%150.00%
Brian Starkey1630.77%150.00%
Total52100.00%2100.00%


static int dma_assign_coherent_memory(struct device *dev, struct dma_coherent_mem *mem) { if (dev->dma_mem) return -EBUSY; dev->dma_mem = mem; /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Marek Szyprowski36100.00%1100.00%
Total36100.00%1100.00%


int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, dma_addr_t device_addr, size_t size, int flags) { struct dma_coherent_mem *mem; if (!dma_init_coherent_memory(phys_addr, device_addr, size, flags, &mem)) return 0; if (dma_assign_coherent_memory(dev, mem) == 0) return flags & DMA_MEMORY_MAP ? DMA_MEMORY_MAP : DMA_MEMORY_IO; dma_release_coherent_memory(mem); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Marek Szyprowski6586.67%150.00%
Michal Nazarewicz1013.33%150.00%
Total75100.00%2100.00%

EXPORT_SYMBOL(dma_declare_coherent_memory);
void dma_release_declared_memory(struct device *dev) { struct dma_coherent_mem *mem = dev->dma_mem; if (!mem) return; dma_release_coherent_memory(mem); dev->dma_mem = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Baryshkov3186.11%150.00%
Marek Szyprowski513.89%150.00%
Total36100.00%2100.00%

EXPORT_SYMBOL(dma_release_declared_memory);
void *dma_mark_declared_memory_occupied(struct device *dev, dma_addr_t device_addr, size_t size) { struct dma_coherent_mem *mem = dev->dma_mem; unsigned long flags; int pos, err; size += device_addr & ~PAGE_MASK; if (!mem) return ERR_PTR(-EINVAL); spin_lock_irqsave(&mem->spinlock, flags); pos = (device_addr - mem->device_base) >> PAGE_SHIFT; err = bitmap_allocate_region(mem->bitmap, pos, get_order(size)); spin_unlock_irqrestore(&mem->spinlock, flags); if (err != 0) return ERR_PTR(err); return mem->virt_base + (pos << PAGE_SHIFT); }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Baryshkov9979.20%133.33%
Marek Szyprowski2419.20%133.33%
Jan Beulich21.60%133.33%
Total125100.00%3100.00%

EXPORT_SYMBOL(dma_mark_declared_memory_occupied); /** * dma_alloc_from_coherent() - try to allocate memory from the per-device coherent area * * @dev: device from which we allocate memory * @size: size of requested memory area * @dma_handle: This will be filled with the correct dma handle * @ret: This pointer will be filled with the virtual address * to allocated area. * * This function should be only called from per-arch dma_alloc_coherent() * to support allocation from per-device coherent memory pools. * * Returns 0 if dma_alloc_coherent should continue with allocating from * generic memory areas, or !0 if dma_alloc_coherent should return @ret. */
int dma_alloc_from_coherent(struct device *dev, ssize_t size, dma_addr_t *dma_handle, void **ret) { struct dma_coherent_mem *mem; int order = get_order(size); unsigned long flags; int pageno; int dma_memory_map; if (!dev) return 0; mem = dev->dma_mem; if (!mem) return 0; *ret = NULL; spin_lock_irqsave(&mem->spinlock, flags); if (unlikely(size > (mem->size << PAGE_SHIFT))) goto err; pageno = bitmap_find_free_region(mem->bitmap, mem->size, order); if (unlikely(pageno < 0)) goto err; /* * Memory was found in the per-device area. */ *dma_handle = mem->device_base + (pageno << PAGE_SHIFT); *ret = mem->virt_base + (pageno << PAGE_SHIFT); dma_memory_map = (mem->flags & DMA_MEMORY_MAP); spin_unlock_irqrestore(&mem->spinlock, flags); if (dma_memory_map) memset(*ret, 0, size); else memset_io(*ret, 0, size); return 1; err: spin_unlock_irqrestore(&mem->spinlock, flags); /* * In the case where the allocation can not be satisfied from the * per-device area, try to fall back to generic memory if the * constraints allow it. */ return mem->flags & DMA_MEMORY_EXCLUSIVE; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Baryshkov9542.79%112.50%
Andrew Morton2712.16%112.50%
Marek Szyprowski2410.81%112.50%
Paul Mundt2310.36%112.50%
Bastian Hecht219.46%112.50%
Brian Starkey177.66%112.50%
Johannes Weiner114.95%112.50%
Adrian McMenamin41.80%112.50%
Total222100.00%8100.00%

EXPORT_SYMBOL(dma_alloc_from_coherent); /** * dma_release_from_coherent() - try to free the memory allocated from per-device coherent memory pool * @dev: device from which the memory was allocated * @order: the order of pages allocated * @vaddr: virtual address of allocated pages * * This checks whether the memory was allocated from the per-device * coherent memory pool and if so, releases that memory. * * Returns 1 if we correctly released the memory, or 0 if * dma_release_coherent() should proceed with releasing memory from * generic pools. */
int dma_release_from_coherent(struct device *dev, int order, void *vaddr) { struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) { int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; unsigned long flags; spin_lock_irqsave(&mem->spinlock, flags); bitmap_release_region(mem->bitmap, page, order); spin_unlock_irqrestore(&mem->spinlock, flags); return 1; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitry Baryshkov8878.57%150.00%
Marek Szyprowski2421.43%150.00%
Total112100.00%2100.00%

EXPORT_SYMBOL(dma_release_from_coherent); /** * dma_mmap_from_coherent() - try to mmap the memory allocated from * per-device coherent memory pool to userspace * @dev: device from which the memory was allocated * @vma: vm_area for the userspace memory * @vaddr: cpu address returned by dma_alloc_from_coherent * @size: size of the memory buffer allocated by dma_alloc_from_coherent * @ret: result from remap_pfn_range() * * This checks whether the memory was allocated from the per-device * coherent memory pool and if so, maps that memory to the provided vma. * * Returns 1 if we correctly mapped the memory, or 0 if the caller should * proceed with mapping memory from generic pools. */
int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma, void *vaddr, size_t size, int *ret) { struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; if (mem && vaddr >= mem->virt_base && vaddr + size <= (mem->virt_base + (mem->size << PAGE_SHIFT))) { unsigned long off = vma->vm_pgoff; int start = (vaddr - mem->virt_base) >> PAGE_SHIFT; int user_count = vma_pages(vma); int count = PAGE_ALIGN(size) >> PAGE_SHIFT; *ret = -ENXIO; if (off < count && user_count <= count - off) { unsigned long pfn = mem->pfn_base + start + off; *ret = remap_pfn_range(vma, vma->vm_start, pfn, user_count << PAGE_SHIFT, vma->vm_page_prot); } return 1; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Marek Szyprowski16195.83%125.00%
Muhammad Falak R Wani31.79%125.00%
George G. Davis31.79%125.00%
Björn Helgaas10.60%125.00%
Total168100.00%4100.00%

EXPORT_SYMBOL(dma_mmap_from_coherent); /* * Support for reserved memory regions defined in device tree */ #ifdef CONFIG_OF_RESERVED_MEM #include <linux/of.h> #include <linux/of_fdt.h> #include <linux/of_reserved_mem.h>
static int rmem_dma_device_init(struct reserved_mem *rmem, struct device *dev) { struct dma_coherent_mem *mem = rmem->priv; if (!mem && !dma_init_coherent_memory(rmem->base, rmem->base, rmem->size, DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE, &mem)) { pr_err("Reserved memory: failed to init DMA memory pool at %pa, size %ld MiB\n", &rmem->base, (unsigned long)rmem->size / SZ_1M); return -ENODEV; } rmem->priv = mem; dma_assign_coherent_memory(dev, mem); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Marek Szyprowski9498.95%150.00%
Michal Nazarewicz11.05%150.00%
Total95100.00%2100.00%


static void rmem_dma_device_release(struct reserved_mem *rmem, struct device *dev) { dev->dma_mem = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Marek Szyprowski22100.00%1100.00%
Total22100.00%1100.00%

static const struct reserved_mem_ops rmem_dma_ops = { .device_init = rmem_dma_device_init, .device_release = rmem_dma_device_release, };
static int __init rmem_dma_setup(struct reserved_mem *rmem) { unsigned long node = rmem->fdt_node; if (of_get_flat_dt_prop(node, "reusable", NULL)) return -EINVAL; #ifdef CONFIG_ARM if (!of_get_flat_dt_prop(node, "no-map", NULL)) { pr_err("Reserved memory: regions without no-map are not yet supported\n"); return -EINVAL; } #endif rmem->ops = &rmem_dma_ops; pr_info("Reserved memory: created DMA memory pool at %pa, size %ld MiB\n", &rmem->base, (unsigned long)rmem->size / SZ_1M); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Marek Szyprowski93100.00%1100.00%
Total93100.00%1100.00%

RESERVEDMEM_OF_DECLARE(dma, "shared-dma-pool", rmem_dma_setup); #endif

Overall Contributors

PersonTokensPropCommitsCommitProp
Marek Szyprowski67448.18%29.52%
Dmitry Baryshkov52337.38%29.52%
Brian Starkey684.86%29.52%
Andrew Morton271.93%14.76%
Paul Mundt241.72%14.76%
Bastian Hecht211.50%14.76%
Michal Nazarewicz141.00%14.76%
Johannes Weiner110.79%14.76%
Ingo Molnar100.71%14.76%
Björn Helgaas70.50%14.76%
Adrian McMenamin40.29%14.76%
George G. Davis30.21%14.76%
Tejun Heo30.21%14.76%
Muhammad Falak R Wani30.21%14.76%
Paul Gortmaker30.21%14.76%
Jan Beulich20.14%14.76%
Laurent Pinchart10.07%14.76%
Marin Mitov10.07%14.76%
Total1399100.00%21100.00%
Directory: drivers/base
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.