Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dma.c
Go to the documentation of this file.
1 /*
2  * linux/arch/unicore32/kernel/dma.c
3  *
4  * Code specific to PKUnity SoC and UniCore ISA
5  *
6  * Maintained by GUAN Xue-tao <[email protected]>
7  * Copyright (C) 2001-2010 Guan Xuetao
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13 
14 #include <linux/module.h>
15 #include <linux/init.h>
16 #include <linux/kernel.h>
17 #include <linux/interrupt.h>
18 #include <linux/errno.h>
19 #include <linux/io.h>
20 
21 #include <asm/irq.h>
22 #include <mach/hardware.h>
23 #include <mach/dma.h>
24 
25 struct dma_channel {
26  char *name;
28  void (*irq_handler)(int, void *);
29  void (*err_handler)(int, void *);
30  void *data;
31 };
32 
33 static struct dma_channel dma_channels[MAX_DMA_CHANNELS];
34 
36  void (*irq_handler)(int, void *),
37  void (*err_handler)(int, void *),
38  void *data)
39 {
40  unsigned long flags;
41  int i, found = 0;
42 
43  /* basic sanity checks */
44  if (!name)
45  return -EINVAL;
46 
47  local_irq_save(flags);
48 
49  do {
50  /* try grabbing a DMA channel with the requested priority */
51  for (i = 0; i < MAX_DMA_CHANNELS; i++) {
52  if ((dma_channels[i].prio == prio) &&
53  !dma_channels[i].name) {
54  found = 1;
55  break;
56  }
57  }
58  /* if requested prio group is full, try a hier priority */
59  } while (!found && prio--);
60 
61  if (found) {
62  dma_channels[i].name = name;
63  dma_channels[i].irq_handler = irq_handler;
64  dma_channels[i].err_handler = err_handler;
65  dma_channels[i].data = data;
66  } else {
67  printk(KERN_WARNING "No more available DMA channels for %s\n",
68  name);
69  i = -ENODEV;
70  }
71 
72  local_irq_restore(flags);
73  return i;
74 }
76 
78 {
79  unsigned long flags;
80 
81  if (!dma_channels[dma_ch].name) {
83  "%s: trying to free channel %d which is already freed\n",
84  __func__, dma_ch);
85  return;
86  }
87 
88  local_irq_save(flags);
89  dma_channels[dma_ch].name = NULL;
90  dma_channels[dma_ch].err_handler = NULL;
91  local_irq_restore(flags);
92 }
94 
95 static irqreturn_t dma_irq_handler(int irq, void *dev_id)
96 {
97  int i, dint;
98 
99  dint = readl(DMAC_ITCSR);
100  for (i = 0; i < MAX_DMA_CHANNELS; i++) {
101  if (dint & DMAC_CHANNEL(i)) {
102  struct dma_channel *channel = &dma_channels[i];
103 
104  /* Clear TC interrupt of channel i */
106  writel(0, DMAC_ITCCR);
107 
108  if (channel->name && channel->irq_handler) {
109  channel->irq_handler(i, channel->data);
110  } else {
111  /*
112  * IRQ for an unregistered DMA channel:
113  * let's clear the interrupts and disable it.
114  */
115  printk(KERN_WARNING "spurious IRQ for"
116  " DMA channel %d\n", i);
117  }
118  }
119  }
120  return IRQ_HANDLED;
121 }
122 
123 static irqreturn_t dma_err_handler(int irq, void *dev_id)
124 {
125  int i, dint;
126 
127  dint = readl(DMAC_IESR);
128  for (i = 0; i < MAX_DMA_CHANNELS; i++) {
129  if (dint & DMAC_CHANNEL(i)) {
130  struct dma_channel *channel = &dma_channels[i];
131 
132  /* Clear Err interrupt of channel i */
134  writel(0, DMAC_IECR);
135 
136  if (channel->name && channel->err_handler) {
137  channel->err_handler(i, channel->data);
138  } else {
139  /*
140  * IRQ for an unregistered DMA channel:
141  * let's clear the interrupts and disable it.
142  */
143  printk(KERN_WARNING "spurious IRQ for"
144  " DMA channel %d\n", i);
145  }
146  }
147  }
148  return IRQ_HANDLED;
149 }
150 
152 {
153  int i, ret;
154 
155  /* dma channel priorities on v8 processors:
156  * ch 0 - 1 <--> (0) DMA_PRIO_HIGH
157  * ch 2 - 3 <--> (1) DMA_PRIO_MEDIUM
158  * ch 4 - 5 <--> (2) DMA_PRIO_LOW
159  */
160  for (i = 0; i < MAX_DMA_CHANNELS; i++) {
161  puv3_stop_dma(i);
162  dma_channels[i].name = NULL;
163  dma_channels[i].prio = min((i & 0x7) >> 1, DMA_PRIO_LOW);
164  }
165 
166  ret = request_irq(IRQ_DMA, dma_irq_handler, 0, "DMA", NULL);
167  if (ret) {
168  printk(KERN_CRIT "Can't register IRQ for DMA\n");
169  return ret;
170  }
171 
172  ret = request_irq(IRQ_DMAERR, dma_err_handler, 0, "DMAERR", NULL);
173  if (ret) {
174  printk(KERN_CRIT "Can't register IRQ for DMAERR\n");
175  free_irq(IRQ_DMA, "DMA");
176  return ret;
177  }
178 
179  return 0;
180 }
181