Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Ben Dooks and committed by
Linus Torvalds
68c5ed59 26f14947

+47 -18
+47 -15
drivers/mmc/host/s3cmci.c
··· 183 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 201 static inline u32 enable_imask(struct s3cmci_host *host, u32 imask) 187 202 { 188 203 u32 newmask; ··· 801 786 dbg(host, dbg_dma, "DMA FINISHED Size:%i DSTA:%08x DCNT:%08x\n", 802 787 size, mci_dsta, mci_dcnt); 803 788 789 + host->dma_complete = 1; 804 790 host->complete_what = COMPLETION_FINALIZE; 805 791 806 792 out: ··· 832 816 if (cmd->data && (cmd->error == 0) && 833 817 (cmd->data->error == 0)) { 834 818 if (s3cmci_host_usedma(host) && (!host->dma_complete)) { 835 - dbg(host, dbg_dma, "DMA Missing!\n"); 819 + dbg(host, dbg_dma, "DMA Missing (%d)!\n", 820 + host->dma_complete); 836 821 return; 837 822 } 838 823 } ··· 1082 1065 static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) 1083 1066 { 1084 1067 int dma_len, i; 1085 - int rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0; 1068 + int rw = data->flags & MMC_DATA_WRITE; 1086 1069 1087 1070 BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR); 1088 1071 ··· 1090 1073 s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); 1091 1074 1092 1075 dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, 1093 - (rw) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); 1076 + rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE); 1094 1077 1095 1078 if (dma_len == 0) 1096 1079 return -ENOMEM; ··· 1101 1084 for (i = 0; i < dma_len; i++) { 1102 1085 int res; 1103 1086 1104 - dbg(host, dbg_dma, "enqueue %i:%u@%u\n", i, 1105 - sg_dma_address(&data->sg[i]), 1106 - sg_dma_len(&data->sg[i])); 1087 + dbg(host, dbg_dma, "enqueue %i: %08x@%u\n", i, 1088 + sg_dma_address(&data->sg[i]), 1089 + sg_dma_len(&data->sg[i])); 1107 1090 1108 - res = s3c2410_dma_enqueue(host->dma, (void *) host, 1091 + res = s3c2410_dma_enqueue(host->dma, host, 1109 1092 sg_dma_address(&data->sg[i]), 1110 1093 sg_dma_len(&data->sg[i])); 1111 1094 ··· 1598 1581 host->complete_what = COMPLETION_NONE; 1599 1582 host->pio_active = XFER_NONE; 1600 1583 1601 - host->dma = S3CMCI_DMA; 1602 - 1603 1584 #ifdef CONFIG_MMC_S3C_PIODMA 1604 1585 host->dodma = host->pdata->dma; 1605 1586 #endif ··· 1680 1665 gpio_direction_input(host->pdata->gpio_wprotect); 1681 1666 } 1682 1667 1683 - if (s3c2410_dma_request(S3CMCI_DMA, &s3cmci_dma_client, NULL) < 0) { 1684 - dev_err(&pdev->dev, "unable to get DMA channel.\n"); 1685 - ret = -EBUSY; 1686 - goto probe_free_gpio_wp; 1668 + /* depending on the dma state, get a dma channel to use. */ 1669 + 1670 + if (s3cmci_host_usedma(host)) { 1671 + host->dma = s3c2410_dma_request(DMACH_SDI, &s3cmci_dma_client, 1672 + host); 1673 + if (host->dma < 0) { 1674 + dev_err(&pdev->dev, "cannot get DMA channel.\n"); 1675 + if (!s3cmci_host_canpio()) { 1676 + ret = -EBUSY; 1677 + goto probe_free_gpio_wp; 1678 + } else { 1679 + dev_warn(&pdev->dev, "falling back to PIO.\n"); 1680 + host->dodma = 0; 1681 + } 1682 + } 1687 1683 } 1688 1684 1689 1685 host->clk = clk_get(&pdev->dev, "sdi"); ··· 1702 1676 dev_err(&pdev->dev, "failed to find clock source.\n"); 1703 1677 ret = PTR_ERR(host->clk); 1704 1678 host->clk = NULL; 1705 - goto probe_free_host; 1679 + goto probe_free_dma; 1706 1680 } 1707 1681 1708 1682 ret = clk_enable(host->clk); ··· 1764 1738 clk_free: 1765 1739 clk_put(host->clk); 1766 1740 1741 + probe_free_dma: 1742 + if (s3cmci_host_usedma(host)) 1743 + s3c2410_dma_free(host->dma, &s3cmci_dma_client); 1744 + 1767 1745 probe_free_gpio_wp: 1768 1746 if (host->pdata->gpio_wprotect) 1769 1747 gpio_free(host->pdata->gpio_wprotect); ··· 1826 1796 clk_put(host->clk); 1827 1797 1828 1798 tasklet_disable(&host->pio_tasklet); 1829 - s3c2410_dma_free(S3CMCI_DMA, &s3cmci_dma_client); 1799 + 1800 + if (s3cmci_host_usedma(host)) 1801 + s3c2410_dma_free(host->dma, &s3cmci_dma_client); 1830 1802 1831 1803 free_irq(host->irq, host); 1832 1804
-3
drivers/mmc/host/s3cmci.h
··· 8 8 * published by the Free Software Foundation. 9 9 */ 10 10 11 - /* FIXME: DMA Resource management ?! */ 12 - #define S3CMCI_DMA 0 13 - 14 11 enum s3cmci_waitfor { 15 12 COMPLETION_NONE, 16 13 COMPLETION_FINALIZE,