LCOV - code coverage report
Current view: top level - sound/core - sgbuf.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 96 0.0 %
Date: 2022-04-01 14:58:12 Functions: 0 3 0.0 %
Branches: 0 40 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-or-later
       2                 :            : /*
       3                 :            :  * Scatter-Gather buffer
       4                 :            :  *
       5                 :            :  *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
       6                 :            :  */
       7                 :            : 
       8                 :            : #include <linux/slab.h>
       9                 :            : #include <linux/mm.h>
      10                 :            : #include <linux/vmalloc.h>
      11                 :            : #include <linux/export.h>
      12                 :            : #include <asm/pgtable.h>
      13                 :            : #include <sound/memalloc.h>
      14                 :            : 
      15                 :            : 
      16                 :            : /* table entries are align to 32 */
      17                 :            : #define SGBUF_TBL_ALIGN         32
      18                 :            : #define sgbuf_align_table(tbl)  ALIGN((tbl), SGBUF_TBL_ALIGN)
      19                 :            : 
      20                 :          0 : int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
      21                 :            : {
      22                 :          0 :         struct snd_sg_buf *sgbuf = dmab->private_data;
      23                 :          0 :         struct snd_dma_buffer tmpb;
      24                 :          0 :         int i;
      25                 :            : 
      26         [ #  # ]:          0 :         if (! sgbuf)
      27                 :            :                 return -EINVAL;
      28                 :            : 
      29                 :          0 :         vunmap(dmab->area);
      30                 :          0 :         dmab->area = NULL;
      31                 :            : 
      32                 :          0 :         tmpb.dev.type = SNDRV_DMA_TYPE_DEV;
      33         [ #  # ]:          0 :         if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG)
      34                 :          0 :                 tmpb.dev.type = SNDRV_DMA_TYPE_DEV_UC;
      35                 :          0 :         tmpb.dev.dev = sgbuf->dev;
      36         [ #  # ]:          0 :         for (i = 0; i < sgbuf->pages; i++) {
      37         [ #  # ]:          0 :                 if (!(sgbuf->table[i].addr & ~PAGE_MASK))
      38                 :          0 :                         continue; /* continuous pages */
      39                 :          0 :                 tmpb.area = sgbuf->table[i].buf;
      40                 :          0 :                 tmpb.addr = sgbuf->table[i].addr & PAGE_MASK;
      41                 :          0 :                 tmpb.bytes = (sgbuf->table[i].addr & ~PAGE_MASK) << PAGE_SHIFT;
      42                 :          0 :                 snd_dma_free_pages(&tmpb);
      43                 :            :         }
      44                 :            : 
      45                 :          0 :         kfree(sgbuf->table);
      46                 :          0 :         kfree(sgbuf->page_table);
      47                 :          0 :         kfree(sgbuf);
      48                 :          0 :         dmab->private_data = NULL;
      49                 :            :         
      50                 :          0 :         return 0;
      51                 :            : }
      52                 :            : 
      53                 :            : #define MAX_ALLOC_PAGES         32
      54                 :            : 
      55                 :          0 : void *snd_malloc_sgbuf_pages(struct device *device,
      56                 :            :                              size_t size, struct snd_dma_buffer *dmab,
      57                 :            :                              size_t *res_size)
      58                 :            : {
      59                 :          0 :         struct snd_sg_buf *sgbuf;
      60                 :          0 :         unsigned int i, pages, chunk, maxpages;
      61                 :          0 :         struct snd_dma_buffer tmpb;
      62                 :          0 :         struct snd_sg_page *table;
      63                 :          0 :         struct page **pgtable;
      64                 :          0 :         int type = SNDRV_DMA_TYPE_DEV;
      65                 :          0 :         pgprot_t prot = PAGE_KERNEL;
      66                 :            : 
      67                 :          0 :         dmab->area = NULL;
      68                 :          0 :         dmab->addr = 0;
      69                 :          0 :         dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL);
      70         [ #  # ]:          0 :         if (! sgbuf)
      71                 :            :                 return NULL;
      72         [ #  # ]:          0 :         if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG) {
      73                 :          0 :                 type = SNDRV_DMA_TYPE_DEV_UC;
      74                 :            : #ifdef pgprot_noncached
      75         [ #  # ]:          0 :                 prot = pgprot_noncached(PAGE_KERNEL);
      76                 :            : #endif
      77                 :            :         }
      78                 :          0 :         sgbuf->dev = device;
      79                 :          0 :         pages = snd_sgbuf_aligned_pages(size);
      80                 :          0 :         sgbuf->tblsize = sgbuf_align_table(pages);
      81                 :          0 :         table = kcalloc(sgbuf->tblsize, sizeof(*table), GFP_KERNEL);
      82         [ #  # ]:          0 :         if (!table)
      83                 :          0 :                 goto _failed;
      84                 :          0 :         sgbuf->table = table;
      85                 :          0 :         pgtable = kcalloc(sgbuf->tblsize, sizeof(*pgtable), GFP_KERNEL);
      86         [ #  # ]:          0 :         if (!pgtable)
      87                 :          0 :                 goto _failed;
      88                 :          0 :         sgbuf->page_table = pgtable;
      89                 :            : 
      90                 :            :         /* allocate pages */
      91                 :          0 :         maxpages = MAX_ALLOC_PAGES;
      92         [ #  # ]:          0 :         while (pages > 0) {
      93                 :          0 :                 chunk = pages;
      94                 :            :                 /* don't be too eager to take a huge chunk */
      95                 :          0 :                 if (chunk > maxpages)
      96                 :            :                         chunk = maxpages;
      97                 :          0 :                 chunk <<= PAGE_SHIFT;
      98         [ #  # ]:          0 :                 if (snd_dma_alloc_pages_fallback(type, device,
      99                 :            :                                                  chunk, &tmpb) < 0) {
     100         [ #  # ]:          0 :                         if (!sgbuf->pages)
     101                 :          0 :                                 goto _failed;
     102         [ #  # ]:          0 :                         if (!res_size)
     103                 :          0 :                                 goto _failed;
     104                 :          0 :                         size = sgbuf->pages * PAGE_SIZE;
     105                 :          0 :                         break;
     106                 :            :                 }
     107                 :          0 :                 chunk = tmpb.bytes >> PAGE_SHIFT;
     108         [ #  # ]:          0 :                 for (i = 0; i < chunk; i++) {
     109                 :          0 :                         table->buf = tmpb.area;
     110                 :          0 :                         table->addr = tmpb.addr;
     111         [ #  # ]:          0 :                         if (!i)
     112                 :          0 :                                 table->addr |= chunk; /* mark head */
     113                 :          0 :                         table++;
     114         [ #  # ]:          0 :                         *pgtable++ = virt_to_page(tmpb.area);
     115                 :          0 :                         tmpb.area += PAGE_SIZE;
     116                 :          0 :                         tmpb.addr += PAGE_SIZE;
     117                 :            :                 }
     118                 :          0 :                 sgbuf->pages += chunk;
     119                 :          0 :                 pages -= chunk;
     120                 :          0 :                 if (chunk < maxpages)
     121                 :            :                         maxpages = chunk;
     122                 :            :         }
     123                 :            : 
     124                 :          0 :         sgbuf->size = size;
     125                 :          0 :         dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, prot);
     126         [ #  # ]:          0 :         if (! dmab->area)
     127                 :          0 :                 goto _failed;
     128         [ #  # ]:          0 :         if (res_size)
     129                 :          0 :                 *res_size = sgbuf->size;
     130                 :          0 :         return dmab->area;
     131                 :            : 
     132                 :          0 :  _failed:
     133                 :          0 :         snd_free_sgbuf_pages(dmab); /* free the table */
     134                 :          0 :         return NULL;
     135                 :            : }
     136                 :            : 
     137                 :            : /*
     138                 :            :  * compute the max chunk size with continuous pages on sg-buffer
     139                 :            :  */
     140                 :          0 : unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
     141                 :            :                                       unsigned int ofs, unsigned int size)
     142                 :            : {
     143                 :          0 :         struct snd_sg_buf *sg = dmab->private_data;
     144                 :          0 :         unsigned int start, end, pg;
     145                 :            : 
     146                 :          0 :         start = ofs >> PAGE_SHIFT;
     147                 :          0 :         end = (ofs + size - 1) >> PAGE_SHIFT;
     148                 :            :         /* check page continuity */
     149                 :          0 :         pg = sg->table[start].addr >> PAGE_SHIFT;
     150                 :          0 :         for (;;) {
     151                 :          0 :                 start++;
     152         [ #  # ]:          0 :                 if (start > end)
     153                 :            :                         break;
     154                 :          0 :                 pg++;
     155         [ #  # ]:          0 :                 if ((sg->table[start].addr >> PAGE_SHIFT) != pg)
     156                 :          0 :                         return (start << PAGE_SHIFT) - ofs;
     157                 :            :         }
     158                 :            :         /* ok, all on continuous pages */
     159                 :            :         return size;
     160                 :            : }
     161                 :            : EXPORT_SYMBOL(snd_sgbuf_get_chunk_size);

Generated by: LCOV version 1.14