root/arch/arm/kernel/dma.c

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

DEFINITIONS

This source file includes following definitions.
  1. dma_channel
  2. isa_dma_add
  3. request_dma
  4. free_dma
  5. set_dma_sg
  6. __set_dma_addr
  7. set_dma_count
  8. set_dma_mode
  9. enable_dma
  10. disable_dma
  11. dma_channel_active
  12. set_dma_page
  13. set_dma_speed
  14. get_dma_residue
  15. proc_dma_show
  16. proc_dma_init

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *  linux/arch/arm/kernel/dma.c
   4  *
   5  *  Copyright (C) 1995-2000 Russell King
   6  *
   7  *  Front-end to the DMA handling.  This handles the allocation/freeing
   8  *  of DMA channels, and provides a unified interface to the machines
   9  *  DMA facilities.
  10  */
  11 #include <linux/module.h>
  12 #include <linux/init.h>
  13 #include <linux/spinlock.h>
  14 #include <linux/errno.h>
  15 #include <linux/scatterlist.h>
  16 #include <linux/seq_file.h>
  17 #include <linux/proc_fs.h>
  18 
  19 #include <asm/dma.h>
  20 
  21 #include <asm/mach/dma.h>
  22 
  23 DEFINE_RAW_SPINLOCK(dma_spin_lock);
  24 EXPORT_SYMBOL(dma_spin_lock);
  25 
  26 static dma_t *dma_chan[MAX_DMA_CHANNELS];
  27 
  28 static inline dma_t *dma_channel(unsigned int chan)
  29 {
  30         if (chan >= MAX_DMA_CHANNELS)
  31                 return NULL;
  32 
  33         return dma_chan[chan];
  34 }
  35 
  36 int __init isa_dma_add(unsigned int chan, dma_t *dma)
  37 {
  38         if (!dma->d_ops)
  39                 return -EINVAL;
  40 
  41         sg_init_table(&dma->buf, 1);
  42 
  43         if (dma_chan[chan])
  44                 return -EBUSY;
  45         dma_chan[chan] = dma;
  46         return 0;
  47 }
  48 
  49 /*
  50  * Request DMA channel
  51  *
  52  * On certain platforms, we have to allocate an interrupt as well...
  53  */
  54 int request_dma(unsigned int chan, const char *device_id)
  55 {
  56         dma_t *dma = dma_channel(chan);
  57         int ret;
  58 
  59         if (!dma)
  60                 goto bad_dma;
  61 
  62         if (xchg(&dma->lock, 1) != 0)
  63                 goto busy;
  64 
  65         dma->device_id = device_id;
  66         dma->active    = 0;
  67         dma->invalid   = 1;
  68 
  69         ret = 0;
  70         if (dma->d_ops->request)
  71                 ret = dma->d_ops->request(chan, dma);
  72 
  73         if (ret)
  74                 xchg(&dma->lock, 0);
  75 
  76         return ret;
  77 
  78 bad_dma:
  79         pr_err("dma: trying to allocate DMA%d\n", chan);
  80         return -EINVAL;
  81 
  82 busy:
  83         return -EBUSY;
  84 }
  85 EXPORT_SYMBOL(request_dma);
  86 
  87 /*
  88  * Free DMA channel
  89  *
  90  * On certain platforms, we have to free interrupt as well...
  91  */
  92 void free_dma(unsigned int chan)
  93 {
  94         dma_t *dma = dma_channel(chan);
  95 
  96         if (!dma)
  97                 goto bad_dma;
  98 
  99         if (dma->active) {
 100                 pr_err("dma%d: freeing active DMA\n", chan);
 101                 dma->d_ops->disable(chan, dma);
 102                 dma->active = 0;
 103         }
 104 
 105         if (xchg(&dma->lock, 0) != 0) {
 106                 if (dma->d_ops->free)
 107                         dma->d_ops->free(chan, dma);
 108                 return;
 109         }
 110 
 111         pr_err("dma%d: trying to free free DMA\n", chan);
 112         return;
 113 
 114 bad_dma:
 115         pr_err("dma: trying to free DMA%d\n", chan);
 116 }
 117 EXPORT_SYMBOL(free_dma);
 118 
 119 /* Set DMA Scatter-Gather list
 120  */
 121 void set_dma_sg (unsigned int chan, struct scatterlist *sg, int nr_sg)
 122 {
 123         dma_t *dma = dma_channel(chan);
 124 
 125         if (dma->active)
 126                 pr_err("dma%d: altering DMA SG while DMA active\n", chan);
 127 
 128         dma->sg = sg;
 129         dma->sgcount = nr_sg;
 130         dma->invalid = 1;
 131 }
 132 EXPORT_SYMBOL(set_dma_sg);
 133 
 134 /* Set DMA address
 135  *
 136  * Copy address to the structure, and set the invalid bit
 137  */
 138 void __set_dma_addr (unsigned int chan, void *addr)
 139 {
 140         dma_t *dma = dma_channel(chan);
 141 
 142         if (dma->active)
 143                 pr_err("dma%d: altering DMA address while DMA active\n", chan);
 144 
 145         dma->sg = NULL;
 146         dma->addr = addr;
 147         dma->invalid = 1;
 148 }
 149 EXPORT_SYMBOL(__set_dma_addr);
 150 
 151 /* Set DMA byte count
 152  *
 153  * Copy address to the structure, and set the invalid bit
 154  */
 155 void set_dma_count (unsigned int chan, unsigned long count)
 156 {
 157         dma_t *dma = dma_channel(chan);
 158 
 159         if (dma->active)
 160                 pr_err("dma%d: altering DMA count while DMA active\n", chan);
 161 
 162         dma->sg = NULL;
 163         dma->count = count;
 164         dma->invalid = 1;
 165 }
 166 EXPORT_SYMBOL(set_dma_count);
 167 
 168 /* Set DMA direction mode
 169  */
 170 void set_dma_mode (unsigned int chan, unsigned int mode)
 171 {
 172         dma_t *dma = dma_channel(chan);
 173 
 174         if (dma->active)
 175                 pr_err("dma%d: altering DMA mode while DMA active\n", chan);
 176 
 177         dma->dma_mode = mode;
 178         dma->invalid = 1;
 179 }
 180 EXPORT_SYMBOL(set_dma_mode);
 181 
 182 /* Enable DMA channel
 183  */
 184 void enable_dma (unsigned int chan)
 185 {
 186         dma_t *dma = dma_channel(chan);
 187 
 188         if (!dma->lock)
 189                 goto free_dma;
 190 
 191         if (dma->active == 0) {
 192                 dma->active = 1;
 193                 dma->d_ops->enable(chan, dma);
 194         }
 195         return;
 196 
 197 free_dma:
 198         pr_err("dma%d: trying to enable free DMA\n", chan);
 199         BUG();
 200 }
 201 EXPORT_SYMBOL(enable_dma);
 202 
 203 /* Disable DMA channel
 204  */
 205 void disable_dma (unsigned int chan)
 206 {
 207         dma_t *dma = dma_channel(chan);
 208 
 209         if (!dma->lock)
 210                 goto free_dma;
 211 
 212         if (dma->active == 1) {
 213                 dma->active = 0;
 214                 dma->d_ops->disable(chan, dma);
 215         }
 216         return;
 217 
 218 free_dma:
 219         pr_err("dma%d: trying to disable free DMA\n", chan);
 220         BUG();
 221 }
 222 EXPORT_SYMBOL(disable_dma);
 223 
 224 /*
 225  * Is the specified DMA channel active?
 226  */
 227 int dma_channel_active(unsigned int chan)
 228 {
 229         dma_t *dma = dma_channel(chan);
 230         return dma->active;
 231 }
 232 EXPORT_SYMBOL(dma_channel_active);
 233 
 234 void set_dma_page(unsigned int chan, char pagenr)
 235 {
 236         pr_err("dma%d: trying to set_dma_page\n", chan);
 237 }
 238 EXPORT_SYMBOL(set_dma_page);
 239 
 240 void set_dma_speed(unsigned int chan, int cycle_ns)
 241 {
 242         dma_t *dma = dma_channel(chan);
 243         int ret = 0;
 244 
 245         if (dma->d_ops->setspeed)
 246                 ret = dma->d_ops->setspeed(chan, dma, cycle_ns);
 247         dma->speed = ret;
 248 }
 249 EXPORT_SYMBOL(set_dma_speed);
 250 
 251 int get_dma_residue(unsigned int chan)
 252 {
 253         dma_t *dma = dma_channel(chan);
 254         int ret = 0;
 255 
 256         if (dma->d_ops->residue)
 257                 ret = dma->d_ops->residue(chan, dma);
 258 
 259         return ret;
 260 }
 261 EXPORT_SYMBOL(get_dma_residue);
 262 
 263 #ifdef CONFIG_PROC_FS
 264 static int proc_dma_show(struct seq_file *m, void *v)
 265 {
 266         int i;
 267 
 268         for (i = 0 ; i < MAX_DMA_CHANNELS ; i++) {
 269                 dma_t *dma = dma_channel(i);
 270                 if (dma && dma->lock)
 271                         seq_printf(m, "%2d: %s\n", i, dma->device_id);
 272         }
 273         return 0;
 274 }
 275 
 276 static int __init proc_dma_init(void)
 277 {
 278         proc_create_single("dma", 0, NULL, proc_dma_show);
 279         return 0;
 280 }
 281 
 282 __initcall(proc_dma_init);
 283 #endif

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