LCOV - code coverage report
Current view: top level - drivers/dma-buf/heaps - cma_heap.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 13 54 24.1 %
Date: 2020-09-30 20:25:40 Functions: 2 4 50.0 %
Branches: 3 20 15.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * DMABUF CMA heap exporter
       4                 :            :  *
       5                 :            :  * Copyright (C) 2012, 2019 Linaro Ltd.
       6                 :            :  * Author: <benjamin.gaignard@linaro.org> for ST-Ericsson.
       7                 :            :  */
       8                 :            : 
       9                 :            : #include <linux/cma.h>
      10                 :            : #include <linux/device.h>
      11                 :            : #include <linux/dma-buf.h>
      12                 :            : #include <linux/dma-heap.h>
      13                 :            : #include <linux/dma-contiguous.h>
      14                 :            : #include <linux/err.h>
      15                 :            : #include <linux/errno.h>
      16                 :            : #include <linux/highmem.h>
      17                 :            : #include <linux/module.h>
      18                 :            : #include <linux/slab.h>
      19                 :            : #include <linux/scatterlist.h>
      20                 :            : #include <linux/sched/signal.h>
      21                 :            : 
      22                 :            : #include "heap-helpers.h"
      23                 :            : 
      24                 :            : struct cma_heap {
      25                 :            :         struct dma_heap *heap;
      26                 :            :         struct cma *cma;
      27                 :            : };
      28                 :            : 
      29                 :          0 : static void cma_heap_free(struct heap_helper_buffer *buffer)
      30                 :            : {
      31                 :          0 :         struct cma_heap *cma_heap = dma_heap_get_drvdata(buffer->heap);
      32                 :          0 :         unsigned long nr_pages = buffer->pagecount;
      33                 :          0 :         struct page *cma_pages = buffer->priv_virt;
      34                 :            : 
      35                 :            :         /* free page list */
      36                 :          0 :         kfree(buffer->pages);
      37                 :            :         /* release memory */
      38                 :          0 :         cma_release(cma_heap->cma, cma_pages, nr_pages);
      39                 :          0 :         kfree(buffer);
      40                 :          0 : }
      41                 :            : 
      42                 :            : /* dmabuf heap CMA operations functions */
      43                 :          0 : static int cma_heap_allocate(struct dma_heap *heap,
      44                 :            :                              unsigned long len,
      45                 :            :                              unsigned long fd_flags,
      46                 :            :                              unsigned long heap_flags)
      47                 :            : {
      48                 :          0 :         struct cma_heap *cma_heap = dma_heap_get_drvdata(heap);
      49                 :            :         struct heap_helper_buffer *helper_buffer;
      50                 :            :         struct page *cma_pages;
      51                 :          0 :         size_t size = PAGE_ALIGN(len);
      52                 :          0 :         unsigned long nr_pages = size >> PAGE_SHIFT;
      53                 :          0 :         unsigned long align = get_order(size);
      54                 :            :         struct dma_buf *dmabuf;
      55                 :            :         int ret = -ENOMEM;
      56                 :            :         pgoff_t pg;
      57                 :            : 
      58         [ #  # ]:          0 :         if (align > CONFIG_CMA_ALIGNMENT)
      59                 :            :                 align = CONFIG_CMA_ALIGNMENT;
      60                 :            : 
      61                 :          0 :         helper_buffer = kzalloc(sizeof(*helper_buffer), GFP_KERNEL);
      62         [ #  # ]:          0 :         if (!helper_buffer)
      63                 :            :                 return -ENOMEM;
      64                 :            : 
      65                 :          0 :         init_heap_helper_buffer(helper_buffer, cma_heap_free);
      66                 :          0 :         helper_buffer->heap = heap;
      67                 :          0 :         helper_buffer->size = len;
      68                 :            : 
      69                 :          0 :         cma_pages = cma_alloc(cma_heap->cma, nr_pages, align, false);
      70         [ #  # ]:          0 :         if (!cma_pages)
      71                 :            :                 goto free_buf;
      72                 :            : 
      73                 :            :         if (PageHighMem(cma_pages)) {
      74                 :            :                 unsigned long nr_clear_pages = nr_pages;
      75                 :            :                 struct page *page = cma_pages;
      76                 :            : 
      77                 :            :                 while (nr_clear_pages > 0) {
      78                 :            :                         void *vaddr = kmap_atomic(page);
      79                 :            : 
      80                 :            :                         memset(vaddr, 0, PAGE_SIZE);
      81                 :            :                         kunmap_atomic(vaddr);
      82                 :            :                         /*
      83                 :            :                          * Avoid wasting time zeroing memory if the process
      84                 :            :                          * has been killed by by SIGKILL
      85                 :            :                          */
      86                 :            :                         if (fatal_signal_pending(current))
      87                 :            :                                 goto free_cma;
      88                 :            : 
      89                 :            :                         page++;
      90                 :            :                         nr_clear_pages--;
      91                 :            :                 }
      92                 :            :         } else {
      93                 :          0 :                 memset(page_address(cma_pages), 0, size);
      94                 :            :         }
      95                 :            : 
      96                 :          0 :         helper_buffer->pagecount = nr_pages;
      97                 :          0 :         helper_buffer->pages = kmalloc_array(helper_buffer->pagecount,
      98                 :            :                                              sizeof(*helper_buffer->pages),
      99                 :            :                                              GFP_KERNEL);
     100         [ #  # ]:          0 :         if (!helper_buffer->pages) {
     101                 :            :                 ret = -ENOMEM;
     102                 :            :                 goto free_cma;
     103                 :            :         }
     104                 :            : 
     105         [ #  # ]:          0 :         for (pg = 0; pg < helper_buffer->pagecount; pg++)
     106                 :          0 :                 helper_buffer->pages[pg] = &cma_pages[pg];
     107                 :            : 
     108                 :            :         /* create the dmabuf */
     109                 :          0 :         dmabuf = heap_helper_export_dmabuf(helper_buffer, fd_flags);
     110         [ #  # ]:          0 :         if (IS_ERR(dmabuf)) {
     111                 :            :                 ret = PTR_ERR(dmabuf);
     112                 :            :                 goto free_pages;
     113                 :            :         }
     114                 :            : 
     115                 :          0 :         helper_buffer->dmabuf = dmabuf;
     116                 :          0 :         helper_buffer->priv_virt = cma_pages;
     117                 :            : 
     118                 :          0 :         ret = dma_buf_fd(dmabuf, fd_flags);
     119         [ #  # ]:          0 :         if (ret < 0) {
     120                 :          0 :                 dma_buf_put(dmabuf);
     121                 :            :                 /* just return, as put will call release and that will free */
     122                 :          0 :                 return ret;
     123                 :            :         }
     124                 :            : 
     125                 :            :         return ret;
     126                 :            : 
     127                 :            : free_pages:
     128                 :          0 :         kfree(helper_buffer->pages);
     129                 :            : free_cma:
     130                 :          0 :         cma_release(cma_heap->cma, cma_pages, nr_pages);
     131                 :            : free_buf:
     132                 :          0 :         kfree(helper_buffer);
     133                 :          0 :         return ret;
     134                 :            : }
     135                 :            : 
     136                 :            : static const struct dma_heap_ops cma_heap_ops = {
     137                 :            :         .allocate = cma_heap_allocate,
     138                 :            : };
     139                 :            : 
     140                 :        207 : static int __add_cma_heap(struct cma *cma, void *data)
     141                 :            : {
     142                 :            :         struct cma_heap *cma_heap;
     143                 :            :         struct dma_heap_export_info exp_info;
     144                 :            : 
     145                 :        207 :         cma_heap = kzalloc(sizeof(*cma_heap), GFP_KERNEL);
     146         [ +  - ]:        207 :         if (!cma_heap)
     147                 :            :                 return -ENOMEM;
     148                 :        207 :         cma_heap->cma = cma;
     149                 :            : 
     150                 :        207 :         exp_info.name = cma_get_name(cma);
     151                 :        207 :         exp_info.ops = &cma_heap_ops;
     152                 :        207 :         exp_info.priv = cma_heap;
     153                 :            : 
     154                 :        207 :         cma_heap->heap = dma_heap_add(&exp_info);
     155         [ -  + ]:        207 :         if (IS_ERR(cma_heap->heap)) {
     156                 :            :                 int ret = PTR_ERR(cma_heap->heap);
     157                 :            : 
     158                 :          0 :                 kfree(cma_heap);
     159                 :          0 :                 return ret;
     160                 :            :         }
     161                 :            : 
     162                 :            :         return 0;
     163                 :            : }
     164                 :            : 
     165                 :        207 : static int add_default_cma_heap(void)
     166                 :            : {
     167                 :            :         struct cma *default_cma = dev_get_cma_area(NULL);
     168                 :            :         int ret = 0;
     169                 :            : 
     170         [ +  - ]:        207 :         if (default_cma)
     171                 :        207 :                 ret = __add_cma_heap(default_cma, NULL);
     172                 :            : 
     173                 :        207 :         return ret;
     174                 :            : }
     175                 :            : module_init(add_default_cma_heap);
     176                 :            : MODULE_DESCRIPTION("DMA-BUF CMA Heap");
     177                 :            : MODULE_LICENSE("GPL v2");

Generated by: LCOV version 1.14