2 * arch/sh/drivers/dma/dma-api.c
4 * SuperH-specific DMA management API
6 * Copyright (C) 2003, 2004, 2005 Paul Mundt
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/spinlock.h>
15 #include <linux/proc_fs.h>
16 #include <linux/seq_file.h>
17 #include <linux/list.h>
18 #include <linux/platform_device.h>
20 #include <linux/sched.h>
21 #include <linux/slab.h>
24 DEFINE_SPINLOCK(dma_spin_lock
);
25 static LIST_HEAD(registered_dmac_list
);
27 struct dma_info
*get_dma_info(unsigned int chan
)
29 struct dma_info
*info
;
32 * Look for each DMAC's range to determine who the owner of
35 list_for_each_entry(info
, ®istered_dmac_list
, list
) {
36 if ((chan
< info
->first_vchannel_nr
) ||
37 (chan
>= info
->first_vchannel_nr
+ info
->nr_channels
))
45 EXPORT_SYMBOL(get_dma_info
);
47 struct dma_info
*get_dma_info_by_name(const char *dmac_name
)
49 struct dma_info
*info
;
51 list_for_each_entry(info
, ®istered_dmac_list
, list
) {
52 if (dmac_name
&& (strcmp(dmac_name
, info
->name
) != 0))
60 EXPORT_SYMBOL(get_dma_info_by_name
);
62 static unsigned int get_nr_channels(void)
64 struct dma_info
*info
;
67 if (unlikely(list_empty(®istered_dmac_list
)))
70 list_for_each_entry(info
, ®istered_dmac_list
, list
)
71 nr
+= info
->nr_channels
;
76 struct dma_channel
*get_dma_channel(unsigned int chan
)
78 struct dma_info
*info
= get_dma_info(chan
);
79 struct dma_channel
*channel
;
83 return ERR_PTR(-EINVAL
);
85 for (i
= 0; i
< info
->nr_channels
; i
++) {
86 channel
= &info
->channels
[i
];
87 if (channel
->vchan
== chan
)
93 EXPORT_SYMBOL(get_dma_channel
);
95 int get_dma_residue(unsigned int chan
)
97 struct dma_info
*info
= get_dma_info(chan
);
98 struct dma_channel
*channel
= get_dma_channel(chan
);
100 if (info
->ops
->get_residue
)
101 return info
->ops
->get_residue(channel
);
105 EXPORT_SYMBOL(get_dma_residue
);
107 static int search_cap(const char **haystack
, const char *needle
)
111 for (p
= haystack
; *p
; p
++)
112 if (strcmp(*p
, needle
) == 0)
119 * request_dma_bycap - Allocate a DMA channel based on its capabilities
120 * @dmac: List of DMA controllers to search
121 * @caps: List of capabilities
123 * Search all channels of all DMA controllers to find a channel which
124 * matches the requested capabilities. The result is the channel
125 * number if a match is found, or %-ENODEV if no match is found.
127 * Note that not all DMA controllers export capabilities, in which
128 * case they can never be allocated using this API, and so
129 * request_dma() must be used specifying the channel number.
131 int request_dma_bycap(const char **dmac
, const char **caps
, const char *dev_id
)
133 unsigned int found
= 0;
134 struct dma_info
*info
;
138 BUG_ON(!dmac
|| !caps
);
140 list_for_each_entry(info
, ®istered_dmac_list
, list
)
141 if (strcmp(*dmac
, info
->name
) == 0) {
149 for (i
= 0; i
< info
->nr_channels
; i
++) {
150 struct dma_channel
*channel
= &info
->channels
[i
];
152 if (unlikely(!channel
->caps
))
155 for (p
= caps
; *p
; p
++) {
156 if (!search_cap(channel
->caps
, *p
))
158 if (request_dma(channel
->chan
, dev_id
) == 0)
159 return channel
->chan
;
165 EXPORT_SYMBOL(request_dma_bycap
);
167 int dmac_search_free_channel(const char *dev_id
)
169 struct dma_channel
*channel
= { 0 };
170 struct dma_info
*info
= get_dma_info(0);
173 for (i
= 0; i
< info
->nr_channels
; i
++) {
174 channel
= &info
->channels
[i
];
175 if (unlikely(!channel
))
178 if (atomic_read(&channel
->busy
) == 0)
182 if (info
->ops
->request
) {
183 int result
= info
->ops
->request(channel
);
187 atomic_set(&channel
->busy
, 1);
188 return channel
->chan
;
194 int request_dma(unsigned int chan
, const char *dev_id
)
196 struct dma_channel
*channel
= { 0 };
197 struct dma_info
*info
= get_dma_info(chan
);
200 channel
= get_dma_channel(chan
);
201 if (atomic_xchg(&channel
->busy
, 1))
204 strlcpy(channel
->dev_id
, dev_id
, sizeof(channel
->dev_id
));
206 if (info
->ops
->request
) {
207 result
= info
->ops
->request(channel
);
209 atomic_set(&channel
->busy
, 0);
216 EXPORT_SYMBOL(request_dma
);
218 void free_dma(unsigned int chan
)
220 struct dma_info
*info
= get_dma_info(chan
);
221 struct dma_channel
*channel
= get_dma_channel(chan
);
224 info
->ops
->free(channel
);
226 atomic_set(&channel
->busy
, 0);
228 EXPORT_SYMBOL(free_dma
);
230 void dma_wait_for_completion(unsigned int chan
)
232 struct dma_info
*info
= get_dma_info(chan
);
233 struct dma_channel
*channel
= get_dma_channel(chan
);
235 if (channel
->flags
& DMA_TEI_CAPABLE
) {
236 wait_event(channel
->wait_queue
,
237 (info
->ops
->get_residue(channel
) == 0));
241 while (info
->ops
->get_residue(channel
))
244 EXPORT_SYMBOL(dma_wait_for_completion
);
246 int register_chan_caps(const char *dmac
, struct dma_chan_caps
*caps
)
248 struct dma_info
*info
;
249 unsigned int found
= 0;
252 list_for_each_entry(info
, ®istered_dmac_list
, list
)
253 if (strcmp(dmac
, info
->name
) == 0) {
258 if (unlikely(!found
))
261 for (i
= 0; i
< info
->nr_channels
; i
++, caps
++) {
262 struct dma_channel
*channel
;
264 if ((info
->first_channel_nr
+ i
) != caps
->ch_num
)
267 channel
= &info
->channels
[i
];
268 channel
->caps
= caps
->caplist
;
273 EXPORT_SYMBOL(register_chan_caps
);
275 void dma_configure_channel(unsigned int chan
, unsigned long flags
)
277 struct dma_info
*info
= get_dma_info(chan
);
278 struct dma_channel
*channel
= get_dma_channel(chan
);
280 if (info
->ops
->configure
)
281 info
->ops
->configure(channel
, flags
);
283 EXPORT_SYMBOL(dma_configure_channel
);
285 int dma_xfer(unsigned int chan
, unsigned long from
,
286 unsigned long to
, size_t size
, unsigned int mode
)
288 struct dma_info
*info
= get_dma_info(chan
);
289 struct dma_channel
*channel
= get_dma_channel(chan
);
293 channel
->count
= size
;
294 channel
->mode
= mode
;
296 return info
->ops
->xfer(channel
);
298 EXPORT_SYMBOL(dma_xfer
);
300 int dma_extend(unsigned int chan
, unsigned long op
, void *param
)
302 struct dma_info
*info
= get_dma_info(chan
);
303 struct dma_channel
*channel
= get_dma_channel(chan
);
305 if (info
->ops
->extend
)
306 return info
->ops
->extend(channel
, op
, param
);
310 EXPORT_SYMBOL(dma_extend
);
312 static int dma_proc_show(struct seq_file
*m
, void *v
)
314 struct dma_info
*info
= v
;
316 if (list_empty(®istered_dmac_list
))
320 * Iterate over each registered DMAC
322 list_for_each_entry(info
, ®istered_dmac_list
, list
) {
326 * Iterate over each channel
328 for (i
= 0; i
< info
->nr_channels
; i
++) {
329 struct dma_channel
*channel
= info
->channels
+ i
;
331 if (!(channel
->flags
& DMA_CONFIGURED
))
334 seq_printf(m
, "%2d: %14s %s\n", i
,
335 info
->name
, channel
->dev_id
);
342 static int dma_proc_open(struct inode
*inode
, struct file
*file
)
344 return single_open(file
, dma_proc_show
, NULL
);
347 static const struct file_operations dma_proc_fops
= {
348 .open
= dma_proc_open
,
351 .release
= single_release
,
354 int register_dmac(struct dma_info
*info
)
356 unsigned int total_channels
, i
;
358 INIT_LIST_HEAD(&info
->list
);
360 printk(KERN_INFO
"DMA: Registering %s handler (%d channel%s).\n",
361 info
->name
, info
->nr_channels
, info
->nr_channels
> 1 ? "s" : "");
363 BUG_ON((info
->flags
& DMAC_CHANNELS_CONFIGURED
) && !info
->channels
);
365 info
->pdev
= platform_device_register_simple(info
->name
, -1,
367 if (IS_ERR(info
->pdev
))
368 return PTR_ERR(info
->pdev
);
371 * Don't touch pre-configured channels
373 if (!(info
->flags
& DMAC_CHANNELS_CONFIGURED
)) {
376 size
= sizeof(struct dma_channel
) * info
->nr_channels
;
378 info
->channels
= kzalloc(size
, GFP_KERNEL
);
383 total_channels
= get_nr_channels();
384 info
->first_vchannel_nr
= total_channels
;
385 for (i
= 0; i
< info
->nr_channels
; i
++) {
386 struct dma_channel
*chan
= &info
->channels
[i
];
388 atomic_set(&chan
->busy
, 0);
390 chan
->chan
= info
->first_channel_nr
+ i
;
391 chan
->vchan
= info
->first_channel_nr
+ i
+ total_channels
;
393 memcpy(chan
->dev_id
, "Unused", 7);
395 if (info
->flags
& DMAC_CHANNELS_TEI_CAPABLE
)
396 chan
->flags
|= DMA_TEI_CAPABLE
;
398 init_waitqueue_head(&chan
->wait_queue
);
399 dma_create_sysfs_files(chan
, info
);
402 list_add(&info
->list
, ®istered_dmac_list
);
406 EXPORT_SYMBOL(register_dmac
);
408 void unregister_dmac(struct dma_info
*info
)
412 for (i
= 0; i
< info
->nr_channels
; i
++)
413 dma_remove_sysfs_files(info
->channels
+ i
, info
);
415 if (!(info
->flags
& DMAC_CHANNELS_CONFIGURED
))
416 kfree(info
->channels
);
418 list_del(&info
->list
);
419 platform_device_unregister(info
->pdev
);
421 EXPORT_SYMBOL(unregister_dmac
);
423 static int __init
dma_api_init(void)
425 printk(KERN_NOTICE
"DMA: Registering DMA API.\n");
426 return proc_create("dma", 0, NULL
, &dma_proc_fops
) ? 0 : -ENOMEM
;
428 subsys_initcall(dma_api_init
);
430 MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
431 MODULE_DESCRIPTION("DMA API for SuperH");
432 MODULE_LICENSE("GPL");