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