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