LCOV - code coverage report
Current view: top level - drivers/base - dma-coherent.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 72 0.0 %
Date: 2014-02-18 Functions: 0 6 0.0 %
Branches: 0 264 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Coherent per-device memory handling.
       3                 :            :  * Borrowed from i386
       4                 :            :  */
       5                 :            : #include <linux/slab.h>
       6                 :            : #include <linux/kernel.h>
       7                 :            : #include <linux/module.h>
       8                 :            : #include <linux/dma-mapping.h>
       9                 :            : 
      10                 :            : struct dma_coherent_mem {
      11                 :            :         void            *virt_base;
      12                 :            :         dma_addr_t      device_base;
      13                 :            :         phys_addr_t     pfn_base;
      14                 :            :         int             size;
      15                 :            :         int             flags;
      16                 :            :         unsigned long   *bitmap;
      17                 :            : };
      18                 :            : 
      19                 :          0 : int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
      20                 :            :                                 dma_addr_t device_addr, size_t size, int flags)
      21                 :            : {
      22                 :            :         void __iomem *mem_base = NULL;
      23                 :          0 :         int pages = size >> PAGE_SHIFT;
      24                 :          0 :         int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
      25                 :            : 
      26         [ #  # ]:          0 :         if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0)
      27                 :            :                 goto out;
      28         [ #  # ]:          0 :         if (!size)
      29                 :            :                 goto out;
      30         [ #  # ]:          0 :         if (dev->dma_mem)
      31                 :            :                 goto out;
      32                 :            : 
      33                 :            :         /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
      34                 :            : 
      35                 :          0 :         mem_base = ioremap(bus_addr, size);
      36         [ #  # ]:          0 :         if (!mem_base)
      37                 :            :                 goto out;
      38                 :            : 
      39                 :          0 :         dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
      40         [ #  # ]:          0 :         if (!dev->dma_mem)
      41                 :            :                 goto out;
      42                 :          0 :         dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
      43         [ #  # ]:          0 :         if (!dev->dma_mem->bitmap)
      44                 :            :                 goto free1_out;
      45                 :            : 
      46                 :          0 :         dev->dma_mem->virt_base = mem_base;
      47                 :          0 :         dev->dma_mem->device_base = device_addr;
      48                 :          0 :         dev->dma_mem->pfn_base = PFN_DOWN(bus_addr);
      49                 :          0 :         dev->dma_mem->size = pages;
      50                 :          0 :         dev->dma_mem->flags = flags;
      51                 :            : 
      52         [ #  # ]:          0 :         if (flags & DMA_MEMORY_MAP)
      53                 :            :                 return DMA_MEMORY_MAP;
      54                 :            : 
      55                 :          0 :         return DMA_MEMORY_IO;
      56                 :            : 
      57                 :            :  free1_out:
      58                 :          0 :         kfree(dev->dma_mem);
      59                 :            :  out:
      60         [ #  # ]:          0 :         if (mem_base)
      61                 :          0 :                 iounmap(mem_base);
      62                 :            :         return 0;
      63                 :            : }
      64                 :            : EXPORT_SYMBOL(dma_declare_coherent_memory);
      65                 :            : 
      66                 :          0 : void dma_release_declared_memory(struct device *dev)
      67                 :            : {
      68                 :          0 :         struct dma_coherent_mem *mem = dev->dma_mem;
      69                 :            : 
      70         [ #  # ]:          0 :         if (!mem)
      71                 :          0 :                 return;
      72                 :          0 :         dev->dma_mem = NULL;
      73                 :          0 :         iounmap(mem->virt_base);
      74                 :          0 :         kfree(mem->bitmap);
      75                 :          0 :         kfree(mem);
      76                 :            : }
      77                 :            : EXPORT_SYMBOL(dma_release_declared_memory);
      78                 :            : 
      79                 :          0 : void *dma_mark_declared_memory_occupied(struct device *dev,
      80                 :            :                                         dma_addr_t device_addr, size_t size)
      81                 :            : {
      82                 :          0 :         struct dma_coherent_mem *mem = dev->dma_mem;
      83                 :            :         int pos, err;
      84                 :            : 
      85                 :          0 :         size += device_addr & ~PAGE_MASK;
      86                 :            : 
      87         [ #  # ]:          0 :         if (!mem)
      88                 :            :                 return ERR_PTR(-EINVAL);
      89                 :            : 
      90                 :          0 :         pos = (device_addr - mem->device_base) >> PAGE_SHIFT;
      91 [ #  # ][ #  # ]:          0 :         err = bitmap_allocate_region(mem->bitmap, pos, get_order(size));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      92         [ #  # ]:          0 :         if (err != 0)
      93                 :          0 :                 return ERR_PTR(err);
      94                 :          0 :         return mem->virt_base + (pos << PAGE_SHIFT);
      95                 :            : }
      96                 :            : EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
      97                 :            : 
      98                 :            : /**
      99                 :            :  * dma_alloc_from_coherent() - try to allocate memory from the per-device coherent area
     100                 :            :  *
     101                 :            :  * @dev:        device from which we allocate memory
     102                 :            :  * @size:       size of requested memory area
     103                 :            :  * @dma_handle: This will be filled with the correct dma handle
     104                 :            :  * @ret:        This pointer will be filled with the virtual address
     105                 :            :  *              to allocated area.
     106                 :            :  *
     107                 :            :  * This function should be only called from per-arch dma_alloc_coherent()
     108                 :            :  * to support allocation from per-device coherent memory pools.
     109                 :            :  *
     110                 :            :  * Returns 0 if dma_alloc_coherent should continue with allocating from
     111                 :            :  * generic memory areas, or !0 if dma_alloc_coherent should return @ret.
     112                 :            :  */
     113                 :          0 : int dma_alloc_from_coherent(struct device *dev, ssize_t size,
     114                 :            :                                        dma_addr_t *dma_handle, void **ret)
     115                 :            : {
     116                 :            :         struct dma_coherent_mem *mem;
     117 [ #  # ][ #  # ]:          0 :         int order = get_order(size);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     118                 :            :         int pageno;
     119                 :            : 
     120         [ #  # ]:          0 :         if (!dev)
     121                 :            :                 return 0;
     122                 :          0 :         mem = dev->dma_mem;
     123         [ #  # ]:          0 :         if (!mem)
     124                 :            :                 return 0;
     125                 :            : 
     126                 :          0 :         *ret = NULL;
     127                 :            : 
     128         [ #  # ]:          0 :         if (unlikely(size > (mem->size << PAGE_SHIFT)))
     129                 :            :                 goto err;
     130                 :            : 
     131                 :          0 :         pageno = bitmap_find_free_region(mem->bitmap, mem->size, order);
     132         [ #  # ]:          0 :         if (unlikely(pageno < 0))
     133                 :            :                 goto err;
     134                 :            : 
     135                 :            :         /*
     136                 :            :          * Memory was found in the per-device area.
     137                 :            :          */
     138                 :          0 :         *dma_handle = mem->device_base + (pageno << PAGE_SHIFT);
     139                 :          0 :         *ret = mem->virt_base + (pageno << PAGE_SHIFT);
     140         [ #  # ]:          0 :         memset(*ret, 0, size);
     141                 :            : 
     142                 :            :         return 1;
     143                 :            : 
     144                 :            : err:
     145                 :            :         /*
     146                 :            :          * In the case where the allocation can not be satisfied from the
     147                 :            :          * per-device area, try to fall back to generic memory if the
     148                 :            :          * constraints allow it.
     149                 :            :          */
     150                 :          0 :         return mem->flags & DMA_MEMORY_EXCLUSIVE;
     151                 :            : }
     152                 :            : EXPORT_SYMBOL(dma_alloc_from_coherent);
     153                 :            : 
     154                 :            : /**
     155                 :            :  * dma_release_from_coherent() - try to free the memory allocated from per-device coherent memory pool
     156                 :            :  * @dev:        device from which the memory was allocated
     157                 :            :  * @order:      the order of pages allocated
     158                 :            :  * @vaddr:      virtual address of allocated pages
     159                 :            :  *
     160                 :            :  * This checks whether the memory was allocated from the per-device
     161                 :            :  * coherent memory pool and if so, releases that memory.
     162                 :            :  *
     163                 :            :  * Returns 1 if we correctly released the memory, or 0 if
     164                 :            :  * dma_release_coherent() should proceed with releasing memory from
     165                 :            :  * generic pools.
     166                 :            :  */
     167                 :          0 : int dma_release_from_coherent(struct device *dev, int order, void *vaddr)
     168                 :            : {
     169         [ #  # ]:          0 :         struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
     170                 :            : 
     171 [ #  # ][ #  # ]:          0 :         if (mem && vaddr >= mem->virt_base && vaddr <
                 [ #  # ]
     172                 :          0 :                    (mem->virt_base + (mem->size << PAGE_SHIFT))) {
     173                 :          0 :                 int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
     174                 :            : 
     175                 :          0 :                 bitmap_release_region(mem->bitmap, page, order);
     176                 :          0 :                 return 1;
     177                 :            :         }
     178                 :            :         return 0;
     179                 :            : }
     180                 :            : EXPORT_SYMBOL(dma_release_from_coherent);
     181                 :            : 
     182                 :            : /**
     183                 :            :  * dma_mmap_from_coherent() - try to mmap the memory allocated from
     184                 :            :  * per-device coherent memory pool to userspace
     185                 :            :  * @dev:        device from which the memory was allocated
     186                 :            :  * @vma:        vm_area for the userspace memory
     187                 :            :  * @vaddr:      cpu address returned by dma_alloc_from_coherent
     188                 :            :  * @size:       size of the memory buffer allocated by dma_alloc_from_coherent
     189                 :            :  * @ret:        result from remap_pfn_range()
     190                 :            :  *
     191                 :            :  * This checks whether the memory was allocated from the per-device
     192                 :            :  * coherent memory pool and if so, maps that memory to the provided vma.
     193                 :            :  *
     194                 :            :  * Returns 1 if we correctly mapped the memory, or 0 if the caller should
     195                 :            :  * proceed with mapping memory from generic pools.
     196                 :            :  */
     197                 :          0 : int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
     198                 :            :                            void *vaddr, size_t size, int *ret)
     199                 :            : {
     200         [ #  # ]:          0 :         struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
     201                 :            : 
     202 [ #  # ][ #  # ]:          0 :         if (mem && vaddr >= mem->virt_base && vaddr + size <=
                 [ #  # ]
     203                 :          0 :                    (mem->virt_base + (mem->size << PAGE_SHIFT))) {
     204                 :          0 :                 unsigned long off = vma->vm_pgoff;
     205                 :          0 :                 int start = (vaddr - mem->virt_base) >> PAGE_SHIFT;
     206                 :          0 :                 int user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
     207                 :          0 :                 int count = size >> PAGE_SHIFT;
     208                 :            : 
     209                 :          0 :                 *ret = -ENXIO;
     210 [ #  # ][ #  # ]:          0 :                 if (off < count && user_count <= count - off) {
     211                 :          0 :                         unsigned pfn = mem->pfn_base + start + off;
     212                 :          0 :                         *ret = remap_pfn_range(vma, vma->vm_start, pfn,
     213                 :          0 :                                                user_count << PAGE_SHIFT,
     214                 :            :                                                vma->vm_page_prot);
     215                 :            :                 }
     216                 :            :                 return 1;
     217                 :            :         }
     218                 :            :         return 0;
     219                 :            : }
     220                 :            : EXPORT_SYMBOL(dma_mmap_from_coherent);

Generated by: LCOV version 1.9