linux/arch/arm/plat-pxa/dma.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/plat-pxa/dma.c
   3 *
   4 *  PXA DMA registration and IRQ dispatching
   5 *
   6 *  Author:     Nicolas Pitre
   7 *  Created:    Nov 15, 2001
   8 *  Copyright:  MontaVista Software Inc.
   9 *
  10 *  This program is free software; you can redistribute it and/or modify
  11 *  it under the terms of the GNU General Public License version 2 as
  12 *  published by the Free Software Foundation.
  13 */
  14
  15#include <linux/module.h>
  16#include <linux/init.h>
  17#include <linux/slab.h>
  18#include <linux/kernel.h>
  19#include <linux/interrupt.h>
  20#include <linux/errno.h>
  21#include <linux/dma-mapping.h>
  22
  23#include <asm/irq.h>
  24#include <asm/memory.h>
  25#include <mach/hardware.h>
  26#include <mach/dma.h>
  27
  28#define DMA_DEBUG_NAME          "pxa_dma"
  29#define DMA_MAX_REQUESTERS      64
  30
  31struct dma_channel {
  32        char *name;
  33        pxa_dma_prio prio;
  34        void (*irq_handler)(int, void *);
  35        void *data;
  36        spinlock_t lock;
  37};
  38
  39static struct dma_channel *dma_channels;
  40static int num_dma_channels;
  41
  42/*
  43 * Debug fs
  44 */
  45#ifdef CONFIG_DEBUG_FS
  46#include <linux/debugfs.h>
  47#include <linux/uaccess.h>
  48#include <linux/seq_file.h>
  49
  50static struct dentry *dbgfs_root, *dbgfs_state, **dbgfs_chan;
  51
  52static int dbg_show_requester_chan(struct seq_file *s, void *p)
  53{
  54        int pos = 0;
  55        int chan = (int)s->private;
  56        int i;
  57        u32 drcmr;
  58
  59        pos += seq_printf(s, "DMA channel %d requesters list :\n", chan);
  60        for (i = 0; i < DMA_MAX_REQUESTERS; i++) {
  61                drcmr = DRCMR(i);
  62                if ((drcmr & DRCMR_CHLNUM) == chan)
  63                        pos += seq_printf(s, "\tRequester %d (MAPVLD=%d)\n", i,
  64                                          !!(drcmr & DRCMR_MAPVLD));
  65        }
  66        return pos;
  67}
  68
  69static inline int dbg_burst_from_dcmd(u32 dcmd)
  70{
  71        int burst = (dcmd >> 16) & 0x3;
  72
  73        return burst ? 4 << burst : 0;
  74}
  75
  76static int is_phys_valid(unsigned long addr)
  77{
  78        return pfn_valid(__phys_to_pfn(addr));
  79}
  80
  81#define DCSR_STR(flag) (dcsr & DCSR_##flag ? #flag" " : "")
  82#define DCMD_STR(flag) (dcmd & DCMD_##flag ? #flag" " : "")
  83
  84static int dbg_show_descriptors(struct seq_file *s, void *p)
  85{
  86        int pos = 0;
  87        int chan = (int)s->private;
  88        int i, max_show = 20, burst, width;
  89        u32 dcmd;
  90        unsigned long phys_desc;
  91        struct pxa_dma_desc *desc;
  92        unsigned long flags;
  93
  94        spin_lock_irqsave(&dma_channels[chan].lock, flags);
  95        phys_desc = DDADR(chan);
  96
  97        pos += seq_printf(s, "DMA channel %d descriptors :\n", chan);
  98        pos += seq_printf(s, "[%03d] First descriptor unknown\n", 0);
  99        for (i = 1; i < max_show && is_phys_valid(phys_desc); i++) {
 100                desc = phys_to_virt(phys_desc);
 101                dcmd = desc->dcmd;
 102                burst = dbg_burst_from_dcmd(dcmd);
 103                width = (1 << ((dcmd >> 14) & 0x3)) >> 1;
 104
 105                pos += seq_printf(s, "[%03d] Desc at %08lx(virt %p)\n",
 106                                  i, phys_desc, desc);
 107                pos += seq_printf(s, "\tDDADR = %08x\n", desc->ddadr);
 108                pos += seq_printf(s, "\tDSADR = %08x\n", desc->dsadr);
 109                pos += seq_printf(s, "\tDTADR = %08x\n", desc->dtadr);
 110                pos += seq_printf(s, "\tDCMD  = %08x (%s%s%s%s%s%s%sburst=%d"
 111                                  " width=%d len=%d)\n",
 112                                  dcmd,
 113                                  DCMD_STR(INCSRCADDR), DCMD_STR(INCTRGADDR),
 114                                  DCMD_STR(FLOWSRC), DCMD_STR(FLOWTRG),
 115                                  DCMD_STR(STARTIRQEN), DCMD_STR(ENDIRQEN),
 116                                  DCMD_STR(ENDIAN), burst, width,
 117                                  dcmd & DCMD_LENGTH);
 118                phys_desc = desc->ddadr;
 119        }
 120        if (i == max_show)
 121                pos += seq_printf(s, "[%03d] Desc at %08lx ... max display reached\n",
 122                                  i, phys_desc);
 123        else
 124                pos += seq_printf(s, "[%03d] Desc at %08lx is %s\n",
 125                                  i, phys_desc, phys_desc == DDADR_STOP ?
 126                                  "DDADR_STOP" : "invalid");
 127
 128        spin_unlock_irqrestore(&dma_channels[chan].lock, flags);
 129        return pos;
 130}
 131
 132static int dbg_show_chan_state(struct seq_file *s, void *p)
 133{
 134        int pos = 0;
 135        int chan = (int)s->private;
 136        u32 dcsr, dcmd;
 137        int burst, width;
 138        static char *str_prio[] = { "high", "normal", "low" };
 139
 140        dcsr = DCSR(chan);
 141        dcmd = DCMD(chan);
 142        burst = dbg_burst_from_dcmd(dcmd);
 143        width = (1 << ((dcmd >> 14) & 0x3)) >> 1;
 144
 145        pos += seq_printf(s, "DMA channel %d\n", chan);
 146        pos += seq_printf(s, "\tPriority : %s\n",
 147                          str_prio[dma_channels[chan].prio]);
 148        pos += seq_printf(s, "\tUnaligned transfer bit: %s\n",
 149                          DALGN & (1 << chan) ? "yes" : "no");
 150        pos += seq_printf(s, "\tDCSR  = %08x (%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n",
 151                          dcsr, DCSR_STR(RUN), DCSR_STR(NODESC),
 152                          DCSR_STR(STOPIRQEN), DCSR_STR(EORIRQEN),
 153                          DCSR_STR(EORJMPEN), DCSR_STR(EORSTOPEN),
 154                          DCSR_STR(SETCMPST), DCSR_STR(CLRCMPST),
 155                          DCSR_STR(CMPST), DCSR_STR(EORINTR), DCSR_STR(REQPEND),
 156                          DCSR_STR(STOPSTATE), DCSR_STR(ENDINTR),
 157                          DCSR_STR(STARTINTR), DCSR_STR(BUSERR));
 158
 159        pos += seq_printf(s, "\tDCMD  = %08x (%s%s%s%s%s%s%sburst=%d width=%d"
 160                          " len=%d)\n",
 161                          dcmd,
 162                          DCMD_STR(INCSRCADDR), DCMD_STR(INCTRGADDR),
 163                          DCMD_STR(FLOWSRC), DCMD_STR(FLOWTRG),
 164                          DCMD_STR(STARTIRQEN), DCMD_STR(ENDIRQEN),
 165                          DCMD_STR(ENDIAN), burst, width, dcmd & DCMD_LENGTH);
 166        pos += seq_printf(s, "\tDSADR = %08x\n", DSADR(chan));
 167        pos += seq_printf(s, "\tDTADR = %08x\n", DTADR(chan));
 168        pos += seq_printf(s, "\tDDADR = %08x\n", DDADR(chan));
 169        return pos;
 170}
 171
 172static int dbg_show_state(struct seq_file *s, void *p)
 173{
 174        int pos = 0;
 175
 176        /* basic device status */
 177        pos += seq_printf(s, "DMA engine status\n");
 178        pos += seq_printf(s, "\tChannel number: %d\n", num_dma_channels);
 179
 180        return pos;
 181}
 182
 183#define DBGFS_FUNC_DECL(name) \
 184static int dbg_open_##name(struct inode *inode, struct file *file) \
 185{ \
 186        return single_open(file, dbg_show_##name, inode->i_private); \
 187} \
 188static const struct file_operations dbg_fops_##name = { \
 189        .owner          = THIS_MODULE, \
 190        .open           = dbg_open_##name, \
 191        .llseek         = seq_lseek, \
 192        .read           = seq_read, \
 193        .release        = single_release, \
 194}
 195
 196DBGFS_FUNC_DECL(state);
 197DBGFS_FUNC_DECL(chan_state);
 198DBGFS_FUNC_DECL(descriptors);
 199DBGFS_FUNC_DECL(requester_chan);
 200
 201static struct dentry *pxa_dma_dbg_alloc_chan(int ch, struct dentry *chandir)
 202{
 203        char chan_name[11];
 204        struct dentry *chan, *chan_state = NULL, *chan_descr = NULL;
 205        struct dentry *chan_reqs = NULL;
 206        void *dt;
 207
 208        scnprintf(chan_name, sizeof(chan_name), "%d", ch);
 209        chan = debugfs_create_dir(chan_name, chandir);
 210        dt = (void *)ch;
 211
 212        if (chan)
 213                chan_state = debugfs_create_file("state", 0400, chan, dt,
 214                                                 &dbg_fops_chan_state);
 215        if (chan_state)
 216                chan_descr = debugfs_create_file("descriptors", 0400, chan, dt,
 217                                                 &dbg_fops_descriptors);
 218        if (chan_descr)
 219                chan_reqs = debugfs_create_file("requesters", 0400, chan, dt,
 220                                                &dbg_fops_requester_chan);
 221        if (!chan_reqs)
 222                goto err_state;
 223
 224        return chan;
 225
 226err_state:
 227        debugfs_remove_recursive(chan);
 228        return NULL;
 229}
 230
 231static void pxa_dma_init_debugfs(void)
 232{
 233        int i;
 234        struct dentry *chandir;
 235
 236        dbgfs_root = debugfs_create_dir(DMA_DEBUG_NAME, NULL);
 237        if (IS_ERR(dbgfs_root) || !dbgfs_root)
 238                goto err_root;
 239
 240        dbgfs_state = debugfs_create_file("state", 0400, dbgfs_root, NULL,
 241                                          &dbg_fops_state);
 242        if (!dbgfs_state)
 243                goto err_state;
 244
 245        dbgfs_chan = kmalloc(sizeof(*dbgfs_state) * num_dma_channels,
 246                             GFP_KERNEL);
 247        if (!dbgfs_chan)
 248                goto err_alloc;
 249
 250        chandir = debugfs_create_dir("channels", dbgfs_root);
 251        if (!chandir)
 252                goto err_chandir;
 253
 254        for (i = 0; i < num_dma_channels; i++) {
 255                dbgfs_chan[i] = pxa_dma_dbg_alloc_chan(i, chandir);
 256                if (!dbgfs_chan[i])
 257                        goto err_chans;
 258        }
 259
 260        return;
 261err_chans:
 262err_chandir:
 263        kfree(dbgfs_chan);
 264err_alloc:
 265err_state:
 266        debugfs_remove_recursive(dbgfs_root);
 267err_root:
 268        pr_err("pxa_dma: debugfs is not available\n");
 269}
 270
 271static void __exit pxa_dma_cleanup_debugfs(void)
 272{
 273        debugfs_remove_recursive(dbgfs_root);
 274}
 275#else
 276static inline void pxa_dma_init_debugfs(void) {}
 277static inline void pxa_dma_cleanup_debugfs(void) {}
 278#endif
 279
 280int pxa_request_dma (char *name, pxa_dma_prio prio,
 281                        void (*irq_handler)(int, void *),
 282                        void *data)
 283{
 284        unsigned long flags;
 285        int i, found = 0;
 286
 287        /* basic sanity checks */
 288        if (!name || !irq_handler)
 289                return -EINVAL;
 290
 291        local_irq_save(flags);
 292
 293        do {
 294                /* try grabbing a DMA channel with the requested priority */
 295                for (i = 0; i < num_dma_channels; i++) {
 296                        if ((dma_channels[i].prio == prio) &&
 297                            !dma_channels[i].name) {
 298                                found = 1;
 299                                break;
 300                        }
 301                }
 302                /* if requested prio group is full, try a hier priority */
 303        } while (!found && prio--);
 304
 305        if (found) {
 306                DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
 307                dma_channels[i].name = name;
 308                dma_channels[i].irq_handler = irq_handler;
 309                dma_channels[i].data = data;
 310        } else {
 311                printk (KERN_WARNING "No more available DMA channels for %s\n", name);
 312                i = -ENODEV;
 313        }
 314
 315        local_irq_restore(flags);
 316        return i;
 317}
 318EXPORT_SYMBOL(pxa_request_dma);
 319
 320void pxa_free_dma (int dma_ch)
 321{
 322        unsigned long flags;
 323
 324        if (!dma_channels[dma_ch].name) {
 325                printk (KERN_CRIT
 326                        "%s: trying to free channel %d which is already freed\n",
 327                        __func__, dma_ch);
 328                return;
 329        }
 330
 331        local_irq_save(flags);
 332        DCSR(dma_ch) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
 333        dma_channels[dma_ch].name = NULL;
 334        local_irq_restore(flags);
 335}
 336EXPORT_SYMBOL(pxa_free_dma);
 337
 338static irqreturn_t dma_irq_handler(int irq, void *dev_id)
 339{
 340        int i, dint = DINT;
 341        struct dma_channel *channel;
 342
 343        while (dint) {
 344                i = __ffs(dint);
 345                dint &= (dint - 1);
 346                channel = &dma_channels[i];
 347                if (channel->name && channel->irq_handler) {
 348                        channel->irq_handler(i, channel->data);
 349                } else {
 350                        /*
 351                         * IRQ for an unregistered DMA channel:
 352                         * let's clear the interrupts and disable it.
 353                         */
 354                        printk (KERN_WARNING "spurious IRQ for DMA channel %d\n", i);
 355                        DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
 356                }
 357        }
 358        return IRQ_HANDLED;
 359}
 360
 361int __init pxa_init_dma(int irq, int num_ch)
 362{
 363        int i, ret;
 364
 365        dma_channels = kzalloc(sizeof(struct dma_channel) * num_ch, GFP_KERNEL);
 366        if (dma_channels == NULL)
 367                return -ENOMEM;
 368
 369        /* dma channel priorities on pxa2xx processors:
 370         * ch 0 - 3,  16 - 19  <--> (0) DMA_PRIO_HIGH
 371         * ch 4 - 7,  20 - 23  <--> (1) DMA_PRIO_MEDIUM
 372         * ch 8 - 15, 24 - 31  <--> (2) DMA_PRIO_LOW
 373         */
 374        for (i = 0; i < num_ch; i++) {
 375                DCSR(i) = 0;
 376                dma_channels[i].prio = min((i & 0xf) >> 2, DMA_PRIO_LOW);
 377                spin_lock_init(&dma_channels[i].lock);
 378        }
 379
 380        ret = request_irq(irq, dma_irq_handler, IRQF_DISABLED, "DMA", NULL);
 381        if (ret) {
 382                printk (KERN_CRIT "Wow!  Can't register IRQ for DMA\n");
 383                kfree(dma_channels);
 384                return ret;
 385        }
 386        num_dma_channels = num_ch;
 387
 388        pxa_dma_init_debugfs();
 389
 390        return 0;
 391}
 392