LCOV - code coverage report
Current view: top level - drivers/dma - virt-dma.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 29 42 69.0 %
Date: 2020-09-30 20:25:40 Functions: 4 6 66.7 %
Branches: 4 12 33.3 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * Virtual DMA channel support for DMAengine
       4                 :            :  *
       5                 :            :  * Copyright (C) 2012 Russell King
       6                 :            :  */
       7                 :            : #include <linux/device.h>
       8                 :            : #include <linux/dmaengine.h>
       9                 :            : #include <linux/module.h>
      10                 :            : #include <linux/spinlock.h>
      11                 :            : 
      12                 :            : #include "virt-dma.h"
      13                 :            : 
      14                 :            : static struct virt_dma_desc *to_virt_desc(struct dma_async_tx_descriptor *tx)
      15                 :            : {
      16                 :            :         return container_of(tx, struct virt_dma_desc, tx);
      17                 :            : }
      18                 :            : 
      19                 :    1041277 : dma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *tx)
      20                 :            : {
      21                 :    1041277 :         struct virt_dma_chan *vc = to_virt_chan(tx->chan);
      22                 :            :         struct virt_dma_desc *vd = to_virt_desc(tx);
      23                 :            :         unsigned long flags;
      24                 :            :         dma_cookie_t cookie;
      25                 :            : 
      26                 :    1041277 :         spin_lock_irqsave(&vc->lock, flags);
      27                 :            :         cookie = dma_cookie_assign(tx);
      28                 :            : 
      29                 :    1041277 :         list_move_tail(&vd->node, &vc->desc_submitted);
      30                 :            :         spin_unlock_irqrestore(&vc->lock, flags);
      31                 :            : 
      32                 :            :         dev_dbg(vc->chan.device->dev, "vchan %p: txd %p[%x]: submitted\n",
      33                 :            :                 vc, vd, cookie);
      34                 :            : 
      35                 :    1041277 :         return cookie;
      36                 :            : }
      37                 :            : EXPORT_SYMBOL_GPL(vchan_tx_submit);
      38                 :            : 
      39                 :            : /**
      40                 :            :  * vchan_tx_desc_free - free a reusable descriptor
      41                 :            :  * @tx: the transfer
      42                 :            :  *
      43                 :            :  * This function frees a previously allocated reusable descriptor. The only
      44                 :            :  * other way is to clear the DMA_CTRL_REUSE flag and submit one last time the
      45                 :            :  * transfer.
      46                 :            :  *
      47                 :            :  * Returns 0 upon success
      48                 :            :  */
      49                 :          0 : int vchan_tx_desc_free(struct dma_async_tx_descriptor *tx)
      50                 :            : {
      51                 :          0 :         struct virt_dma_chan *vc = to_virt_chan(tx->chan);
      52                 :            :         struct virt_dma_desc *vd = to_virt_desc(tx);
      53                 :            :         unsigned long flags;
      54                 :            : 
      55                 :          0 :         spin_lock_irqsave(&vc->lock, flags);
      56                 :            :         list_del(&vd->node);
      57                 :            :         spin_unlock_irqrestore(&vc->lock, flags);
      58                 :            : 
      59                 :            :         dev_dbg(vc->chan.device->dev, "vchan %p: txd %p[%x]: freeing\n",
      60                 :            :                 vc, vd, vd->tx.cookie);
      61                 :          0 :         vc->desc_free(vd);
      62                 :          0 :         return 0;
      63                 :            : }
      64                 :            : EXPORT_SYMBOL_GPL(vchan_tx_desc_free);
      65                 :            : 
      66                 :          0 : struct virt_dma_desc *vchan_find_desc(struct virt_dma_chan *vc,
      67                 :            :         dma_cookie_t cookie)
      68                 :            : {
      69                 :            :         struct virt_dma_desc *vd;
      70                 :            : 
      71         [ #  # ]:          0 :         list_for_each_entry(vd, &vc->desc_issued, node)
      72         [ #  # ]:          0 :                 if (vd->tx.cookie == cookie)
      73                 :          0 :                         return vd;
      74                 :            : 
      75                 :            :         return NULL;
      76                 :            : }
      77                 :            : EXPORT_SYMBOL_GPL(vchan_find_desc);
      78                 :            : 
      79                 :            : /*
      80                 :            :  * This tasklet handles the completion of a DMA descriptor by
      81                 :            :  * calling its callback and freeing it.
      82                 :            :  */
      83                 :    1041276 : static void vchan_complete(unsigned long arg)
      84                 :            : {
      85                 :    1041276 :         struct virt_dma_chan *vc = (struct virt_dma_chan *)arg;
      86                 :            :         struct virt_dma_desc *vd, *_vd;
      87                 :            :         struct dmaengine_desc_callback cb;
      88                 :    1041276 :         LIST_HEAD(head);
      89                 :            : 
      90                 :            :         spin_lock_irq(&vc->lock);
      91                 :    1041276 :         list_splice_tail_init(&vc->desc_completed, &head);
      92                 :    1041276 :         vd = vc->cyclic;
      93         [ -  + ]:    1041276 :         if (vd) {
      94                 :          0 :                 vc->cyclic = NULL;
      95                 :            :                 dmaengine_desc_get_callback(&vd->tx, &cb);
      96                 :            :         } else {
      97                 :    1041276 :                 memset(&cb, 0, sizeof(cb));
      98                 :            :         }
      99                 :            :         spin_unlock_irq(&vc->lock);
     100                 :            : 
     101                 :    1041276 :         dmaengine_desc_callback_invoke(&cb, &vd->tx_result);
     102                 :            : 
     103         [ +  + ]:    2082552 :         list_for_each_entry_safe(vd, _vd, &head, node) {
     104                 :            :                 dmaengine_desc_get_callback(&vd->tx, &cb);
     105                 :            : 
     106                 :            :                 list_del(&vd->node);
     107                 :    1041276 :                 dmaengine_desc_callback_invoke(&cb, &vd->tx_result);
     108                 :            :                 vchan_vdesc_fini(vd);
     109                 :            :         }
     110                 :    1041276 : }
     111                 :            : 
     112                 :        207 : void vchan_dma_desc_free_list(struct virt_dma_chan *vc, struct list_head *head)
     113                 :            : {
     114                 :            :         struct virt_dma_desc *vd, *_vd;
     115                 :            : 
     116         [ -  + ]:        207 :         list_for_each_entry_safe(vd, _vd, head, node) {
     117         [ #  # ]:          0 :                 if (dmaengine_desc_test_reuse(&vd->tx)) {
     118                 :          0 :                         list_move_tail(&vd->node, &vc->desc_allocated);
     119                 :            :                 } else {
     120                 :            :                         dev_dbg(vc->chan.device->dev, "txd %p: freeing\n", vd);
     121                 :            :                         list_del(&vd->node);
     122                 :          0 :                         vc->desc_free(vd);
     123                 :            :                 }
     124                 :            :         }
     125                 :        207 : }
     126                 :            : EXPORT_SYMBOL_GPL(vchan_dma_desc_free_list);
     127                 :            : 
     128                 :       2070 : void vchan_init(struct virt_dma_chan *vc, struct dma_device *dmadev)
     129                 :            : {
     130                 :            :         dma_cookie_init(&vc->chan);
     131                 :            : 
     132                 :       2070 :         spin_lock_init(&vc->lock);
     133                 :       2070 :         INIT_LIST_HEAD(&vc->desc_allocated);
     134                 :       2070 :         INIT_LIST_HEAD(&vc->desc_submitted);
     135                 :       2070 :         INIT_LIST_HEAD(&vc->desc_issued);
     136                 :       2070 :         INIT_LIST_HEAD(&vc->desc_completed);
     137                 :            : 
     138                 :       2070 :         tasklet_init(&vc->task, vchan_complete, (unsigned long)vc);
     139                 :            : 
     140                 :       2070 :         vc->chan.device = dmadev;
     141                 :       2070 :         list_add_tail(&vc->chan.device_node, &dmadev->channels);
     142                 :       2070 : }
     143                 :            : EXPORT_SYMBOL_GPL(vchan_init);
     144                 :            : 
     145                 :            : MODULE_AUTHOR("Russell King");
     146                 :            : MODULE_LICENSE("GPL");

Generated by: LCOV version 1.14