From c5c98927d74cd6853579e1a5b56cd6eb0d4885f0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 13 Apr 2012 12:14:39 +0100 Subject: mmc: omap_hsmmc: add DMA engine support Add DMA engine support to the OMAP HSMMC driver. This supplements the private DMA API implementation contained within this driver, and the driver can be switched at build time between using DMA engine and the private DMA API. Tested-by: Grazvydas Ignotas Tested-by: Tony Lindgren Acked-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/omap_hsmmc.c | 192 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 165 insertions(+), 27 deletions(-) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 389a3ee..effe328 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -165,7 +166,9 @@ struct omap_hsmmc_host { u32 bytesleft; int suspended; int irq; - int use_dma, dma_ch; + int use_dma, dma_ch, dma2; + struct dma_chan *tx_chan; + struct dma_chan *rx_chan; int dma_line_tx, dma_line_rx; int slot_id; int response_busy; @@ -797,19 +800,26 @@ omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data) return DMA_FROM_DEVICE; } +static struct dma_chan *omap_hsmmc_get_dma_chan(struct omap_hsmmc_host *host, + struct mmc_data *data) +{ + return data->flags & MMC_DATA_WRITE ? host->tx_chan : host->rx_chan; +} + static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq) { - int dma_ch; + int dma_ch, dma2; unsigned long flags; spin_lock_irqsave(&host->irq_lock, flags); host->req_in_progress = 0; dma_ch = host->dma_ch; + dma2 = host->dma2; spin_unlock_irqrestore(&host->irq_lock, flags); omap_hsmmc_disable_irq(host); /* Do not complete the request if DMA is still in progress */ - if (mrq->data && host->use_dma && dma_ch != -1) + if (mrq->data && host->use_dma && (dma_ch != -1 || dma2 != -1)) return; host->mrq = NULL; mmc_request_done(host->mmc, mrq); @@ -878,7 +888,7 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd) */ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) { - int dma_ch; + int dma_ch, dma2; unsigned long flags; host->data->error = errno; @@ -886,8 +896,20 @@ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) spin_lock_irqsave(&host->irq_lock, flags); dma_ch = host->dma_ch; host->dma_ch = -1; + dma2 = host->dma2; + host->dma2 = -1; spin_unlock_irqrestore(&host->irq_lock, flags); + if (host->use_dma && dma2 != -1) { + struct dma_chan *chan = omap_hsmmc_get_dma_chan(host, host->data); + + dmaengine_terminate_all(chan); + dma_unmap_sg(chan->device->dev, + host->data->sg, host->data->sg_len, + omap_hsmmc_get_dma_dir(host, host->data)); + + host->data->host_cookie = 0; + } if (host->use_dma && dma_ch != -1) { dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->data->sg_len, @@ -1284,9 +1306,43 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) } } +static void omap_hsmmc_dma_callback(void *param) +{ + struct omap_hsmmc_host *host = param; + struct dma_chan *chan; + struct mmc_data *data; + int req_in_progress; + + spin_lock_irq(&host->irq_lock); + if (host->dma2 < 0) { + spin_unlock_irq(&host->irq_lock); + return; + } + + data = host->mrq->data; + chan = omap_hsmmc_get_dma_chan(host, data); + if (!data->host_cookie) + dma_unmap_sg(chan->device->dev, + data->sg, data->sg_len, + omap_hsmmc_get_dma_dir(host, data)); + + req_in_progress = host->req_in_progress; + host->dma2 = -1; + spin_unlock_irq(&host->irq_lock); + + /* If DMA has finished after TC, complete the request */ + if (!req_in_progress) { + struct mmc_request *mrq = host->mrq; + + host->mrq = NULL; + mmc_request_done(host->mmc, mrq); + } +} + static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host, struct mmc_data *data, - struct omap_hsmmc_next *next) + struct omap_hsmmc_next *next, + struct device *dev) { int dma_len; @@ -1301,8 +1357,7 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host, /* Check if next job is already prepared */ if (next || (!next && data->host_cookie != host->next_data.cookie)) { - dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, + dma_len = dma_map_sg(dev, data->sg, data->sg_len, omap_hsmmc_get_dma_dir(host, data)); } else { @@ -1331,6 +1386,7 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host, { int dma_ch = 0, ret = 0, i; struct mmc_data *data = req->data; + struct dma_chan *chan; /* Sanity check: all the SG entries must be aligned by block size. */ for (i = 0; i < data->sg_len; i++) { @@ -1346,24 +1402,66 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host, */ return -EINVAL; - BUG_ON(host->dma_ch != -1); + BUG_ON(host->dma_ch != -1 || host->dma2 != -1); - ret = omap_request_dma(omap_hsmmc_get_dma_sync_dev(host, data), - "MMC/SD", omap_hsmmc_dma_cb, host, &dma_ch); - if (ret != 0) { - dev_err(mmc_dev(host->mmc), - "%s: omap_request_dma() failed with %d\n", - mmc_hostname(host->mmc), ret); - return ret; - } - ret = omap_hsmmc_pre_dma_transfer(host, data, NULL); - if (ret) - return ret; + chan = omap_hsmmc_get_dma_chan(host, data); + if (!chan) { + ret = omap_request_dma(omap_hsmmc_get_dma_sync_dev(host, data), + "MMC/SD", omap_hsmmc_dma_cb, host, &dma_ch); + if (ret != 0) { + dev_err(mmc_dev(host->mmc), + "%s: omap_request_dma() failed with %d\n", + mmc_hostname(host->mmc), ret); + return ret; + } + ret = omap_hsmmc_pre_dma_transfer(host, data, NULL, + mmc_dev(host->mmc)); + if (ret) + return ret; + + host->dma_ch = dma_ch; + host->dma_sg_idx = 0; + + omap_hsmmc_config_dma_params(host, data, data->sg); + } else { + struct dma_slave_config cfg; + struct dma_async_tx_descriptor *tx; + + cfg.src_addr = host->mapbase + OMAP_HSMMC_DATA; + cfg.dst_addr = host->mapbase + OMAP_HSMMC_DATA; + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + cfg.src_maxburst = data->blksz / 4; + cfg.dst_maxburst = data->blksz / 4; + + ret = dmaengine_slave_config(chan, &cfg); + if (ret) + return ret; + + ret = omap_hsmmc_pre_dma_transfer(host, data, NULL, + chan->device->dev); + if (ret) + return ret; + + tx = dmaengine_prep_slave_sg(chan, data->sg, data->sg_len, + data->flags & MMC_DATA_WRITE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!tx) { + dev_err(mmc_dev(host->mmc), "prep_slave_sg() failed\n"); + /* FIXME: cleanup */ + return -1; + } - host->dma_ch = dma_ch; - host->dma_sg_idx = 0; + tx->callback = omap_hsmmc_dma_callback; + tx->callback_param = host; - omap_hsmmc_config_dma_params(host, data, data->sg); + /* Does not fail */ + dmaengine_submit(tx); + + host->dma2 = 1; + + dma_async_issue_pending(chan); + } return 0; } @@ -1446,9 +1544,12 @@ static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, struct mmc_data *data = mrq->data; if (host->use_dma) { + struct dma_chan *c = omap_hsmmc_get_dma_chan(host, data); + struct device *dev = c ? c->device->dev : mmc_dev(mmc); + if (data->host_cookie) - dma_unmap_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, + dma_unmap_sg(dev, + data->sg, data->sg_len, omap_hsmmc_get_dma_dir(host, data)); data->host_cookie = 0; } @@ -1464,10 +1565,14 @@ static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, return ; } - if (host->use_dma) + if (host->use_dma) { + struct dma_chan *c = omap_hsmmc_get_dma_chan(host, mrq->data); + struct device *dev = c ? c->device->dev : mmc_dev(mmc); + if (omap_hsmmc_pre_dma_transfer(host, mrq->data, - &host->next_data)) + &host->next_data, dev)) mrq->data->host_cookie = 0; + } } /* @@ -1479,7 +1584,7 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req) int err; BUG_ON(host->req_in_progress); - BUG_ON(host->dma_ch != -1); + BUG_ON(host->dma_ch != -1 || host->dma2 != -1); if (host->protect_card) { if (host->reqs_blocked < 3) { /* @@ -1846,6 +1951,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) host->use_dma = 1; host->dev->dma_mask = &pdata->dma_mask; host->dma_ch = -1; + host->dma2 = -1; host->irq = irq; host->slot_id = 0; host->mapbase = res->start + pdata->reg_offset; @@ -1942,6 +2048,29 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) } host->dma_line_rx = res->start; + { + dma_cap_mask_t mask; + unsigned sig; + extern bool omap_dma_filter_fn(struct dma_chan *chan, void *param); + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); +#if 1 + sig = host->dma_line_rx; + host->rx_chan = dma_request_channel(mask, omap_dma_filter_fn, &sig); + if (!host->rx_chan) { + dev_warn(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", sig); + } +#endif +#if 1 + sig = host->dma_line_tx; + host->tx_chan = dma_request_channel(mask, omap_dma_filter_fn, &sig); + if (!host->tx_chan) { + dev_warn(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel %u\n", sig); + } +#endif + } + /* Request IRQ for MMC operations */ ret = request_irq(host->irq, omap_hsmmc_irq, 0, mmc_hostname(mmc), host); @@ -2019,6 +2148,10 @@ err_reg: err_irq_cd_init: free_irq(host->irq, host); err_irq: + if (host->tx_chan) + dma_release_channel(host->tx_chan); + if (host->rx_chan) + dma_release_channel(host->rx_chan); pm_runtime_put_sync(host->dev); pm_runtime_disable(host->dev); clk_put(host->fclk); @@ -2054,6 +2187,11 @@ static int __devexit omap_hsmmc_remove(struct platform_device *pdev) if (mmc_slot(host).card_detect_irq) free_irq(mmc_slot(host).card_detect_irq, host); + if (host->tx_chan) + dma_release_channel(host->tx_chan); + if (host->rx_chan) + dma_release_channel(host->rx_chan); + pm_runtime_put_sync(host->dev); pm_runtime_disable(host->dev); clk_put(host->fclk); -- cgit v1.1 From 26b88520b80695a6fa5fd95b5d97c03f4daf87e0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 13 Apr 2012 12:27:37 +0100 Subject: mmc: omap_hsmmc: remove private DMA API implementation Remove the private DMA API implementation from omap_hsmmc, making it use entirely the DMA engine API. Tested-by: Tony Lindgren Tested-by: Venkatraman S Signed-off-by: Russell King --- drivers/mmc/host/omap_hsmmc.c | 263 ++++++++++-------------------------------- 1 file changed, 63 insertions(+), 200 deletions(-) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index effe328..2b2c987 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -166,10 +165,9 @@ struct omap_hsmmc_host { u32 bytesleft; int suspended; int irq; - int use_dma, dma_ch, dma2; + int use_dma, dma_ch; struct dma_chan *tx_chan; struct dma_chan *rx_chan; - int dma_line_tx, dma_line_rx; int slot_id; int response_busy; int context_loss; @@ -808,18 +806,17 @@ static struct dma_chan *omap_hsmmc_get_dma_chan(struct omap_hsmmc_host *host, static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq) { - int dma_ch, dma2; + int dma_ch; unsigned long flags; spin_lock_irqsave(&host->irq_lock, flags); host->req_in_progress = 0; dma_ch = host->dma_ch; - dma2 = host->dma2; spin_unlock_irqrestore(&host->irq_lock, flags); omap_hsmmc_disable_irq(host); /* Do not complete the request if DMA is still in progress */ - if (mrq->data && host->use_dma && (dma_ch != -1 || dma2 != -1)) + if (mrq->data && host->use_dma && dma_ch != -1) return; host->mrq = NULL; mmc_request_done(host->mmc, mrq); @@ -888,7 +885,7 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd) */ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) { - int dma_ch, dma2; + int dma_ch; unsigned long flags; host->data->error = errno; @@ -896,11 +893,9 @@ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) spin_lock_irqsave(&host->irq_lock, flags); dma_ch = host->dma_ch; host->dma_ch = -1; - dma2 = host->dma2; - host->dma2 = -1; spin_unlock_irqrestore(&host->irq_lock, flags); - if (host->use_dma && dma2 != -1) { + if (host->use_dma && dma_ch != -1) { struct dma_chan *chan = omap_hsmmc_get_dma_chan(host, host->data); dmaengine_terminate_all(chan); @@ -910,13 +905,6 @@ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) host->data->host_cookie = 0; } - if (host->use_dma && dma_ch != -1) { - dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, - host->data->sg_len, - omap_hsmmc_get_dma_dir(host, host->data)); - omap_free_dma(dma_ch); - host->data->host_cookie = 0; - } host->data = NULL; } @@ -1212,100 +1200,6 @@ static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id) return IRQ_HANDLED; } -static int omap_hsmmc_get_dma_sync_dev(struct omap_hsmmc_host *host, - struct mmc_data *data) -{ - int sync_dev; - - if (data->flags & MMC_DATA_WRITE) - sync_dev = host->dma_line_tx; - else - sync_dev = host->dma_line_rx; - return sync_dev; -} - -static void omap_hsmmc_config_dma_params(struct omap_hsmmc_host *host, - struct mmc_data *data, - struct scatterlist *sgl) -{ - int blksz, nblk, dma_ch; - - dma_ch = host->dma_ch; - if (data->flags & MMC_DATA_WRITE) { - omap_set_dma_dest_params(dma_ch, 0, OMAP_DMA_AMODE_CONSTANT, - (host->mapbase + OMAP_HSMMC_DATA), 0, 0); - omap_set_dma_src_params(dma_ch, 0, OMAP_DMA_AMODE_POST_INC, - sg_dma_address(sgl), 0, 0); - } else { - omap_set_dma_src_params(dma_ch, 0, OMAP_DMA_AMODE_CONSTANT, - (host->mapbase + OMAP_HSMMC_DATA), 0, 0); - omap_set_dma_dest_params(dma_ch, 0, OMAP_DMA_AMODE_POST_INC, - sg_dma_address(sgl), 0, 0); - } - - blksz = host->data->blksz; - nblk = sg_dma_len(sgl) / blksz; - - omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S32, - blksz / 4, nblk, OMAP_DMA_SYNC_FRAME, - omap_hsmmc_get_dma_sync_dev(host, data), - !(data->flags & MMC_DATA_WRITE)); - - omap_start_dma(dma_ch); -} - -/* - * DMA call back function - */ -static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data) -{ - struct omap_hsmmc_host *host = cb_data; - struct mmc_data *data; - int dma_ch, req_in_progress; - unsigned long flags; - - if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) { - dev_warn(mmc_dev(host->mmc), "unexpected dma status %x\n", - ch_status); - return; - } - - spin_lock_irqsave(&host->irq_lock, flags); - if (host->dma_ch < 0) { - spin_unlock_irqrestore(&host->irq_lock, flags); - return; - } - - data = host->mrq->data; - host->dma_sg_idx++; - if (host->dma_sg_idx < host->dma_len) { - /* Fire up the next transfer. */ - omap_hsmmc_config_dma_params(host, data, - data->sg + host->dma_sg_idx); - spin_unlock_irqrestore(&host->irq_lock, flags); - return; - } - - if (!data->host_cookie) - dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - omap_hsmmc_get_dma_dir(host, data)); - - req_in_progress = host->req_in_progress; - dma_ch = host->dma_ch; - host->dma_ch = -1; - spin_unlock_irqrestore(&host->irq_lock, flags); - - omap_free_dma(dma_ch); - - /* If DMA has finished after TC, complete the request */ - if (!req_in_progress) { - struct mmc_request *mrq = host->mrq; - - host->mrq = NULL; - mmc_request_done(host->mmc, mrq); - } -} - static void omap_hsmmc_dma_callback(void *param) { struct omap_hsmmc_host *host = param; @@ -1314,7 +1208,7 @@ static void omap_hsmmc_dma_callback(void *param) int req_in_progress; spin_lock_irq(&host->irq_lock); - if (host->dma2 < 0) { + if (host->dma_ch < 0) { spin_unlock_irq(&host->irq_lock); return; } @@ -1327,7 +1221,7 @@ static void omap_hsmmc_dma_callback(void *param) omap_hsmmc_get_dma_dir(host, data)); req_in_progress = host->req_in_progress; - host->dma2 = -1; + host->dma_ch = -1; spin_unlock_irq(&host->irq_lock); /* If DMA has finished after TC, complete the request */ @@ -1342,7 +1236,7 @@ static void omap_hsmmc_dma_callback(void *param) static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host, struct mmc_data *data, struct omap_hsmmc_next *next, - struct device *dev) + struct dma_chan *chan) { int dma_len; @@ -1357,7 +1251,7 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host, /* Check if next job is already prepared */ if (next || (!next && data->host_cookie != host->next_data.cookie)) { - dma_len = dma_map_sg(dev, data->sg, data->sg_len, + dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len, omap_hsmmc_get_dma_dir(host, data)); } else { @@ -1384,7 +1278,9 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host, static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host, struct mmc_request *req) { - int dma_ch = 0, ret = 0, i; + struct dma_slave_config cfg; + struct dma_async_tx_descriptor *tx; + int ret = 0, i; struct mmc_data *data = req->data; struct dma_chan *chan; @@ -1402,66 +1298,43 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host, */ return -EINVAL; - BUG_ON(host->dma_ch != -1 || host->dma2 != -1); + BUG_ON(host->dma_ch != -1); chan = omap_hsmmc_get_dma_chan(host, data); - if (!chan) { - ret = omap_request_dma(omap_hsmmc_get_dma_sync_dev(host, data), - "MMC/SD", omap_hsmmc_dma_cb, host, &dma_ch); - if (ret != 0) { - dev_err(mmc_dev(host->mmc), - "%s: omap_request_dma() failed with %d\n", - mmc_hostname(host->mmc), ret); - return ret; - } - ret = omap_hsmmc_pre_dma_transfer(host, data, NULL, - mmc_dev(host->mmc)); - if (ret) - return ret; - - host->dma_ch = dma_ch; - host->dma_sg_idx = 0; - omap_hsmmc_config_dma_params(host, data, data->sg); - } else { - struct dma_slave_config cfg; - struct dma_async_tx_descriptor *tx; + cfg.src_addr = host->mapbase + OMAP_HSMMC_DATA; + cfg.dst_addr = host->mapbase + OMAP_HSMMC_DATA; + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + cfg.src_maxburst = data->blksz / 4; + cfg.dst_maxburst = data->blksz / 4; - cfg.src_addr = host->mapbase + OMAP_HSMMC_DATA; - cfg.dst_addr = host->mapbase + OMAP_HSMMC_DATA; - cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - cfg.src_maxburst = data->blksz / 4; - cfg.dst_maxburst = data->blksz / 4; - - ret = dmaengine_slave_config(chan, &cfg); - if (ret) - return ret; + ret = dmaengine_slave_config(chan, &cfg); + if (ret) + return ret; - ret = omap_hsmmc_pre_dma_transfer(host, data, NULL, - chan->device->dev); - if (ret) - return ret; + ret = omap_hsmmc_pre_dma_transfer(host, data, NULL, chan); + if (ret) + return ret; - tx = dmaengine_prep_slave_sg(chan, data->sg, data->sg_len, - data->flags & MMC_DATA_WRITE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!tx) { - dev_err(mmc_dev(host->mmc), "prep_slave_sg() failed\n"); - /* FIXME: cleanup */ - return -1; - } + tx = dmaengine_prep_slave_sg(chan, data->sg, data->sg_len, + data->flags & MMC_DATA_WRITE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!tx) { + dev_err(mmc_dev(host->mmc), "prep_slave_sg() failed\n"); + /* FIXME: cleanup */ + return -1; + } - tx->callback = omap_hsmmc_dma_callback; - tx->callback_param = host; + tx->callback = omap_hsmmc_dma_callback; + tx->callback_param = host; - /* Does not fail */ - dmaengine_submit(tx); + /* Does not fail */ + dmaengine_submit(tx); - host->dma2 = 1; + host->dma_ch = 1; - dma_async_issue_pending(chan); - } + dma_async_issue_pending(chan); return 0; } @@ -1543,14 +1416,11 @@ static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, struct omap_hsmmc_host *host = mmc_priv(mmc); struct mmc_data *data = mrq->data; - if (host->use_dma) { + if (host->use_dma && data->host_cookie) { struct dma_chan *c = omap_hsmmc_get_dma_chan(host, data); - struct device *dev = c ? c->device->dev : mmc_dev(mmc); - if (data->host_cookie) - dma_unmap_sg(dev, - data->sg, data->sg_len, - omap_hsmmc_get_dma_dir(host, data)); + dma_unmap_sg(c->device->dev, data->sg, data->sg_len, + omap_hsmmc_get_dma_dir(host, data)); data->host_cookie = 0; } } @@ -1567,10 +1437,9 @@ static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, if (host->use_dma) { struct dma_chan *c = omap_hsmmc_get_dma_chan(host, mrq->data); - struct device *dev = c ? c->device->dev : mmc_dev(mmc); if (omap_hsmmc_pre_dma_transfer(host, mrq->data, - &host->next_data, dev)) + &host->next_data, c)) mrq->data->host_cookie = 0; } } @@ -1584,7 +1453,7 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req) int err; BUG_ON(host->req_in_progress); - BUG_ON(host->dma_ch != -1 || host->dma2 != -1); + BUG_ON(host->dma_ch != -1); if (host->protect_card) { if (host->reqs_blocked < 3) { /* @@ -1897,6 +1766,8 @@ static inline struct omap_mmc_platform_data } #endif +extern bool omap_dma_filter_fn(struct dma_chan *chan, void *param); + static int __devinit omap_hsmmc_probe(struct platform_device *pdev) { struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; @@ -1905,6 +1776,8 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) struct resource *res; int ret, irq; const struct of_device_id *match; + dma_cap_mask_t mask; + unsigned tx_req, rx_req; match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev); if (match) { @@ -1949,9 +1822,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) host->pdata = pdata; host->dev = &pdev->dev; host->use_dma = 1; - host->dev->dma_mask = &pdata->dma_mask; host->dma_ch = -1; - host->dma2 = -1; host->irq = irq; host->slot_id = 0; host->mapbase = res->start + pdata->reg_offset; @@ -2039,36 +1910,28 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n"); goto err_irq; } - host->dma_line_tx = res->start; + tx_req = res->start; res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); if (!res) { dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n"); goto err_irq; } - host->dma_line_rx = res->start; + rx_req = res->start; - { - dma_cap_mask_t mask; - unsigned sig; - extern bool omap_dma_filter_fn(struct dma_chan *chan, void *param); - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); -#if 1 - sig = host->dma_line_rx; - host->rx_chan = dma_request_channel(mask, omap_dma_filter_fn, &sig); - if (!host->rx_chan) { - dev_warn(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", sig); - } -#endif -#if 1 - sig = host->dma_line_tx; - host->tx_chan = dma_request_channel(mask, omap_dma_filter_fn, &sig); - if (!host->tx_chan) { - dev_warn(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel %u\n", sig); - } -#endif + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + host->rx_chan = dma_request_channel(mask, omap_dma_filter_fn, &rx_req); + if (!host->rx_chan) { + dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", rx_req); + goto err_irq; + } + + host->tx_chan = dma_request_channel(mask, omap_dma_filter_fn, &tx_req); + if (!host->tx_chan) { + dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel %u\n", tx_req); + goto err_irq; } /* Request IRQ for MMC operations */ -- cgit v1.1 From 3451c06754b5777d227aa99f85c35bdfabac3ca0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 21 Apr 2012 22:35:42 +0100 Subject: mmc: omap: add DMA engine support Add DMA engine support to the OMAP driver. This supplements the private DMA API implementation contained within this driver, and the driver can be switched at build time between using DMA engine and the private DMA API. Tested-by: Tony Lindgren Acked-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/omap.c | 199 +++++++++++++++++++++++++++++++++++++++--- drivers/mmc/host/omap_hsmmc.c | 3 +- 2 files changed, 190 insertions(+), 12 deletions(-) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 3e8dcf8..25e7efe 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -17,10 +17,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -99,6 +101,8 @@ struct mmc_omap_host; +#define USE_DMA_PRIVATE + struct mmc_omap_slot { int id; unsigned int vdd; @@ -128,6 +132,10 @@ struct mmc_omap_host { unsigned char id; /* 16xx chips have 2 MMC blocks */ struct clk * iclk; struct clk * fclk; + struct dma_chan *dma_rx; + u32 dma_rx_burst; + struct dma_chan *dma_tx; + u32 dma_tx_burst; struct resource *mem_res; void __iomem *virt_base; unsigned int phys_base; @@ -153,12 +161,14 @@ struct mmc_omap_host { unsigned use_dma:1; unsigned brs_received:1, dma_done:1; - unsigned dma_is_read:1; unsigned dma_in_use:1; +#ifdef USE_DMA_PRIVATE + unsigned dma_is_read:1; int dma_ch; - spinlock_t dma_lock; struct timer_list dma_timer; unsigned dma_len; +#endif + spinlock_t dma_lock; struct mmc_omap_slot *slots[OMAP_MMC_MAX_SLOTS]; struct mmc_omap_slot *current_slot; @@ -406,18 +416,32 @@ mmc_omap_release_dma(struct mmc_omap_host *host, struct mmc_data *data, int abort) { enum dma_data_direction dma_data_dir; + struct device *dev = mmc_dev(host->mmc); + struct dma_chan *c; +#ifdef USE_DMA_PRIVATE BUG_ON(host->dma_ch < 0); if (data->error) omap_stop_dma(host->dma_ch); /* Release DMA channel lazily */ mod_timer(&host->dma_timer, jiffies + HZ); - if (data->flags & MMC_DATA_WRITE) +#endif + if (data->flags & MMC_DATA_WRITE) { dma_data_dir = DMA_TO_DEVICE; - else + c = host->dma_tx; + } else { dma_data_dir = DMA_FROM_DEVICE; - dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len, - dma_data_dir); + c = host->dma_rx; + } + if (c) { + if (data->error) { + dmaengine_terminate_all(c); + /* Claim nothing transferred on error... */ + data->bytes_xfered = 0; + } + dev = c->device->dev; + } + dma_unmap_sg(dev, data->sg, host->sg_len, dma_data_dir); } static void mmc_omap_send_stop_work(struct work_struct *work) @@ -524,6 +548,7 @@ mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data) mmc_omap_xfer_done(host, data); } +#ifdef USE_DMA_PRIVATE static void mmc_omap_dma_timer(unsigned long data) { @@ -533,6 +558,7 @@ mmc_omap_dma_timer(unsigned long data) omap_free_dma(host->dma_ch); host->dma_ch = -1; } +#endif static void mmc_omap_dma_done(struct mmc_omap_host *host, struct mmc_data *data) @@ -891,6 +917,18 @@ static void mmc_omap_cover_handler(unsigned long param) jiffies + msecs_to_jiffies(OMAP_MMC_COVER_POLL_DELAY)); } +static void mmc_omap_dma_callback(void *priv) +{ + struct mmc_omap_host *host = priv; + struct mmc_data *data = host->data; + + /* If we got to the end of DMA, assume everything went well */ + data->bytes_xfered += data->blocks * data->blksz; + + mmc_omap_dma_done(host, data); +} + +#ifdef USE_DMA_PRIVATE /* Prepare to transfer the next segment of a scatterlist */ static void mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data) @@ -1045,6 +1083,7 @@ static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data return 0; } +#endif static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_request *req) { @@ -1118,6 +1157,80 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) host->sg_idx = 0; if (use_dma) { + enum dma_data_direction dma_data_dir; + struct dma_async_tx_descriptor *tx; + struct dma_chan *c; + u32 burst, *bp; + u16 buf; + + /* + * FIFO is 16x2 bytes on 15xx, and 32x2 bytes on 16xx + * and 24xx. Use 16 or 32 word frames when the + * blocksize is at least that large. Blocksize is + * usually 512 bytes; but not for some SD reads. + */ + burst = cpu_is_omap15xx() ? 32 : 64; + if (burst > data->blksz) + burst = data->blksz; + + burst >>= 1; + + if (data->flags & MMC_DATA_WRITE) { + c = host->dma_tx; + bp = &host->dma_tx_burst; + buf = 0x0f80 | (burst - 1) << 0; + dma_data_dir = DMA_TO_DEVICE; + } else { + c = host->dma_rx; + bp = &host->dma_rx_burst; + buf = 0x800f | (burst - 1) << 8; + dma_data_dir = DMA_FROM_DEVICE; + } + + if (!c) + goto use_pio; + + /* Only reconfigure if we have a different burst size */ + if (*bp != burst) { + struct dma_slave_config cfg; + + cfg.src_addr = host->phys_base + OMAP_MMC_REG(host, DATA); + cfg.dst_addr = host->phys_base + OMAP_MMC_REG(host, DATA); + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + cfg.src_maxburst = burst; + cfg.dst_maxburst = burst; + + if (dmaengine_slave_config(c, &cfg)) + goto use_pio; + + *bp = burst; + } + + host->sg_len = dma_map_sg(c->device->dev, data->sg, sg_len, + dma_data_dir); + if (host->sg_len == 0) + goto use_pio; + + tx = dmaengine_prep_slave_sg(c, data->sg, host->sg_len, + data->flags & MMC_DATA_WRITE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!tx) + goto use_pio; + + OMAP_MMC_WRITE(host, BUF, buf); + + tx->callback = mmc_omap_dma_callback; + tx->callback_param = host; + dmaengine_submit(tx); + host->brs_received = 0; + host->dma_done = 0; + host->dma_in_use = 1; + return; + } + use_pio: +#ifdef USE_DMA_PRIVATE + if (use_dma) { if (mmc_omap_get_dma_channel(host, data) == 0) { enum dma_data_direction dma_data_dir; @@ -1136,6 +1249,9 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) } else use_dma = 0; } +#else + use_dma = 0; +#endif /* Revert to PIO? */ if (!use_dma) { @@ -1157,8 +1273,17 @@ static void mmc_omap_start_request(struct mmc_omap_host *host, /* only touch fifo AFTER the controller readies it */ mmc_omap_prepare_data(host, req); mmc_omap_start_command(host, req->cmd); - if (host->dma_in_use) - omap_start_dma(host->dma_ch); + if (host->dma_in_use) { + struct dma_chan *c = host->data->flags & MMC_DATA_WRITE ? + host->dma_tx : host->dma_rx; + + if (c) + dma_async_issue_pending(c); +#ifdef USE_DMA_PRIVATE + else + omap_start_dma(host->dma_ch); +#endif + } } static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req) @@ -1400,6 +1525,8 @@ static int __devinit mmc_omap_probe(struct platform_device *pdev) struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; struct mmc_omap_host *host = NULL; struct resource *res; + dma_cap_mask_t mask; + unsigned sig; int i, ret = 0; int irq; @@ -1439,7 +1566,9 @@ static int __devinit mmc_omap_probe(struct platform_device *pdev) setup_timer(&host->clk_timer, mmc_omap_clk_timer, (unsigned long) host); spin_lock_init(&host->dma_lock); +#ifdef USE_DMA_PRIVATE setup_timer(&host->dma_timer, mmc_omap_dma_timer, (unsigned long) host); +#endif spin_lock_init(&host->slot_lock); init_waitqueue_head(&host->slot_wq); @@ -1452,8 +1581,10 @@ static int __devinit mmc_omap_probe(struct platform_device *pdev) host->irq = irq; host->use_dma = 1; +#ifdef USE_DMA_PRIVATE host->dev->dma_mask = &pdata->dma_mask; host->dma_ch = -1; +#endif host->irq = irq; host->phys_base = host->mem_res->start; @@ -1474,9 +1605,48 @@ static int __devinit mmc_omap_probe(struct platform_device *pdev) goto err_free_iclk; } + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + host->dma_tx_burst = -1; + host->dma_rx_burst = -1; + + if (cpu_is_omap24xx()) + sig = host->id == 0 ? OMAP24XX_DMA_MMC1_TX : OMAP24XX_DMA_MMC2_TX; + else + sig = host->id == 0 ? OMAP_DMA_MMC_TX : OMAP_DMA_MMC2_TX; + host->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig); +#if 0 + if (!host->dma_tx) { + dev_err(host->dev, "unable to obtain TX DMA engine channel %u\n", + sig); + goto err_dma; + } +#else + if (!host->dma_tx) + dev_warn(host->dev, "unable to obtain TX DMA engine channel %u\n", + sig); +#endif + if (cpu_is_omap24xx()) + sig = host->id == 0 ? OMAP24XX_DMA_MMC1_RX : OMAP24XX_DMA_MMC2_RX; + else + sig = host->id == 0 ? OMAP_DMA_MMC_RX : OMAP_DMA_MMC2_RX; + host->dma_rx = dma_request_channel(mask, omap_dma_filter_fn, &sig); +#if 0 + if (!host->dma_rx) { + dev_err(host->dev, "unable to obtain RX DMA engine channel %u\n", + sig); + goto err_dma; + } +#else + if (!host->dma_rx) + dev_warn(host->dev, "unable to obtain RX DMA engine channel %u\n", + sig); +#endif + ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host); if (ret) - goto err_free_fclk; + goto err_free_dma; if (pdata->init != NULL) { ret = pdata->init(&pdev->dev); @@ -1510,7 +1680,11 @@ err_plat_cleanup: pdata->cleanup(&pdev->dev); err_free_irq: free_irq(host->irq, host); -err_free_fclk: +err_free_dma: + if (host->dma_tx) + dma_release_channel(host->dma_tx); + if (host->dma_rx) + dma_release_channel(host->dma_rx); clk_put(host->fclk); err_free_iclk: clk_disable(host->iclk); @@ -1545,6 +1719,11 @@ static int __devexit mmc_omap_remove(struct platform_device *pdev) clk_disable(host->iclk); clk_put(host->iclk); + if (host->dma_tx) + dma_release_channel(host->dma_tx); + if (host->dma_rx) + dma_release_channel(host->dma_rx); + iounmap(host->virt_base); release_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1); diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 2b2c987..2338703 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -1766,8 +1767,6 @@ static inline struct omap_mmc_platform_data } #endif -extern bool omap_dma_filter_fn(struct dma_chan *chan, void *param); - static int __devinit omap_hsmmc_probe(struct platform_device *pdev) { struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; -- cgit v1.1 From 4e078fbd581a92fa26ba2def4ac8f2a633cdcb5b Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 21 Apr 2012 22:41:10 +0100 Subject: mmc: omap: remove private DMA API implementation Remove the private DMA API implementation from omap, making it use entirely the DMA engine API. Tested-by: Tony Lindgren Signed-off-by: Russell King --- drivers/mmc/host/omap.c | 235 ++---------------------------------------------- 1 file changed, 6 insertions(+), 229 deletions(-) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 25e7efe..50e08f0 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -101,8 +101,6 @@ struct mmc_omap_host; -#define USE_DMA_PRIVATE - struct mmc_omap_slot { int id; unsigned int vdd; @@ -162,12 +160,6 @@ struct mmc_omap_host { unsigned use_dma:1; unsigned brs_received:1, dma_done:1; unsigned dma_in_use:1; -#ifdef USE_DMA_PRIVATE - unsigned dma_is_read:1; - int dma_ch; - struct timer_list dma_timer; - unsigned dma_len; -#endif spinlock_t dma_lock; struct mmc_omap_slot *slots[OMAP_MMC_MAX_SLOTS]; @@ -419,13 +411,6 @@ mmc_omap_release_dma(struct mmc_omap_host *host, struct mmc_data *data, struct device *dev = mmc_dev(host->mmc); struct dma_chan *c; -#ifdef USE_DMA_PRIVATE - BUG_ON(host->dma_ch < 0); - if (data->error) - omap_stop_dma(host->dma_ch); - /* Release DMA channel lazily */ - mod_timer(&host->dma_timer, jiffies + HZ); -#endif if (data->flags & MMC_DATA_WRITE) { dma_data_dir = DMA_TO_DEVICE; c = host->dma_tx; @@ -548,18 +533,6 @@ mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data) mmc_omap_xfer_done(host, data); } -#ifdef USE_DMA_PRIVATE -static void -mmc_omap_dma_timer(unsigned long data) -{ - struct mmc_omap_host *host = (struct mmc_omap_host *) data; - - BUG_ON(host->dma_ch < 0); - omap_free_dma(host->dma_ch); - host->dma_ch = -1; -} -#endif - static void mmc_omap_dma_done(struct mmc_omap_host *host, struct mmc_data *data) { @@ -928,163 +901,6 @@ static void mmc_omap_dma_callback(void *priv) mmc_omap_dma_done(host, data); } -#ifdef USE_DMA_PRIVATE -/* Prepare to transfer the next segment of a scatterlist */ -static void -mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data) -{ - int dma_ch = host->dma_ch; - unsigned long data_addr; - u16 buf, frame; - u32 count; - struct scatterlist *sg = &data->sg[host->sg_idx]; - int src_port = 0; - int dst_port = 0; - int sync_dev = 0; - - data_addr = host->phys_base + OMAP_MMC_REG(host, DATA); - frame = data->blksz; - count = sg_dma_len(sg); - - if ((data->blocks == 1) && (count > data->blksz)) - count = frame; - - host->dma_len = count; - - /* FIFO is 16x2 bytes on 15xx, and 32x2 bytes on 16xx and 24xx. - * Use 16 or 32 word frames when the blocksize is at least that large. - * Blocksize is usually 512 bytes; but not for some SD reads. - */ - if (cpu_is_omap15xx() && frame > 32) - frame = 32; - else if (frame > 64) - frame = 64; - count /= frame; - frame >>= 1; - - if (!(data->flags & MMC_DATA_WRITE)) { - buf = 0x800f | ((frame - 1) << 8); - - if (cpu_class_is_omap1()) { - src_port = OMAP_DMA_PORT_TIPB; - dst_port = OMAP_DMA_PORT_EMIFF; - } - if (cpu_is_omap24xx()) - sync_dev = OMAP24XX_DMA_MMC1_RX; - - omap_set_dma_src_params(dma_ch, src_port, - OMAP_DMA_AMODE_CONSTANT, - data_addr, 0, 0); - omap_set_dma_dest_params(dma_ch, dst_port, - OMAP_DMA_AMODE_POST_INC, - sg_dma_address(sg), 0, 0); - omap_set_dma_dest_data_pack(dma_ch, 1); - omap_set_dma_dest_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4); - } else { - buf = 0x0f80 | ((frame - 1) << 0); - - if (cpu_class_is_omap1()) { - src_port = OMAP_DMA_PORT_EMIFF; - dst_port = OMAP_DMA_PORT_TIPB; - } - if (cpu_is_omap24xx()) - sync_dev = OMAP24XX_DMA_MMC1_TX; - - omap_set_dma_dest_params(dma_ch, dst_port, - OMAP_DMA_AMODE_CONSTANT, - data_addr, 0, 0); - omap_set_dma_src_params(dma_ch, src_port, - OMAP_DMA_AMODE_POST_INC, - sg_dma_address(sg), 0, 0); - omap_set_dma_src_data_pack(dma_ch, 1); - omap_set_dma_src_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4); - } - - /* Max limit for DMA frame count is 0xffff */ - BUG_ON(count > 0xffff); - - OMAP_MMC_WRITE(host, BUF, buf); - omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S16, - frame, count, OMAP_DMA_SYNC_FRAME, - sync_dev, 0); -} - -/* A scatterlist segment completed */ -static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data) -{ - struct mmc_omap_host *host = (struct mmc_omap_host *) data; - struct mmc_data *mmcdat = host->data; - - if (unlikely(host->dma_ch < 0)) { - dev_err(mmc_dev(host->mmc), - "DMA callback while DMA not enabled\n"); - return; - } - /* FIXME: We really should do something to _handle_ the errors */ - if (ch_status & OMAP1_DMA_TOUT_IRQ) { - dev_err(mmc_dev(host->mmc),"DMA timeout\n"); - return; - } - if (ch_status & OMAP_DMA_DROP_IRQ) { - dev_err(mmc_dev(host->mmc), "DMA sync error\n"); - return; - } - if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) { - return; - } - mmcdat->bytes_xfered += host->dma_len; - host->sg_idx++; - if (host->sg_idx < host->sg_len) { - mmc_omap_prepare_dma(host, host->data); - omap_start_dma(host->dma_ch); - } else - mmc_omap_dma_done(host, host->data); -} - -static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data *data) -{ - const char *dma_dev_name; - int sync_dev, dma_ch, is_read, r; - - is_read = !(data->flags & MMC_DATA_WRITE); - del_timer_sync(&host->dma_timer); - if (host->dma_ch >= 0) { - if (is_read == host->dma_is_read) - return 0; - omap_free_dma(host->dma_ch); - host->dma_ch = -1; - } - - if (is_read) { - if (host->id == 0) { - sync_dev = OMAP_DMA_MMC_RX; - dma_dev_name = "MMC1 read"; - } else { - sync_dev = OMAP_DMA_MMC2_RX; - dma_dev_name = "MMC2 read"; - } - } else { - if (host->id == 0) { - sync_dev = OMAP_DMA_MMC_TX; - dma_dev_name = "MMC1 write"; - } else { - sync_dev = OMAP_DMA_MMC2_TX; - dma_dev_name = "MMC2 write"; - } - } - r = omap_request_dma(sync_dev, dma_dev_name, mmc_omap_dma_cb, - host, &dma_ch); - if (r != 0) { - dev_dbg(mmc_dev(host->mmc), "omap_request_dma() failed with %d\n", r); - return r; - } - host->dma_ch = dma_ch; - host->dma_is_read = is_read; - - return 0; -} -#endif - static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_request *req) { u16 reg; @@ -1229,38 +1045,13 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) return; } use_pio: -#ifdef USE_DMA_PRIVATE - if (use_dma) { - if (mmc_omap_get_dma_channel(host, data) == 0) { - enum dma_data_direction dma_data_dir; - - if (data->flags & MMC_DATA_WRITE) - dma_data_dir = DMA_TO_DEVICE; - else - dma_data_dir = DMA_FROM_DEVICE; - - host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg, - sg_len, dma_data_dir); - host->total_bytes_left = 0; - mmc_omap_prepare_dma(host, req->data); - host->brs_received = 0; - host->dma_done = 0; - host->dma_in_use = 1; - } else - use_dma = 0; - } -#else - use_dma = 0; -#endif /* Revert to PIO? */ - if (!use_dma) { - OMAP_MMC_WRITE(host, BUF, 0x1f1f); - host->total_bytes_left = data->blocks * block_size; - host->sg_len = sg_len; - mmc_omap_sg_to_buf(host); - host->dma_in_use = 0; - } + OMAP_MMC_WRITE(host, BUF, 0x1f1f); + host->total_bytes_left = data->blocks * block_size; + host->sg_len = sg_len; + mmc_omap_sg_to_buf(host); + host->dma_in_use = 0; } static void mmc_omap_start_request(struct mmc_omap_host *host, @@ -1277,12 +1068,7 @@ static void mmc_omap_start_request(struct mmc_omap_host *host, struct dma_chan *c = host->data->flags & MMC_DATA_WRITE ? host->dma_tx : host->dma_rx; - if (c) - dma_async_issue_pending(c); -#ifdef USE_DMA_PRIVATE - else - omap_start_dma(host->dma_ch); -#endif + dma_async_issue_pending(c); } } @@ -1566,9 +1352,6 @@ static int __devinit mmc_omap_probe(struct platform_device *pdev) setup_timer(&host->clk_timer, mmc_omap_clk_timer, (unsigned long) host); spin_lock_init(&host->dma_lock); -#ifdef USE_DMA_PRIVATE - setup_timer(&host->dma_timer, mmc_omap_dma_timer, (unsigned long) host); -#endif spin_lock_init(&host->slot_lock); init_waitqueue_head(&host->slot_wq); @@ -1579,13 +1362,7 @@ static int __devinit mmc_omap_probe(struct platform_device *pdev) host->id = pdev->id; host->mem_res = res; host->irq = irq; - host->use_dma = 1; -#ifdef USE_DMA_PRIVATE - host->dev->dma_mask = &pdata->dma_mask; - host->dma_ch = -1; -#endif - host->irq = irq; host->phys_base = host->mem_res->start; host->virt_base = ioremap(res->start, resource_size(res)); -- cgit v1.1 From 04e8c7bc2c1eda2d06ff6eb57a7df97e64d895e6 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Wed, 11 Jul 2012 17:51:40 +0100 Subject: ARM: 7464/1: mmc: omap_hsmmc: ensure probe returns error if DMA channel request fails If dma_request_channel() fails (e.g. because DMA enine is not built into the kernel), the return value from probe is zero causing the driver to be bound to the device even though probe failed. To fix, ensure that probe returns an error value when a DMA channel request fail. Signed-off-by: Kevin Hilman Signed-off-by: Russell King --- drivers/mmc/host/omap_hsmmc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mmc/host') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 2338703..823d21c 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1924,12 +1924,14 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) host->rx_chan = dma_request_channel(mask, omap_dma_filter_fn, &rx_req); if (!host->rx_chan) { dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", rx_req); + ret = -ENXIO; goto err_irq; } host->tx_chan = dma_request_channel(mask, omap_dma_filter_fn, &tx_req); if (!host->tx_chan) { dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel %u\n", tx_req); + ret = -ENXIO; goto err_irq; } -- cgit v1.1