diff options
author | Ben Dooks <ben@simtec.co.uk> | 2009-10-01 18:44:19 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-10-01 19:11:15 -0400 |
commit | 68c5ed592fdae16982ffe36aef89faba70a32cfc (patch) | |
tree | 11436cddd195f1c316e9ffb7fd7d2a5f417d8687 /drivers/mmc/host | |
parent | 26f14947dbf31d60d1a67eee837a6d28c1e8830d (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/host')
-rw-r--r-- | drivers/mmc/host/s3cmci.c | 62 | ||||
-rw-r--r-- | drivers/mmc/host/s3cmci.h | 3 |
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 | */ | ||
192 | static 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 | |||
186 | static inline u32 enable_imask(struct s3cmci_host *host, u32 imask) | 201 | static 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 | ||
791 | out: | 807 | out: |
@@ -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) | |||
1065 | static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) | 1082 | static 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 | |||
14 | enum s3cmci_waitfor { | 11 | enum s3cmci_waitfor { |
15 | COMPLETION_NONE, | 12 | COMPLETION_NONE, |
16 | COMPLETION_FINALIZE, | 13 | COMPLETION_FINALIZE, |