aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/dw_mmc.c
diff options
context:
space:
mode:
authorSeungwon Jeon <tgih.jun@samsung.com>2012-02-06 02:55:07 -0500
committerChris Ball <cjb@laptop.org>2012-03-25 19:33:45 -0400
commit9aa514089ed4f3a943ab9445e23e03a7be3044e6 (patch)
tree4d2d643f683cc430d8a47a8769b888118609be70 /drivers/mmc/host/dw_mmc.c
parent3e44a1a7d22cdc44c98569fedbd993985bfd64d3 (diff)
mmc: dw_mmc: Add support for pre_req and post_req
This patch implements pre_req and post_req in dw_mmc to support asynchronous mmc request. Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com> Acked-by: Jaehoon Chung <jh80.chung@samsung.com> Acked-by: Will Newton <will.newton@imgtec.com> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/host/dw_mmc.c')
-rw-r--r--drivers/mmc/host/dw_mmc.c129
1 files changed, 102 insertions, 27 deletions
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index d1edf15b29fc..7d6ad6cd4a50 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -296,14 +296,24 @@ static void dw_mci_stop_dma(struct dw_mci *host)
296} 296}
297 297
298#ifdef CONFIG_MMC_DW_IDMAC 298#ifdef CONFIG_MMC_DW_IDMAC
299static int dw_mci_get_dma_dir(struct mmc_data *data)
300{
301 if (data->flags & MMC_DATA_WRITE)
302 return DMA_TO_DEVICE;
303 else
304 return DMA_FROM_DEVICE;
305}
306
299static void dw_mci_dma_cleanup(struct dw_mci *host) 307static void dw_mci_dma_cleanup(struct dw_mci *host)
300{ 308{
301 struct mmc_data *data = host->data; 309 struct mmc_data *data = host->data;
302 310
303 if (data) 311 if (data)
304 dma_unmap_sg(&host->dev, data->sg, data->sg_len, 312 if (!data->host_cookie)
305 ((data->flags & MMC_DATA_WRITE) 313 dma_unmap_sg(&host->dev,
306 ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); 314 data->sg,
315 data->sg_len,
316 dw_mci_get_dma_dir(data));
307} 317}
308 318
309static void dw_mci_idmac_stop_dma(struct dw_mci *host) 319static void dw_mci_idmac_stop_dma(struct dw_mci *host)
@@ -419,26 +429,15 @@ static int dw_mci_idmac_init(struct dw_mci *host)
419 return 0; 429 return 0;
420} 430}
421 431
422static struct dw_mci_dma_ops dw_mci_idmac_ops = { 432static int dw_mci_pre_dma_transfer(struct dw_mci *host,
423 .init = dw_mci_idmac_init, 433 struct mmc_data *data,
424 .start = dw_mci_idmac_start_dma, 434 bool next)
425 .stop = dw_mci_idmac_stop_dma,
426 .complete = dw_mci_idmac_complete_dma,
427 .cleanup = dw_mci_dma_cleanup,
428};
429#endif /* CONFIG_MMC_DW_IDMAC */
430
431static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
432{ 435{
433 struct scatterlist *sg; 436 struct scatterlist *sg;
434 unsigned int i, direction, sg_len; 437 unsigned int i, sg_len;
435 u32 temp;
436
437 host->using_dma = 0;
438 438
439 /* If we don't have a channel, we can't do DMA */ 439 if (!next && data->host_cookie)
440 if (!host->use_dma) 440 return data->host_cookie;
441 return -ENODEV;
442 441
443 /* 442 /*
444 * We don't do DMA on "complex" transfers, i.e. with 443 * We don't do DMA on "complex" transfers, i.e. with
@@ -447,6 +446,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
447 */ 446 */
448 if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD) 447 if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD)
449 return -EINVAL; 448 return -EINVAL;
449
450 if (data->blksz & 3) 450 if (data->blksz & 3)
451 return -EINVAL; 451 return -EINVAL;
452 452
@@ -455,15 +455,88 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
455 return -EINVAL; 455 return -EINVAL;
456 } 456 }
457 457
458 host->using_dma = 1; 458 sg_len = dma_map_sg(&host->dev,
459 data->sg,
460 data->sg_len,
461 dw_mci_get_dma_dir(data));
462 if (sg_len == 0)
463 return -EINVAL;
459 464
460 if (data->flags & MMC_DATA_READ) 465 if (next)
461 direction = DMA_FROM_DEVICE; 466 data->host_cookie = sg_len;
462 else 467
463 direction = DMA_TO_DEVICE; 468 return sg_len;
469}
470
471static struct dw_mci_dma_ops dw_mci_idmac_ops = {
472 .init = dw_mci_idmac_init,
473 .start = dw_mci_idmac_start_dma,
474 .stop = dw_mci_idmac_stop_dma,
475 .complete = dw_mci_idmac_complete_dma,
476 .cleanup = dw_mci_dma_cleanup,
477};
478#else
479static int dw_mci_pre_dma_transfer(struct dw_mci *host,
480 struct mmc_data *data,
481 bool next)
482{
483 return -ENOSYS;
484}
485#endif /* CONFIG_MMC_DW_IDMAC */
486
487static void dw_mci_pre_req(struct mmc_host *mmc,
488 struct mmc_request *mrq,
489 bool is_first_req)
490{
491 struct dw_mci_slot *slot = mmc_priv(mmc);
492 struct mmc_data *data = mrq->data;
493
494 if (!slot->host->use_dma || !data)
495 return;
496
497 if (data->host_cookie) {
498 data->host_cookie = 0;
499 return;
500 }
501
502 if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0)
503 data->host_cookie = 0;
504}
505
506static void dw_mci_post_req(struct mmc_host *mmc,
507 struct mmc_request *mrq,
508 int err)
509{
510 struct dw_mci_slot *slot = mmc_priv(mmc);
511 struct mmc_data *data = mrq->data;
512
513 if (!slot->host->use_dma || !data)
514 return;
515
516 if (data->host_cookie)
517 dma_unmap_sg(&slot->host->dev,
518 data->sg,
519 data->sg_len,
520 dw_mci_get_dma_dir(data));
521 data->host_cookie = 0;
522}
523
524static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
525{
526 int sg_len;
527 u32 temp;
464 528
465 sg_len = dma_map_sg(&host->dev, data->sg, data->sg_len, 529 host->using_dma = 0;
466 direction); 530
531 /* If we don't have a channel, we can't do DMA */
532 if (!host->use_dma)
533 return -ENODEV;
534
535 sg_len = dw_mci_pre_dma_transfer(host, data, 0);
536 if (sg_len < 0)
537 return sg_len;
538
539 host->using_dma = 1;
467 540
468 dev_vdbg(&host->dev, 541 dev_vdbg(&host->dev,
469 "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n", 542 "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
@@ -800,6 +873,8 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
800 873
801static const struct mmc_host_ops dw_mci_ops = { 874static const struct mmc_host_ops dw_mci_ops = {
802 .request = dw_mci_request, 875 .request = dw_mci_request,
876 .pre_req = dw_mci_pre_req,
877 .post_req = dw_mci_post_req,
803 .set_ios = dw_mci_set_ios, 878 .set_ios = dw_mci_set_ios,
804 .get_ro = dw_mci_get_ro, 879 .get_ro = dw_mci_get_ro,
805 .get_cd = dw_mci_get_cd, 880 .get_cd = dw_mci_get_cd,