root/arch/sh/drivers/dma/dma-api.c

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

DEFINITIONS

This source file includes following definitions.
  1. get_dma_info
  2. get_dma_info_by_name
  3. get_nr_channels
  4. get_dma_channel
  5. get_dma_residue
  6. search_cap
  7. request_dma_bycap
  8. dmac_search_free_channel
  9. request_dma
  10. free_dma
  11. dma_wait_for_completion
  12. register_chan_caps
  13. dma_configure_channel
  14. dma_xfer
  15. dma_extend
  16. dma_proc_show
  17. register_dmac
  18. unregister_dmac
  19. dma_api_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * arch/sh/drivers/dma/dma-api.c
   4  *
   5  * SuperH-specific DMA management API
   6  *
   7  * Copyright (C) 2003, 2004, 2005  Paul Mundt
   8  */
   9 #include <linux/init.h>
  10 #include <linux/module.h>
  11 #include <linux/spinlock.h>
  12 #include <linux/proc_fs.h>
  13 #include <linux/seq_file.h>
  14 #include <linux/list.h>
  15 #include <linux/platform_device.h>
  16 #include <linux/mm.h>
  17 #include <linux/sched.h>
  18 #include <linux/slab.h>
  19 #include <asm/dma.h>
  20 
  21 DEFINE_SPINLOCK(dma_spin_lock);
  22 static LIST_HEAD(registered_dmac_list);
  23 
  24 struct dma_info *get_dma_info(unsigned int chan)
  25 {
  26         struct dma_info *info;
  27 
  28         /*
  29          * Look for each DMAC's range to determine who the owner of
  30          * the channel is.
  31          */
  32         list_for_each_entry(info, &registered_dmac_list, list) {
  33                 if ((chan <  info->first_vchannel_nr) ||
  34                     (chan >= info->first_vchannel_nr + info->nr_channels))
  35                         continue;
  36 
  37                 return info;
  38         }
  39 
  40         return NULL;
  41 }
  42 EXPORT_SYMBOL(get_dma_info);
  43 
  44 struct dma_info *get_dma_info_by_name(const char *dmac_name)
  45 {
  46         struct dma_info *info;
  47 
  48         list_for_each_entry(info, &registered_dmac_list, list) {
  49                 if (dmac_name && (strcmp(dmac_name, info->name) != 0))
  50                         continue;
  51                 else
  52                         return info;
  53         }
  54 
  55         return NULL;
  56 }
  57 EXPORT_SYMBOL(get_dma_info_by_name);
  58 
  59 static unsigned int get_nr_channels(void)
  60 {
  61         struct dma_info *info;
  62         unsigned int nr = 0;
  63 
  64         if (unlikely(list_empty(&registered_dmac_list)))
  65                 return nr;
  66 
  67         list_for_each_entry(info, &registered_dmac_list, list)
  68                 nr += info->nr_channels;
  69 
  70         return nr;
  71 }
  72 
  73 struct dma_channel *get_dma_channel(unsigned int chan)
  74 {
  75         struct dma_info *info = get_dma_info(chan);
  76         struct dma_channel *channel;
  77         int i;
  78 
  79         if (unlikely(!info))
  80                 return ERR_PTR(-EINVAL);
  81 
  82         for (i = 0; i < info->nr_channels; i++) {
  83                 channel = &info->channels[i];
  84                 if (channel->vchan == chan)
  85                         return channel;
  86         }
  87 
  88         return NULL;
  89 }
  90 EXPORT_SYMBOL(get_dma_channel);
  91 
  92 int get_dma_residue(unsigned int chan)
  93 {
  94         struct dma_info *info = get_dma_info(chan);
  95         struct dma_channel *channel = get_dma_channel(chan);
  96 
  97         if (info->ops->get_residue)
  98                 return info->ops->get_residue(channel);
  99 
 100         return 0;
 101 }
 102 EXPORT_SYMBOL(get_dma_residue);
 103 
 104 static int search_cap(const char **haystack, const char *needle)
 105 {
 106         const char **p;
 107 
 108         for (p = haystack; *p; p++)
 109                 if (strcmp(*p, needle) == 0)
 110                         return 1;
 111 
 112         return 0;
 113 }
 114 
 115 /**
 116  * request_dma_bycap - Allocate a DMA channel based on its capabilities
 117  * @dmac: List of DMA controllers to search
 118  * @caps: List of capabilities
 119  *
 120  * Search all channels of all DMA controllers to find a channel which
 121  * matches the requested capabilities. The result is the channel
 122  * number if a match is found, or %-ENODEV if no match is found.
 123  *
 124  * Note that not all DMA controllers export capabilities, in which
 125  * case they can never be allocated using this API, and so
 126  * request_dma() must be used specifying the channel number.
 127  */
 128 int request_dma_bycap(const char **dmac, const char **caps, const char *dev_id)
 129 {
 130         unsigned int found = 0;
 131         struct dma_info *info;
 132         const char **p;
 133         int i;
 134 
 135         BUG_ON(!dmac || !caps);
 136 
 137         list_for_each_entry(info, &registered_dmac_list, list)
 138                 if (strcmp(*dmac, info->name) == 0) {
 139                         found = 1;
 140                         break;
 141                 }
 142 
 143         if (!found)
 144                 return -ENODEV;
 145 
 146         for (i = 0; i < info->nr_channels; i++) {
 147                 struct dma_channel *channel = &info->channels[i];
 148 
 149                 if (unlikely(!channel->caps))
 150                         continue;
 151 
 152                 for (p = caps; *p; p++) {
 153                         if (!search_cap(channel->caps, *p))
 154                                 break;
 155                         if (request_dma(channel->chan, dev_id) == 0)
 156                                 return channel->chan;
 157                 }
 158         }
 159 
 160         return -EINVAL;
 161 }
 162 EXPORT_SYMBOL(request_dma_bycap);
 163 
 164 int dmac_search_free_channel(const char *dev_id)
 165 {
 166         struct dma_channel *channel = { 0 };
 167         struct dma_info *info = get_dma_info(0);
 168         int i;
 169 
 170         for (i = 0; i < info->nr_channels; i++) {
 171                 channel = &info->channels[i];
 172                 if (unlikely(!channel))
 173                         return -ENODEV;
 174 
 175                 if (atomic_read(&channel->busy) == 0)
 176                         break;
 177         }
 178 
 179         if (info->ops->request) {
 180                 int result = info->ops->request(channel);
 181                 if (result)
 182                         return result;
 183 
 184                 atomic_set(&channel->busy, 1);
 185                 return channel->chan;
 186         }
 187 
 188         return -ENOSYS;
 189 }
 190 
 191 int request_dma(unsigned int chan, const char *dev_id)
 192 {
 193         struct dma_channel *channel = { 0 };
 194         struct dma_info *info = get_dma_info(chan);
 195         int result;
 196 
 197         channel = get_dma_channel(chan);
 198         if (atomic_xchg(&channel->busy, 1))
 199                 return -EBUSY;
 200 
 201         strlcpy(channel->dev_id, dev_id, sizeof(channel->dev_id));
 202 
 203         if (info->ops->request) {
 204                 result = info->ops->request(channel);
 205                 if (result)
 206                         atomic_set(&channel->busy, 0);
 207 
 208                 return result;
 209         }
 210 
 211         return 0;
 212 }
 213 EXPORT_SYMBOL(request_dma);
 214 
 215 void free_dma(unsigned int chan)
 216 {
 217         struct dma_info *info = get_dma_info(chan);
 218         struct dma_channel *channel = get_dma_channel(chan);
 219 
 220         if (info->ops->free)
 221                 info->ops->free(channel);
 222 
 223         atomic_set(&channel->busy, 0);
 224 }
 225 EXPORT_SYMBOL(free_dma);
 226 
 227 void dma_wait_for_completion(unsigned int chan)
 228 {
 229         struct dma_info *info = get_dma_info(chan);
 230         struct dma_channel *channel = get_dma_channel(chan);
 231 
 232         if (channel->flags & DMA_TEI_CAPABLE) {
 233                 wait_event(channel->wait_queue,
 234                            (info->ops->get_residue(channel) == 0));
 235                 return;
 236         }
 237 
 238         while (info->ops->get_residue(channel))
 239                 cpu_relax();
 240 }
 241 EXPORT_SYMBOL(dma_wait_for_completion);
 242 
 243 int register_chan_caps(const char *dmac, struct dma_chan_caps *caps)
 244 {
 245         struct dma_info *info;
 246         unsigned int found = 0;
 247         int i;
 248 
 249         list_for_each_entry(info, &registered_dmac_list, list)
 250                 if (strcmp(dmac, info->name) == 0) {
 251                         found = 1;
 252                         break;
 253                 }
 254 
 255         if (unlikely(!found))
 256                 return -ENODEV;
 257 
 258         for (i = 0; i < info->nr_channels; i++, caps++) {
 259                 struct dma_channel *channel;
 260 
 261                 if ((info->first_channel_nr + i) != caps->ch_num)
 262                         return -EINVAL;
 263 
 264                 channel = &info->channels[i];
 265                 channel->caps = caps->caplist;
 266         }
 267 
 268         return 0;
 269 }
 270 EXPORT_SYMBOL(register_chan_caps);
 271 
 272 void dma_configure_channel(unsigned int chan, unsigned long flags)
 273 {
 274         struct dma_info *info = get_dma_info(chan);
 275         struct dma_channel *channel = get_dma_channel(chan);
 276 
 277         if (info->ops->configure)
 278                 info->ops->configure(channel, flags);
 279 }
 280 EXPORT_SYMBOL(dma_configure_channel);
 281 
 282 int dma_xfer(unsigned int chan, unsigned long from,
 283              unsigned long to, size_t size, unsigned int mode)
 284 {
 285         struct dma_info *info = get_dma_info(chan);
 286         struct dma_channel *channel = get_dma_channel(chan);
 287 
 288         channel->sar    = from;
 289         channel->dar    = to;
 290         channel->count  = size;
 291         channel->mode   = mode;
 292 
 293         return info->ops->xfer(channel);
 294 }
 295 EXPORT_SYMBOL(dma_xfer);
 296 
 297 int dma_extend(unsigned int chan, unsigned long op, void *param)
 298 {
 299         struct dma_info *info = get_dma_info(chan);
 300         struct dma_channel *channel = get_dma_channel(chan);
 301 
 302         if (info->ops->extend)
 303                 return info->ops->extend(channel, op, param);
 304 
 305         return -ENOSYS;
 306 }
 307 EXPORT_SYMBOL(dma_extend);
 308 
 309 static int dma_proc_show(struct seq_file *m, void *v)
 310 {
 311         struct dma_info *info = v;
 312 
 313         if (list_empty(&registered_dmac_list))
 314                 return 0;
 315 
 316         /*
 317          * Iterate over each registered DMAC
 318          */
 319         list_for_each_entry(info, &registered_dmac_list, list) {
 320                 int i;
 321 
 322                 /*
 323                  * Iterate over each channel
 324                  */
 325                 for (i = 0; i < info->nr_channels; i++) {
 326                         struct dma_channel *channel = info->channels + i;
 327 
 328                         if (!(channel->flags & DMA_CONFIGURED))
 329                                 continue;
 330 
 331                         seq_printf(m, "%2d: %14s    %s\n", i,
 332                                    info->name, channel->dev_id);
 333                 }
 334         }
 335 
 336         return 0;
 337 }
 338 
 339 int register_dmac(struct dma_info *info)
 340 {
 341         unsigned int total_channels, i;
 342 
 343         INIT_LIST_HEAD(&info->list);
 344 
 345         printk(KERN_INFO "DMA: Registering %s handler (%d channel%s).\n",
 346                info->name, info->nr_channels, info->nr_channels > 1 ? "s" : "");
 347 
 348         BUG_ON((info->flags & DMAC_CHANNELS_CONFIGURED) && !info->channels);
 349 
 350         info->pdev = platform_device_register_simple(info->name, -1,
 351                                                      NULL, 0);
 352         if (IS_ERR(info->pdev))
 353                 return PTR_ERR(info->pdev);
 354 
 355         /*
 356          * Don't touch pre-configured channels
 357          */
 358         if (!(info->flags & DMAC_CHANNELS_CONFIGURED)) {
 359                 unsigned int size;
 360 
 361                 size = sizeof(struct dma_channel) * info->nr_channels;
 362 
 363                 info->channels = kzalloc(size, GFP_KERNEL);
 364                 if (!info->channels)
 365                         return -ENOMEM;
 366         }
 367 
 368         total_channels = get_nr_channels();
 369         info->first_vchannel_nr = total_channels;
 370         for (i = 0; i < info->nr_channels; i++) {
 371                 struct dma_channel *chan = &info->channels[i];
 372 
 373                 atomic_set(&chan->busy, 0);
 374 
 375                 chan->chan  = info->first_channel_nr + i;
 376                 chan->vchan = info->first_channel_nr + i + total_channels;
 377 
 378                 memcpy(chan->dev_id, "Unused", 7);
 379 
 380                 if (info->flags & DMAC_CHANNELS_TEI_CAPABLE)
 381                         chan->flags |= DMA_TEI_CAPABLE;
 382 
 383                 init_waitqueue_head(&chan->wait_queue);
 384                 dma_create_sysfs_files(chan, info);
 385         }
 386 
 387         list_add(&info->list, &registered_dmac_list);
 388 
 389         return 0;
 390 }
 391 EXPORT_SYMBOL(register_dmac);
 392 
 393 void unregister_dmac(struct dma_info *info)
 394 {
 395         unsigned int i;
 396 
 397         for (i = 0; i < info->nr_channels; i++)
 398                 dma_remove_sysfs_files(info->channels + i, info);
 399 
 400         if (!(info->flags & DMAC_CHANNELS_CONFIGURED))
 401                 kfree(info->channels);
 402 
 403         list_del(&info->list);
 404         platform_device_unregister(info->pdev);
 405 }
 406 EXPORT_SYMBOL(unregister_dmac);
 407 
 408 static int __init dma_api_init(void)
 409 {
 410         printk(KERN_NOTICE "DMA: Registering DMA API.\n");
 411         return proc_create_single("dma", 0, NULL, dma_proc_show) ? 0 : -ENOMEM;
 412 }
 413 subsys_initcall(dma_api_init);
 414 
 415 MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
 416 MODULE_DESCRIPTION("DMA API for SuperH");
 417 MODULE_LICENSE("GPL v2");

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