* [CFT 02/11] mmc: omap_hsmmc: add DMA engine support
[not found] <20120607110610.GB15973@n2100.arm.linux.org.uk>
@ 2012-06-07 11:06 ` Russell King
2012-06-07 17:04 ` Tony Lindgren
2012-06-08 8:53 ` Linus Walleij
2012-06-07 11:07 ` [CFT 03/11] mmc: omap_hsmmc: remove private DMA API implementation Russell King
` (2 subsequent siblings)
3 siblings, 2 replies; 12+ messages in thread
From: Russell King @ 2012-06-07 11:06 UTC (permalink / raw)
To: linux-arm-kernel, linux-omap; +Cc: Chris Ball, linux-mmc
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 <notasas@gmail.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/mmc/host/omap_hsmmc.c | 192 +++++++++++++++++++++++++++++++++++------
1 files changed, 165 insertions(+), 27 deletions(-)
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 9a7a60a..f80361f 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>
+#include <linux/dmaengine.h>
#include <linux/seq_file.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
@@ -167,7 +168,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;
@@ -802,19 +805,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);
@@ -886,7 +896,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;
@@ -894,8 +904,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,
@@ -1292,9 +1314,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;
@@ -1309,8 +1365,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 {
@@ -1339,6 +1394,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++) {
@@ -1354,24 +1410,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;
}
@@ -1454,9 +1552,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;
}
@@ -1472,10 +1573,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;
+ }
}
/*
@@ -1487,7 +1592,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) {
/*
@@ -1854,6 +1959,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;
@@ -1951,6 +2057,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);
@@ -2028,6 +2157,10 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
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);
@@ -2063,6 +2196,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);
--
1.7.4.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [CFT 03/11] mmc: omap_hsmmc: remove private DMA API implementation
[not found] <20120607110610.GB15973@n2100.arm.linux.org.uk>
2012-06-07 11:06 ` [CFT 02/11] mmc: omap_hsmmc: add DMA engine support Russell King
@ 2012-06-07 11:07 ` Russell King
2012-06-07 17:04 ` Tony Lindgren
` (2 more replies)
2012-06-07 11:07 ` [CFT 04/11] mmc: omap: add DMA engine support Russell King
2012-06-07 11:07 ` [CFT 05/11] mmc: omap: remove private DMA API implementation Russell King
3 siblings, 3 replies; 12+ messages in thread
From: Russell King @ 2012-06-07 11:07 UTC (permalink / raw)
To: linux-arm-kernel, linux-omap; +Cc: Chris Ball, linux-mmc
Remove the private DMA API implementation from omap_hsmmc, making it
use entirely the DMA engine API.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/mmc/host/omap_hsmmc.c | 265 ++++++++++-------------------------------
1 files changed, 64 insertions(+), 201 deletions(-)
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index f80361f..9504092 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -38,7 +38,6 @@
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
-#include <plat/dma.h>
#include <mach/hardware.h>
#include <plat/board.h>
#include <plat/mmc.h>
@@ -168,10 +167,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;
@@ -813,18 +811,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);
@@ -896,7 +893,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;
@@ -904,11 +901,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);
@@ -918,13 +913,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;
}
@@ -1220,100 +1208,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;
@@ -1322,7 +1216,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;
}
@@ -1335,7 +1229,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 */
@@ -1350,7 +1244,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;
@@ -1365,7 +1259,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 {
@@ -1392,7 +1286,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;
@@ -1410,66 +1306,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;
}
@@ -1551,14 +1424,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;
}
}
@@ -1575,10 +1445,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;
}
}
@@ -1592,7 +1461,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) {
/*
@@ -1905,6 +1774,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;
@@ -1913,6 +1784,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) {
@@ -1957,9 +1830,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;
@@ -2048,36 +1919,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 */
--
1.7.4.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [CFT 04/11] mmc: omap: add DMA engine support
[not found] <20120607110610.GB15973@n2100.arm.linux.org.uk>
2012-06-07 11:06 ` [CFT 02/11] mmc: omap_hsmmc: add DMA engine support Russell King
2012-06-07 11:07 ` [CFT 03/11] mmc: omap_hsmmc: remove private DMA API implementation Russell King
@ 2012-06-07 11:07 ` Russell King
2012-06-07 17:05 ` Tony Lindgren
2012-06-08 8:52 ` Linus Walleij
2012-06-07 11:07 ` [CFT 05/11] mmc: omap: remove private DMA API implementation Russell King
3 siblings, 2 replies; 12+ messages in thread
From: Russell King @ 2012-06-07 11:07 UTC (permalink / raw)
To: linux-arm-kernel, linux-omap; +Cc: Jarkko Lavinen, Chris Ball, linux-mmc
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.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/mmc/host/omap.c | 199 ++++++++++++++++++++++++++++++++++++++--
drivers/mmc/host/omap_hsmmc.c | 3 +-
2 files changed, 190 insertions(+), 12 deletions(-)
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index 552196c..eaea251 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -17,10 +17,12 @@
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
+#include <linux/omap-dma.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/clk.h>
@@ -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);
@@ -1508,7 +1678,11 @@ static int __devinit mmc_omap_probe(struct platform_device *pdev)
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);
@@ -1543,6 +1717,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 9504092..5d7dbc9 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -30,6 +30,7 @@
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_device.h>
+#include <linux/omap-dma.h>
#include <linux/mmc/host.h>
#include <linux/mmc/core.h>
#include <linux/mmc/mmc.h>
@@ -1774,8 +1775,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;
--
1.7.4.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [CFT 05/11] mmc: omap: remove private DMA API implementation
[not found] <20120607110610.GB15973@n2100.arm.linux.org.uk>
` (2 preceding siblings ...)
2012-06-07 11:07 ` [CFT 04/11] mmc: omap: add DMA engine support Russell King
@ 2012-06-07 11:07 ` Russell King
2012-06-07 17:05 ` Tony Lindgren
3 siblings, 1 reply; 12+ messages in thread
From: Russell King @ 2012-06-07 11:07 UTC (permalink / raw)
To: linux-arm-kernel, linux-omap; +Cc: Jarkko Lavinen, Chris Ball, linux-mmc
Remove the private DMA API implementation from omap, making it use
entirely the DMA engine API.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/mmc/host/omap.c | 235 +---------------------------------------------
1 files changed, 6 insertions(+), 229 deletions(-)
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index eaea251..4026392 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));
--
1.7.4.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [CFT 02/11] mmc: omap_hsmmc: add DMA engine support
2012-06-07 11:06 ` [CFT 02/11] mmc: omap_hsmmc: add DMA engine support Russell King
@ 2012-06-07 17:04 ` Tony Lindgren
2012-06-08 8:53 ` Linus Walleij
1 sibling, 0 replies; 12+ messages in thread
From: Tony Lindgren @ 2012-06-07 17:04 UTC (permalink / raw)
To: Russell King; +Cc: linux-arm-kernel, linux-omap, Chris Ball, linux-mmc
* Russell King <rmk+kernel@arm.linux.org.uk> [120607 04:11]:
> 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 <notasas@gmail.com>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Gave this quick boot test on 2430sdp, zoom3, n900 and blaze:
Tested-by: Tony Lindgren <tony@atomide.com>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [CFT 03/11] mmc: omap_hsmmc: remove private DMA API implementation
2012-06-07 11:07 ` [CFT 03/11] mmc: omap_hsmmc: remove private DMA API implementation Russell King
@ 2012-06-07 17:04 ` Tony Lindgren
2012-06-07 17:53 ` S, Venkatraman
2012-07-10 21:48 ` Kevin Hilman
2 siblings, 0 replies; 12+ messages in thread
From: Tony Lindgren @ 2012-06-07 17:04 UTC (permalink / raw)
To: Russell King; +Cc: linux-arm-kernel, linux-omap, Chris Ball, linux-mmc
* Russell King <rmk+kernel@arm.linux.org.uk> [120607 04:11]:
> Remove the private DMA API implementation from omap_hsmmc, making it
> use entirely the DMA engine API.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Tested-by: Tony Lindgren <tony@atomide.com>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [CFT 04/11] mmc: omap: add DMA engine support
2012-06-07 11:07 ` [CFT 04/11] mmc: omap: add DMA engine support Russell King
@ 2012-06-07 17:05 ` Tony Lindgren
2012-06-08 8:52 ` Linus Walleij
1 sibling, 0 replies; 12+ messages in thread
From: Tony Lindgren @ 2012-06-07 17:05 UTC (permalink / raw)
To: Russell King
Cc: linux-arm-kernel, linux-omap, Jarkko Lavinen, Chris Ball,
linux-mmc
* Russell King <rmk+kernel@arm.linux.org.uk> [120607 04:11]:
> 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.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This I boot tested on 770 and N800:
Tested-by: Tony Lindgren <tony@atomide.com>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [CFT 05/11] mmc: omap: remove private DMA API implementation
2012-06-07 11:07 ` [CFT 05/11] mmc: omap: remove private DMA API implementation Russell King
@ 2012-06-07 17:05 ` Tony Lindgren
0 siblings, 0 replies; 12+ messages in thread
From: Tony Lindgren @ 2012-06-07 17:05 UTC (permalink / raw)
To: Russell King
Cc: linux-arm-kernel, linux-omap, Jarkko Lavinen, Chris Ball,
linux-mmc
* Russell King <rmk+kernel@arm.linux.org.uk> [120607 04:12]:
> Remove the private DMA API implementation from omap, making it use
> entirely the DMA engine API.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Tested-by: Tony Lindgren <tony@atomide.com>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [CFT 03/11] mmc: omap_hsmmc: remove private DMA API implementation
2012-06-07 11:07 ` [CFT 03/11] mmc: omap_hsmmc: remove private DMA API implementation Russell King
2012-06-07 17:04 ` Tony Lindgren
@ 2012-06-07 17:53 ` S, Venkatraman
2012-07-10 21:48 ` Kevin Hilman
2 siblings, 0 replies; 12+ messages in thread
From: S, Venkatraman @ 2012-06-07 17:53 UTC (permalink / raw)
To: Russell King; +Cc: linux-arm-kernel, linux-omap, Chris Ball, linux-mmc
On Thu, Jun 7, 2012 at 4:37 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:
> Remove the private DMA API implementation from omap_hsmmc, making it
> use entirely the DMA engine API.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Tested this on 4430SDP with rootfs usage, untarring the kernel source
and compiling it natively.
Tested-by: Venkatraman S <svenkatr@ti.com>
> ---
> drivers/mmc/host/omap_hsmmc.c | 265 ++++++++++-------------------------------
> 1 files changed, 64 insertions(+), 201 deletions(-)
>
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [CFT 04/11] mmc: omap: add DMA engine support
2012-06-07 11:07 ` [CFT 04/11] mmc: omap: add DMA engine support Russell King
2012-06-07 17:05 ` Tony Lindgren
@ 2012-06-08 8:52 ` Linus Walleij
1 sibling, 0 replies; 12+ messages in thread
From: Linus Walleij @ 2012-06-08 8:52 UTC (permalink / raw)
To: Russell King
Cc: linux-arm-kernel, linux-omap, Jarkko Lavinen, Chris Ball,
linux-mmc
On Thu, Jun 7, 2012 at 1:07 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:
> 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.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This looks good as well:
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Thanks,
Linus Walleij
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [CFT 02/11] mmc: omap_hsmmc: add DMA engine support
2012-06-07 11:06 ` [CFT 02/11] mmc: omap_hsmmc: add DMA engine support Russell King
2012-06-07 17:04 ` Tony Lindgren
@ 2012-06-08 8:53 ` Linus Walleij
1 sibling, 0 replies; 12+ messages in thread
From: Linus Walleij @ 2012-06-08 8:53 UTC (permalink / raw)
To: Russell King; +Cc: linux-arm-kernel, linux-omap, Chris Ball, linux-mmc
On Thu, Jun 7, 2012 at 1:06 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:
> 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 <notasas@gmail.com>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Looks good:
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Thanks,
Linus Walleij
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [CFT 03/11] mmc: omap_hsmmc: remove private DMA API implementation
2012-06-07 11:07 ` [CFT 03/11] mmc: omap_hsmmc: remove private DMA API implementation Russell King
2012-06-07 17:04 ` Tony Lindgren
2012-06-07 17:53 ` S, Venkatraman
@ 2012-07-10 21:48 ` Kevin Hilman
2 siblings, 0 replies; 12+ messages in thread
From: Kevin Hilman @ 2012-07-10 21:48 UTC (permalink / raw)
To: Russell King; +Cc: linux-arm-kernel, linux-omap, Chris Ball, linux-mmc
Hi Russell,
Russell King <rmk+kernel@arm.linux.org.uk> writes:
> Remove the private DMA API implementation from omap_hsmmc, making it
> use entirely the DMA engine API.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
While testing this, I noticed a minor problem in the case of probe
failure (e.g. if dmaengine is not built into the kernel.)
The current driver suffers from this same problem but should probably be
fixed when converting to dmaengine...
[...]
> @@ -2048,36 +1919,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;
> }
If either of these fails, ret is zero so even though this results in a
failed probe, the return value (ret) is zero meaning the driver still
gets bound to the device.
The patch below fixes this and applies on your 'for-next' branch. Or,
feel free to fold this into the original if you prefer.
Kevin
>From af7537997b46ee3991985fecd4b4a302bdc0df31 Mon Sep 17 00:00:00 2001
From: Kevin Hilman <khilman@ti.com>
Date: Tue, 10 Jul 2012 14:30:18 -0700
Subject: [PATCH] mmc: omap_hsmmc: ensure probe returns error if DMA channel
request fails
If dma_request_channel() fails (e.g. because DMA engine 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.
Cc: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Kevin Hilman <khilman@ti.com>
---
drivers/mmc/host/omap_hsmmc.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 2338703..ddcecf8 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;
}
--
1.7.9.2
^ permalink raw reply related [flat|nested] 12+ messages in thread
end of thread, other threads:[~2012-07-10 21:48 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20120607110610.GB15973@n2100.arm.linux.org.uk>
2012-06-07 11:06 ` [CFT 02/11] mmc: omap_hsmmc: add DMA engine support Russell King
2012-06-07 17:04 ` Tony Lindgren
2012-06-08 8:53 ` Linus Walleij
2012-06-07 11:07 ` [CFT 03/11] mmc: omap_hsmmc: remove private DMA API implementation Russell King
2012-06-07 17:04 ` Tony Lindgren
2012-06-07 17:53 ` S, Venkatraman
2012-07-10 21:48 ` Kevin Hilman
2012-06-07 11:07 ` [CFT 04/11] mmc: omap: add DMA engine support Russell King
2012-06-07 17:05 ` Tony Lindgren
2012-06-08 8:52 ` Linus Walleij
2012-06-07 11:07 ` [CFT 05/11] mmc: omap: remove private DMA API implementation Russell King
2012-06-07 17:05 ` Tony Lindgren
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).