From 4adbbcc7b6cfb3dcf5ab49b06edb7752391b0e80 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Sun, 8 Nov 2009 13:00:37 -0800 Subject: mmc: msm_sdcc: Clean up clock management and add a 10us delay after enabling clocks It appears that in some cases there may be a delay on the ARM9 in enabling our clock. As a result, we may put the controller into a bad state. Delay 10us after enabling clocks to let the peripheral settle. Note - this is all imperical. Also ensure set_ios() callback grabs the host lock. Signed-off-by: San Mehat Signed-off-by: Daniel Walker --- drivers/mmc/host/msm_sdcc.c | 80 ++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 40 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 4c068e5fe6b2..977932a4bf4b 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -735,20 +735,42 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) spin_unlock_irqrestore(&host->lock, flags); } +static int inline +msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable) +{ + int rc; + if (enable) { + rc = clk_enable(host->pclk); + if (rc) + return rc; + rc = clk_enable(host->clk); + if (rc) { + clk_disable(host->pclk); + return rc; + } + host->clks_on = 1; + udelay(10); + } else { + clk_disable(host->clk); + clk_disable(host->pclk); + host->clks_on = 0; + } + return 0; +} + static void msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct msmsdcc_host *host = mmc_priv(mmc); u32 clk = 0, pwr = 0; int rc; + unsigned long flags; + spin_lock_irqsave(&host->lock, flags); if (ios->clock) { - if (!host->clks_on) { - clk_enable(host->pclk); - clk_enable(host->clk); - host->clks_on = 1; - } + if (!host->clks_on) + msmsdcc_enable_clocks(host, 1); if (ios->clock != host->clk_rate) { rc = clk_set_rate(host->clk, ios->clock); if (rc < 0) @@ -793,11 +815,9 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) writel(pwr, host->base + MMCIPOWER); } - if (!(clk & MCI_CLK_ENABLE) && host->clks_on) { - clk_disable(host->clk); - clk_disable(host->pclk); - host->clks_on = 0; - } + if (!(clk & MCI_CLK_ENABLE) && host->clks_on) + msmsdcc_enable_clocks(host, 0); + spin_unlock_irqrestore(&host->lock, flags); } static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) @@ -899,7 +919,6 @@ msmsdcc_command_expired(unsigned long _data) pr_err("%s: Command timeout (%p %p %p %p)\n", mmc_hostname(host->mmc), mrq, mrq->cmd, mrq->data, host->dma.sg); - mrq->cmd->error = -ETIMEDOUT; msmsdcc_stop_data(host); @@ -1031,31 +1050,21 @@ msmsdcc_probe(struct platform_device *pdev) */ msmsdcc_init_dma(host); - /* - * Setup main peripheral bus clock - */ + /* Get our clocks */ host->pclk = clk_get(&pdev->dev, "sdc_pclk"); if (IS_ERR(host->pclk)) { ret = PTR_ERR(host->pclk); goto host_free; } - ret = clk_enable(host->pclk); - if (ret) - goto pclk_put; - - host->pclk_rate = clk_get_rate(host->pclk); - - /* - * Setup SDC MMC clock - */ host->clk = clk_get(&pdev->dev, "sdc_clk"); if (IS_ERR(host->clk)) { ret = PTR_ERR(host->clk); - goto pclk_disable; + goto pclk_put; } - ret = clk_enable(host->clk); + /* Enable clocks */ + ret = msmsdcc_enable_clocks(host, 1); if (ret) goto clk_put; @@ -1065,10 +1074,9 @@ msmsdcc_probe(struct platform_device *pdev) goto clk_disable; } + host->pclk_rate = clk_get_rate(host->pclk); host->clk_rate = clk_get_rate(host->clk); - host->clks_on = 1; - /* * Setup MMC host structure */ @@ -1187,11 +1195,9 @@ msmsdcc_probe(struct platform_device *pdev) if (host->stat_irq) free_irq(host->stat_irq, host); clk_disable: - clk_disable(host->clk); + msmsdcc_enable_clocks(host, 0); clk_put: clk_put(host->clk); - pclk_disable: - clk_disable(host->pclk); pclk_put: clk_put(host->pclk); host_free: @@ -1217,11 +1223,8 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) if (!rc) { writel(0, host->base + MMCIMASK0); - if (host->clks_on) { - clk_disable(host->clk); - clk_disable(host->pclk); - host->clks_on = 0; - } + if (host->clks_on) + msmsdcc_enable_clocks(host, 0); } } return rc; @@ -1238,11 +1241,8 @@ msmsdcc_resume(struct platform_device *dev) spin_lock_irqsave(&host->lock, flags); - if (!host->clks_on) { - clk_enable(host->pclk); - clk_enable(host->clk); - host->clks_on = 1; - } + if (!host->clks_on) + msmsdcc_enable_clocks(host, 1); writel(host->saved_irq0mask, host->base + MMCIMASK0); -- cgit v1.2.3 From b3fa579118b239e218e690f5ef76870aff6fe738 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Mon, 2 Nov 2009 18:46:09 -0800 Subject: mmc: msm_sdcc: Snoop SDIO_CCCR_ABORT register Signed-off-by: San Mehat Signed-off-by: Daniel Walker --- drivers/mmc/host/msm_sdcc.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 977932a4bf4b..f4f7883271f0 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -355,6 +356,16 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) } } +static int +snoop_cccr_abort(struct mmc_command *cmd) +{ + if ((cmd->opcode == 52) && + (cmd->arg & 0x80000000) && + (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT)) + return 1; + return 0; +} + static void msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) { @@ -381,6 +392,9 @@ msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) if (cmd == cmd->mrq->stop) c |= MCI_CSPM_MCIABORT; + if (snoop_cccr_abort(cmd)) + c |= MCI_CSPM_MCIABORT; + host->curr.cmd = cmd; host->stats.cmds++; -- cgit v1.2.3 From 5b00f40f90e7b17c11cf388680f43e8466b3666d Mon Sep 17 00:00:00 2001 From: San Mehat Date: Sat, 21 Nov 2009 09:22:14 -0800 Subject: msm: Add 'execute' datamover callback 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 Cc: Brent DeGraaf Cc: Brian Swetland Signed-off-by: Daniel Walker --- arch/arm/mach-msm/dma.c | 5 +++++ arch/arm/mach-msm/include/mach/dma.h | 2 ++ drivers/mmc/host/msm_sdcc.c | 1 + 3 files changed, 8 insertions(+) (limited to 'drivers/mmc') diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c index f5420f9585c5..8df798ac70c7 100644 --- a/arch/arm/mach-msm/dma.c +++ b/arch/arm/mach-msm/dma.c @@ -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)); } diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h index 5ab5bdffab07..78b0ffdf27e8 100644 --- a/arch/arm/mach-msm/include/mach/dma.h +++ b/arch/arm/mach-msm/include/mach/dma.h @@ -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); diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index f4f7883271f0..02bec7c739e0 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -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; } -- cgit v1.2.3 From 865c8064a2fb07100525097983966b8e789bde1a Mon Sep 17 00:00:00 2001 From: San Mehat Date: Fri, 13 Nov 2009 13:42:06 -0800 Subject: mmc: msm_sdcc: Driver clocking/irq improvements - Clocks are now disabled after 1 second of inactivity - Fixed issue which was causing us to loop through our ISR twice - Bump core clock enable delay to 30us Signed-off-by: San Mehat Signed-off-by: Daniel Walker --- drivers/mmc/host/msm_sdcc.c | 89 +++++++++++++++++++++++++++++++-------------- drivers/mmc/host/msm_sdcc.h | 2 + 2 files changed, 63 insertions(+), 28 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 02bec7c739e0..b4b637223b75 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -57,6 +57,32 @@ static unsigned int msmsdcc_sdioirq; #define PIO_SPINMAX 30 #define CMD_SPINMAX 20 + +static inline int +msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable) +{ + int rc; + WARN_ON(enable == host->clks_on); + if (enable) { + rc = clk_enable(host->pclk); + if (rc) + return rc; + rc = clk_enable(host->clk); + if (rc) { + clk_disable(host->pclk); + return rc; + } + udelay(30); + host->clks_on = 1; + } else { + clk_disable(host->clk); + clk_disable(host->pclk); + host->clks_on = 0; + } + return 0; +} + + static void msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c); @@ -76,6 +102,8 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) if (mrq->cmd->error == -ETIMEDOUT) mdelay(5); + if (host->use_bustimer) + mod_timer(&host->busclk_timer, jiffies + HZ); /* * Need to drop the host lock here; mmc_request_done may call * back into the driver... @@ -676,6 +704,12 @@ msmsdcc_irq(int irq, void *dev_id) status &= (readl(base + MMCIMASK0) | MCI_DATABLOCKENDMASK); writel(status, base + MMCICLEAR); + if (status & MCI_SDIOINTR) + status &= ~MCI_SDIOINTR; + + if (!status) + break; + msmsdcc_handle_irq_data(host, status, base); if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | @@ -729,6 +763,8 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) } host->curr.mrq = mrq; + if (!host->clks_on) + msmsdcc_enable_clocks(host, 1); if (mrq->data && mrq->data->flags & MMC_DATA_READ) msmsdcc_start_data(host, mrq->data); @@ -750,29 +786,6 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) spin_unlock_irqrestore(&host->lock, flags); } -static int inline -msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable) -{ - int rc; - if (enable) { - rc = clk_enable(host->pclk); - if (rc) - return rc; - rc = clk_enable(host->clk); - if (rc) { - clk_disable(host->pclk); - return rc; - } - host->clks_on = 1; - udelay(10); - } else { - clk_disable(host->clk); - clk_disable(host->pclk); - host->clks_on = 0; - } - return 0; -} - static void msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { @@ -782,10 +795,10 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) unsigned long flags; spin_lock_irqsave(&host->lock, flags); - if (ios->clock) { + if (!host->clks_on) + msmsdcc_enable_clocks(host, 1); - if (!host->clks_on) - msmsdcc_enable_clocks(host, 1); + if (ios->clock) { if (ios->clock != host->clk_rate) { rc = clk_set_rate(host->clk, ios->clock); if (rc < 0) @@ -829,8 +842,7 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->pwr = pwr; writel(pwr, host->base + MMCIPOWER); } - - if (!(clk & MCI_CLK_ENABLE) && host->clks_on) + if (host->clks_on) msmsdcc_enable_clocks(host, 0); spin_unlock_irqrestore(&host->lock, flags); } @@ -909,6 +921,19 @@ msmsdcc_status_notify_cb(int card_present, void *dev_id) msmsdcc_check_status((unsigned long) host); } +static void +msmsdcc_busclk_expired(unsigned long _data) +{ + struct msmsdcc_host *host = (struct msmsdcc_host *) _data; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + if (host->clks_on) + msmsdcc_enable_clocks(host, 0); + + spin_unlock_irqrestore(&host->lock, flags); +} + /* * called when a command expires. * Dump some debugging, and then error @@ -942,6 +967,8 @@ msmsdcc_command_expired(unsigned long _data) host->curr.mrq = NULL; host->curr.cmd = NULL; + if (host->clks_on) + msmsdcc_enable_clocks(host, 0); spin_unlock_irqrestore(&host->lock, flags); mmc_request_done(host->mmc, mrq); } @@ -1048,6 +1075,8 @@ msmsdcc_probe(struct platform_device *pdev) host->cmdpoll = 1; + host->use_bustimer = 1; + host->base = ioremap(memres->start, PAGE_SIZE); if (!host->base) { ret = -ENOMEM; @@ -1167,6 +1196,10 @@ msmsdcc_probe(struct platform_device *pdev) host->command_timer.data = (unsigned long) host; host->command_timer.function = msmsdcc_command_expired; + init_timer(&host->busclk_timer); + host->busclk_timer.data = (unsigned long) host; + host->busclk_timer.function = msmsdcc_busclk_expired; + ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); if (ret) diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h index 8c8448469811..6846bd7dff22 100644 --- a/drivers/mmc/host/msm_sdcc.h +++ b/drivers/mmc/host/msm_sdcc.h @@ -214,6 +214,8 @@ struct msmsdcc_host { struct clk *pclk; /* SDCC peripheral bus clock */ unsigned int clks_on; /* set if clocks are enabled */ struct timer_list command_timer; + struct timer_list busclk_timer; + int use_bustimer; unsigned int eject; /* eject state */ -- cgit v1.2.3 From 8b1c2ba274c8416afb7eab3bd788f98a917efe06 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Mon, 16 Nov 2009 10:17:30 -0800 Subject: mmc: msm_sdcc: Wrap readl/writel calls with appropriate clk delays As it turns out, all sdcc register writes must be delayed by at least 3 core clock cycles for the writes to take effect. *sigh* Also removes the 30us constant delay on clock enable in favor of a 3 core clock delay. Signed-off-by: San Mehat Signed-off-by: Daniel Walker --- drivers/mmc/host/msm_sdcc.c | 116 +++++++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 55 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index b4b637223b75..3b096f64ec52 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -62,6 +62,7 @@ static inline int msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable) { int rc; + WARN_ON(enable == host->clks_on); if (enable) { rc = clk_enable(host->pclk); @@ -72,7 +73,8 @@ msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable) clk_disable(host->pclk); return rc; } - udelay(30); + udelay(1 + ((3 * USEC_PER_SEC) / + (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); host->clks_on = 1; } else { clk_disable(host->clk); @@ -82,6 +84,20 @@ msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable) return 0; } +static inline unsigned int +msmsdcc_readl(struct msmsdcc_host *host, unsigned int reg) +{ + return readl(host->base + reg); +} + +static inline void +msmsdcc_writel(struct msmsdcc_host *host, u32 data, unsigned int reg) +{ + writel(data, host->base + reg); + /* 3 clk delay required! */ + udelay(1 + ((3 * USEC_PER_SEC) / + (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); +} static void msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, @@ -90,7 +106,7 @@ msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, static void msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) { - writel(0, host->base + MMCICOMMAND); + msmsdcc_writel(host, 0, MMCICOMMAND); BUG_ON(host->curr.data); @@ -116,7 +132,7 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) static void msmsdcc_stop_data(struct msmsdcc_host *host) { - writel(0, host->base + MMCIDATACTRL); + msmsdcc_writel(host, 0, MMCIDATACTRL); host->curr.data = NULL; host->curr.got_dataend = host->curr.got_datablkend = 0; } @@ -200,7 +216,7 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, if (!mrq->data->error) host->curr.data_xfered = host->curr.xfer_size; if (!mrq->data->stop || mrq->cmd->error) { - writel(0, host->base + MMCICOMMAND); + msmsdcc_writel(host, 0, MMCICOMMAND); host->curr.mrq = NULL; host->curr.cmd = NULL; mrq->data->bytes_xfered = host->curr.data_xfered; @@ -337,7 +353,6 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) { unsigned int datactrl, timeout; unsigned long long clks; - void __iomem *base = host->base; unsigned int pio_irqmask = 0; host->curr.data = data; @@ -352,9 +367,9 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) clks = (unsigned long long)data->timeout_ns * host->clk_rate; do_div(clks, NSEC_PER_SEC); timeout = data->timeout_clks + (unsigned int)clks; - writel(timeout, base + MMCIDATATIMER); + msmsdcc_writel(host, timeout, MMCIDATATIMER); - writel(host->curr.xfer_size, base + MMCIDATALENGTH); + msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH); datactrl = MCI_DPSM_ENABLE | (data->blksz << 4); @@ -376,8 +391,8 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) if (data->flags & MMC_DATA_READ) datactrl |= MCI_DPSM_DIRECTION; - writel(pio_irqmask, base + MMCIMASK1); - writel(datactrl, base + MMCIDATACTRL); + msmsdcc_writel(host, pio_irqmask, MMCIMASK1); + msmsdcc_writel(host, datactrl, MMCIDATACTRL); if (datactrl & MCI_DPSM_DMAENABLE) { host->dma.busy = 1; @@ -398,12 +413,8 @@ snoop_cccr_abort(struct mmc_command *cmd) static void msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) { - void __iomem *base = host->base; - - if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) { - writel(0, base + MMCICOMMAND); - udelay(2 + ((5 * 1000000) / host->clk_rate)); - } + if (msmsdcc_readl(host, MMCICOMMAND) & MCI_CPSM_ENABLE) + msmsdcc_writel(host, 0, MMCICOMMAND); c |= cmd->opcode | MCI_CPSM_ENABLE; @@ -428,8 +439,8 @@ msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) host->stats.cmds++; - writel(cmd->arg, base + MMCIARGUMENT); - writel(c, base + MMCICOMMAND); + msmsdcc_writel(host, cmd->arg, MMCIARGUMENT); + msmsdcc_writel(host, c, MMCICOMMAND); } static void @@ -463,13 +474,11 @@ msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data, static int msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain) { - void __iomem *base = host->base; uint32_t *ptr = (uint32_t *) buffer; int count = 0; - while (readl(base + MMCISTATUS) & MCI_RXDATAAVLBL) { - - *ptr = readl(base + MMCIFIFO + (count % MCI_FIFOSIZE)); + while (msmsdcc_readl(host, MMCISTATUS) & MCI_RXDATAAVLBL) { + *ptr = msmsdcc_readl(host, MMCIFIFO + (count % MCI_FIFOSIZE)); ptr++; count += sizeof(uint32_t); @@ -501,7 +510,7 @@ msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer, if (remain == 0) break; - status = readl(base + MMCISTATUS); + status = msmsdcc_readl(host, MMCISTATUS); } while (status & MCI_TXFIFOHALFEMPTY); return ptr - buffer; @@ -511,7 +520,7 @@ static int msmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin) { while (maxspin) { - if ((readl(host->base + MMCISTATUS) & mask)) + if ((msmsdcc_readl(host, MMCISTATUS) & mask)) return 0; udelay(1); --maxspin; @@ -523,10 +532,9 @@ static int msmsdcc_pio_irq(int irq, void *dev_id) { struct msmsdcc_host *host = dev_id; - void __iomem *base = host->base; uint32_t status; - status = readl(base + MMCISTATUS); + status = msmsdcc_readl(host, MMCISTATUS); do { unsigned long flags; @@ -581,14 +589,14 @@ msmsdcc_pio_irq(int irq, void *dev_id) host->pio.sg_off = 0; } - status = readl(base + MMCISTATUS); + status = msmsdcc_readl(host, MMCISTATUS); } while (1); if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) - writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); + msmsdcc_writel(host, MCI_RXDATAAVLBLMASK, MMCIMASK1); if (!host->curr.xfer_remain) - writel(0, base + MMCIMASK1); + msmsdcc_writel(host, 0, MMCIMASK1); return IRQ_HANDLED; } @@ -596,13 +604,12 @@ msmsdcc_pio_irq(int irq, void *dev_id) static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) { struct mmc_command *cmd = host->curr.cmd; - void __iomem *base = host->base; host->curr.cmd = NULL; - cmd->resp[0] = readl(base + MMCIRESPONSE0); - cmd->resp[1] = readl(base + MMCIRESPONSE1); - cmd->resp[2] = readl(base + MMCIRESPONSE2); - cmd->resp[3] = readl(base + MMCIRESPONSE3); + cmd->resp[0] = msmsdcc_readl(host, MMCIRESPONSE0); + cmd->resp[1] = msmsdcc_readl(host, MMCIRESPONSE1); + cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2); + cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3); del_timer(&host->command_timer); if (status & MCI_CMDTIMEOUT) { @@ -699,10 +706,11 @@ msmsdcc_irq(int irq, void *dev_id) spin_lock(&host->lock); do { - status = readl(base + MMCISTATUS); - - status &= (readl(base + MMCIMASK0) | MCI_DATABLOCKENDMASK); - writel(status, base + MMCICLEAR); + struct mmc_data *data; + status = msmsdcc_readl(host, MMCISTATUS); + status &= (msmsdcc_readl(host, MMCIMASK0) | + MCI_DATABLOCKENDMASK); + msmsdcc_writel(host, status, MMCICLEAR); if (status & MCI_SDIOINTR) status &= ~MCI_SDIOINTR; @@ -774,10 +782,11 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) if (host->cmdpoll && !msmsdcc_spin_on_status(host, MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT, CMD_SPINMAX)) { - uint32_t status = readl(host->base + MMCISTATUS); + uint32_t status = msmsdcc_readl(host, MMCISTATUS); msmsdcc_do_cmdirq(host, status); - writel(MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT, - host->base + MMCICLEAR); + msmsdcc_writel(host, + MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT, + MMCICLEAR); host->stats.cmdpoll_hits++; } else { host->stats.cmdpoll_misses++; @@ -836,11 +845,11 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) pwr |= MCI_OD; - writel(clk, host->base + MMCICLOCK); + msmsdcc_writel(host, clk, MMCICLOCK); if (host->pwr != pwr) { host->pwr = pwr; - writel(pwr, host->base + MMCIPOWER); + msmsdcc_writel(host, pwr, MMCIPOWER); } if (host->clks_on) msmsdcc_enable_clocks(host, 0); @@ -855,13 +864,13 @@ static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) spin_lock_irqsave(&host->lock, flags); if (msmsdcc_sdioirq == 1) { - status = readl(host->base + MMCIMASK0); + status = msmsdcc_readl(host, MMCIMASK0); if (enable) status |= MCI_SDIOINTOPERMASK; else status &= ~MCI_SDIOINTOPERMASK; host->saved_irq0mask = status; - writel(status, host->base + MMCIMASK0); + msmsdcc_writel(host, status, MMCIMASK0); } spin_unlock_irqrestore(&host->lock, flags); } @@ -950,19 +959,16 @@ msmsdcc_command_expired(unsigned long _data) mrq = host->curr.mrq; if (!mrq) { - pr_info("%s: Command expiry misfire\n", - mmc_hostname(host->mmc)); spin_unlock_irqrestore(&host->lock, flags); return; } - pr_err("%s: Command timeout (%p %p %p %p)\n", - mmc_hostname(host->mmc), mrq, mrq->cmd, - mrq->data, host->dma.sg); + pr_err("%s: Controller lockup detected\n", + mmc_hostname(host->mmc)); mrq->cmd->error = -ETIMEDOUT; msmsdcc_stop_data(host); - writel(0, host->base + MMCICOMMAND); + msmsdcc_writel(host, 0, MMCICOMMAND); host->curr.mrq = NULL; host->curr.cmd = NULL; @@ -1143,10 +1149,10 @@ msmsdcc_probe(struct platform_device *pdev) mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */ mmc->max_seg_size = mmc->max_req_size; - writel(0, host->base + MMCIMASK0); - writel(0x5e007ff, host->base + MMCICLEAR); /* Add: 1 << 25 */ + msmsdcc_writel(host, 0, MMCIMASK0); + msmsdcc_writel(host, 0x5e007ff, MMCICLEAR); - writel(MCI_IRQENABLE, host->base + MMCIMASK0); + msmsdcc_writel(host, MCI_IRQENABLE, MMCIMASK0); host->saved_irq0mask = MCI_IRQENABLE; /* @@ -1269,7 +1275,7 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) rc = mmc_suspend_host(mmc, state); if (!rc) { - writel(0, host->base + MMCIMASK0); + msmsdcc_writel(host, 0, MMCIMASK0); if (host->clks_on) msmsdcc_enable_clocks(host, 0); @@ -1292,7 +1298,7 @@ msmsdcc_resume(struct platform_device *dev) if (!host->clks_on) msmsdcc_enable_clocks(host, 1); - writel(host->saved_irq0mask, host->base + MMCIMASK0); + msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0); spin_unlock_irqrestore(&host->lock, flags); -- cgit v1.2.3 From 51905dcbcf1f72a17f491c64485d513986110a6f Mon Sep 17 00:00:00 2001 From: San Mehat Date: Mon, 16 Nov 2009 11:59:01 -0800 Subject: mmc: msm_sdcc: Schedule clock disable after probe Signed-off-by: San Mehat Signed-off-by: Daniel Walker --- drivers/mmc/host/msm_sdcc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 3b096f64ec52..84b284e3a288 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -1242,6 +1242,8 @@ msmsdcc_probe(struct platform_device *pdev) if (host->timer.function) pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc)); + if (host->use_bustimer) + mod_timer(&host->busclk_timer, jiffies + HZ); return 0; cmd_irq_free: free_irq(cmd_irqres->start, host); -- cgit v1.2.3 From 56a8b5b8ae81bd766e527a0e5274a087c3c1109d Mon Sep 17 00:00:00 2001 From: San Mehat Date: Sat, 21 Nov 2009 12:29:46 -0800 Subject: mmc: msm_sdcc: Reduce command timeouts and improve reliability. Based on an original patch by Brent DeGraaf: "Previous versions of the SD driver were beset with excessive command timeouts. These timeouts were silent by default, but happened frequently, especially during heavy system activity and concurrent access of two or more SD devices. Worst case, these timeouts would occasionally hit at the end of a successful write, resulting in false failures that could adversely affect journaling file systems if timing was unfortunate. This update tightens the association and timing between dma transfers and the commands that trigger them by utilizing a new api implemented in the datamover. In addition, it also fixes a dma cache coherency issue that was exposed during testing of this fix that occasionally resulted in card corruption. Processing of results in the interrupt status routine was modified to process command results prior to data because overwritten command results were observed during testing since the data section can result in command issuances of its own. This change also eliminates the software command timeout, relying entirely on the hardware version, since the software timeout was found to cause problems of its own after extensive testing (having hardware timer and software timers addressing the same issue was found to cause a race condition under heavy system load)." This change originally added PROG_DONE handling, which has been split out into a separate patch. Also on our platform, the data mover driver maintains coherency to ensure API reliability, so the above mentioned cache corruption issue was not an issue for us. Signed-off-by: San Mehat Cc: Brian Swetland Change-Id: Ifbf17cfafb858106d73bf49af52b5161a265a484 Signed-off-by: San Mehat Signed-off-by: Daniel Walker --- drivers/mmc/host/msm_sdcc.c | 267 ++++++++++++++++++++++++-------------------- drivers/mmc/host/msm_sdcc.h | 14 ++- 2 files changed, 161 insertions(+), 120 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 84b284e3a288..524858597901 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -3,6 +3,7 @@ * * Copyright (C) 2007 Google Inc, * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. + * Copyright (C) 2009, Code Aurora Forum. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -47,6 +48,7 @@ #define DRIVER_NAME "msm-sdcc" +#define BUSCLK_TIMEOUT (HZ * 5) static unsigned int msmsdcc_fmin = 144000; static unsigned int msmsdcc_fmax = 50000000; static unsigned int msmsdcc_4bit = 1; @@ -106,8 +108,6 @@ msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, static void msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) { - msmsdcc_writel(host, 0, MMCICOMMAND); - BUG_ON(host->curr.data); host->curr.mrq = NULL; @@ -119,7 +119,7 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) mdelay(5); if (host->use_bustimer) - mod_timer(&host->busclk_timer, jiffies + HZ); + mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); /* * Need to drop the host lock here; mmc_request_done may call * back into the driver... @@ -132,7 +132,6 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) static void msmsdcc_stop_data(struct msmsdcc_host *host) { - msmsdcc_writel(host, 0, MMCIDATACTRL); host->curr.data = NULL; host->curr.got_dataend = host->curr.got_datablkend = 0; } @@ -153,6 +152,29 @@ uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host) return 0; } +static inline void +msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c) { + msmsdcc_writel(host, arg, MMCIARGUMENT); + msmsdcc_writel(host, c, MMCICOMMAND); +} + +static void +msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd) +{ + struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->data; + + writel(host->cmd_timeout, host->base + MMCIDATATIMER); + writel((unsigned int)host->curr.xfer_size, host->base + MMCIDATALENGTH); + writel(host->cmd_pio_irqmask, host->base + MMCIMASK1); + writel(host->cmd_datactrl, host->base + MMCIDATACTRL); + + if (host->cmd_cmd) { + msmsdcc_start_command_exec(host, + (u32)host->cmd_cmd->arg, (u32)host->cmd_c); + } + host->dma.active = 1; +} + static void msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, unsigned int result, @@ -165,6 +187,8 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, struct mmc_request *mrq; spin_lock_irqsave(&host->lock, flags); + host->dma.active = 0; + mrq = host->curr.mrq; BUG_ON(!mrq); @@ -190,7 +214,6 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, if (!mrq->data->error) mrq->data->error = -EIO; } - host->dma.busy = 0; dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, host->dma.dir); @@ -203,6 +226,7 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, } host->dma.sg = NULL; + host->dma.busy = 0; if ((host->curr.got_dataend && host->curr.got_datablkend) || mrq->data->error) { @@ -262,6 +286,8 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) host->dma.sg = data->sg; host->dma.num_ents = data->sg_len; + BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */ + nc = host->dma.nc; switch (host->pdev_id) { @@ -290,22 +316,15 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) host->curr.user_pages = 0; - n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, - host->dma.num_ents, host->dma.dir); - - if (n != host->dma.num_ents) { - pr_err("%s: Unable to map in all sg elements\n", - mmc_hostname(host->mmc)); - host->dma.sg = NULL; - host->dma.num_ents = 0; - return -ENOMEM; - } - box = &nc->cmd[0]; for (i = 0; i < host->dma.num_ents; i++) { box->cmd = CMD_MODE_BOX; - if (i == (host->dma.num_ents - 1)) + /* Initialize sg dma address */ + sg->dma_address = page_to_dma(mmc_dev(host->mmc), sg_page(sg)) + + sg->offset; + + if (i == (host->dma.num_ents - 1)) box->cmd |= CMD_LC; rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ? (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 : @@ -343,13 +362,68 @@ 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; + n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, + host->dma.num_ents, host->dma.dir); +/* dsb inside dma_map_sg will write nc out to mem as well */ + + if (n != host->dma.num_ents) { + printk(KERN_ERR "%s: Unable to map in all sg elements\n", + mmc_hostname(host->mmc)); + host->dma.sg = NULL; + host->dma.num_ents = 0; + return -ENOMEM; + } + + return 0; +} + +static int +snoop_cccr_abort(struct mmc_command *cmd) +{ + if ((cmd->opcode == 52) && + (cmd->arg & 0x80000000) && + (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT)) + return 1; return 0; } static void -msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) +msmsdcc_start_command_deferred(struct msmsdcc_host *host, + struct mmc_command *cmd, u32 *c) +{ + *c |= (cmd->opcode | MCI_CPSM_ENABLE); + + if (cmd->flags & MMC_RSP_PRESENT) { + if (cmd->flags & MMC_RSP_136) + *c |= MCI_CPSM_LONGRSP; + *c |= MCI_CPSM_RESPONSE; + } + + if (/*interrupt*/0) + *c |= MCI_CPSM_INTERRUPT; + + if ((((cmd->opcode == 17) || (cmd->opcode == 18)) || + ((cmd->opcode == 24) || (cmd->opcode == 25))) || + (cmd->opcode == 53)) + *c |= MCI_CSPM_DATCMD; + + if (cmd == cmd->mrq->stop) + *c |= MCI_CSPM_MCIABORT; + + if (snoop_cccr_abort(cmd)) + *c |= MCI_CSPM_MCIABORT; + + if (host->curr.cmd != NULL) { + printk(KERN_ERR "%s: Overlapping command requests\n", + mmc_hostname(host->mmc)); + } + host->curr.cmd = cmd; +} + +static void +msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data, + struct mmc_command *cmd, u32 c) { unsigned int datactrl, timeout; unsigned long long clks; @@ -364,13 +438,6 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) memset(&host->pio, 0, sizeof(host->pio)); - clks = (unsigned long long)data->timeout_ns * host->clk_rate; - do_div(clks, NSEC_PER_SEC); - timeout = data->timeout_clks + (unsigned int)clks; - msmsdcc_writel(host, timeout, MMCIDATATIMER); - - msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH); - datactrl = MCI_DPSM_ENABLE | (data->blksz << 4); if (!msmsdcc_config_dma(host, data)) @@ -391,56 +458,51 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data) if (data->flags & MMC_DATA_READ) datactrl |= MCI_DPSM_DIRECTION; - msmsdcc_writel(host, pio_irqmask, MMCIMASK1); - msmsdcc_writel(host, datactrl, MMCIDATACTRL); + clks = (unsigned long long)data->timeout_ns * host->clk_rate; + do_div(clks, NSEC_PER_SEC); + timeout = data->timeout_clks + (unsigned int)clks*2 ; if (datactrl & MCI_DPSM_DMAENABLE) { + /* Save parameters for the exec function */ + host->cmd_timeout = timeout; + host->cmd_pio_irqmask = pio_irqmask; + host->cmd_datactrl = datactrl; + host->cmd_cmd = cmd; + + host->dma.hdr.execute_func = msmsdcc_dma_exec_func; + host->dma.hdr.data = (void *)host; host->dma.busy = 1; + + if (cmd) { + msmsdcc_start_command_deferred(host, cmd, &c); + host->cmd_c = c; + } msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr); - } -} + } else { + msmsdcc_writel(host, timeout, MMCIDATATIMER); -static int -snoop_cccr_abort(struct mmc_command *cmd) -{ - if ((cmd->opcode == 52) && - (cmd->arg & 0x80000000) && - (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT)) - return 1; - return 0; + msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH); + + msmsdcc_writel(host, pio_irqmask, MMCIMASK1); + msmsdcc_writel(host, datactrl, MMCIDATACTRL); + + if (cmd) { + /* Daisy-chain the command if requested */ + msmsdcc_start_command(host, cmd, c); + } + } } static void msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) { - if (msmsdcc_readl(host, MMCICOMMAND) & MCI_CPSM_ENABLE) - msmsdcc_writel(host, 0, MMCICOMMAND); - - c |= cmd->opcode | MCI_CPSM_ENABLE; - - if (cmd->flags & MMC_RSP_PRESENT) { - if (cmd->flags & MMC_RSP_136) - c |= MCI_CPSM_LONGRSP; - c |= MCI_CPSM_RESPONSE; - } - - if (cmd->opcode == 17 || cmd->opcode == 18 || - cmd->opcode == 24 || cmd->opcode == 25 || - cmd->opcode == 53) - c |= MCI_CSPM_DATCMD; - if (cmd == cmd->mrq->stop) c |= MCI_CSPM_MCIABORT; - if (snoop_cccr_abort(cmd)) - c |= MCI_CSPM_MCIABORT; - - host->curr.cmd = cmd; - host->stats.cmds++; - msmsdcc_writel(host, cmd->arg, MMCIARGUMENT); - msmsdcc_writel(host, c, MMCICOMMAND); + msmsdcc_start_command_deferred(host, cmd, &c); + msmsdcc_start_command_exec(host, cmd->arg, c); } static void @@ -611,7 +673,6 @@ static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2); cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3); - del_timer(&host->command_timer); if (status & MCI_CMDTIMEOUT) { cmd->error = -ETIMEDOUT; } else if (status & MCI_CMDCRCFAIL && @@ -629,16 +690,24 @@ static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) msmsdcc_request_end(host, cmd->mrq); } else /* host->data == NULL */ msmsdcc_request_end(host, cmd->mrq); - } else if (!(cmd->data->flags & MMC_DATA_READ)) - msmsdcc_start_data(host, cmd->data); + } else if (cmd->data) + if (!(cmd->data->flags & MMC_DATA_READ)) + msmsdcc_start_data(host, cmd->data, + NULL, 0); } static void msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, void __iomem *base) { - struct mmc_data *data = host->curr.data; + struct mmc_data *data; + if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | + MCI_CMDTIMEOUT) && host->curr.cmd) { + msmsdcc_do_cmdirq(host, status); + } + + data = host->curr.data; if (!data) return; @@ -720,11 +789,6 @@ msmsdcc_irq(int irq, void *dev_id) msmsdcc_handle_irq_data(host, status, base); - if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | - MCI_CMDTIMEOUT) && host->curr.cmd) { - msmsdcc_do_cmdirq(host, status); - } - if (status & MCI_SDIOINTOPER) { cardint = 1; status &= ~MCI_SDIOINTOPER; @@ -775,9 +839,10 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) msmsdcc_enable_clocks(host, 1); if (mrq->data && mrq->data->flags & MMC_DATA_READ) - msmsdcc_start_data(host, mrq->data); - - msmsdcc_start_command(host, mrq->cmd, 0); + /* Queue/read data, daisy-chain command when data starts */ + msmsdcc_start_data(host, mrq->data, mrq->cmd, 0); + else + msmsdcc_start_command(host, mrq->cmd, 0); if (host->cmdpoll && !msmsdcc_spin_on_status(host, MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT, @@ -790,7 +855,6 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) host->stats.cmdpoll_hits++; } else { host->stats.cmdpoll_misses++; - mod_timer(&host->command_timer, jiffies + HZ); } spin_unlock_irqrestore(&host->lock, flags); } @@ -943,42 +1007,6 @@ msmsdcc_busclk_expired(unsigned long _data) spin_unlock_irqrestore(&host->lock, flags); } -/* - * called when a command expires. - * Dump some debugging, and then error - * out the transaction. - */ -static void -msmsdcc_command_expired(unsigned long _data) -{ - struct msmsdcc_host *host = (struct msmsdcc_host *) _data; - struct mmc_request *mrq; - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - mrq = host->curr.mrq; - - if (!mrq) { - spin_unlock_irqrestore(&host->lock, flags); - return; - } - - pr_err("%s: Controller lockup detected\n", - mmc_hostname(host->mmc)); - mrq->cmd->error = -ETIMEDOUT; - msmsdcc_stop_data(host); - - msmsdcc_writel(host, 0, MMCICOMMAND); - - host->curr.mrq = NULL; - host->curr.cmd = NULL; - - if (host->clks_on) - msmsdcc_enable_clocks(host, 0); - spin_unlock_irqrestore(&host->lock, flags); - mmc_request_done(host->mmc, mrq); -} - static int msmsdcc_init_dma(struct msmsdcc_host *host) { @@ -1078,6 +1106,7 @@ msmsdcc_probe(struct platform_device *pdev) host->pdev_id = pdev->id; host->plat = plat; host->mmc = mmc; + host->curr.cmd = NULL; host->cmdpoll = 1; @@ -1194,14 +1223,6 @@ msmsdcc_probe(struct platform_device *pdev) host->eject = !host->oldstat; } - /* - * Setup a command timer. We currently need this due to - * some 'strange' timeout / error handling situations. - */ - init_timer(&host->command_timer); - host->command_timer.data = (unsigned long) host; - host->command_timer.function = msmsdcc_command_expired; - init_timer(&host->busclk_timer); host->busclk_timer.data = (unsigned long) host; host->busclk_timer.function = msmsdcc_busclk_expired; @@ -1243,7 +1264,7 @@ msmsdcc_probe(struct platform_device *pdev) pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc)); if (host->use_bustimer) - mod_timer(&host->busclk_timer, jiffies + HZ); + mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); return 0; cmd_irq_free: free_irq(cmd_irqres->start, host); @@ -1267,10 +1288,14 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) { struct mmc_host *mmc = mmc_get_drvdata(dev); int rc = 0; + unsigned long flags; if (mmc) { struct msmsdcc_host *host = mmc_priv(mmc); + if (host->use_bustimer) + del_timer_sync(&host->busclk_timer); + spin_lock_irqsave(&host->lock, flags); if (host->stat_irq) disable_irq(host->stat_irq); @@ -1282,6 +1307,7 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) if (host->clks_on) msmsdcc_enable_clocks(host, 0); } + spin_unlock_irqrestore(&host->lock, flags); } return rc; } @@ -1300,6 +1326,9 @@ msmsdcc_resume(struct platform_device *dev) if (!host->clks_on) msmsdcc_enable_clocks(host, 1); + if (host->use_bustimer) + mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); + msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0); spin_unlock_irqrestore(&host->lock, flags); diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h index 6846bd7dff22..361cb6efd248 100644 --- a/drivers/mmc/host/msm_sdcc.h +++ b/drivers/mmc/host/msm_sdcc.h @@ -171,6 +171,7 @@ struct msmsdcc_dma_data { int channel; struct msmsdcc_host *host; int busy; /* Set if DM is busy */ + int active; }; struct msmsdcc_pio_data { @@ -213,7 +214,6 @@ struct msmsdcc_host { struct clk *clk; /* main MMC bus clock */ struct clk *pclk; /* SDCC peripheral bus clock */ unsigned int clks_on; /* set if clocks are enabled */ - struct timer_list command_timer; struct timer_list busclk_timer; int use_bustimer; @@ -235,6 +235,18 @@ struct msmsdcc_host { struct msmsdcc_pio_data pio; int cmdpoll; struct msmsdcc_stats stats; + +#ifdef CONFIG_MMC_MSM7X00A_RESUME_IN_WQ + struct work_struct resume_task; +#endif + + /* Command parameters */ + unsigned int cmd_timeout; + unsigned int cmd_pio_irqmask; + unsigned int cmd_datactrl; + struct mmc_command *cmd_cmd; + u32 cmd_c; + }; #endif -- cgit v1.2.3 From c7fc9370df1433486dfa9460a833fae664e8be6c Mon Sep 17 00:00:00 2001 From: San Mehat Date: Sun, 22 Nov 2009 17:19:07 -0800 Subject: mmc: msm_sdcc: Fix bug where busclk expiry timer was not properly disabled Signed-off-by: San Mehat Signed-off-by: Daniel Walker --- drivers/mmc/host/msm_sdcc.c | 99 ++++++++++++++++++++++++--------------------- drivers/mmc/host/msm_sdcc.h | 1 - 2 files changed, 52 insertions(+), 48 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 524858597901..591ef3c4e9a7 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -48,7 +48,7 @@ #define DRIVER_NAME "msm-sdcc" -#define BUSCLK_TIMEOUT (HZ * 5) +#define BUSCLK_TIMEOUT (HZ) static unsigned int msmsdcc_fmin = 144000; static unsigned int msmsdcc_fmax = 50000000; static unsigned int msmsdcc_4bit = 1; @@ -60,29 +60,42 @@ static unsigned int msmsdcc_sdioirq; #define CMD_SPINMAX 20 -static inline int -msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable) +static inline void +msmsdcc_disable_clocks(struct msmsdcc_host *host, int deferr) { - int rc; + WARN_ON(!host->clks_on); - WARN_ON(enable == host->clks_on); - if (enable) { - rc = clk_enable(host->pclk); - if (rc) - return rc; - rc = clk_enable(host->clk); - if (rc) { - clk_disable(host->pclk); - return rc; - } - udelay(1 + ((3 * USEC_PER_SEC) / - (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); - host->clks_on = 1; + if (deferr) { + mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); } else { + del_timer_sync(&host->busclk_timer); +// dev_info(mmc_dev(host->mmc), "Immediate clock shutdown\n"); clk_disable(host->clk); clk_disable(host->pclk); host->clks_on = 0; } +} + +static inline int +msmsdcc_enable_clocks(struct msmsdcc_host *host) +{ + int rc; + + WARN_ON(host->clks_on); + + del_timer_sync(&host->busclk_timer); + + rc = clk_enable(host->pclk); + if (rc) + return rc; + rc = clk_enable(host->clk); + if (rc) { + clk_disable(host->pclk); + return rc; + } + udelay(1 + ((3 * USEC_PER_SEC) / + (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); + host->clks_on = 1; return 0; } @@ -118,8 +131,7 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) if (mrq->cmd->error == -ETIMEDOUT) mdelay(5); - if (host->use_bustimer) - mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); + msmsdcc_disable_clocks(host, 1); /* * Need to drop the host lock here; mmc_request_done may call * back into the driver... @@ -240,12 +252,12 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, if (!mrq->data->error) host->curr.data_xfered = host->curr.xfer_size; if (!mrq->data->stop || mrq->cmd->error) { - msmsdcc_writel(host, 0, MMCICOMMAND); host->curr.mrq = NULL; host->curr.cmd = NULL; mrq->data->bytes_xfered = host->curr.data_xfered; spin_unlock_irqrestore(&host->lock, flags); + msmsdcc_disable_clocks(host, 1); mmc_request_done(host->mmc, mrq); return; } else @@ -835,8 +847,14 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) } host->curr.mrq = mrq; + + /* Need to drop the host lock here in case + * the busclk wd fires + */ + spin_unlock_irqrestore(&host->lock, flags); if (!host->clks_on) - msmsdcc_enable_clocks(host, 1); + msmsdcc_enable_clocks(host); + spin_lock_irqsave(&host->lock, flags); if (mrq->data && mrq->data->flags & MMC_DATA_READ) /* Queue/read data, daisy-chain command when data starts */ @@ -867,9 +885,10 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) int rc; unsigned long flags; - spin_lock_irqsave(&host->lock, flags); if (!host->clks_on) - msmsdcc_enable_clocks(host, 1); + msmsdcc_enable_clocks(host); + + spin_lock_irqsave(&host->lock, flags); if (ios->clock) { if (ios->clock != host->clk_rate) { @@ -915,8 +934,7 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->pwr = pwr; msmsdcc_writel(host, pwr, MMCIPOWER); } - if (host->clks_on) - msmsdcc_enable_clocks(host, 0); + msmsdcc_disable_clocks(host, 1); spin_unlock_irqrestore(&host->lock, flags); } @@ -1001,9 +1019,9 @@ msmsdcc_busclk_expired(unsigned long _data) unsigned long flags; spin_lock_irqsave(&host->lock, flags); + dev_info(mmc_dev(host->mmc), "Bus clock timer expired\n"); if (host->clks_on) - msmsdcc_enable_clocks(host, 0); - + msmsdcc_disable_clocks(host, 0); spin_unlock_irqrestore(&host->lock, flags); } @@ -1110,8 +1128,6 @@ msmsdcc_probe(struct platform_device *pdev) host->cmdpoll = 1; - host->use_bustimer = 1; - host->base = ioremap(memres->start, PAGE_SIZE); if (!host->base) { ret = -ENOMEM; @@ -1143,7 +1159,7 @@ msmsdcc_probe(struct platform_device *pdev) } /* Enable clocks */ - ret = msmsdcc_enable_clocks(host, 1); + ret = msmsdcc_enable_clocks(host); if (ret) goto clk_put; @@ -1263,8 +1279,7 @@ msmsdcc_probe(struct platform_device *pdev) if (host->timer.function) pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc)); - if (host->use_bustimer) - mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); + msmsdcc_disable_clocks(host, 1); return 0; cmd_irq_free: free_irq(cmd_irqres->start, host); @@ -1272,7 +1287,7 @@ msmsdcc_probe(struct platform_device *pdev) if (host->stat_irq) free_irq(host->stat_irq, host); clk_disable: - msmsdcc_enable_clocks(host, 0); + msmsdcc_disable_clocks(host, 0); clk_put: clk_put(host->clk); pclk_put: @@ -1293,8 +1308,6 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) if (mmc) { struct msmsdcc_host *host = mmc_priv(mmc); - if (host->use_bustimer) - del_timer_sync(&host->busclk_timer); spin_lock_irqsave(&host->lock, flags); if (host->stat_irq) disable_irq(host->stat_irq); @@ -1304,10 +1317,10 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) if (!rc) { msmsdcc_writel(host, 0, MMCIMASK0); - if (host->clks_on) - msmsdcc_enable_clocks(host, 0); } spin_unlock_irqrestore(&host->lock, flags); + if (host->clks_on) + msmsdcc_disable_clocks(host, 0); } return rc; } @@ -1316,27 +1329,19 @@ static int msmsdcc_resume(struct platform_device *dev) { struct mmc_host *mmc = mmc_get_drvdata(dev); - unsigned long flags; if (mmc) { struct msmsdcc_host *host = mmc_priv(mmc); - spin_lock_irqsave(&host->lock, flags); - - if (!host->clks_on) - msmsdcc_enable_clocks(host, 1); - - if (host->use_bustimer) - mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); + msmsdcc_enable_clocks(host); msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0); - spin_unlock_irqrestore(&host->lock, flags); - if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) mmc_resume_host(mmc); if (host->stat_irq) enable_irq(host->stat_irq); + msmsdcc_disable_clocks(host, 1); } return 0; } diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h index 361cb6efd248..da0039c9285e 100644 --- a/drivers/mmc/host/msm_sdcc.h +++ b/drivers/mmc/host/msm_sdcc.h @@ -215,7 +215,6 @@ struct msmsdcc_host { struct clk *pclk; /* SDCC peripheral bus clock */ unsigned int clks_on; /* set if clocks are enabled */ struct timer_list busclk_timer; - int use_bustimer; unsigned int eject; /* eject state */ -- cgit v1.2.3 From f4748499d3dc5e7cadecb977f0d4f1f4f4a8d8c5 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Mon, 23 Nov 2009 15:36:31 -0800 Subject: mmc: msm_sdcc: Featurize busclock power save and disable it by default Signed-off-by: San Mehat Signed-off-by: Daniel Walker --- drivers/mmc/host/msm_sdcc.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 591ef3c4e9a7..bdafb642a713 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -48,6 +48,7 @@ #define DRIVER_NAME "msm-sdcc" +#define BUSCLK_PWRSAVE 0 #define BUSCLK_TIMEOUT (HZ) static unsigned int msmsdcc_fmin = 144000; static unsigned int msmsdcc_fmax = 50000000; @@ -65,6 +66,8 @@ msmsdcc_disable_clocks(struct msmsdcc_host *host, int deferr) { WARN_ON(!host->clks_on); + BUG_ON(host->curr.mrq); + if (deferr) { mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); } else { @@ -131,7 +134,9 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) if (mrq->cmd->error == -ETIMEDOUT) mdelay(5); +#if BUSCLK_PWRSAVE msmsdcc_disable_clocks(host, 1); +#endif /* * Need to drop the host lock here; mmc_request_done may call * back into the driver... @@ -257,7 +262,9 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, mrq->data->bytes_xfered = host->curr.data_xfered; spin_unlock_irqrestore(&host->lock, flags); +#if BUSCLK_PWRSAVE msmsdcc_disable_clocks(host, 1); +#endif mmc_request_done(host->mmc, mrq); return; } else @@ -934,7 +941,9 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->pwr = pwr; msmsdcc_writel(host, pwr, MMCIPOWER); } +#if BUSCLK_PWRSAVE msmsdcc_disable_clocks(host, 1); +#endif spin_unlock_irqrestore(&host->lock, flags); } @@ -1279,7 +1288,9 @@ msmsdcc_probe(struct platform_device *pdev) if (host->timer.function) pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc)); +#if BUSCLK_PWRSAVE msmsdcc_disable_clocks(host, 1); +#endif return 0; cmd_irq_free: free_irq(cmd_irqres->start, host); @@ -1341,7 +1352,9 @@ msmsdcc_resume(struct platform_device *dev) mmc_resume_host(mmc); if (host->stat_irq) enable_irq(host->stat_irq); +#if BUSCLK_PWRSAVE msmsdcc_disable_clocks(host, 1); +#endif } return 0; } -- cgit v1.2.3 From b3b0ca84cfec581fba3ea8efaa8052cb5e6fc857 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Tue, 24 Nov 2009 12:24:55 -0800 Subject: mmc: msm_sdcc: Fix issue where we might not end a sucessfull request Signed-off-by: San Mehat Signed-off-by: Daniel Walker --- drivers/mmc/host/msm_sdcc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index bdafb642a713..3ea66971edfc 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -208,6 +208,7 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, mrq = host->curr.mrq; BUG_ON(!mrq); + WARN_ON(!mrq->data); if (!(result & DMOV_RSLT_VALID)) { pr_err("msmsdcc: Invalid DataMover result\n"); @@ -719,14 +720,13 @@ static void msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, void __iomem *base) { - struct mmc_data *data; + struct mmc_data *data = host->curr.data; if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT) && host->curr.cmd) { msmsdcc_do_cmdirq(host, status); } - data = host->curr.data; if (!data) return; @@ -739,7 +739,8 @@ msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, msm_dmov_stop_cmd(host->dma.channel, &host->dma.hdr, 0); else { - msmsdcc_stop_data(host); + if (host->curr.data) + msmsdcc_stop_data(host); if (!data->stop) msmsdcc_request_end(host, data->mrq); else -- cgit v1.2.3 From 673ce00d7cb4ec060b5091992959da4a1d91c634 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Wed, 25 Nov 2009 11:16:57 -0800 Subject: mmc: msm_sdcc: Don't disable interrupts while suspending Signed-off-by: San Mehat Signed-off-by: Daniel Walker --- drivers/mmc/host/msm_sdcc.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 3ea66971edfc..6e50939b6f88 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -1315,12 +1315,10 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) { struct mmc_host *mmc = mmc_get_drvdata(dev); int rc = 0; - unsigned long flags; if (mmc) { struct msmsdcc_host *host = mmc_priv(mmc); - spin_lock_irqsave(&host->lock, flags); if (host->stat_irq) disable_irq(host->stat_irq); @@ -1330,7 +1328,6 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) msmsdcc_writel(host, 0, MMCIMASK0); } - spin_unlock_irqrestore(&host->lock, flags); if (host->clks_on) msmsdcc_disable_clocks(host, 0); } -- cgit v1.2.3 From 24bbd7d5b422cde6a149ac2f9ac6e61e66536532 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Tue, 1 Dec 2009 10:10:47 -0800 Subject: mmc: msm_sdcc: Enable busclk idle timer for power savings Signed-off-by: San Mehat Signed-off-by: Daniel Walker --- drivers/mmc/host/msm_sdcc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 6e50939b6f88..d42a2dd69325 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -48,7 +48,7 @@ #define DRIVER_NAME "msm-sdcc" -#define BUSCLK_PWRSAVE 0 +#define BUSCLK_PWRSAVE 1 #define BUSCLK_TIMEOUT (HZ) static unsigned int msmsdcc_fmin = 144000; static unsigned int msmsdcc_fmax = 50000000; @@ -72,7 +72,6 @@ msmsdcc_disable_clocks(struct msmsdcc_host *host, int deferr) mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); } else { del_timer_sync(&host->busclk_timer); -// dev_info(mmc_dev(host->mmc), "Immediate clock shutdown\n"); clk_disable(host->clk); clk_disable(host->pclk); host->clks_on = 0; -- cgit v1.2.3 From 91bb64952a8c57826b01878925bea8831c71a492 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Wed, 2 Dec 2009 17:21:07 -0800 Subject: mmc: msm_sdcc: Don't set host->curr.mrq until after we're sure the busclk timer won't fire Signed-off-by: San Mehat Signed-off-by: Daniel Walker --- drivers/mmc/host/msm_sdcc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index d42a2dd69325..28899ee392e2 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -853,8 +853,6 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) return; } - host->curr.mrq = mrq; - /* Need to drop the host lock here in case * the busclk wd fires */ @@ -863,6 +861,8 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) msmsdcc_enable_clocks(host); spin_lock_irqsave(&host->lock, flags); + host->curr.mrq = mrq; + if (mrq->data && mrq->data->flags & MMC_DATA_READ) /* Queue/read data, daisy-chain command when data starts */ msmsdcc_start_data(host, mrq->data, mrq->cmd, 0); -- cgit v1.2.3 From 6ac9ea69069804d357064357d0082b0eab4c87ce Mon Sep 17 00:00:00 2001 From: San Mehat Date: Wed, 2 Dec 2009 17:24:58 -0800 Subject: mmc: msm_sdcc: Fix the dma exec function to use the proper delays Signed-off-by: San Mehat Signed-off-by: Daniel Walker --- drivers/mmc/host/msm_sdcc.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 28899ee392e2..8329fd650c5f 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -177,17 +177,18 @@ msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c) { static void msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd) { - struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->data; + struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->data; - writel(host->cmd_timeout, host->base + MMCIDATATIMER); - writel((unsigned int)host->curr.xfer_size, host->base + MMCIDATALENGTH); - writel(host->cmd_pio_irqmask, host->base + MMCIMASK1); - writel(host->cmd_datactrl, host->base + MMCIDATACTRL); + msmsdcc_writel(host, host->cmd_timeout, MMCIDATATIMER); + msmsdcc_writel(host, (unsigned int)host->curr.xfer_size, MMCIDATALENGTH); + msmsdcc_writel(host, host->cmd_pio_irqmask, MMCIMASK1); + msmsdcc_writel(host, host->cmd_datactrl, MMCIDATACTRL); - if (host->cmd_cmd) { - msmsdcc_start_command_exec(host, - (u32)host->cmd_cmd->arg, (u32)host->cmd_c); - } + if (host->cmd_cmd) { + msmsdcc_start_command_exec(host, + (u32) host->cmd_cmd->arg, + (u32) host->cmd_c); + } host->dma.active = 1; } -- cgit v1.2.3 From d0719e59f4ad96616f7c02ef0201667e41778c88 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Thu, 3 Dec 2009 10:58:54 -0800 Subject: mmc: msm_sdcc: Fix issue where clocks could be disabled mid transaction msmsdcc_enable_clocks() was incorrectly being called depending on the state of host->clks_on. This means the busclk idle timer was never being deleted if the clock was already on.. Bogus. Also fixes a possible double clk disable if the call to del_timer_sync() in msmsdcc_disable_clocks() raced with the busclk timer. Signed-off-by: San Mehat Signed-off-by: Daniel Walker --- drivers/mmc/host/msm_sdcc.c | 61 ++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 34 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 8329fd650c5f..47b1f2526521 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -61,7 +61,7 @@ static unsigned int msmsdcc_sdioirq; #define CMD_SPINMAX 20 -static inline void +static inline void msmsdcc_disable_clocks(struct msmsdcc_host *host, int deferr) { WARN_ON(!host->clks_on); @@ -72,9 +72,14 @@ msmsdcc_disable_clocks(struct msmsdcc_host *host, int deferr) mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); } else { del_timer_sync(&host->busclk_timer); - clk_disable(host->clk); - clk_disable(host->pclk); - host->clks_on = 0; + /* Need to check clks_on again in case the busclk + * timer fired + */ + if (host->clks_on) { + clk_disable(host->clk); + clk_disable(host->pclk); + host->clks_on = 0; + } } } @@ -83,21 +88,21 @@ msmsdcc_enable_clocks(struct msmsdcc_host *host) { int rc; - WARN_ON(host->clks_on); - del_timer_sync(&host->busclk_timer); - rc = clk_enable(host->pclk); - if (rc) - return rc; - rc = clk_enable(host->clk); - if (rc) { - clk_disable(host->pclk); - return rc; + if (!host->clks_on) { + rc = clk_enable(host->pclk); + if (rc) + return rc; + rc = clk_enable(host->clk); + if (rc) { + clk_disable(host->pclk); + return rc; + } + udelay(1 + ((3 * USEC_PER_SEC) / + (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); + host->clks_on = 1; } - udelay(1 + ((3 * USEC_PER_SEC) / - (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); - host->clks_on = 1; return 0; } @@ -180,7 +185,8 @@ msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd) struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->data; msmsdcc_writel(host, host->cmd_timeout, MMCIDATATIMER); - msmsdcc_writel(host, (unsigned int)host->curr.xfer_size, MMCIDATALENGTH); + msmsdcc_writel(host, (unsigned int)host->curr.xfer_size, + MMCIDATALENGTH); msmsdcc_writel(host, host->cmd_pio_irqmask, MMCIMASK1); msmsdcc_writel(host, host->cmd_datactrl, MMCIDATACTRL); @@ -854,13 +860,7 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) return; } - /* Need to drop the host lock here in case - * the busclk wd fires - */ - spin_unlock_irqrestore(&host->lock, flags); - if (!host->clks_on) - msmsdcc_enable_clocks(host); - spin_lock_irqsave(&host->lock, flags); + msmsdcc_enable_clocks(host); host->curr.mrq = mrq; @@ -893,11 +893,10 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) int rc; unsigned long flags; - if (!host->clks_on) - msmsdcc_enable_clocks(host); - spin_lock_irqsave(&host->lock, flags); + msmsdcc_enable_clocks(host); + if (ios->clock) { if (ios->clock != host->clk_rate) { rc = clk_set_rate(host->clk, ios->clock); @@ -1026,13 +1025,9 @@ static void msmsdcc_busclk_expired(unsigned long _data) { struct msmsdcc_host *host = (struct msmsdcc_host *) _data; - unsigned long flags; - spin_lock_irqsave(&host->lock, flags); - dev_info(mmc_dev(host->mmc), "Bus clock timer expired\n"); if (host->clks_on) msmsdcc_disable_clocks(host, 0); - spin_unlock_irqrestore(&host->lock, flags); } static int @@ -1324,10 +1319,8 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) rc = mmc_suspend_host(mmc, state); - if (!rc) { + if (!rc) msmsdcc_writel(host, 0, MMCIMASK0); - - } if (host->clks_on) msmsdcc_disable_clocks(host, 0); } -- cgit v1.2.3 From 1cd2296909e77702c68021ede9d87a1d967a6a99 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Wed, 3 Feb 2010 12:59:29 -0800 Subject: drivers: mmc: msm_sdcc: Add EMBEDDED_SDIO support Signed-off-by: Dmitry Shmidt Signed-off-by: Daniel Walker --- drivers/mmc/host/msm_sdcc.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 47b1f2526521..b40558e18e87 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -616,7 +616,7 @@ msmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin) return -ETIMEDOUT; } -static int +static irqreturn_t msmsdcc_pio_irq(int irq, void *dev_id) { struct msmsdcc_host *host = dev_id; @@ -801,7 +801,6 @@ msmsdcc_irq(int irq, void *dev_id) spin_lock(&host->lock); do { - struct mmc_data *data; status = msmsdcc_readl(host, MMCISTATUS); status &= (msmsdcc_readl(host, MMCIMASK0) | MCI_DATABLOCKENDMASK); @@ -1145,6 +1144,15 @@ msmsdcc_probe(struct platform_device *pdev) host->dmares = dmares; spin_lock_init(&host->lock); +#ifdef CONFIG_MMC_EMBEDDED_SDIO + if (plat->embedded_sdio) + mmc_set_embedded_sdio_data(mmc, + &plat->embedded_sdio->cis, + &plat->embedded_sdio->cccr, + plat->embedded_sdio->funcs, + plat->embedded_sdio->num_funcs); +#endif + /* * Setup DMA */ -- cgit v1.2.3 From c3635c78e500a52c9fcd55de381a72928d9e054d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 26 Mar 2010 16:44:01 -0700 Subject: DMAENGINE: generic slave control v2 Convert the device_terminate_all() operation on the DMA engine to a generic device_control() operation which can now optionally support also pausing and resuming DMA on a certain channel. Implemented for the COH 901 318 DMAC as an example. [dan.j.williams@intel.com: update for timberdale] Signed-off-by: Linus Walleij Acked-by: Mark Brown Cc: Maciej Sosnowski Cc: Nicolas Ferre Cc: Pavel Machek Cc: Li Yang Cc: Guennadi Liakhovetski Cc: Paul Mundt Cc: Ralf Baechle Cc: Haavard Skinnemoen Cc: Magnus Damm Cc: Liam Girdwood Cc: Joe Perches Cc: Roland Dreier Signed-off-by: Dan Williams --- arch/arm/mach-u300/include/mach/coh901318.h | 14 ---------- drivers/dma/at_hdmac.c | 10 +++++-- drivers/dma/coh901318.c | 42 +++++++++++++++++++---------- drivers/dma/dmaengine.c | 2 +- drivers/dma/dw_dmac.c | 10 +++++-- drivers/dma/fsldma.c | 13 ++++++--- drivers/dma/ipu/ipu_idmac.c | 21 ++++++++++----- drivers/dma/shdma.c | 12 ++++++--- drivers/dma/timb_dma.c | 9 +++++-- drivers/dma/txx9dmac.c | 10 +++++-- drivers/mmc/host/atmel-mci.c | 2 +- drivers/serial/sh-sci.c | 2 +- drivers/video/mx3fb.c | 3 ++- include/linux/dmaengine.h | 18 +++++++++++-- sound/soc/txx9/txx9aclc.c | 6 ++--- 15 files changed, 117 insertions(+), 57 deletions(-) (limited to 'drivers/mmc') diff --git a/arch/arm/mach-u300/include/mach/coh901318.h b/arch/arm/mach-u300/include/mach/coh901318.h index b8155b4e5ffa..43ec040e765b 100644 --- a/arch/arm/mach-u300/include/mach/coh901318.h +++ b/arch/arm/mach-u300/include/mach/coh901318.h @@ -109,20 +109,6 @@ struct coh901318_platform { */ u32 coh901318_get_bytes_left(struct dma_chan *chan); -/** - * coh901318_stop() - Stops dma transfer - * @chan: dma channel handle - * return 0 on success otherwise negative value - */ -void coh901318_stop(struct dma_chan *chan); - -/** - * coh901318_continue() - Resumes a stopped dma transfer - * @chan: dma channel handle - * return 0 on success otherwise negative value - */ -void coh901318_continue(struct dma_chan *chan); - /** * coh901318_filter_id() - DMA channel filter function * @chan: dma channel handle diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index efc1a61ca231..f9143cf9e50a 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -759,13 +759,17 @@ err_desc_get: return NULL; } -static void atc_terminate_all(struct dma_chan *chan) +static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) { struct at_dma_chan *atchan = to_at_dma_chan(chan); struct at_dma *atdma = to_at_dma(chan->device); struct at_desc *desc, *_desc; LIST_HEAD(list); + /* Only supports DMA_TERMINATE_ALL */ + if (cmd != DMA_TERMINATE_ALL) + return -ENXIO; + /* * This is only called when something went wrong elsewhere, so * we don't really care about the data. Just disable the @@ -789,6 +793,8 @@ static void atc_terminate_all(struct dma_chan *chan) /* Flush all pending and queued descriptors */ list_for_each_entry_safe(desc, _desc, &list, desc_node) atc_chain_complete(atchan, desc); + + return 0; } /** @@ -1091,7 +1097,7 @@ static int __init at_dma_probe(struct platform_device *pdev) if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)) { atdma->dma_common.device_prep_slave_sg = atc_prep_slave_sg; - atdma->dma_common.device_terminate_all = atc_terminate_all; + atdma->dma_common.device_control = atc_control; } dma_writel(atdma, EN, AT_DMA_ENABLE); diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c index f636c4a87c7f..53c54e034aa3 100644 --- a/drivers/dma/coh901318.c +++ b/drivers/dma/coh901318.c @@ -506,10 +506,11 @@ u32 coh901318_get_bytes_left(struct dma_chan *chan) EXPORT_SYMBOL(coh901318_get_bytes_left); -/* Stops a transfer without losing data. Enables power save. - Use this function in conjunction with coh901318_continue(..) -*/ -void coh901318_stop(struct dma_chan *chan) +/* + * Pauses a transfer without losing data. Enables power save. + * Use this function in conjunction with coh901318_resume. + */ +static void coh901318_pause(struct dma_chan *chan) { u32 val; unsigned long flags; @@ -550,12 +551,11 @@ void coh901318_stop(struct dma_chan *chan) spin_unlock_irqrestore(&cohc->lock, flags); } -EXPORT_SYMBOL(coh901318_stop); -/* Continues a transfer that has been stopped via 300_dma_stop(..). +/* Resumes a transfer that has been stopped via 300_dma_stop(..). Power save is handled. */ -void coh901318_continue(struct dma_chan *chan) +static void coh901318_resume(struct dma_chan *chan) { u32 val; unsigned long flags; @@ -581,7 +581,6 @@ void coh901318_continue(struct dma_chan *chan) spin_unlock_irqrestore(&cohc->lock, flags); } -EXPORT_SYMBOL(coh901318_continue); bool coh901318_filter_id(struct dma_chan *chan, void *chan_id) { @@ -945,7 +944,7 @@ coh901318_free_chan_resources(struct dma_chan *chan) spin_unlock_irqrestore(&cohc->lock, flags); - chan->device->device_terminate_all(chan); + chan->device->device_control(chan, DMA_TERMINATE_ALL); } @@ -1179,16 +1178,29 @@ coh901318_issue_pending(struct dma_chan *chan) spin_unlock_irqrestore(&cohc->lock, flags); } -static void -coh901318_terminate_all(struct dma_chan *chan) +static int +coh901318_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) { unsigned long flags; struct coh901318_chan *cohc = to_coh901318_chan(chan); struct coh901318_desc *cohd; void __iomem *virtbase = cohc->base->virtbase; - coh901318_stop(chan); + if (cmd == DMA_PAUSE) { + coh901318_pause(chan); + return 0; + } + + if (cmd == DMA_RESUME) { + coh901318_resume(chan); + return 0; + } + + if (cmd != DMA_TERMINATE_ALL) + return -ENXIO; + /* The remainder of this function terminates the transfer */ + coh901318_pause(chan); spin_lock_irqsave(&cohc->lock, flags); /* Clear any pending BE or TC interrupt */ @@ -1227,6 +1239,8 @@ coh901318_terminate_all(struct dma_chan *chan) cohc->busy = 0; spin_unlock_irqrestore(&cohc->lock, flags); + + return 0; } void coh901318_base_init(struct dma_device *dma, const int *pick_chans, struct coh901318_base *base) @@ -1344,7 +1358,7 @@ static int __init coh901318_probe(struct platform_device *pdev) base->dma_slave.device_prep_slave_sg = coh901318_prep_slave_sg; base->dma_slave.device_is_tx_complete = coh901318_is_tx_complete; base->dma_slave.device_issue_pending = coh901318_issue_pending; - base->dma_slave.device_terminate_all = coh901318_terminate_all; + base->dma_slave.device_control = coh901318_control; base->dma_slave.dev = &pdev->dev; err = dma_async_device_register(&base->dma_slave); @@ -1364,7 +1378,7 @@ static int __init coh901318_probe(struct platform_device *pdev) base->dma_memcpy.device_prep_dma_memcpy = coh901318_prep_memcpy; base->dma_memcpy.device_is_tx_complete = coh901318_is_tx_complete; base->dma_memcpy.device_issue_pending = coh901318_issue_pending; - base->dma_memcpy.device_terminate_all = coh901318_terminate_all; + base->dma_memcpy.device_control = coh901318_control; base->dma_memcpy.dev = &pdev->dev; /* * This controller can only access address at even 32bit boundaries, diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 87399cafce37..ffc4ee9c5e21 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -694,7 +694,7 @@ int dma_async_device_register(struct dma_device *device) BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) && !device->device_prep_slave_sg); BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) && - !device->device_terminate_all); + !device->device_control); BUG_ON(!device->device_alloc_chan_resources); BUG_ON(!device->device_free_chan_resources); diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index d28369f7afd2..8a6b85f61176 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -781,13 +781,17 @@ err_desc_get: return NULL; } -static void dwc_terminate_all(struct dma_chan *chan) +static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) { struct dw_dma_chan *dwc = to_dw_dma_chan(chan); struct dw_dma *dw = to_dw_dma(chan->device); struct dw_desc *desc, *_desc; LIST_HEAD(list); + /* Only supports DMA_TERMINATE_ALL */ + if (cmd != DMA_TERMINATE_ALL) + return -ENXIO; + /* * This is only called when something went wrong elsewhere, so * we don't really care about the data. Just disable the @@ -810,6 +814,8 @@ static void dwc_terminate_all(struct dma_chan *chan) /* Flush all pending and queued descriptors */ list_for_each_entry_safe(desc, _desc, &list, desc_node) dwc_descriptor_complete(dwc, desc); + + return 0; } static enum dma_status @@ -1338,7 +1344,7 @@ static int __init dw_probe(struct platform_device *pdev) dw->dma.device_prep_dma_memcpy = dwc_prep_dma_memcpy; dw->dma.device_prep_slave_sg = dwc_prep_slave_sg; - dw->dma.device_terminate_all = dwc_terminate_all; + dw->dma.device_control = dwc_control; dw->dma.device_is_tx_complete = dwc_is_tx_complete; dw->dma.device_issue_pending = dwc_issue_pending; diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index bbb4be5a3ff4..714fc46e7695 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -774,13 +774,18 @@ fail: return NULL; } -static void fsl_dma_device_terminate_all(struct dma_chan *dchan) +static int fsl_dma_device_control(struct dma_chan *dchan, + enum dma_ctrl_cmd cmd) { struct fsldma_chan *chan; unsigned long flags; + /* Only supports DMA_TERMINATE_ALL */ + if (cmd != DMA_TERMINATE_ALL) + return -ENXIO; + if (!dchan) - return; + return -EINVAL; chan = to_fsl_chan(dchan); @@ -794,6 +799,8 @@ static void fsl_dma_device_terminate_all(struct dma_chan *dchan) fsldma_free_desc_list(chan, &chan->ld_running); spin_unlock_irqrestore(&chan->desc_lock, flags); + + return 0; } /** @@ -1332,7 +1339,7 @@ static int __devinit fsldma_of_probe(struct of_device *op, fdev->common.device_is_tx_complete = fsl_dma_is_complete; fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending; fdev->common.device_prep_slave_sg = fsl_dma_prep_slave_sg; - fdev->common.device_terminate_all = fsl_dma_device_terminate_all; + fdev->common.device_control = fsl_dma_device_control; fdev->common.dev = &op->dev; dev_set_drvdata(&op->dev, fdev); diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c index 2a446397c884..39e7fb2a90e3 100644 --- a/drivers/dma/ipu/ipu_idmac.c +++ b/drivers/dma/ipu/ipu_idmac.c @@ -1472,13 +1472,17 @@ static void idmac_issue_pending(struct dma_chan *chan) */ } -static void __idmac_terminate_all(struct dma_chan *chan) +static int __idmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) { struct idmac_channel *ichan = to_idmac_chan(chan); struct idmac *idmac = to_idmac(chan->device); unsigned long flags; int i; + /* Only supports DMA_TERMINATE_ALL */ + if (cmd != DMA_TERMINATE_ALL) + return -ENXIO; + ipu_disable_channel(idmac, ichan, ichan->status >= IPU_CHANNEL_ENABLED); @@ -1505,17 +1509,22 @@ static void __idmac_terminate_all(struct dma_chan *chan) tasklet_enable(&to_ipu(idmac)->tasklet); ichan->status = IPU_CHANNEL_INITIALIZED; + + return 0; } -static void idmac_terminate_all(struct dma_chan *chan) +static int idmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) { struct idmac_channel *ichan = to_idmac_chan(chan); + int ret; mutex_lock(&ichan->chan_mutex); - __idmac_terminate_all(chan); + ret = __idmac_control(chan, cmd); mutex_unlock(&ichan->chan_mutex); + + return ret; } #ifdef DEBUG @@ -1607,7 +1616,7 @@ static void idmac_free_chan_resources(struct dma_chan *chan) mutex_lock(&ichan->chan_mutex); - __idmac_terminate_all(chan); + __idmac_control(chan, DMA_TERMINATE_ALL); if (ichan->status > IPU_CHANNEL_FREE) { #ifdef DEBUG @@ -1669,7 +1678,7 @@ static int __init ipu_idmac_init(struct ipu *ipu) /* Compulsory for DMA_SLAVE fields */ dma->device_prep_slave_sg = idmac_prep_slave_sg; - dma->device_terminate_all = idmac_terminate_all; + dma->device_control = idmac_control; INIT_LIST_HEAD(&dma->channels); for (i = 0; i < IPU_CHANNELS_NUM; i++) { @@ -1703,7 +1712,7 @@ static void __exit ipu_idmac_exit(struct ipu *ipu) for (i = 0; i < IPU_CHANNELS_NUM; i++) { struct idmac_channel *ichan = ipu->channel + i; - idmac_terminate_all(&ichan->dma_chan); + idmac_control(&ichan->dma_chan, DMA_TERMINATE_ALL); idmac_prep_slave_sg(&ichan->dma_chan, NULL, 0, DMA_NONE, 0); } diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index 5d17e09cb625..ce28c1e22825 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -580,12 +580,16 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_slave_sg( direction, flags); } -static void sh_dmae_terminate_all(struct dma_chan *chan) +static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) { struct sh_dmae_chan *sh_chan = to_sh_chan(chan); + /* Only supports DMA_TERMINATE_ALL */ + if (cmd != DMA_TERMINATE_ALL) + return -ENXIO; + if (!chan) - return; + return -EINVAL; dmae_halt(sh_chan); @@ -601,6 +605,8 @@ static void sh_dmae_terminate_all(struct dma_chan *chan) spin_unlock_bh(&sh_chan->desc_lock); sh_dmae_chan_ld_cleanup(sh_chan, true); + + return 0; } static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all) @@ -1029,7 +1035,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev) /* Compulsory for DMA_SLAVE fields */ shdev->common.device_prep_slave_sg = sh_dmae_prep_slave_sg; - shdev->common.device_terminate_all = sh_dmae_terminate_all; + shdev->common.device_control = sh_dmae_control; shdev->common.dev = &pdev->dev; /* Default transfer size of 32 bytes requires 32-byte alignment */ diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c index 145f1c23408f..7c06471ef863 100644 --- a/drivers/dma/timb_dma.c +++ b/drivers/dma/timb_dma.c @@ -613,7 +613,7 @@ static struct dma_async_tx_descriptor *td_prep_slave_sg(struct dma_chan *chan, return &td_desc->txd; } -static void td_terminate_all(struct dma_chan *chan) +static int td_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) { struct timb_dma_chan *td_chan = container_of(chan, struct timb_dma_chan, chan); @@ -621,6 +621,9 @@ static void td_terminate_all(struct dma_chan *chan) dev_dbg(chan2dev(chan), "%s: Entry\n", __func__); + if (cmd != DMA_TERMINATE_ALL) + return -ENXIO; + /* first the easy part, put the queue into the free list */ spin_lock_bh(&td_chan->lock); list_for_each_entry_safe(td_desc, _td_desc, &td_chan->queue, @@ -630,6 +633,8 @@ static void td_terminate_all(struct dma_chan *chan) /* now tear down the runnning */ __td_finish(td_chan); spin_unlock_bh(&td_chan->lock); + + return 0; } static void td_tasklet(unsigned long data) @@ -743,7 +748,7 @@ static int __devinit td_probe(struct platform_device *pdev) dma_cap_set(DMA_SLAVE, td->dma.cap_mask); dma_cap_set(DMA_PRIVATE, td->dma.cap_mask); td->dma.device_prep_slave_sg = td_prep_slave_sg; - td->dma.device_terminate_all = td_terminate_all; + td->dma.device_control = td_control; td->dma.dev = &pdev->dev; diff --git a/drivers/dma/txx9dmac.c b/drivers/dma/txx9dmac.c index 3ebc61067e54..e528e15f44ab 100644 --- a/drivers/dma/txx9dmac.c +++ b/drivers/dma/txx9dmac.c @@ -938,12 +938,16 @@ txx9dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, return &first->txd; } -static void txx9dmac_terminate_all(struct dma_chan *chan) +static int txx9dmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) { struct txx9dmac_chan *dc = to_txx9dmac_chan(chan); struct txx9dmac_desc *desc, *_desc; LIST_HEAD(list); + /* Only supports DMA_TERMINATE_ALL */ + if (cmd != DMA_TERMINATE_ALL) + return -EINVAL; + dev_vdbg(chan2dev(chan), "terminate_all\n"); spin_lock_bh(&dc->lock); @@ -958,6 +962,8 @@ static void txx9dmac_terminate_all(struct dma_chan *chan) /* Flush all pending and queued descriptors */ list_for_each_entry_safe(desc, _desc, &list, desc_node) txx9dmac_descriptor_complete(dc, desc); + + return 0; } static enum dma_status @@ -1153,7 +1159,7 @@ static int __init txx9dmac_chan_probe(struct platform_device *pdev) dc->dma.dev = &pdev->dev; dc->dma.device_alloc_chan_resources = txx9dmac_alloc_chan_resources; dc->dma.device_free_chan_resources = txx9dmac_free_chan_resources; - dc->dma.device_terminate_all = txx9dmac_terminate_all; + dc->dma.device_control = txx9dmac_control; dc->dma.device_is_tx_complete = txx9dmac_is_tx_complete; dc->dma.device_issue_pending = txx9dmac_issue_pending; if (pdata && pdata->memcpy_chan == ch) { diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 8072128e933b..ae6d24ba4f08 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -578,7 +578,7 @@ static void atmci_stop_dma(struct atmel_mci *host) struct dma_chan *chan = host->data_chan; if (chan) { - chan->device->device_terminate_all(chan); + chan->device->device_control(chan, DMA_TERMINATE_ALL); atmci_dma_cleanup(host); } else { /* Data transfer was stopped by the interrupt handler */ diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index f7b9aff88f4a..690988237971 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -1087,7 +1087,7 @@ static void work_fn_rx(struct work_struct *work) unsigned long flags; int count; - chan->device->device_terminate_all(chan); + chan->device->device_control(chan, DMA_TERMINATE_ALL); dev_dbg(port->dev, "Read %u bytes with cookie %d\n", sh_desc->partial, sh_desc->cookie); diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index 772ba3f45e6f..3aa50bc276eb 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -387,7 +387,8 @@ static void sdc_disable_channel(struct mx3fb_info *mx3_fbi) spin_unlock_irqrestore(&mx3fb->lock, flags); - mx3_fbi->txd->chan->device->device_terminate_all(mx3_fbi->txd->chan); + mx3_fbi->txd->chan->device->device_control(mx3_fbi->txd->chan, + DMA_TERMINATE_ALL); mx3_fbi->txd = NULL; mx3_fbi->cookie = -EINVAL; } diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 20ea12c86fd0..0731802f876f 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -106,6 +106,19 @@ enum dma_ctrl_flags { DMA_PREP_FENCE = (1 << 9), }; +/** + * enum dma_ctrl_cmd - DMA operations that can optionally be exercised + * on a running channel. + * @DMA_TERMINATE_ALL: terminate all ongoing transfers + * @DMA_PAUSE: pause ongoing transfers + * @DMA_RESUME: resume paused transfer + */ +enum dma_ctrl_cmd { + DMA_TERMINATE_ALL, + DMA_PAUSE, + DMA_RESUME, +}; + /** * enum sum_check_bits - bit position of pq_check_flags */ @@ -261,7 +274,8 @@ struct dma_async_tx_descriptor { * @device_prep_dma_memset: prepares a memset operation * @device_prep_dma_interrupt: prepares an end of chain interrupt operation * @device_prep_slave_sg: prepares a slave dma operation - * @device_terminate_all: terminate all pending operations + * @device_control: manipulate all pending operations on a channel, returns + * zero or error code * @device_is_tx_complete: poll for transaction completion * @device_issue_pending: push pending transactions to hardware */ @@ -313,7 +327,7 @@ struct dma_device { struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, enum dma_data_direction direction, unsigned long flags); - void (*device_terminate_all)(struct dma_chan *chan); + int (*device_control)(struct dma_chan *chan, enum dma_ctrl_cmd cmd); enum dma_status (*device_is_tx_complete)(struct dma_chan *chan, dma_cookie_t cookie, dma_cookie_t *last, diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index efed64b8b026..b35d00706c0e 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c @@ -159,7 +159,7 @@ static void txx9aclc_dma_tasklet(unsigned long data) void __iomem *base = drvdata->base; spin_unlock_irqrestore(&dmadata->dma_lock, flags); - chan->device->device_terminate_all(chan); + chan->device->device_control(chan, DMA_TERMINATE_ALL); /* first time */ for (i = 0; i < NR_DMA_CHAIN; i++) { desc = txx9aclc_dma_submit(dmadata, @@ -267,7 +267,7 @@ static int txx9aclc_pcm_close(struct snd_pcm_substream *substream) struct dma_chan *chan = dmadata->dma_chan; dmadata->frag_count = -1; - chan->device->device_terminate_all(chan); + chan->device->device_control(chan, DMA_TERMINATE_ALL); return 0; } @@ -396,7 +396,7 @@ static int txx9aclc_pcm_remove(struct platform_device *pdev) struct dma_chan *chan = dmadata->dma_chan; if (chan) { dmadata->frag_count = -1; - chan->device->device_terminate_all(chan); + chan->device->device_control(chan, DMA_TERMINATE_ALL); dma_release_channel(chan); } dev->dmadata[i].dma_chan = NULL; -- cgit v1.2.3 From 771dc157e06d69fcece0b2c8a29b9010345d8e9a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 8 Apr 2010 07:38:52 +0100 Subject: ARM: 6032/1: ARM: MMCI: support 8bit mode on the ST Micro version This adds support for an 8bit wide bus to the card (data lines MCIDAT0 through 7 exist) on the ST Micro version and alters the U300 platform to support this. Also add some ST_ prefix to the ST-specific registers. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/mach-u300/mmc.c | 2 +- drivers/mmc/host/mmci.c | 6 ++++-- drivers/mmc/host/mmci.h | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/mmc') diff --git a/arch/arm/mach-u300/mmc.c b/arch/arm/mach-u300/mmc.c index 109f5a6e71c7..ef8032d2f5bf 100644 --- a/arch/arm/mach-u300/mmc.c +++ b/arch/arm/mach-u300/mmc.c @@ -105,7 +105,7 @@ int __devinit mmc_init(struct amba_device *adev) mmci_card->mmc0_plat_data.gpio_wp = -1; mmci_card->mmc0_plat_data.gpio_cd = -1; mmci_card->mmc0_plat_data.capabilities = MMC_CAP_MMC_HIGHSPEED | - MMC_CAP_SD_HIGHSPEED | MMC_CAP_4_BIT_DATA; + MMC_CAP_SD_HIGHSPEED | MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; mmcsd_device->platform_data = (void *) &mmci_card->mmc0_plat_data; diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 84c103a7ee13..7e70c1a06d8a 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -55,14 +55,16 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) host->cclk = host->mclk / (2 * (clk + 1)); } if (host->hw_designer == AMBA_VENDOR_ST) - clk |= MCI_FCEN; /* Bug fix in ST IP block */ + clk |= MCI_ST_FCEN; /* Bug fix in ST IP block */ clk |= MCI_CLK_ENABLE; /* This hasn't proven to be worthwhile */ /* clk |= MCI_CLK_PWRSAVE; */ } if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) - clk |= MCI_WIDE_BUS; + clk |= MCI_4BIT_BUS; + if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8) + clk |= MCI_ST_8BIT_BUS; writel(clk, host->base + MMCICLOCK); } diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 1ceb9a90f59b..d77062e5e3af 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -25,9 +25,11 @@ #define MCI_CLK_ENABLE (1 << 8) #define MCI_CLK_PWRSAVE (1 << 9) #define MCI_CLK_BYPASS (1 << 10) -#define MCI_WIDE_BUS (1 << 11) +#define MCI_4BIT_BUS (1 << 11) +/* 8bit wide buses supported in ST Micro versions */ +#define MCI_ST_8BIT_BUS (1 << 12) /* HW flow control on the ST Micro version */ -#define MCI_FCEN (1 << 13) +#define MCI_ST_FCEN (1 << 13) #define MMCIARGUMENT 0x008 #define MMCICOMMAND 0x00c -- cgit v1.2.3 From 808d97ccbe8e8251b1435e86c762965fd7e8a75e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 8 Apr 2010 07:39:38 +0100 Subject: ARM: 6033/1: ARM: MMCI: pass max frequency from platform This introduce the field f_max into the mmci_platform_data, making it possible to pass in a desired block clocking frequency from a board configuration. This is often more desirable than using a module parameter. We keep the module parameter as a fallback as well as the default frequency specified for this parameter if a parameter is not provided. This also adds some kerneldoc style documentation to the platform data struct in mmci.h. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 13 ++++++++++++- include/linux/amba/mmci.h | 23 ++++++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 7e70c1a06d8a..ff115d920888 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -631,7 +631,18 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) mmc->ops = &mmci_ops; mmc->f_min = (host->mclk + 511) / 512; - mmc->f_max = min(host->mclk, fmax); + /* + * If the platform data supplies a maximum operating + * frequency, this takes precedence. Else, we fall back + * to using the module parameter, which has a (low) + * default value in case it is not specified. Either + * value must not exceed the clock rate into the block, + * of course. + */ + if (plat->f_max) + mmc->f_max = min(host->mclk, plat->f_max); + else + mmc->f_max = min(host->mclk, fmax); dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max); #ifdef CONFIG_REGULATOR diff --git a/include/linux/amba/mmci.h b/include/linux/amba/mmci.h index 6b4241748dda..7e466fe72025 100644 --- a/include/linux/amba/mmci.h +++ b/include/linux/amba/mmci.h @@ -6,8 +6,29 @@ #include +/** + * struct mmci_platform_data - platform configuration for the MMCI + * (also known as PL180) block. + * @f_max: the maximum operational frequency for this host in this + * platform configuration. When this is specified it takes precedence + * over the module parameter for the same frequency. + * @ocr_mask: available voltages on the 4 pins from the block, this + * is ignored if a regulator is used, see the MMC_VDD_* masks in + * mmc/host.h + * @translate_vdd: a callback function to translate a MMC_VDD_* + * mask into a value to be binary or:ed and written into the + * MMCIPWR register of the block + * @status: if no GPIO read function was given to the block in + * gpio_wp (below) this function will be called to determine + * whether a card is present in the MMC slot or not + * @gpio_wp: read this GPIO pin to see if the card is write protected + * @gpio_cd: read this GPIO pin to detect card insertion + * @capabilities: the capabilities of the block as implemented in + * this platform, signify anything MMC_CAP_* from mmc/host.h + */ struct mmci_platform_data { - unsigned int ocr_mask; /* available voltages */ + unsigned int f_max; + unsigned int ocr_mask; u32 (*translate_vdd)(struct device *, unsigned int); unsigned int (*status)(struct device *); int gpio_wp; -- cgit v1.2.3 From f97cab28b1895ecb0aa317cc785bb209f57fc1e8 Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Wed, 14 Apr 2010 07:00:42 +0800 Subject: [ARM] pxa: make it clear by converting MMC 'delay_detect' to millisecond delay_detect in HZ is confusing, convert it to be millisecond based. And thus remove those unnecessary call to msecs_to_jiffies() at runtime for this field. Other constants are converted assuming HZ == 100, which are basically true for those platforms. The assignment in csb726.c was incorrect, and is fixed in this patch as a result. Signed-off-by: Eric Miao Acked-by: Robert Jarzmik Acked-by: Marc Zyngier Acked-by: Marek Vasut Acked-by: Mike Rapoport Acked-by: Daniel Mack --- arch/arm/mach-pxa/cm-x300.c | 4 ++-- arch/arm/mach-pxa/colibri-pxa3xx.c | 2 +- arch/arm/mach-pxa/corgi.c | 2 +- arch/arm/mach-pxa/csb726.c | 11 +---------- arch/arm/mach-pxa/em-x270.c | 2 +- arch/arm/mach-pxa/include/mach/mmc.h | 2 +- arch/arm/mach-pxa/littleton.c | 2 +- arch/arm/mach-pxa/lubbock.c | 2 +- arch/arm/mach-pxa/mioa701.c | 2 +- arch/arm/mach-pxa/mxm8x10.c | 2 +- arch/arm/mach-pxa/palmld.c | 2 +- arch/arm/mach-pxa/palmt5.c | 2 +- arch/arm/mach-pxa/palmtc.c | 2 +- arch/arm/mach-pxa/palmtx.c | 2 +- arch/arm/mach-pxa/pcm990-baseboard.c | 2 +- arch/arm/mach-pxa/poodle.c | 2 +- arch/arm/mach-pxa/raumfeld.c | 2 +- arch/arm/mach-pxa/spitz.c | 2 +- arch/arm/mach-pxa/stargate2.c | 5 +---- arch/arm/mach-pxa/tosa.c | 2 +- arch/arm/mach-pxa/trizeps4.c | 2 +- arch/arm/mach-pxa/vpac270.c | 2 +- arch/arm/mach-pxa/z2.c | 2 +- arch/arm/mach-pxa/zeus.c | 2 +- arch/arm/mach-pxa/zylonite.c | 6 +++--- drivers/mmc/host/pxamci.c | 2 +- 26 files changed, 29 insertions(+), 41 deletions(-) (limited to 'drivers/mmc') diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c index be9dc7a20fbd..fdda6be6c391 100644 --- a/arch/arm/mach-pxa/cm-x300.c +++ b/arch/arm/mach-pxa/cm-x300.c @@ -433,7 +433,7 @@ static inline void cm_x300_init_nand(void) {} #if defined(CONFIG_MMC) || defined(CONFIG_MMC_MODULE) static struct pxamci_platform_data cm_x300_mci_platform_data = { - .detect_delay = 20, + .detect_delay_ms = 200, .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .gpio_card_detect = GPIO82_MMC_IRQ, .gpio_card_ro = GPIO85_MMC_WP, @@ -454,7 +454,7 @@ static void cm_x300_mci2_exit(struct device *dev, void *data) } static struct pxamci_platform_data cm_x300_mci2_platform_data = { - .detect_delay = 20, + .detect_delay_ms = 200, .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .init = cm_x300_mci2_init, .exit = cm_x300_mci2_exit, diff --git a/arch/arm/mach-pxa/colibri-pxa3xx.c b/arch/arm/mach-pxa/colibri-pxa3xx.c index e6c0a2287eb8..199afa2ae303 100644 --- a/arch/arm/mach-pxa/colibri-pxa3xx.c +++ b/arch/arm/mach-pxa/colibri-pxa3xx.c @@ -96,7 +96,7 @@ static void colibri_pxa3xx_mci_exit(struct device *dev, void *data) } static struct pxamci_platform_data colibri_pxa3xx_mci_platform_data = { - .detect_delay = 20, + .detect_delay_ms = 200, .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, .init = colibri_pxa3xx_mci_init, .exit = colibri_pxa3xx_mci_exit, diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index f8e295900c58..3d1dcb9ac08f 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -444,6 +444,7 @@ static struct platform_device corgiled_device = { * to give the card a chance to fully insert/eject. */ static struct pxamci_platform_data corgi_mci_platform_data = { + .detect_delay_ms = 250, .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .gpio_card_detect = -1, .gpio_card_ro = CORGI_GPIO_nSD_WP, @@ -695,7 +696,6 @@ static void __init corgi_init(void) corgi_init_spi(); pxa_set_udc_info(&udc_info); - corgi_mci_platform_data.detect_delay = msecs_to_jiffies(250); pxa_set_mci_info(&corgi_mci_platform_data); pxa_set_ficp_info(&corgi_ficp_platform_data); pxa_set_i2c_info(NULL); diff --git a/arch/arm/mach-pxa/csb726.c b/arch/arm/mach-pxa/csb726.c index 88575b87bd33..91fd4fea6a54 100644 --- a/arch/arm/mach-pxa/csb726.c +++ b/arch/arm/mach-pxa/csb726.c @@ -125,18 +125,9 @@ static unsigned long csb726_pin_config[] = { GPIO118_I2C_SDA, }; -static struct pxamci_platform_data csb726_mci_data; - -static int csb726_mci_init(struct device *dev, - irq_handler_t detect, void *data) -{ - csb726_mci_data.detect_delay = msecs_to_jiffies(500); - return 0; -} - static struct pxamci_platform_data csb726_mci = { + .detect_delay_ms = 500, .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, - .init = csb726_mci_init, /* FIXME setpower */ .gpio_card_detect = CSB726_GPIO_MMC_DETECT, .gpio_card_ro = CSB726_GPIO_MMC_RO, diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c index aab04f33e49b..0517c17978f3 100644 --- a/arch/arm/mach-pxa/em-x270.c +++ b/arch/arm/mach-pxa/em-x270.c @@ -626,6 +626,7 @@ static int em_x270_mci_get_ro(struct device *dev) } static struct pxamci_platform_data em_x270_mci_platform_data = { + .detect_delay_ms = 250, .ocr_mask = MMC_VDD_20_21|MMC_VDD_21_22|MMC_VDD_22_23| MMC_VDD_24_25|MMC_VDD_25_26|MMC_VDD_26_27| MMC_VDD_27_28|MMC_VDD_28_29|MMC_VDD_29_30| @@ -643,7 +644,6 @@ static void __init em_x270_init_mmc(void) if (machine_is_em_x270()) em_x270_mci_platform_data.get_ro = em_x270_mci_get_ro; - em_x270_mci_platform_data.detect_delay = msecs_to_jiffies(250); pxa_set_mci_info(&em_x270_mci_platform_data); } #else diff --git a/arch/arm/mach-pxa/include/mach/mmc.h b/arch/arm/mach-pxa/include/mach/mmc.h index 02a69dc2ee63..9eb515bb799d 100644 --- a/arch/arm/mach-pxa/include/mach/mmc.h +++ b/arch/arm/mach-pxa/include/mach/mmc.h @@ -9,7 +9,7 @@ struct mmc_host; struct pxamci_platform_data { unsigned int ocr_mask; /* available voltages */ - unsigned long detect_delay; /* delay in jiffies before detecting cards after interrupt */ + unsigned long detect_delay_ms; /* delay in millisecond before detecting cards after interrupt */ int (*init)(struct device *, irq_handler_t , void *); int (*get_ro)(struct device *); void (*setpower)(struct device *, unsigned int); diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c index be727aeed217..9b9046185b00 100644 --- a/arch/arm/mach-pxa/littleton.c +++ b/arch/arm/mach-pxa/littleton.c @@ -271,7 +271,7 @@ static inline void littleton_init_keypad(void) {} #if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE) static struct pxamci_platform_data littleton_mci_platform_data = { - .detect_delay = 20, + .detect_delay_ms = 200, .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, .gpio_card_detect = GPIO_MMC1_CARD_DETECT, .gpio_card_ro = -1, diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 63d65a2a0387..330c3282856e 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -478,7 +478,7 @@ static void lubbock_mci_exit(struct device *dev, void *data) static struct pxamci_platform_data lubbock_mci_platform_data = { .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, - .detect_delay = 1, + .detect_delay_ms = 10, .init = lubbock_mci_init, .get_ro = lubbock_mci_get_ro, .exit = lubbock_mci_exit, diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c index 7a50ed8fce94..d60db87dde08 100644 --- a/arch/arm/mach-pxa/mioa701.c +++ b/arch/arm/mach-pxa/mioa701.c @@ -426,6 +426,7 @@ struct gpio_vbus_mach_info gpio_vbus_data = { * to give the card a chance to fully insert/eject. */ static struct pxamci_platform_data mioa701_mci_info = { + .detect_delay_ms = 250, .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, .gpio_card_detect = GPIO15_SDIO_INSERT, .gpio_card_ro = GPIO78_SDIO_RO, @@ -791,7 +792,6 @@ static void __init mioa701_machine_init(void) mio_gpio_request(ARRAY_AND_SIZE(global_gpios)); bootstrap_init(); set_pxa_fb_info(&mioa701_pxafb_info); - mioa701_mci_info.detect_delay = msecs_to_jiffies(250); pxa_set_mci_info(&mioa701_mci_info); pxa_set_keypad_info(&mioa701_keypad_info); wm97xx_bat_set_pdata(&mioa701_battery_data); diff --git a/arch/arm/mach-pxa/mxm8x10.c b/arch/arm/mach-pxa/mxm8x10.c index 8c9c6f0d56bb..462167ac05f9 100644 --- a/arch/arm/mach-pxa/mxm8x10.c +++ b/arch/arm/mach-pxa/mxm8x10.c @@ -325,7 +325,7 @@ static mfp_cfg_t mfp_cfg[] __initdata = { #if defined(CONFIG_MMC) static struct pxamci_platform_data mxm_8x10_mci_platform_data = { .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, - .detect_delay = 1, + .detect_delay_ms = 10, .gpio_card_detect = MXM_8X10_SD_nCD, .gpio_card_ro = MXM_8X10_SD_WP, .gpio_power = -1 diff --git a/arch/arm/mach-pxa/palmld.c b/arch/arm/mach-pxa/palmld.c index f70c75b38769..1963819dba98 100644 --- a/arch/arm/mach-pxa/palmld.c +++ b/arch/arm/mach-pxa/palmld.c @@ -168,7 +168,7 @@ static struct pxamci_platform_data palmld_mci_platform_data = { .gpio_card_detect = GPIO_NR_PALMLD_SD_DETECT_N, .gpio_card_ro = GPIO_NR_PALMLD_SD_READONLY, .gpio_power = GPIO_NR_PALMLD_SD_POWER, - .detect_delay = 20, + .detect_delay_ms = 200, }; /****************************************************************************** diff --git a/arch/arm/mach-pxa/palmt5.c b/arch/arm/mach-pxa/palmt5.c index d902a813aae3..5305a3993e69 100644 --- a/arch/arm/mach-pxa/palmt5.c +++ b/arch/arm/mach-pxa/palmt5.c @@ -110,7 +110,7 @@ static struct pxamci_platform_data palmt5_mci_platform_data = { .gpio_card_detect = GPIO_NR_PALMT5_SD_DETECT_N, .gpio_card_ro = GPIO_NR_PALMT5_SD_READONLY, .gpio_power = GPIO_NR_PALMT5_SD_POWER, - .detect_delay = 20, + .detect_delay_ms = 200, }; /****************************************************************************** diff --git a/arch/arm/mach-pxa/palmtc.c b/arch/arm/mach-pxa/palmtc.c index 717d7a638675..033b567e50bb 100644 --- a/arch/arm/mach-pxa/palmtc.c +++ b/arch/arm/mach-pxa/palmtc.c @@ -121,7 +121,7 @@ static struct pxamci_platform_data palmtc_mci_platform_data = { .gpio_power = GPIO_NR_PALMTC_SD_POWER, .gpio_card_ro = GPIO_NR_PALMTC_SD_READONLY, .gpio_card_detect = GPIO_NR_PALMTC_SD_DETECT_N, - .detect_delay = 20, + .detect_delay_ms = 200, }; /****************************************************************************** diff --git a/arch/arm/mach-pxa/palmtx.c b/arch/arm/mach-pxa/palmtx.c index 007b58c11f8d..ecc1a401598e 100644 --- a/arch/arm/mach-pxa/palmtx.c +++ b/arch/arm/mach-pxa/palmtx.c @@ -170,7 +170,7 @@ static struct pxamci_platform_data palmtx_mci_platform_data = { .gpio_card_detect = GPIO_NR_PALMTX_SD_DETECT_N, .gpio_card_ro = GPIO_NR_PALMTX_SD_READONLY, .gpio_power = GPIO_NR_PALMTX_SD_POWER, - .detect_delay = 20, + .detect_delay_ms = 200, }; /****************************************************************************** diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c index 9d0ecea1760c..f56ae1008759 100644 --- a/arch/arm/mach-pxa/pcm990-baseboard.c +++ b/arch/arm/mach-pxa/pcm990-baseboard.c @@ -326,7 +326,7 @@ static void pcm990_mci_exit(struct device *dev, void *data) #define MSECS_PER_JIFFY (1000/HZ) static struct pxamci_platform_data pcm990_mci_platform_data = { - .detect_delay = 250 / MSECS_PER_JIFFY, + .detect_delay_ms = 250, .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, .init = pcm990_mci_init, .setpower = pcm990_mci_setpower, diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index dcb178807046..f4abdaafdac4 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -276,6 +276,7 @@ static void poodle_mci_exit(struct device *dev, void *data) } static struct pxamci_platform_data poodle_mci_platform_data = { + .detect_delay_ms = 250, .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .init = poodle_mci_init, .setpower = poodle_mci_setpower, @@ -449,7 +450,6 @@ static void __init poodle_init(void) set_pxa_fb_parent(&poodle_locomo_device.dev); set_pxa_fb_info(&poodle_fb_info); pxa_set_udc_info(&udc_info); - poodle_mci_platform_data.detect_delay = msecs_to_jiffies(250); pxa_set_mci_info(&poodle_mci_platform_data); pxa_set_ficp_info(&poodle_ficp_platform_data); pxa_set_i2c_info(NULL); diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index d12667bd9ebe..d4b61b3f08f3 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -714,7 +714,7 @@ static void raumfeld_mci_exit(struct device *dev, void *data) static struct pxamci_platform_data raumfeld_mci_platform_data = { .init = raumfeld_mci_init, .exit = raumfeld_mci_exit, - .detect_delay = 20, + .detect_delay_ms = 200, .gpio_card_detect = -1, .gpio_card_ro = -1, .gpio_power = -1, diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 451029ea9eec..4d2413ed0ffa 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -539,6 +539,7 @@ static void spitz_mci_setpower(struct device *dev, unsigned int vdd) } static struct pxamci_platform_data spitz_mci_platform_data = { + .detect_delay_ms = 250, .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .setpower = spitz_mci_setpower, .gpio_card_detect = SPITZ_GPIO_nSD_DETECT, @@ -759,7 +760,6 @@ static void __init common_init(void) spitz_init_spi(); platform_add_devices(devices, ARRAY_SIZE(devices)); - spitz_mci_platform_data.detect_delay = msecs_to_jiffies(250); pxa_set_mci_info(&spitz_mci_platform_data); pxa_set_ohci_info(&spitz_ohci_platform_data); pxa_set_ficp_info(&spitz_ficp_platform_data); diff --git a/arch/arm/mach-pxa/stargate2.c b/arch/arm/mach-pxa/stargate2.c index 2041eb1d90ba..af40d2a12d37 100644 --- a/arch/arm/mach-pxa/stargate2.c +++ b/arch/arm/mach-pxa/stargate2.c @@ -464,8 +464,6 @@ static struct platform_device smc91x_device = { -static struct pxamci_platform_data stargate2_mci_platform_data; - /* * The card detect interrupt isn't debounced so we delay it by 250ms * to give the card a chance to fully insert / eject. @@ -489,8 +487,6 @@ static int stargate2_mci_init(struct device *dev, goto free_power_en; } gpio_direction_input(SG2_GPIO_nSD_DETECT); - /* Delay to allow for full insertion */ - stargate2_mci_platform_data.detect_delay = msecs_to_jiffies(250); err = request_irq(IRQ_GPIO(SG2_GPIO_nSD_DETECT), stargate2_detect_int, @@ -529,6 +525,7 @@ static void stargate2_mci_exit(struct device *dev, void *data) } static struct pxamci_platform_data stargate2_mci_platform_data = { + .detect_delay_ms = 250, .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, .init = stargate2_mci_init, .setpower = stargate2_mci_setpower, diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index ad552791c4ce..7512b822c6ca 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -275,6 +275,7 @@ static void tosa_mci_exit(struct device *dev, void *data) } static struct pxamci_platform_data tosa_mci_platform_data = { + .detect_delay_ms = 250, .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .init = tosa_mci_init, .exit = tosa_mci_exit, @@ -926,7 +927,6 @@ static void __init tosa_init(void) dummy = gpiochip_reserve(TOSA_SCOOP_JC_GPIO_BASE, 12); dummy = gpiochip_reserve(TOSA_TC6393XB_GPIO_BASE, 16); - tosa_mci_platform_data.detect_delay = msecs_to_jiffies(250); pxa_set_mci_info(&tosa_mci_platform_data); pxa_set_udc_info(&udc_info); pxa_set_ficp_info(&tosa_ficp_platform_data); diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c index 797f2544d0ce..69689112eae7 100644 --- a/arch/arm/mach-pxa/trizeps4.c +++ b/arch/arm/mach-pxa/trizeps4.c @@ -349,7 +349,7 @@ static void trizeps4_mci_exit(struct device *dev, void *data) static struct pxamci_platform_data trizeps4_mci_platform_data = { .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, - .detect_delay = 1, + .detect_delay_ms= 10, .init = trizeps4_mci_init, .exit = trizeps4_mci_exit, .get_ro = NULL, /* write-protection not supported */ diff --git a/arch/arm/mach-pxa/vpac270.c b/arch/arm/mach-pxa/vpac270.c index 0954c2433a98..9884fa978f16 100644 --- a/arch/arm/mach-pxa/vpac270.c +++ b/arch/arm/mach-pxa/vpac270.c @@ -240,7 +240,7 @@ static struct pxamci_platform_data vpac270_mci_platform_data = { .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, .gpio_card_detect = GPIO53_VPAC270_SD_DETECT_N, .gpio_card_ro = GPIO52_VPAC270_SD_READONLY, - .detect_delay = 20, + .detect_delay_ms = 200, }; static void __init vpac270_mmc_init(void) diff --git a/arch/arm/mach-pxa/z2.c b/arch/arm/mach-pxa/z2.c index c837318ec1fa..f5d1ae3db3a4 100644 --- a/arch/arm/mach-pxa/z2.c +++ b/arch/arm/mach-pxa/z2.c @@ -291,7 +291,7 @@ static struct pxamci_platform_data z2_mci_platform_data = { .gpio_card_detect = GPIO96_ZIPITZ2_SD_DETECT, .gpio_power = -1, .gpio_card_ro = -1, - .detect_delay = 20, + .detect_delay_ms = 200, }; static void __init z2_mmc_init(void) diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c index 39896d883584..3680f6a90623 100644 --- a/arch/arm/mach-pxa/zeus.c +++ b/arch/arm/mach-pxa/zeus.c @@ -644,7 +644,7 @@ static struct pxafb_mach_info zeus_fb_info = { static struct pxamci_platform_data zeus_mci_platform_data = { .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, - .detect_delay = HZ/4, + .detect_delay_ms = 250, .gpio_card_detect = ZEUS_MMC_CD_GPIO, .gpio_card_ro = ZEUS_MMC_WP_GPIO, .gpio_card_ro_invert = 1, diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c index 2b4043c04d0c..c479cbecf784 100644 --- a/arch/arm/mach-pxa/zylonite.c +++ b/arch/arm/mach-pxa/zylonite.c @@ -218,7 +218,7 @@ static inline void zylonite_init_lcd(void) {} #if defined(CONFIG_MMC) static struct pxamci_platform_data zylonite_mci_platform_data = { - .detect_delay = 20, + .detect_delay_ms= 200, .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .gpio_card_detect = EXT_GPIO(0), .gpio_card_ro = EXT_GPIO(2), @@ -226,7 +226,7 @@ static struct pxamci_platform_data zylonite_mci_platform_data = { }; static struct pxamci_platform_data zylonite_mci2_platform_data = { - .detect_delay = 20, + .detect_delay_ms= 200, .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .gpio_card_detect = EXT_GPIO(1), .gpio_card_ro = EXT_GPIO(3), @@ -234,7 +234,7 @@ static struct pxamci_platform_data zylonite_mci2_platform_data = { }; static struct pxamci_platform_data zylonite_mci3_platform_data = { - .detect_delay = 20, + .detect_delay_ms= 200, .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .gpio_card_detect = EXT_GPIO(30), .gpio_card_ro = EXT_GPIO(31), diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 0ed48959b590..e4f00e70a749 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -544,7 +544,7 @@ static irqreturn_t pxamci_detect_irq(int irq, void *devid) { struct pxamci_host *host = mmc_priv(devid); - mmc_detect_change(devid, host->pdata->detect_delay); + mmc_detect_change(devid, msecs_to_jiffies(host->pdata->detect_delay_ms)); return IRQ_HANDLED; } -- cgit v1.2.3 From ebb1fea9b3adf25d7e2f643c614163af4f93a17f Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 11 May 2010 14:06:48 -0700 Subject: mmc: atmel-mci: fix two parameters swapped Two parameters were swapped in the calls to atmci_init_slot(). Signed-off-by: Nicolas Ferre Reported-by: Anders Grahn Cc: Haavard Skinnemoen Cc: Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/atmel-mci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 88be37d9e9a5..57d3cb2dbb5f 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -1751,13 +1751,13 @@ static int __init atmci_probe(struct platform_device *pdev) ret = -ENODEV; if (pdata->slot[0].bus_width) { ret = atmci_init_slot(host, &pdata->slot[0], - MCI_SDCSEL_SLOT_A, 0); + 0, MCI_SDCSEL_SLOT_A); if (!ret) nr_slots++; } if (pdata->slot[1].bus_width) { ret = atmci_init_slot(host, &pdata->slot[1], - MCI_SDCSEL_SLOT_B, 1); + 1, MCI_SDCSEL_SLOT_B); if (!ret) nr_slots++; } -- cgit v1.2.3 From 009a891b22395fc86e5f34057d79fffee4509ab5 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 11 May 2010 14:06:49 -0700 Subject: mmc: atmel-mci: prevent kernel oops while removing card The removing of an SD card in certain circumstances can lead to a kernel oops if we do not make sure that the "data" field of the host structure is valid. This patch adds a test in atmci_dma_cleanup() function and also calls atmci_stop_dma() before throwing away the reference to data. Signed-off-by: Nicolas Ferre Cc: Haavard Skinnemoen Cc: Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/atmel-mci.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 57d3cb2dbb5f..2a5d5cafeb5f 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -569,9 +569,10 @@ static void atmci_dma_cleanup(struct atmel_mci *host) { struct mmc_data *data = host->data; - dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len, - ((data->flags & MMC_DATA_WRITE) - ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); + if (data) + dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len, + ((data->flags & MMC_DATA_WRITE) + ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); } static void atmci_stop_dma(struct atmel_mci *host) @@ -1099,8 +1100,8 @@ static void atmci_command_complete(struct atmel_mci *host, "command error: status=0x%08x\n", status); if (cmd->data) { - host->data = NULL; atmci_stop_dma(host); + host->data = NULL; mci_writel(host, IDR, MCI_NOTBUSY | MCI_TXRDY | MCI_RXRDY | ATMCI_DATA_ERROR_FLAGS); -- cgit v1.2.3 From abc2c9fdf636c4335a8d72ac3c5ae152bca44b68 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 11 May 2010 14:06:50 -0700 Subject: mmc: atmel-mci: remove data error interrupt after xfer Disable data error interrupts while we are actually recording that there is not such errors. This will prevent, in some cases, the warning message printed at new request queuing (in atmci_start_request()). Signed-off-by: Nicolas Ferre Cc: Haavard Skinnemoen Cc: Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/atmel-mci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 2a5d5cafeb5f..b77b9b0c0695 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -1294,6 +1294,7 @@ static void atmci_tasklet_func(unsigned long priv) } else { data->bytes_xfered = data->blocks * data->blksz; data->error = 0; + mci_writel(host, IDR, ATMCI_DATA_ERROR_FLAGS); } if (!data->stop) { -- cgit v1.2.3 From d586ebbb8814e039545d38f69029533f3f17748d Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 11 May 2010 14:06:50 -0700 Subject: mmc: atmel-mci: fix in debugfs: response value printing In debugfs, printing of command response reports resp[2] twice: fix it to resp[3]. Signed-off-by: Nicolas Ferre Haavard Skinnemoen Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/atmel-mci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index b77b9b0c0695..fb279f4ed8b3 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -266,7 +266,7 @@ static int atmci_req_show(struct seq_file *s, void *v) "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", cmd->opcode, cmd->arg, cmd->flags, cmd->resp[0], cmd->resp[1], cmd->resp[2], - cmd->resp[2], cmd->error); + cmd->resp[3], cmd->error); if (data) seq_printf(s, "DATA %u / %u * %u flg %x err %d\n", data->bytes_xfered, data->blocks, @@ -276,7 +276,7 @@ static int atmci_req_show(struct seq_file *s, void *v) "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n", stop->opcode, stop->arg, stop->flags, stop->resp[0], stop->resp[1], stop->resp[2], - stop->resp[2], stop->error); + stop->resp[3], stop->error); } spin_unlock_bh(&slot->host->lock); -- cgit v1.2.3 From bdef2fe88b1e4bde7458aedd207929ce3f9d66ee Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Sat, 15 May 2010 12:32:31 -0400 Subject: mmc: at91_mci: modify cache flush routines As we were using an internal dma flushing routine, this patch changes to the DMA API flush_kernel_dcache_page(). Driver is able to compile now. [akpm@linux-foundation.org: flush_kernel_dcache_page() comes before kunmap_atomic()] Signed-off-by: Nicolas Ferre Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/at91_mci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index a6dd7da37357..336d9f553f3e 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -314,8 +314,8 @@ static void at91_mci_post_dma_read(struct at91mci_host *host) dmabuf = (unsigned *)tmpv; } + flush_kernel_dcache_page(sg_page(sg)); kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ); - dmac_flush_range((void *)sgbuffer, ((void *)sgbuffer) + amount); data->bytes_xfered += amount; if (size == 0) break; -- cgit v1.2.3 From 058276303dbc4ed089c1f7dad0871810b1f5ddf1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 17 May 2010 16:30:42 -0700 Subject: DMAENGINE: extend the control command to include an arg This adds an argument to the DMAengine control function, so that we can later provide control commands that need some external data passed in through an argument akin to the ioctl() operation prototype. [dan.j.williams@intel.com: fix up some missed conversions] Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/at_hdmac.c | 3 ++- drivers/dma/coh901318.c | 5 +++-- drivers/dma/dw_dmac.c | 3 ++- drivers/dma/fsldma.c | 2 +- drivers/dma/ipu/ipu_idmac.c | 12 +++++++----- drivers/dma/shdma.c | 3 ++- drivers/dma/ste_dma40.c | 3 ++- drivers/dma/timb_dma.c | 3 ++- drivers/dma/txx9dmac.c | 3 ++- drivers/mmc/host/atmel-mci.c | 2 +- drivers/serial/sh-sci.c | 2 +- drivers/video/mx3fb.c | 2 +- include/linux/dmaengine.h | 3 ++- sound/soc/txx9/txx9aclc.c | 7 ++++--- 14 files changed, 32 insertions(+), 21 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 93ed99c84cf1..ee805a43f879 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -759,7 +759,8 @@ err_desc_get: return NULL; } -static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) +static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + unsigned long arg) { struct at_dma_chan *atchan = to_at_dma_chan(chan); struct at_dma *atdma = to_at_dma(chan->device); diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c index 4233440741a2..a724e6be1b4d 100644 --- a/drivers/dma/coh901318.c +++ b/drivers/dma/coh901318.c @@ -942,7 +942,7 @@ coh901318_free_chan_resources(struct dma_chan *chan) spin_unlock_irqrestore(&cohc->lock, flags); - chan->device->device_control(chan, DMA_TERMINATE_ALL); + chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); } @@ -1176,7 +1176,8 @@ coh901318_issue_pending(struct dma_chan *chan) } static int -coh901318_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) +coh901318_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + unsigned long arg) { unsigned long flags; struct coh901318_chan *cohc = to_coh901318_chan(chan); diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 18fb5b41cedf..a3991ab0d67e 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -781,7 +781,8 @@ err_desc_get: return NULL; } -static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) +static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + unsigned long arg) { struct dw_dma_chan *dwc = to_dw_dma_chan(chan); struct dw_dma *dw = to_dw_dma(chan->device); diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index cb1924f46c9e..005329d496bd 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -775,7 +775,7 @@ fail: } static int fsl_dma_device_control(struct dma_chan *dchan, - enum dma_ctrl_cmd cmd) + enum dma_ctrl_cmd cmd, unsigned long arg) { struct fsldma_chan *chan; unsigned long flags; diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c index 246a6143e4a7..cb26ee9773d6 100644 --- a/drivers/dma/ipu/ipu_idmac.c +++ b/drivers/dma/ipu/ipu_idmac.c @@ -1472,7 +1472,8 @@ static void idmac_issue_pending(struct dma_chan *chan) */ } -static int __idmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) +static int __idmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + unsigned long arg) { struct idmac_channel *ichan = to_idmac_chan(chan); struct idmac *idmac = to_idmac(chan->device); @@ -1513,14 +1514,15 @@ static int __idmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) return 0; } -static int idmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) +static int idmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + unsigned long arg) { struct idmac_channel *ichan = to_idmac_chan(chan); int ret; mutex_lock(&ichan->chan_mutex); - ret = __idmac_control(chan, cmd); + ret = __idmac_control(chan, cmd, arg); mutex_unlock(&ichan->chan_mutex); @@ -1616,7 +1618,7 @@ static void idmac_free_chan_resources(struct dma_chan *chan) mutex_lock(&ichan->chan_mutex); - __idmac_control(chan, DMA_TERMINATE_ALL); + __idmac_control(chan, DMA_TERMINATE_ALL, 0); if (ichan->status > IPU_CHANNEL_FREE) { #ifdef DEBUG @@ -1709,7 +1711,7 @@ static void __exit ipu_idmac_exit(struct ipu *ipu) for (i = 0; i < IPU_CHANNELS_NUM; i++) { struct idmac_channel *ichan = ipu->channel + i; - idmac_control(&ichan->dma_chan, DMA_TERMINATE_ALL); + idmac_control(&ichan->dma_chan, DMA_TERMINATE_ALL, 0); idmac_prep_slave_sg(&ichan->dma_chan, NULL, 0, DMA_NONE, 0); } diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index 98f82cdb404c..e9de1d35c20d 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -580,7 +580,8 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_slave_sg( direction, flags); } -static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) +static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + unsigned long arg) { struct sh_dmae_chan *sh_chan = to_sh_chan(chan); diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 81fec95312b6..c426829f6ab8 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -2065,7 +2065,8 @@ static void d40_issue_pending(struct dma_chan *chan) spin_unlock_irqrestore(&d40c->lock, flags); } -static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) +static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + unsigned long arg) { unsigned long flags; struct d40_chan *d40c = container_of(chan, struct d40_chan, chan); diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c index 44b346d8d319..0172fa3c7a2b 100644 --- a/drivers/dma/timb_dma.c +++ b/drivers/dma/timb_dma.c @@ -611,7 +611,8 @@ static struct dma_async_tx_descriptor *td_prep_slave_sg(struct dma_chan *chan, return &td_desc->txd; } -static int td_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) +static int td_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + unsigned long arg) { struct timb_dma_chan *td_chan = container_of(chan, struct timb_dma_chan, chan); diff --git a/drivers/dma/txx9dmac.c b/drivers/dma/txx9dmac.c index e523737639aa..d02edb05910e 100644 --- a/drivers/dma/txx9dmac.c +++ b/drivers/dma/txx9dmac.c @@ -938,7 +938,8 @@ txx9dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, return &first->txd; } -static int txx9dmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd) +static int txx9dmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + unsigned long arg) { struct txx9dmac_chan *dc = to_txx9dmac_chan(chan); struct txx9dmac_desc *desc, *_desc; diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index ae6d24ba4f08..fd2d24f81478 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -578,7 +578,7 @@ static void atmci_stop_dma(struct atmel_mci *host) struct dma_chan *chan = host->data_chan; if (chan) { - chan->device->device_control(chan, DMA_TERMINATE_ALL); + chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); atmci_dma_cleanup(host); } else { /* Data transfer was stopped by the interrupt handler */ diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 690988237971..882f3d5ed028 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -1087,7 +1087,7 @@ static void work_fn_rx(struct work_struct *work) unsigned long flags; int count; - chan->device->device_control(chan, DMA_TERMINATE_ALL); + chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); dev_dbg(port->dev, "Read %u bytes with cookie %d\n", sh_desc->partial, sh_desc->cookie); diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index 3aa50bc276eb..7cfc170bce19 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -388,7 +388,7 @@ static void sdc_disable_channel(struct mx3fb_info *mx3_fbi) spin_unlock_irqrestore(&mx3fb->lock, flags); mx3_fbi->txd->chan->device->device_control(mx3_fbi->txd->chan, - DMA_TERMINATE_ALL); + DMA_TERMINATE_ALL, 0); mx3_fbi->txd = NULL; mx3_fbi->cookie = -EINVAL; } diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 50b7b3e0d572..17456571ff7a 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -347,7 +347,8 @@ struct dma_device { struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, enum dma_data_direction direction, unsigned long flags); - int (*device_control)(struct dma_chan *chan, enum dma_ctrl_cmd cmd); + int (*device_control)(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + unsigned long arg); enum dma_status (*device_tx_status)(struct dma_chan *chan, dma_cookie_t cookie, diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index b35d00706c0e..9398f507f77f 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c @@ -159,7 +159,7 @@ static void txx9aclc_dma_tasklet(unsigned long data) void __iomem *base = drvdata->base; spin_unlock_irqrestore(&dmadata->dma_lock, flags); - chan->device->device_control(chan, DMA_TERMINATE_ALL); + chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); /* first time */ for (i = 0; i < NR_DMA_CHAIN; i++) { desc = txx9aclc_dma_submit(dmadata, @@ -267,7 +267,7 @@ static int txx9aclc_pcm_close(struct snd_pcm_substream *substream) struct dma_chan *chan = dmadata->dma_chan; dmadata->frag_count = -1; - chan->device->device_control(chan, DMA_TERMINATE_ALL); + chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); return 0; } @@ -396,7 +396,8 @@ static int txx9aclc_pcm_remove(struct platform_device *pdev) struct dma_chan *chan = dmadata->dma_chan; if (chan) { dmadata->frag_count = -1; - chan->device->device_control(chan, DMA_TERMINATE_ALL); + chan->device->device_control(chan, + DMA_TERMINATE_ALL, 0); dma_release_channel(chan); } dev->dmadata[i].dma_chan = NULL; -- cgit v1.2.3