root/drivers/dma/coh901318_lli.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. coh901318_lli_next
  2. coh901318_pool_create
  3. coh901318_pool_destroy
  4. coh901318_lli_alloc
  5. coh901318_lli_free
  6. coh901318_lli_fill_memcpy
  7. coh901318_lli_fill_single
  8. coh901318_lli_fill_sg

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * driver/dma/coh901318_lli.c
   4  *
   5  * Copyright (C) 2007-2009 ST-Ericsson
   6  * Support functions for handling lli for dma
   7  * Author: Per Friden <per.friden@stericsson.com>
   8  */
   9 
  10 #include <linux/spinlock.h>
  11 #include <linux/memory.h>
  12 #include <linux/gfp.h>
  13 #include <linux/dmapool.h>
  14 #include <linux/dmaengine.h>
  15 
  16 #include "coh901318.h"
  17 
  18 #if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_U300_DEBUG))
  19 #define DEBUGFS_POOL_COUNTER_RESET(pool) (pool->debugfs_pool_counter = 0)
  20 #define DEBUGFS_POOL_COUNTER_ADD(pool, add) (pool->debugfs_pool_counter += add)
  21 #else
  22 #define DEBUGFS_POOL_COUNTER_RESET(pool)
  23 #define DEBUGFS_POOL_COUNTER_ADD(pool, add)
  24 #endif
  25 
  26 static struct coh901318_lli *
  27 coh901318_lli_next(struct coh901318_lli *data)
  28 {
  29         if (data == NULL || data->link_addr == 0)
  30                 return NULL;
  31 
  32         return (struct coh901318_lli *) data->virt_link_addr;
  33 }
  34 
  35 int coh901318_pool_create(struct coh901318_pool *pool,
  36                           struct device *dev,
  37                           size_t size, size_t align)
  38 {
  39         spin_lock_init(&pool->lock);
  40         pool->dev = dev;
  41         pool->dmapool = dma_pool_create("lli_pool", dev, size, align, 0);
  42 
  43         DEBUGFS_POOL_COUNTER_RESET(pool);
  44         return 0;
  45 }
  46 
  47 int coh901318_pool_destroy(struct coh901318_pool *pool)
  48 {
  49 
  50         dma_pool_destroy(pool->dmapool);
  51         return 0;
  52 }
  53 
  54 struct coh901318_lli *
  55 coh901318_lli_alloc(struct coh901318_pool *pool, unsigned int len)
  56 {
  57         int i;
  58         struct coh901318_lli *head;
  59         struct coh901318_lli *lli;
  60         struct coh901318_lli *lli_prev;
  61         dma_addr_t phy;
  62 
  63         if (len == 0)
  64                 return NULL;
  65 
  66         spin_lock(&pool->lock);
  67 
  68         head = dma_pool_alloc(pool->dmapool, GFP_NOWAIT, &phy);
  69 
  70         if (head == NULL)
  71                 goto err;
  72 
  73         DEBUGFS_POOL_COUNTER_ADD(pool, 1);
  74 
  75         lli = head;
  76         lli->phy_this = phy;
  77         lli->link_addr = 0x00000000;
  78         lli->virt_link_addr = NULL;
  79 
  80         for (i = 1; i < len; i++) {
  81                 lli_prev = lli;
  82 
  83                 lli = dma_pool_alloc(pool->dmapool, GFP_NOWAIT, &phy);
  84 
  85                 if (lli == NULL)
  86                         goto err_clean_up;
  87 
  88                 DEBUGFS_POOL_COUNTER_ADD(pool, 1);
  89                 lli->phy_this = phy;
  90                 lli->link_addr = 0x00000000;
  91                 lli->virt_link_addr = NULL;
  92 
  93                 lli_prev->link_addr = phy;
  94                 lli_prev->virt_link_addr = lli;
  95         }
  96 
  97         spin_unlock(&pool->lock);
  98 
  99         return head;
 100 
 101  err:
 102         spin_unlock(&pool->lock);
 103         return NULL;
 104 
 105  err_clean_up:
 106         lli_prev->link_addr = 0x00000000U;
 107         spin_unlock(&pool->lock);
 108         coh901318_lli_free(pool, &head);
 109         return NULL;
 110 }
 111 
 112 void coh901318_lli_free(struct coh901318_pool *pool,
 113                         struct coh901318_lli **lli)
 114 {
 115         struct coh901318_lli *l;
 116         struct coh901318_lli *next;
 117 
 118         if (lli == NULL)
 119                 return;
 120 
 121         l = *lli;
 122 
 123         if (l == NULL)
 124                 return;
 125 
 126         spin_lock(&pool->lock);
 127 
 128         while (l->link_addr) {
 129                 next = l->virt_link_addr;
 130                 dma_pool_free(pool->dmapool, l, l->phy_this);
 131                 DEBUGFS_POOL_COUNTER_ADD(pool, -1);
 132                 l = next;
 133         }
 134         dma_pool_free(pool->dmapool, l, l->phy_this);
 135         DEBUGFS_POOL_COUNTER_ADD(pool, -1);
 136 
 137         spin_unlock(&pool->lock);
 138         *lli = NULL;
 139 }
 140 
 141 int
 142 coh901318_lli_fill_memcpy(struct coh901318_pool *pool,
 143                           struct coh901318_lli *lli,
 144                           dma_addr_t source, unsigned int size,
 145                           dma_addr_t destination, u32 ctrl_chained,
 146                           u32 ctrl_eom)
 147 {
 148         int s = size;
 149         dma_addr_t src = source;
 150         dma_addr_t dst = destination;
 151 
 152         lli->src_addr = src;
 153         lli->dst_addr = dst;
 154 
 155         while (lli->link_addr) {
 156                 lli->control = ctrl_chained | MAX_DMA_PACKET_SIZE;
 157                 lli->src_addr = src;
 158                 lli->dst_addr = dst;
 159 
 160                 s -= MAX_DMA_PACKET_SIZE;
 161                 lli = coh901318_lli_next(lli);
 162 
 163                 src += MAX_DMA_PACKET_SIZE;
 164                 dst += MAX_DMA_PACKET_SIZE;
 165         }
 166 
 167         lli->control = ctrl_eom | s;
 168         lli->src_addr = src;
 169         lli->dst_addr = dst;
 170 
 171         return 0;
 172 }
 173 
 174 int
 175 coh901318_lli_fill_single(struct coh901318_pool *pool,
 176                           struct coh901318_lli *lli,
 177                           dma_addr_t buf, unsigned int size,
 178                           dma_addr_t dev_addr, u32 ctrl_chained, u32 ctrl_eom,
 179                           enum dma_transfer_direction dir)
 180 {
 181         int s = size;
 182         dma_addr_t src;
 183         dma_addr_t dst;
 184 
 185 
 186         if (dir == DMA_MEM_TO_DEV) {
 187                 src = buf;
 188                 dst = dev_addr;
 189 
 190         } else if (dir == DMA_DEV_TO_MEM) {
 191 
 192                 src = dev_addr;
 193                 dst = buf;
 194         } else {
 195                 return -EINVAL;
 196         }
 197 
 198         while (lli->link_addr) {
 199                 size_t block_size = MAX_DMA_PACKET_SIZE;
 200                 lli->control = ctrl_chained | MAX_DMA_PACKET_SIZE;
 201 
 202                 /* If we are on the next-to-final block and there will
 203                  * be less than half a DMA packet left for the last
 204                  * block, then we want to make this block a little
 205                  * smaller to balance the sizes. This is meant to
 206                  * avoid too small transfers if the buffer size is
 207                  * (MAX_DMA_PACKET_SIZE*N + 1) */
 208                 if (s < (MAX_DMA_PACKET_SIZE + MAX_DMA_PACKET_SIZE/2))
 209                         block_size = MAX_DMA_PACKET_SIZE/2;
 210 
 211                 s -= block_size;
 212                 lli->src_addr = src;
 213                 lli->dst_addr = dst;
 214 
 215                 lli = coh901318_lli_next(lli);
 216 
 217                 if (dir == DMA_MEM_TO_DEV)
 218                         src += block_size;
 219                 else if (dir == DMA_DEV_TO_MEM)
 220                         dst += block_size;
 221         }
 222 
 223         lli->control = ctrl_eom | s;
 224         lli->src_addr = src;
 225         lli->dst_addr = dst;
 226 
 227         return 0;
 228 }
 229 
 230 int
 231 coh901318_lli_fill_sg(struct coh901318_pool *pool,
 232                       struct coh901318_lli *lli,
 233                       struct scatterlist *sgl, unsigned int nents,
 234                       dma_addr_t dev_addr, u32 ctrl_chained, u32 ctrl,
 235                       u32 ctrl_last,
 236                       enum dma_transfer_direction dir, u32 ctrl_irq_mask)
 237 {
 238         int i;
 239         struct scatterlist *sg;
 240         u32 ctrl_sg;
 241         dma_addr_t src = 0;
 242         dma_addr_t dst = 0;
 243         u32 bytes_to_transfer;
 244         u32 elem_size;
 245 
 246         if (lli == NULL)
 247                 goto err;
 248 
 249         spin_lock(&pool->lock);
 250 
 251         if (dir == DMA_MEM_TO_DEV)
 252                 dst = dev_addr;
 253         else if (dir == DMA_DEV_TO_MEM)
 254                 src = dev_addr;
 255         else
 256                 goto err;
 257 
 258         for_each_sg(sgl, sg, nents, i) {
 259                 if (sg_is_chain(sg)) {
 260                         /* sg continues to the next sg-element don't
 261                          * send ctrl_finish until the last
 262                          * sg-element in the chain
 263                          */
 264                         ctrl_sg = ctrl_chained;
 265                 } else if (i == nents - 1)
 266                         ctrl_sg = ctrl_last;
 267                 else
 268                         ctrl_sg = ctrl ? ctrl : ctrl_last;
 269 
 270 
 271                 if (dir == DMA_MEM_TO_DEV)
 272                         /* increment source address */
 273                         src = sg_dma_address(sg);
 274                 else
 275                         /* increment destination address */
 276                         dst = sg_dma_address(sg);
 277 
 278                 bytes_to_transfer = sg_dma_len(sg);
 279 
 280                 while (bytes_to_transfer) {
 281                         u32 val;
 282 
 283                         if (bytes_to_transfer > MAX_DMA_PACKET_SIZE) {
 284                                 elem_size = MAX_DMA_PACKET_SIZE;
 285                                 val = ctrl_chained;
 286                         } else {
 287                                 elem_size = bytes_to_transfer;
 288                                 val = ctrl_sg;
 289                         }
 290 
 291                         lli->control = val | elem_size;
 292                         lli->src_addr = src;
 293                         lli->dst_addr = dst;
 294 
 295                         if (dir == DMA_DEV_TO_MEM)
 296                                 dst += elem_size;
 297                         else
 298                                 src += elem_size;
 299 
 300                         BUG_ON(lli->link_addr & 3);
 301 
 302                         bytes_to_transfer -= elem_size;
 303                         lli = coh901318_lli_next(lli);
 304                 }
 305 
 306         }
 307         spin_unlock(&pool->lock);
 308 
 309         return 0;
 310  err:
 311         spin_unlock(&pool->lock);
 312         return -EINVAL;
 313 }

/* [<][>][^][v][top][bottom][index][help] */