LCOV - code coverage report
Current view: top level - drivers/dma-buf/heaps - heap-helpers.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 0 113 0.0 %
Date: 2020-09-30 20:25:40 Functions: 0 16 0.0 %
Branches: 0 24 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : #include <linux/device.h>
       3                 :            : #include <linux/dma-buf.h>
       4                 :            : #include <linux/err.h>
       5                 :            : #include <linux/highmem.h>
       6                 :            : #include <linux/idr.h>
       7                 :            : #include <linux/list.h>
       8                 :            : #include <linux/slab.h>
       9                 :            : #include <linux/uaccess.h>
      10                 :            : #include <linux/vmalloc.h>
      11                 :            : #include <uapi/linux/dma-heap.h>
      12                 :            : 
      13                 :            : #include "heap-helpers.h"
      14                 :            : 
      15                 :          0 : void init_heap_helper_buffer(struct heap_helper_buffer *buffer,
      16                 :            :                              void (*free)(struct heap_helper_buffer *))
      17                 :            : {
      18                 :          0 :         buffer->priv_virt = NULL;
      19                 :          0 :         mutex_init(&buffer->lock);
      20                 :          0 :         buffer->vmap_cnt = 0;
      21                 :          0 :         buffer->vaddr = NULL;
      22                 :          0 :         buffer->pagecount = 0;
      23                 :          0 :         buffer->pages = NULL;
      24                 :          0 :         INIT_LIST_HEAD(&buffer->attachments);
      25                 :          0 :         buffer->free = free;
      26                 :          0 : }
      27                 :            : 
      28                 :          0 : struct dma_buf *heap_helper_export_dmabuf(struct heap_helper_buffer *buffer,
      29                 :            :                                           int fd_flags)
      30                 :            : {
      31                 :          0 :         DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
      32                 :            : 
      33                 :          0 :         exp_info.ops = &heap_helper_ops;
      34                 :          0 :         exp_info.size = buffer->size;
      35                 :          0 :         exp_info.flags = fd_flags;
      36                 :          0 :         exp_info.priv = buffer;
      37                 :            : 
      38                 :          0 :         return dma_buf_export(&exp_info);
      39                 :            : }
      40                 :            : 
      41                 :          0 : static void *dma_heap_map_kernel(struct heap_helper_buffer *buffer)
      42                 :            : {
      43                 :            :         void *vaddr;
      44                 :            : 
      45                 :          0 :         vaddr = vmap(buffer->pages, buffer->pagecount, VM_MAP, PAGE_KERNEL);
      46         [ #  # ]:          0 :         if (!vaddr)
      47                 :            :                 return ERR_PTR(-ENOMEM);
      48                 :            : 
      49                 :          0 :         return vaddr;
      50                 :            : }
      51                 :            : 
      52                 :          0 : static void dma_heap_buffer_destroy(struct heap_helper_buffer *buffer)
      53                 :            : {
      54         [ #  # ]:          0 :         if (buffer->vmap_cnt > 0) {
      55                 :          0 :                 WARN(1, "%s: buffer still mapped in the kernel\n", __func__);
      56                 :          0 :                 vunmap(buffer->vaddr);
      57                 :            :         }
      58                 :            : 
      59                 :          0 :         buffer->free(buffer);
      60                 :          0 : }
      61                 :            : 
      62                 :          0 : static void *dma_heap_buffer_vmap_get(struct heap_helper_buffer *buffer)
      63                 :            : {
      64                 :            :         void *vaddr;
      65                 :            : 
      66         [ #  # ]:          0 :         if (buffer->vmap_cnt) {
      67                 :          0 :                 buffer->vmap_cnt++;
      68                 :          0 :                 return buffer->vaddr;
      69                 :            :         }
      70                 :          0 :         vaddr = dma_heap_map_kernel(buffer);
      71         [ #  # ]:          0 :         if (IS_ERR(vaddr))
      72                 :            :                 return vaddr;
      73                 :          0 :         buffer->vaddr = vaddr;
      74                 :          0 :         buffer->vmap_cnt++;
      75                 :          0 :         return vaddr;
      76                 :            : }
      77                 :            : 
      78                 :            : static void dma_heap_buffer_vmap_put(struct heap_helper_buffer *buffer)
      79                 :            : {
      80         [ #  # ]:          0 :         if (!--buffer->vmap_cnt) {
      81                 :          0 :                 vunmap(buffer->vaddr);
      82                 :          0 :                 buffer->vaddr = NULL;
      83                 :            :         }
      84                 :            : }
      85                 :            : 
      86                 :            : struct dma_heaps_attachment {
      87                 :            :         struct device *dev;
      88                 :            :         struct sg_table table;
      89                 :            :         struct list_head list;
      90                 :            : };
      91                 :            : 
      92                 :          0 : static int dma_heap_attach(struct dma_buf *dmabuf,
      93                 :            :                            struct dma_buf_attachment *attachment)
      94                 :            : {
      95                 :            :         struct dma_heaps_attachment *a;
      96                 :          0 :         struct heap_helper_buffer *buffer = dmabuf->priv;
      97                 :            :         int ret;
      98                 :            : 
      99                 :          0 :         a = kzalloc(sizeof(*a), GFP_KERNEL);
     100         [ #  # ]:          0 :         if (!a)
     101                 :            :                 return -ENOMEM;
     102                 :            : 
     103                 :          0 :         ret = sg_alloc_table_from_pages(&a->table, buffer->pages,
     104                 :            :                                         buffer->pagecount, 0,
     105                 :          0 :                                         buffer->pagecount << PAGE_SHIFT,
     106                 :            :                                         GFP_KERNEL);
     107         [ #  # ]:          0 :         if (ret) {
     108                 :          0 :                 kfree(a);
     109                 :          0 :                 return ret;
     110                 :            :         }
     111                 :            : 
     112                 :          0 :         a->dev = attachment->dev;
     113                 :          0 :         INIT_LIST_HEAD(&a->list);
     114                 :            : 
     115                 :          0 :         attachment->priv = a;
     116                 :            : 
     117                 :          0 :         mutex_lock(&buffer->lock);
     118                 :          0 :         list_add(&a->list, &buffer->attachments);
     119                 :          0 :         mutex_unlock(&buffer->lock);
     120                 :            : 
     121                 :          0 :         return 0;
     122                 :            : }
     123                 :            : 
     124                 :          0 : static void dma_heap_detach(struct dma_buf *dmabuf,
     125                 :            :                             struct dma_buf_attachment *attachment)
     126                 :            : {
     127                 :          0 :         struct dma_heaps_attachment *a = attachment->priv;
     128                 :          0 :         struct heap_helper_buffer *buffer = dmabuf->priv;
     129                 :            : 
     130                 :          0 :         mutex_lock(&buffer->lock);
     131                 :            :         list_del(&a->list);
     132                 :          0 :         mutex_unlock(&buffer->lock);
     133                 :            : 
     134                 :          0 :         sg_free_table(&a->table);
     135                 :          0 :         kfree(a);
     136                 :          0 : }
     137                 :            : 
     138                 :            : static
     139                 :          0 : struct sg_table *dma_heap_map_dma_buf(struct dma_buf_attachment *attachment,
     140                 :            :                                       enum dma_data_direction direction)
     141                 :            : {
     142                 :          0 :         struct dma_heaps_attachment *a = attachment->priv;
     143                 :            :         struct sg_table *table;
     144                 :            : 
     145                 :          0 :         table = &a->table;
     146                 :            : 
     147         [ #  # ]:          0 :         if (!dma_map_sg(attachment->dev, table->sgl, table->nents,
     148                 :            :                         direction))
     149                 :            :                 table = ERR_PTR(-ENOMEM);
     150                 :          0 :         return table;
     151                 :            : }
     152                 :            : 
     153                 :          0 : static void dma_heap_unmap_dma_buf(struct dma_buf_attachment *attachment,
     154                 :            :                                    struct sg_table *table,
     155                 :            :                                    enum dma_data_direction direction)
     156                 :            : {
     157                 :          0 :         dma_unmap_sg(attachment->dev, table->sgl, table->nents, direction);
     158                 :          0 : }
     159                 :            : 
     160                 :          0 : static vm_fault_t dma_heap_vm_fault(struct vm_fault *vmf)
     161                 :            : {
     162                 :          0 :         struct vm_area_struct *vma = vmf->vma;
     163                 :          0 :         struct heap_helper_buffer *buffer = vma->vm_private_data;
     164                 :            : 
     165         [ #  # ]:          0 :         if (vmf->pgoff > buffer->pagecount)
     166                 :            :                 return VM_FAULT_SIGBUS;
     167                 :            : 
     168                 :          0 :         vmf->page = buffer->pages[vmf->pgoff];
     169                 :          0 :         get_page(vmf->page);
     170                 :            : 
     171                 :          0 :         return 0;
     172                 :            : }
     173                 :            : 
     174                 :            : static const struct vm_operations_struct dma_heap_vm_ops = {
     175                 :            :         .fault = dma_heap_vm_fault,
     176                 :            : };
     177                 :            : 
     178                 :          0 : static int dma_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
     179                 :            : {
     180                 :          0 :         struct heap_helper_buffer *buffer = dmabuf->priv;
     181                 :            : 
     182         [ #  # ]:          0 :         if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0)
     183                 :            :                 return -EINVAL;
     184                 :            : 
     185                 :          0 :         vma->vm_ops = &dma_heap_vm_ops;
     186                 :          0 :         vma->vm_private_data = buffer;
     187                 :            : 
     188                 :          0 :         return 0;
     189                 :            : }
     190                 :            : 
     191                 :          0 : static void dma_heap_dma_buf_release(struct dma_buf *dmabuf)
     192                 :            : {
     193                 :          0 :         struct heap_helper_buffer *buffer = dmabuf->priv;
     194                 :            : 
     195                 :          0 :         dma_heap_buffer_destroy(buffer);
     196                 :          0 : }
     197                 :            : 
     198                 :          0 : static int dma_heap_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
     199                 :            :                                              enum dma_data_direction direction)
     200                 :            : {
     201                 :          0 :         struct heap_helper_buffer *buffer = dmabuf->priv;
     202                 :            :         struct dma_heaps_attachment *a;
     203                 :            :         int ret = 0;
     204                 :            : 
     205                 :          0 :         mutex_lock(&buffer->lock);
     206                 :            : 
     207                 :            :         if (buffer->vmap_cnt)
     208                 :            :                 invalidate_kernel_vmap_range(buffer->vaddr, buffer->size);
     209                 :            : 
     210         [ #  # ]:          0 :         list_for_each_entry(a, &buffer->attachments, list) {
     211                 :          0 :                 dma_sync_sg_for_cpu(a->dev, a->table.sgl, a->table.nents,
     212                 :            :                                     direction);
     213                 :            :         }
     214                 :          0 :         mutex_unlock(&buffer->lock);
     215                 :            : 
     216                 :          0 :         return ret;
     217                 :            : }
     218                 :            : 
     219                 :          0 : static int dma_heap_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
     220                 :            :                                            enum dma_data_direction direction)
     221                 :            : {
     222                 :          0 :         struct heap_helper_buffer *buffer = dmabuf->priv;
     223                 :            :         struct dma_heaps_attachment *a;
     224                 :            : 
     225                 :          0 :         mutex_lock(&buffer->lock);
     226                 :            : 
     227                 :            :         if (buffer->vmap_cnt)
     228                 :            :                 flush_kernel_vmap_range(buffer->vaddr, buffer->size);
     229                 :            : 
     230         [ #  # ]:          0 :         list_for_each_entry(a, &buffer->attachments, list) {
     231                 :          0 :                 dma_sync_sg_for_device(a->dev, a->table.sgl, a->table.nents,
     232                 :            :                                        direction);
     233                 :            :         }
     234                 :          0 :         mutex_unlock(&buffer->lock);
     235                 :            : 
     236                 :          0 :         return 0;
     237                 :            : }
     238                 :            : 
     239                 :          0 : static void *dma_heap_dma_buf_vmap(struct dma_buf *dmabuf)
     240                 :            : {
     241                 :          0 :         struct heap_helper_buffer *buffer = dmabuf->priv;
     242                 :            :         void *vaddr;
     243                 :            : 
     244                 :          0 :         mutex_lock(&buffer->lock);
     245                 :          0 :         vaddr = dma_heap_buffer_vmap_get(buffer);
     246                 :          0 :         mutex_unlock(&buffer->lock);
     247                 :            : 
     248                 :          0 :         return vaddr;
     249                 :            : }
     250                 :            : 
     251                 :          0 : static void dma_heap_dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)
     252                 :            : {
     253                 :          0 :         struct heap_helper_buffer *buffer = dmabuf->priv;
     254                 :            : 
     255                 :          0 :         mutex_lock(&buffer->lock);
     256                 :            :         dma_heap_buffer_vmap_put(buffer);
     257                 :          0 :         mutex_unlock(&buffer->lock);
     258                 :          0 : }
     259                 :            : 
     260                 :            : const struct dma_buf_ops heap_helper_ops = {
     261                 :            :         .map_dma_buf = dma_heap_map_dma_buf,
     262                 :            :         .unmap_dma_buf = dma_heap_unmap_dma_buf,
     263                 :            :         .mmap = dma_heap_mmap,
     264                 :            :         .release = dma_heap_dma_buf_release,
     265                 :            :         .attach = dma_heap_attach,
     266                 :            :         .detach = dma_heap_detach,
     267                 :            :         .begin_cpu_access = dma_heap_dma_buf_begin_cpu_access,
     268                 :            :         .end_cpu_access = dma_heap_dma_buf_end_cpu_access,
     269                 :            :         .vmap = dma_heap_dma_buf_vmap,
     270                 :            :         .vunmap = dma_heap_dma_buf_vunmap,
     271                 :            : };

Generated by: LCOV version 1.14