diff options
Diffstat (limited to 'arch/arm/mach-msm/dma.c')
-rw-r--r-- | arch/arm/mach-msm/dma.c | 72 |
1 files changed, 52 insertions, 20 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); |