Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

+71 -25
+52 -20
arch/arm/mach-msm/dma.c
··· 26 26 }; 27 27 28 28 static DEFINE_SPINLOCK(msm_dmov_lock); 29 - static struct msm_dmov_cmd active_command; 29 + static unsigned int channel_active; 30 30 static struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT]; 31 31 static struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT]; 32 32 unsigned int msm_dmov_print_mask = MSM_DMOV_PRINT_ERRORS; ··· 42 42 MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_IO, format, args); 43 43 #define PRINT_FLOW(format, args...) \ 44 44 MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_FLOW, format, args); 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 + } 45 50 46 51 void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) 47 52 { ··· 65 60 #endif 66 61 PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n", id, status); 67 62 list_add_tail(&cmd->list, &active_commands[id]); 63 + if (!channel_active) 64 + enable_irq(INT_ADM_AARM); 65 + channel_active |= 1U << id; 68 66 writel(cmd->cmdptr, DMOV_CMD_PTR(id)); 69 67 } else { 70 68 if (list_empty(&active_commands[id])) ··· 84 76 struct completion complete; 85 77 unsigned id; 86 78 unsigned int result; 87 - unsigned int flush[6]; 79 + struct msm_dmov_errdata err; 88 80 }; 89 81 90 - static void dmov_exec_cmdptr_complete_func(struct msm_dmov_cmd *_cmd, unsigned int result) 82 + static void 83 + dmov_exec_cmdptr_complete_func(struct msm_dmov_cmd *_cmd, 84 + unsigned int result, 85 + struct msm_dmov_errdata *err) 91 86 { 92 87 struct msm_dmov_exec_cmdptr_cmd *cmd = container_of(_cmd, struct msm_dmov_exec_cmdptr_cmd, dmov_cmd); 93 88 cmd->result = result; 94 - if (result != 0x80000002) { 95 - cmd->flush[0] = readl(DMOV_FLUSH0(cmd->id)); 96 - cmd->flush[1] = readl(DMOV_FLUSH1(cmd->id)); 97 - cmd->flush[2] = readl(DMOV_FLUSH2(cmd->id)); 98 - cmd->flush[3] = readl(DMOV_FLUSH3(cmd->id)); 99 - cmd->flush[4] = readl(DMOV_FLUSH4(cmd->id)); 100 - cmd->flush[5] = readl(DMOV_FLUSH5(cmd->id)); 101 - } 89 + if (result != 0x80000002 && err) 90 + memcpy(&cmd->err, err, sizeof(struct msm_dmov_errdata)); 91 + 102 92 complete(&cmd->complete); 103 93 } 104 94 ··· 117 111 if (cmd.result != 0x80000002) { 118 112 PRINT_ERROR("dmov_exec_cmdptr(%d): ERROR, result: %x\n", id, cmd.result); 119 113 PRINT_ERROR("dmov_exec_cmdptr(%d): flush: %x %x %x %x\n", 120 - id, cmd.flush[0], cmd.flush[1], cmd.flush[2], cmd.flush[3]); 114 + id, cmd.err.flush[0], cmd.err.flush[1], cmd.err.flush[2], cmd.err.flush[3]); 121 115 return -EIO; 122 116 } 123 117 PRINT_FLOW("dmov_exec_cmdptr(%d, %x) done\n", id, cmdptr); ··· 165 159 "for %p, result %x\n", id, cmd, ch_result); 166 160 if (cmd) { 167 161 list_del(&cmd->list); 168 - cmd->complete_func(cmd, ch_result); 162 + cmd->complete_func(cmd, ch_result, NULL); 169 163 } 170 164 } 171 165 if (ch_result & DMOV_RSLT_FLUSH) { 172 - unsigned int flush0 = readl(DMOV_FLUSH0(id)); 166 + struct msm_dmov_errdata errdata; 167 + 168 + errdata.flush[0] = readl(DMOV_FLUSH0(id)); 169 + errdata.flush[1] = readl(DMOV_FLUSH1(id)); 170 + errdata.flush[2] = readl(DMOV_FLUSH2(id)); 171 + errdata.flush[3] = readl(DMOV_FLUSH3(id)); 172 + errdata.flush[4] = readl(DMOV_FLUSH4(id)); 173 + errdata.flush[5] = readl(DMOV_FLUSH5(id)); 173 174 PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); 174 - PRINT_FLOW("msm_datamover_irq_handler id %d, flush, result %x, flush0 %x\n", id, ch_result, flush0); 175 + PRINT_FLOW("msm_datamover_irq_handler id %d, flush, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]); 175 176 if (cmd) { 176 177 list_del(&cmd->list); 177 - cmd->complete_func(cmd, ch_result); 178 + cmd->complete_func(cmd, ch_result, &errdata); 178 179 } 179 180 } 180 181 if (ch_result & DMOV_RSLT_ERROR) { 181 - unsigned int flush0 = readl(DMOV_FLUSH0(id)); 182 + struct msm_dmov_errdata errdata; 183 + 184 + errdata.flush[0] = readl(DMOV_FLUSH0(id)); 185 + errdata.flush[1] = readl(DMOV_FLUSH1(id)); 186 + errdata.flush[2] = readl(DMOV_FLUSH2(id)); 187 + errdata.flush[3] = readl(DMOV_FLUSH3(id)); 188 + errdata.flush[4] = readl(DMOV_FLUSH4(id)); 189 + errdata.flush[5] = readl(DMOV_FLUSH5(id)); 190 + 182 191 PRINT_ERROR("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); 183 - PRINT_ERROR("msm_datamover_irq_handler id %d, error, result %x, flush0 %x\n", id, ch_result, flush0); 192 + PRINT_ERROR("msm_datamover_irq_handler id %d, error, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]); 184 193 if (cmd) { 185 194 list_del(&cmd->list); 186 - cmd->complete_func(cmd, ch_result); 195 + cmd->complete_func(cmd, ch_result, &errdata); 187 196 } 188 197 /* this does not seem to work, once we get an error */ 189 198 /* the datamover will no longer accept commands */ ··· 214 193 writel(cmd->cmdptr, DMOV_CMD_PTR(id)); 215 194 } 216 195 } while (ch_status & DMOV_STATUS_RSLT_VALID); 196 + if (list_empty(&active_commands[id]) && list_empty(&ready_commands[id])) 197 + channel_active &= ~(1U << id); 217 198 PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); 218 199 } 200 + 201 + if (!channel_active) 202 + disable_irq(INT_ADM_AARM); 203 + 219 204 spin_unlock_irqrestore(&msm_dmov_lock, irq_flags); 220 205 return IRQ_HANDLED; 221 206 } ··· 229 202 static int __init msm_init_datamover(void) 230 203 { 231 204 int i; 205 + int ret; 232 206 for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) { 233 207 INIT_LIST_HEAD(&ready_commands[i]); 234 208 INIT_LIST_HEAD(&active_commands[i]); 235 209 writel(DMOV_CONFIG_IRQ_EN | DMOV_CONFIG_FORCE_TOP_PTR_RSLT | DMOV_CONFIG_FORCE_FLUSH_RSLT, DMOV_CONFIG(i)); 236 210 } 237 - return request_irq(INT_ADM_AARM, msm_datamover_irq_handler, 0, "msmdatamover", NULL); 211 + ret = request_irq(INT_ADM_AARM, msm_datamover_irq_handler, 0, "msmdatamover", NULL); 212 + if (ret) 213 + return ret; 214 + disable_irq(INT_ADM_AARM); 215 + return 0; 238 216 } 239 217 240 218 arch_initcall(msm_init_datamover);
+19 -5
arch/arm/mach-msm/include/mach/dma.h
··· 1 - /* arch/arm/mach-msm/include/mach/dma.h 1 + /* linux/include/asm-arm/arch-msm/dma.h 2 2 * 3 3 * Copyright (C) 2007 Google, Inc. 4 4 * ··· 18 18 #include <linux/list.h> 19 19 #include <mach/msm_iomap.h> 20 20 21 + struct msm_dmov_errdata { 22 + uint32_t flush[6]; 23 + }; 24 + 21 25 struct msm_dmov_cmd { 22 26 struct list_head list; 23 27 unsigned int cmdptr; 24 - void (*complete_func)(struct msm_dmov_cmd *cmd, unsigned int result); 25 - /* void (*user_result_func)(struct msm_dmov_cmd *cmd); */ 28 + void (*complete_func)(struct msm_dmov_cmd *cmd, 29 + unsigned int result, 30 + struct msm_dmov_errdata *err); 26 31 }; 27 32 28 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 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 ··· 125 121 unsigned dst_dscr; 126 122 unsigned _reserved; 127 123 } dmov_sg; 124 + 125 + /* Box mode */ 126 + typedef struct { 127 + uint32_t cmd; 128 + uint32_t src_row_addr; 129 + uint32_t dst_row_addr; 130 + uint32_t src_dst_len; 131 + uint32_t num_rows; 132 + uint32_t row_offset; 133 + } dmov_box; 128 134 129 135 /* bits for the cmd field of the above structures */ 130 136