aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorBen Dooks <ben@simtec.co.uk>2009-10-01 18:44:19 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-10-01 19:11:15 -0400
commit68c5ed592fdae16982ffe36aef89faba70a32cfc (patch)
tree11436cddd195f1c316e9ffb7fd7d2a5f417d8687 /drivers/mmc
parent26f14947dbf31d60d1a67eee837a6d28c1e8830d (diff)
s3cmci: DMA fixes
Fixes for the DMA transfer mode of the driver to try and improve the state of the code: - Ensure that dma_complete is set during the end of the command phase so that transfers do not stall awaiting the completion - Update the DMA debugging to provide a bit more useful information such as how many DMA descriptors where not processed and print the DMA addresses in hexadecimal. - Fix the DMA channel request code to actually request DMA for the S3CMCI block instead of whatever '0' signified. - Add fallback to PIO if we cannot get the DMA channel, as many of the devices with this block only have a limited number of DMA channels. - Only try and claim and free the DMA channel if we are trying to use it. This improves the driver DMA code to the point where it can now identify a card and read the partition table. However the DMA can still stall when trying to move data between the host and memory. Signed-off-by: Ben Dooks <ben@simtec.co.uk> Cc: <linux-mmc@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/s3cmci.c62
-rw-r--r--drivers/mmc/host/s3cmci.h3
2 files changed, 47 insertions, 18 deletions
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
index 0adf31895f2a..0af972275d45 100644
--- a/drivers/mmc/host/s3cmci.c
+++ b/drivers/mmc/host/s3cmci.c
@@ -183,6 +183,21 @@ static inline bool s3cmci_host_usedma(struct s3cmci_host *host)
183#endif 183#endif
184} 184}
185 185
186/**
187 * s3cmci_host_canpio - return true if host has pio code available
188 *
189 * Return true if the driver has been compiled with the PIO support code
190 * available.
191 */
192static inline bool s3cmci_host_canpio(void)
193{
194#ifdef CONFIG_MMC_S3C_PIO
195 return true;
196#else
197 return false;
198#endif
199}
200
186static inline u32 enable_imask(struct s3cmci_host *host, u32 imask) 201static inline u32 enable_imask(struct s3cmci_host *host, u32 imask)
187{ 202{
188 u32 newmask; 203 u32 newmask;
@@ -786,6 +801,7 @@ static void s3cmci_dma_done_callback(struct s3c2410_dma_chan *dma_ch,
786 dbg(host, dbg_dma, "DMA FINISHED Size:%i DSTA:%08x DCNT:%08x\n", 801 dbg(host, dbg_dma, "DMA FINISHED Size:%i DSTA:%08x DCNT:%08x\n",
787 size, mci_dsta, mci_dcnt); 802 size, mci_dsta, mci_dcnt);
788 803
804 host->dma_complete = 1;
789 host->complete_what = COMPLETION_FINALIZE; 805 host->complete_what = COMPLETION_FINALIZE;
790 806
791out: 807out:
@@ -816,7 +832,8 @@ static void finalize_request(struct s3cmci_host *host)
816 if (cmd->data && (cmd->error == 0) && 832 if (cmd->data && (cmd->error == 0) &&
817 (cmd->data->error == 0)) { 833 (cmd->data->error == 0)) {
818 if (s3cmci_host_usedma(host) && (!host->dma_complete)) { 834 if (s3cmci_host_usedma(host) && (!host->dma_complete)) {
819 dbg(host, dbg_dma, "DMA Missing!\n"); 835 dbg(host, dbg_dma, "DMA Missing (%d)!\n",
836 host->dma_complete);
820 return; 837 return;
821 } 838 }
822 } 839 }
@@ -1065,7 +1082,7 @@ static int s3cmci_prepare_pio(struct s3cmci_host *host, struct mmc_data *data)
1065static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) 1082static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data)
1066{ 1083{
1067 int dma_len, i; 1084 int dma_len, i;
1068 int rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0; 1085 int rw = data->flags & MMC_DATA_WRITE;
1069 1086
1070 BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR); 1087 BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR);
1071 1088
@@ -1073,7 +1090,7 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data)
1073 s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); 1090 s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
1074 1091
1075 dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, 1092 dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1076 (rw) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); 1093 rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
1077 1094
1078 if (dma_len == 0) 1095 if (dma_len == 0)
1079 return -ENOMEM; 1096 return -ENOMEM;
@@ -1084,11 +1101,11 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data)
1084 for (i = 0; i < dma_len; i++) { 1101 for (i = 0; i < dma_len; i++) {
1085 int res; 1102 int res;
1086 1103
1087 dbg(host, dbg_dma, "enqueue %i:%u@%u\n", i, 1104 dbg(host, dbg_dma, "enqueue %i: %08x@%u\n", i,
1088 sg_dma_address(&data->sg[i]), 1105 sg_dma_address(&data->sg[i]),
1089 sg_dma_len(&data->sg[i])); 1106 sg_dma_len(&data->sg[i]));
1090 1107
1091 res = s3c2410_dma_enqueue(host->dma, (void *) host, 1108 res = s3c2410_dma_enqueue(host->dma, host,
1092 sg_dma_address(&data->sg[i]), 1109 sg_dma_address(&data->sg[i]),
1093 sg_dma_len(&data->sg[i])); 1110 sg_dma_len(&data->sg[i]));
1094 1111
@@ -1581,8 +1598,6 @@ static int __devinit s3cmci_probe(struct platform_device *pdev)
1581 host->complete_what = COMPLETION_NONE; 1598 host->complete_what = COMPLETION_NONE;
1582 host->pio_active = XFER_NONE; 1599 host->pio_active = XFER_NONE;
1583 1600
1584 host->dma = S3CMCI_DMA;
1585
1586#ifdef CONFIG_MMC_S3C_PIODMA 1601#ifdef CONFIG_MMC_S3C_PIODMA
1587 host->dodma = host->pdata->dma; 1602 host->dodma = host->pdata->dma;
1588#endif 1603#endif
@@ -1665,10 +1680,21 @@ static int __devinit s3cmci_probe(struct platform_device *pdev)
1665 gpio_direction_input(host->pdata->gpio_wprotect); 1680 gpio_direction_input(host->pdata->gpio_wprotect);
1666 } 1681 }
1667 1682
1668 if (s3c2410_dma_request(S3CMCI_DMA, &s3cmci_dma_client, NULL) < 0) { 1683 /* depending on the dma state, get a dma channel to use. */
1669 dev_err(&pdev->dev, "unable to get DMA channel.\n"); 1684
1670 ret = -EBUSY; 1685 if (s3cmci_host_usedma(host)) {
1671 goto probe_free_gpio_wp; 1686 host->dma = s3c2410_dma_request(DMACH_SDI, &s3cmci_dma_client,
1687 host);
1688 if (host->dma < 0) {
1689 dev_err(&pdev->dev, "cannot get DMA channel.\n");
1690 if (!s3cmci_host_canpio()) {
1691 ret = -EBUSY;
1692 goto probe_free_gpio_wp;
1693 } else {
1694 dev_warn(&pdev->dev, "falling back to PIO.\n");
1695 host->dodma = 0;
1696 }
1697 }
1672 } 1698 }
1673 1699
1674 host->clk = clk_get(&pdev->dev, "sdi"); 1700 host->clk = clk_get(&pdev->dev, "sdi");
@@ -1676,7 +1702,7 @@ static int __devinit s3cmci_probe(struct platform_device *pdev)
1676 dev_err(&pdev->dev, "failed to find clock source.\n"); 1702 dev_err(&pdev->dev, "failed to find clock source.\n");
1677 ret = PTR_ERR(host->clk); 1703 ret = PTR_ERR(host->clk);
1678 host->clk = NULL; 1704 host->clk = NULL;
1679 goto probe_free_host; 1705 goto probe_free_dma;
1680 } 1706 }
1681 1707
1682 ret = clk_enable(host->clk); 1708 ret = clk_enable(host->clk);
@@ -1738,6 +1764,10 @@ static int __devinit s3cmci_probe(struct platform_device *pdev)
1738 clk_free: 1764 clk_free:
1739 clk_put(host->clk); 1765 clk_put(host->clk);
1740 1766
1767 probe_free_dma:
1768 if (s3cmci_host_usedma(host))
1769 s3c2410_dma_free(host->dma, &s3cmci_dma_client);
1770
1741 probe_free_gpio_wp: 1771 probe_free_gpio_wp:
1742 if (host->pdata->gpio_wprotect) 1772 if (host->pdata->gpio_wprotect)
1743 gpio_free(host->pdata->gpio_wprotect); 1773 gpio_free(host->pdata->gpio_wprotect);
@@ -1796,7 +1826,9 @@ static int __devexit s3cmci_remove(struct platform_device *pdev)
1796 clk_put(host->clk); 1826 clk_put(host->clk);
1797 1827
1798 tasklet_disable(&host->pio_tasklet); 1828 tasklet_disable(&host->pio_tasklet);
1799 s3c2410_dma_free(S3CMCI_DMA, &s3cmci_dma_client); 1829
1830 if (s3cmci_host_usedma(host))
1831 s3c2410_dma_free(host->dma, &s3cmci_dma_client);
1800 1832
1801 free_irq(host->irq, host); 1833 free_irq(host->irq, host);
1802 1834
diff --git a/drivers/mmc/host/s3cmci.h b/drivers/mmc/host/s3cmci.h
index 62fac6602306..c76b53dbeb61 100644
--- a/drivers/mmc/host/s3cmci.h
+++ b/drivers/mmc/host/s3cmci.h
@@ -8,9 +8,6 @@
8 * published by the Free Software Foundation. 8 * published by the Free Software Foundation.
9 */ 9 */
10 10
11/* FIXME: DMA Resource management ?! */
12#define S3CMCI_DMA 0
13
14enum s3cmci_waitfor { 11enum s3cmci_waitfor {
15 COMPLETION_NONE, 12 COMPLETION_NONE,
16 COMPLETION_FINALIZE, 13 COMPLETION_FINALIZE,