msm: Add 'execute' datamover callback
authorSan Mehat <san@google.com>
Sat, 21 Nov 2009 17:22:14 +0000 (09:22 -0800)
committerDaniel Walker <dwalker@codeaurora.org>
Thu, 18 Mar 2010 19:58:05 +0000 (12:58 -0700)
Based on a patch from Brent DeGraaf:

"The datamover supports channels which can be shared amongst devices.
As a result, the actual data transfer may occur some time after the
request is queued up. Some devices such as mmc host controllers
will timeout if a command is issued too far in advance of the actual
transfer, so if dma to other devices on the same channel is already
in progress or queued up, the added delay can cause pending transfers
to fail before they start. This change extends the api to allow a
user callback to be invoked just before the actual transfer takes
place, thus allowing actions directly associated with the dma
transfer, such as device commands, to be invoked with precise timing.
Without this mechanism, there is no way for a driver to realize
this timing. Also adds a user pointer to the command structure for use
by the caller to reference information that may be needed by the
callback routine for proper identification and processing associated
with that specific request. This change is necessary to fix problems
associated with excessive command timeouts and race conditions in the
mmc driver."

This patch also fixes all the callers of msm_dmov_enqueue_cmd() to
ensure their callback function is NULL.

Signed-off-by: San Mehat <san@google.com>
Cc: Brent DeGraaf <bdegraaf@quicinc.com>
Cc: Brian Swetland <swetland@google.com>
Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
arch/arm/mach-msm/dma.c
arch/arm/mach-msm/include/mach/dma.h
drivers/mmc/host/msm_sdcc.c

index f5420f9585c59ec504dd85325c55e42141e50f96..8df798ac70c7692886a7a137701c8e8b8bbc0ae2 100644 (file)
@@ -63,6 +63,8 @@ void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd)
                        writel(DMOV_CONFIG_IRQ_EN, DMOV_CONFIG(id));
                }
 #endif
+               if (cmd->execute_func)
+                       cmd->execute_func(cmd);
                PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n", id, status);
                list_add_tail(&cmd->list, &active_commands[id]);
                if (!channel_active)
@@ -108,6 +110,7 @@ int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr)
 
        cmd.dmov_cmd.cmdptr = cmdptr;
        cmd.dmov_cmd.complete_func = dmov_exec_cmdptr_complete_func;
+       cmd.dmov_cmd.execute_func = NULL;
        cmd.id = id;
        init_completion(&cmd.complete);
 
@@ -210,6 +213,8 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id)
                                cmd = list_entry(ready_commands[id].next, typeof(*cmd), list);
                                list_del(&cmd->list);
                                list_add_tail(&cmd->list, &active_commands[id]);
+                               if (cmd->execute_func)
+                                       cmd->execute_func(cmd);
                                PRINT_FLOW("msm_datamover_irq_handler id %d, start command\n", id);
                                writel(cmd->cmdptr, DMOV_CMD_PTR(id));
                        }
index 5ab5bdffab07334781b960661deebe041bab408b..78b0ffdf27e8120cb43ecdcc1dcd0592bfd0f3cf 100644 (file)
@@ -28,6 +28,8 @@ struct msm_dmov_cmd {
        void (*complete_func)(struct msm_dmov_cmd *cmd,
                              unsigned int result,
                              struct msm_dmov_errdata *err);
+       void (*execute_func)(struct msm_dmov_cmd *cmd);
+       void *data;
 };
 
 void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd);
index f4f7883271f0a4d0e171b6eac91a92bb62302017..02bec7c739e00e7dc326ec457832b86e8f6e560f 100644 (file)
@@ -299,6 +299,7 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
        host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
                               DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
        host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
+       host->dma.hdr.execute_func = NULL;
 
        return 0;
 }