diff options
author | Paul Mundt <lethal@linux-sh.org> | 2006-09-27 03:53:40 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2006-09-27 03:53:40 -0400 |
commit | e2d1864da5bfa419a108f42c0615f69432b1b876 (patch) | |
tree | 2ebd838b7b6cca8d5db7d2991797a5bc9ae1d1ab | |
parent | ade2b3f6ed199dc4a7a0be53edf20f9399023640 (diff) |
sh: G2 DMA IRQ and residue sampling.
This fixes a long-standing FIXME for G2 DMA, where we finally
wire up the IRQ handler and allow for sampling remaining bytes
while in-flight.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r-- | arch/sh/drivers/dma/dma-g2.c | 54 |
1 files changed, 41 insertions, 13 deletions
diff --git a/arch/sh/drivers/dma/dma-g2.c b/arch/sh/drivers/dma/dma-g2.c index 0f866f8789f0..9cb070924180 100644 --- a/arch/sh/drivers/dma/dma-g2.c +++ b/arch/sh/drivers/dma/dma-g2.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * G2 bus DMA support | 4 | * G2 bus DMA support |
5 | * | 5 | * |
6 | * Copyright (C) 2003, 2004 Paul Mundt | 6 | * Copyright (C) 2003 - 2006 Paul Mundt |
7 | * | 7 | * |
8 | * This file is subject to the terms and conditions of the GNU General Public | 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 | 9 | * License. See the file "COPYING" in the main directory of this archive |
@@ -13,7 +13,7 @@ | |||
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
16 | 16 | #include <asm/cacheflush.h> | |
17 | #include <asm/mach/sysasic.h> | 17 | #include <asm/mach/sysasic.h> |
18 | #include <asm/mach/dma.h> | 18 | #include <asm/mach/dma.h> |
19 | #include <asm/dma.h> | 19 | #include <asm/dma.h> |
@@ -47,17 +47,31 @@ struct g2_dma_info { | |||
47 | 47 | ||
48 | static volatile struct g2_dma_info *g2_dma = (volatile struct g2_dma_info *)0xa05f7800; | 48 | static volatile struct g2_dma_info *g2_dma = (volatile struct g2_dma_info *)0xa05f7800; |
49 | 49 | ||
50 | #define g2_bytes_remaining(i) \ | ||
51 | ((g2_dma->channel[i].size - \ | ||
52 | g2_dma->status[i].size) & 0x0fffffff) | ||
53 | |||
50 | static irqreturn_t g2_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 54 | static irqreturn_t g2_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
51 | { | 55 | { |
52 | /* FIXME: Do some meaningful completion work here.. */ | 56 | int i; |
53 | return IRQ_HANDLED; | ||
54 | } | ||
55 | 57 | ||
56 | static struct irqaction g2_dma_irq = { | 58 | for (i = 0; i < G2_NR_DMA_CHANNELS; i++) { |
57 | .name = "g2 DMA handler", | 59 | if (g2_dma->status[i].status & 0x20000000) { |
58 | .handler = g2_dma_interrupt, | 60 | unsigned int bytes = g2_bytes_remaining(i); |
59 | .flags = IRQF_DISABLED, | 61 | |
60 | }; | 62 | if (likely(bytes == 0)) { |
63 | struct dma_info *info = dev_id; | ||
64 | struct dma_channel *chan = info->channels + i; | ||
65 | |||
66 | wake_up(&chan->wait_queue); | ||
67 | |||
68 | return IRQ_HANDLED; | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | |||
73 | return IRQ_NONE; | ||
74 | } | ||
61 | 75 | ||
62 | static int g2_enable_dma(struct dma_channel *chan) | 76 | static int g2_enable_dma(struct dma_channel *chan) |
63 | { | 77 | { |
@@ -135,8 +149,14 @@ static int g2_xfer_dma(struct dma_channel *chan) | |||
135 | return 0; | 149 | return 0; |
136 | } | 150 | } |
137 | 151 | ||
152 | static int g2_get_residue(struct dma_channel *chan) | ||
153 | { | ||
154 | return g2_bytes_remaining(chan->chan); | ||
155 | } | ||
156 | |||
138 | static struct dma_ops g2_dma_ops = { | 157 | static struct dma_ops g2_dma_ops = { |
139 | .xfer = g2_xfer_dma, | 158 | .xfer = g2_xfer_dma, |
159 | .get_residue = g2_get_residue, | ||
140 | }; | 160 | }; |
141 | 161 | ||
142 | static struct dma_info g2_dma_info = { | 162 | static struct dma_info g2_dma_info = { |
@@ -148,13 +168,22 @@ static struct dma_info g2_dma_info = { | |||
148 | 168 | ||
149 | static int __init g2_dma_init(void) | 169 | static int __init g2_dma_init(void) |
150 | { | 170 | { |
151 | setup_irq(HW_EVENT_G2_DMA, &g2_dma_irq); | 171 | int ret; |
172 | |||
173 | ret = request_irq(HW_EVENT_G2_DMA, g2_dma_interrupt, IRQF_DISABLED, | ||
174 | "g2 DMA handler", &g2_dma_info); | ||
175 | if (unlikely(ret)) | ||
176 | return -EINVAL; | ||
152 | 177 | ||
153 | /* Magic */ | 178 | /* Magic */ |
154 | g2_dma->wait_state = 27; | 179 | g2_dma->wait_state = 27; |
155 | g2_dma->magic = 0x4659404f; | 180 | g2_dma->magic = 0x4659404f; |
156 | 181 | ||
157 | return register_dmac(&g2_dma_info); | 182 | ret = register_dmac(&g2_dma_info); |
183 | if (unlikely(ret != 0)) | ||
184 | free_irq(HW_EVENT_G2_DMA, 0); | ||
185 | |||
186 | return ret; | ||
158 | } | 187 | } |
159 | 188 | ||
160 | static void __exit g2_dma_exit(void) | 189 | static void __exit g2_dma_exit(void) |
@@ -169,4 +198,3 @@ module_exit(g2_dma_exit); | |||
169 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>"); | 198 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>"); |
170 | MODULE_DESCRIPTION("G2 bus DMA driver"); | 199 | MODULE_DESCRIPTION("G2 bus DMA driver"); |
171 | MODULE_LICENSE("GPL"); | 200 | MODULE_LICENSE("GPL"); |
172 | |||