diff options
author | Brian Swetland <swetland@google.com> | 2008-09-10 17:58:25 -0400 |
---|---|---|
committer | Brian Swetland <swetland@google.com> | 2008-10-22 05:41:00 -0400 |
commit | 8a0f6f17c43933a4768ab79b9ac3ad24cd3c2c3f (patch) | |
tree | 3768860bbca3d9bc25ddaab987aedd88a901d7fe /arch | |
parent | 600f7cfebeef74a6ba961c507079e3629da5dd7a (diff) |
[ARM] msm: dma: various basic dma improvements and bugfixes
San:
- Propagate DM errors to the originator of the request.
- Implement msm_dmov_stop_cmd()
- Add return value to init code
- Modify msm_dmov_stop_cmd() to support ungraceful flushing
Arve:
- Disable datamover interrupt when not in use.
We turn off the interrrupt to allow power collapse from idle.
Signed-off-by: San Mehat <san@android.com>
Signed-off-by: Arve Hjønnevåg <arve@android.com>
Signed-off-by: Brian Swetland <swetland@google.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-msm/dma.c | 72 | ||||
-rw-r--r-- | arch/arm/mach-msm/include/mach/dma.h | 24 |
2 files changed, 71 insertions, 25 deletions
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c index 0c8f252637e1..f5420f9585c5 100644 --- a/arch/arm/mach-msm/dma.c +++ b/arch/arm/mach-msm/dma.c | |||
@@ -26,7 +26,7 @@ enum { | |||
26 | }; | 26 | }; |
27 | 27 | ||
28 | static DEFINE_SPINLOCK(msm_dmov_lock); | 28 | static DEFINE_SPINLOCK(msm_dmov_lock); |
29 | static struct msm_dmov_cmd active_command; | 29 | static unsigned int channel_active; |
30 | static struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT]; | 30 | static struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT]; |
31 | static struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT]; | 31 | static struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT]; |
32 | unsigned int msm_dmov_print_mask = MSM_DMOV_PRINT_ERRORS; | 32 | unsigned int msm_dmov_print_mask = MSM_DMOV_PRINT_ERRORS; |
@@ -43,6 +43,11 @@ unsigned int msm_dmov_print_mask = MSM_DMOV_PRINT_ERRORS; | |||
43 | #define PRINT_FLOW(format, args...) \ | 43 | #define PRINT_FLOW(format, args...) \ |
44 | MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_FLOW, format, args); | 44 | MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_FLOW, format, args); |
45 | 45 | ||
46 | void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful) | ||
47 | { | ||
48 | writel((graceful << 31), DMOV_FLUSH0(id)); | ||
49 | } | ||
50 | |||
46 | void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) | 51 | void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) |
47 | { | 52 | { |
48 | unsigned long irq_flags; | 53 | unsigned long irq_flags; |
@@ -60,6 +65,9 @@ void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) | |||
60 | #endif | 65 | #endif |
61 | PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n", id, status); | 66 | PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n", id, status); |
62 | list_add_tail(&cmd->list, &active_commands[id]); | 67 | list_add_tail(&cmd->list, &active_commands[id]); |
68 | if (!channel_active) | ||
69 | enable_irq(INT_ADM_AARM); | ||
70 | channel_active |= 1U << id; | ||
63 | writel(cmd->cmdptr, DMOV_CMD_PTR(id)); | 71 | writel(cmd->cmdptr, DMOV_CMD_PTR(id)); |
64 | } else { | 72 | } else { |
65 | if (list_empty(&active_commands[id])) | 73 | if (list_empty(&active_commands[id])) |
@@ -76,21 +84,19 @@ struct msm_dmov_exec_cmdptr_cmd { | |||
76 | struct completion complete; | 84 | struct completion complete; |
77 | unsigned id; | 85 | unsigned id; |
78 | unsigned int result; | 86 | unsigned int result; |
79 | unsigned int flush[6]; | 87 | struct msm_dmov_errdata err; |
80 | }; | 88 | }; |
81 | 89 | ||
82 | static void dmov_exec_cmdptr_complete_func(struct msm_dmov_cmd *_cmd, unsigned int result) | 90 | static void |
91 | dmov_exec_cmdptr_complete_func(struct msm_dmov_cmd *_cmd, | ||
92 | unsigned int result, | ||
93 | struct msm_dmov_errdata *err) | ||
83 | { | 94 | { |
84 | struct msm_dmov_exec_cmdptr_cmd *cmd = container_of(_cmd, struct msm_dmov_exec_cmdptr_cmd, dmov_cmd); | 95 | struct msm_dmov_exec_cmdptr_cmd *cmd = container_of(_cmd, struct msm_dmov_exec_cmdptr_cmd, dmov_cmd); |
85 | cmd->result = result; | 96 | cmd->result = result; |
86 | if (result != 0x80000002) { | 97 | if (result != 0x80000002 && err) |
87 | cmd->flush[0] = readl(DMOV_FLUSH0(cmd->id)); | 98 | memcpy(&cmd->err, err, sizeof(struct msm_dmov_errdata)); |
88 | cmd->flush[1] = readl(DMOV_FLUSH1(cmd->id)); | 99 | |
89 | cmd->flush[2] = readl(DMOV_FLUSH2(cmd->id)); | ||
90 | cmd->flush[3] = readl(DMOV_FLUSH3(cmd->id)); | ||
91 | cmd->flush[4] = readl(DMOV_FLUSH4(cmd->id)); | ||
92 | cmd->flush[5] = readl(DMOV_FLUSH5(cmd->id)); | ||
93 | } | ||
94 | complete(&cmd->complete); | 100 | complete(&cmd->complete); |
95 | } | 101 | } |
96 | 102 | ||
@@ -111,7 +117,7 @@ int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr) | |||
111 | if (cmd.result != 0x80000002) { | 117 | if (cmd.result != 0x80000002) { |
112 | PRINT_ERROR("dmov_exec_cmdptr(%d): ERROR, result: %x\n", id, cmd.result); | 118 | PRINT_ERROR("dmov_exec_cmdptr(%d): ERROR, result: %x\n", id, cmd.result); |
113 | PRINT_ERROR("dmov_exec_cmdptr(%d): flush: %x %x %x %x\n", | 119 | PRINT_ERROR("dmov_exec_cmdptr(%d): flush: %x %x %x %x\n", |
114 | id, cmd.flush[0], cmd.flush[1], cmd.flush[2], cmd.flush[3]); | 120 | id, cmd.err.flush[0], cmd.err.flush[1], cmd.err.flush[2], cmd.err.flush[3]); |
115 | return -EIO; | 121 | return -EIO; |
116 | } | 122 | } |
117 | PRINT_FLOW("dmov_exec_cmdptr(%d, %x) done\n", id, cmdptr); | 123 | PRINT_FLOW("dmov_exec_cmdptr(%d, %x) done\n", id, cmdptr); |
@@ -159,25 +165,40 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) | |||
159 | "for %p, result %x\n", id, cmd, ch_result); | 165 | "for %p, result %x\n", id, cmd, ch_result); |
160 | if (cmd) { | 166 | if (cmd) { |
161 | list_del(&cmd->list); | 167 | list_del(&cmd->list); |
162 | cmd->complete_func(cmd, ch_result); | 168 | cmd->complete_func(cmd, ch_result, NULL); |
163 | } | 169 | } |
164 | } | 170 | } |
165 | if (ch_result & DMOV_RSLT_FLUSH) { | 171 | if (ch_result & DMOV_RSLT_FLUSH) { |
166 | unsigned int flush0 = readl(DMOV_FLUSH0(id)); | 172 | struct msm_dmov_errdata errdata; |
173 | |||
174 | errdata.flush[0] = readl(DMOV_FLUSH0(id)); | ||
175 | errdata.flush[1] = readl(DMOV_FLUSH1(id)); | ||
176 | errdata.flush[2] = readl(DMOV_FLUSH2(id)); | ||
177 | errdata.flush[3] = readl(DMOV_FLUSH3(id)); | ||
178 | errdata.flush[4] = readl(DMOV_FLUSH4(id)); | ||
179 | errdata.flush[5] = readl(DMOV_FLUSH5(id)); | ||
167 | PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); | 180 | PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); |
168 | PRINT_FLOW("msm_datamover_irq_handler id %d, flush, result %x, flush0 %x\n", id, ch_result, flush0); | 181 | PRINT_FLOW("msm_datamover_irq_handler id %d, flush, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]); |
169 | if (cmd) { | 182 | if (cmd) { |
170 | list_del(&cmd->list); | 183 | list_del(&cmd->list); |
171 | cmd->complete_func(cmd, ch_result); | 184 | cmd->complete_func(cmd, ch_result, &errdata); |
172 | } | 185 | } |
173 | } | 186 | } |
174 | if (ch_result & DMOV_RSLT_ERROR) { | 187 | if (ch_result & DMOV_RSLT_ERROR) { |
175 | unsigned int flush0 = readl(DMOV_FLUSH0(id)); | 188 | struct msm_dmov_errdata errdata; |
189 | |||
190 | errdata.flush[0] = readl(DMOV_FLUSH0(id)); | ||
191 | errdata.flush[1] = readl(DMOV_FLUSH1(id)); | ||
192 | errdata.flush[2] = readl(DMOV_FLUSH2(id)); | ||
193 | errdata.flush[3] = readl(DMOV_FLUSH3(id)); | ||
194 | errdata.flush[4] = readl(DMOV_FLUSH4(id)); | ||
195 | errdata.flush[5] = readl(DMOV_FLUSH5(id)); | ||
196 | |||
176 | PRINT_ERROR("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); | 197 | PRINT_ERROR("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); |
177 | PRINT_ERROR("msm_datamover_irq_handler id %d, error, result %x, flush0 %x\n", id, ch_result, flush0); | 198 | PRINT_ERROR("msm_datamover_irq_handler id %d, error, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]); |
178 | if (cmd) { | 199 | if (cmd) { |
179 | list_del(&cmd->list); | 200 | list_del(&cmd->list); |
180 | cmd->complete_func(cmd, ch_result); | 201 | cmd->complete_func(cmd, ch_result, &errdata); |
181 | } | 202 | } |
182 | /* this does not seem to work, once we get an error */ | 203 | /* this does not seem to work, once we get an error */ |
183 | /* the datamover will no longer accept commands */ | 204 | /* the datamover will no longer accept commands */ |
@@ -193,8 +214,14 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) | |||
193 | writel(cmd->cmdptr, DMOV_CMD_PTR(id)); | 214 | writel(cmd->cmdptr, DMOV_CMD_PTR(id)); |
194 | } | 215 | } |
195 | } while (ch_status & DMOV_STATUS_RSLT_VALID); | 216 | } while (ch_status & DMOV_STATUS_RSLT_VALID); |
217 | if (list_empty(&active_commands[id]) && list_empty(&ready_commands[id])) | ||
218 | channel_active &= ~(1U << id); | ||
196 | PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); | 219 | PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); |
197 | } | 220 | } |
221 | |||
222 | if (!channel_active) | ||
223 | disable_irq(INT_ADM_AARM); | ||
224 | |||
198 | spin_unlock_irqrestore(&msm_dmov_lock, irq_flags); | 225 | spin_unlock_irqrestore(&msm_dmov_lock, irq_flags); |
199 | return IRQ_HANDLED; | 226 | return IRQ_HANDLED; |
200 | } | 227 | } |
@@ -202,12 +229,17 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) | |||
202 | static int __init msm_init_datamover(void) | 229 | static int __init msm_init_datamover(void) |
203 | { | 230 | { |
204 | int i; | 231 | int i; |
232 | int ret; | ||
205 | for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) { | 233 | for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) { |
206 | INIT_LIST_HEAD(&ready_commands[i]); | 234 | INIT_LIST_HEAD(&ready_commands[i]); |
207 | INIT_LIST_HEAD(&active_commands[i]); | 235 | INIT_LIST_HEAD(&active_commands[i]); |
208 | writel(DMOV_CONFIG_IRQ_EN | DMOV_CONFIG_FORCE_TOP_PTR_RSLT | DMOV_CONFIG_FORCE_FLUSH_RSLT, DMOV_CONFIG(i)); | 236 | writel(DMOV_CONFIG_IRQ_EN | DMOV_CONFIG_FORCE_TOP_PTR_RSLT | DMOV_CONFIG_FORCE_FLUSH_RSLT, DMOV_CONFIG(i)); |
209 | } | 237 | } |
210 | return request_irq(INT_ADM_AARM, msm_datamover_irq_handler, 0, "msmdatamover", NULL); | 238 | ret = request_irq(INT_ADM_AARM, msm_datamover_irq_handler, 0, "msmdatamover", NULL); |
239 | if (ret) | ||
240 | return ret; | ||
241 | disable_irq(INT_ADM_AARM); | ||
242 | return 0; | ||
211 | } | 243 | } |
212 | 244 | ||
213 | arch_initcall(msm_init_datamover); | 245 | arch_initcall(msm_init_datamover); |
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h index ad1c87f86d10..5ab5bdffab07 100644 --- a/arch/arm/mach-msm/include/mach/dma.h +++ b/arch/arm/mach-msm/include/mach/dma.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* arch/arm/mach-msm/include/mach/dma.h | 1 | /* linux/include/asm-arm/arch-msm/dma.h |
2 | * | 2 | * |
3 | * Copyright (C) 2007 Google, Inc. | 3 | * Copyright (C) 2007 Google, Inc. |
4 | * | 4 | * |
@@ -18,17 +18,21 @@ | |||
18 | #include <linux/list.h> | 18 | #include <linux/list.h> |
19 | #include <mach/msm_iomap.h> | 19 | #include <mach/msm_iomap.h> |
20 | 20 | ||
21 | struct msm_dmov_errdata { | ||
22 | uint32_t flush[6]; | ||
23 | }; | ||
24 | |||
21 | struct msm_dmov_cmd { | 25 | struct msm_dmov_cmd { |
22 | struct list_head list; | 26 | struct list_head list; |
23 | unsigned int cmdptr; | 27 | unsigned int cmdptr; |
24 | void (*complete_func)(struct msm_dmov_cmd *cmd, unsigned int result); | 28 | void (*complete_func)(struct msm_dmov_cmd *cmd, |
25 | /* void (*user_result_func)(struct msm_dmov_cmd *cmd); */ | 29 | unsigned int result, |
30 | struct msm_dmov_errdata *err); | ||
26 | }; | 31 | }; |
27 | 32 | ||
28 | void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd); | 33 | void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd); |
29 | void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd); | 34 | void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful); |
30 | int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr); | 35 | int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr); |
31 | /* int msm_dmov_exec_cmd_etc(unsigned id, unsigned int cmdptr, int timeout, int interruptible); */ | ||
32 | 36 | ||
33 | 37 | ||
34 | 38 | ||
@@ -122,6 +126,16 @@ typedef struct { | |||
122 | unsigned _reserved; | 126 | unsigned _reserved; |
123 | } dmov_sg; | 127 | } dmov_sg; |
124 | 128 | ||
129 | /* Box mode */ | ||
130 | typedef struct { | ||
131 | uint32_t cmd; | ||
132 | uint32_t src_row_addr; | ||
133 | uint32_t dst_row_addr; | ||
134 | uint32_t src_dst_len; | ||
135 | uint32_t num_rows; | ||
136 | uint32_t row_offset; | ||
137 | } dmov_box; | ||
138 | |||
125 | /* bits for the cmd field of the above structures */ | 139 | /* bits for the cmd field of the above structures */ |
126 | 140 | ||
127 | #define CMD_LC (1 << 31) /* last command */ | 141 | #define CMD_LC (1 << 31) /* last command */ |