aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/ste_dma40.c
diff options
context:
space:
mode:
authorPer Forlin <per.forlin@stericsson.com>2010-12-20 12:31:38 -0500
committerDan Williams <dan.j.williams@intel.com>2011-01-04 20:20:43 -0500
commitd49278e3351b34870cbffffc5067348a318e7b06 (patch)
treea8569e9a24286a0bd885f96e27342e4de2fdecbb /drivers/dma/ste_dma40.c
parente8a7e48bb248a1196484d3f8afa53bded2b24e71 (diff)
dmaengine: dma40: Add support to split up large elements
The maximum transfer size of the stedma40 is (64k-1) x data-width. If the transfer size of one element exceeds this limit the job is split up and sent as linked transfer. Signed-off-by: Per Forlin <per.forlin@linaro.org> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/dma/ste_dma40.c')
-rw-r--r--drivers/dma/ste_dma40.c191
1 files changed, 152 insertions, 39 deletions
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index fab68a553205..6e1d46a65d0e 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (C) ST-Ericsson SA 2007-2010 2 * Copyright (C) Ericsson AB 2007-2008
3 * Copyright (C) ST-Ericsson SA 2008-2010
3 * Author: Per Forlin <per.forlin@stericsson.com> for ST-Ericsson 4 * Author: Per Forlin <per.forlin@stericsson.com> for ST-Ericsson
4 * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson 5 * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
5 * License terms: GNU General Public License (GPL) version 2 6 * License terms: GNU General Public License (GPL) version 2
@@ -554,8 +555,66 @@ static struct d40_desc *d40_last_queued(struct d40_chan *d40c)
554 return d; 555 return d;
555} 556}
556 557
557/* Support functions for logical channels */ 558static int d40_psize_2_burst_size(bool is_log, int psize)
559{
560 if (is_log) {
561 if (psize == STEDMA40_PSIZE_LOG_1)
562 return 1;
563 } else {
564 if (psize == STEDMA40_PSIZE_PHY_1)
565 return 1;
566 }
567
568 return 2 << psize;
569}
570
571/*
572 * The dma only supports transmitting packages up to
573 * STEDMA40_MAX_SEG_SIZE << data_width. Calculate the total number of
574 * dma elements required to send the entire sg list
575 */
576static int d40_size_2_dmalen(int size, u32 data_width1, u32 data_width2)
577{
578 int dmalen;
579 u32 max_w = max(data_width1, data_width2);
580 u32 min_w = min(data_width1, data_width2);
581 u32 seg_max = ALIGN(STEDMA40_MAX_SEG_SIZE << min_w, 1 << max_w);
582
583 if (seg_max > STEDMA40_MAX_SEG_SIZE)
584 seg_max -= (1 << max_w);
585
586 if (!IS_ALIGNED(size, 1 << max_w))
587 return -EINVAL;
588
589 if (size <= seg_max)
590 dmalen = 1;
591 else {
592 dmalen = size / seg_max;
593 if (dmalen * seg_max < size)
594 dmalen++;
595 }
596 return dmalen;
597}
598
599static int d40_sg_2_dmalen(struct scatterlist *sgl, int sg_len,
600 u32 data_width1, u32 data_width2)
601{
602 struct scatterlist *sg;
603 int i;
604 int len = 0;
605 int ret;
606
607 for_each_sg(sgl, sg, sg_len, i) {
608 ret = d40_size_2_dmalen(sg_dma_len(sg),
609 data_width1, data_width2);
610 if (ret < 0)
611 return ret;
612 len += ret;
613 }
614 return len;
615}
558 616
617/* Support functions for logical channels */
559 618
560static int d40_channel_execute_command(struct d40_chan *d40c, 619static int d40_channel_execute_command(struct d40_chan *d40c,
561 enum d40_command command) 620 enum d40_command command)
@@ -1241,6 +1300,21 @@ static int d40_validate_conf(struct d40_chan *d40c,
1241 res = -EINVAL; 1300 res = -EINVAL;
1242 } 1301 }
1243 1302
1303 if (d40_psize_2_burst_size(is_log, conf->src_info.psize) *
1304 (1 << conf->src_info.data_width) !=
1305 d40_psize_2_burst_size(is_log, conf->dst_info.psize) *
1306 (1 << conf->dst_info.data_width)) {
1307 /*
1308 * The DMAC hardware only supports
1309 * src (burst x width) == dst (burst x width)
1310 */
1311
1312 dev_err(&d40c->chan.dev->device,
1313 "[%s] src (burst x width) != dst (burst x width)\n",
1314 __func__);
1315 res = -EINVAL;
1316 }
1317
1244 return res; 1318 return res;
1245} 1319}
1246 1320
@@ -1638,13 +1712,21 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
1638 if (d40d == NULL) 1712 if (d40d == NULL)
1639 goto err; 1713 goto err;
1640 1714
1641 d40d->lli_len = sgl_len; 1715 d40d->lli_len = d40_sg_2_dmalen(sgl_dst, sgl_len,
1716 d40c->dma_cfg.src_info.data_width,
1717 d40c->dma_cfg.dst_info.data_width);
1718 if (d40d->lli_len < 0) {
1719 dev_err(&d40c->chan.dev->device,
1720 "[%s] Unaligned size\n", __func__);
1721 goto err;
1722 }
1723
1642 d40d->lli_current = 0; 1724 d40d->lli_current = 0;
1643 d40d->txd.flags = dma_flags; 1725 d40d->txd.flags = dma_flags;
1644 1726
1645 if (d40c->log_num != D40_PHY_CHAN) { 1727 if (d40c->log_num != D40_PHY_CHAN) {
1646 1728
1647 if (d40_pool_lli_alloc(d40d, sgl_len, true) < 0) { 1729 if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) {
1648 dev_err(&d40c->chan.dev->device, 1730 dev_err(&d40c->chan.dev->device,
1649 "[%s] Out of memory\n", __func__); 1731 "[%s] Out of memory\n", __func__);
1650 goto err; 1732 goto err;
@@ -1654,15 +1736,17 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
1654 sgl_len, 1736 sgl_len,
1655 d40d->lli_log.src, 1737 d40d->lli_log.src,
1656 d40c->log_def.lcsp1, 1738 d40c->log_def.lcsp1,
1657 d40c->dma_cfg.src_info.data_width); 1739 d40c->dma_cfg.src_info.data_width,
1740 d40c->dma_cfg.dst_info.data_width);
1658 1741
1659 (void) d40_log_sg_to_lli(sgl_dst, 1742 (void) d40_log_sg_to_lli(sgl_dst,
1660 sgl_len, 1743 sgl_len,
1661 d40d->lli_log.dst, 1744 d40d->lli_log.dst,
1662 d40c->log_def.lcsp3, 1745 d40c->log_def.lcsp3,
1663 d40c->dma_cfg.dst_info.data_width); 1746 d40c->dma_cfg.dst_info.data_width,
1747 d40c->dma_cfg.src_info.data_width);
1664 } else { 1748 } else {
1665 if (d40_pool_lli_alloc(d40d, sgl_len, false) < 0) { 1749 if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) {
1666 dev_err(&d40c->chan.dev->device, 1750 dev_err(&d40c->chan.dev->device,
1667 "[%s] Out of memory\n", __func__); 1751 "[%s] Out of memory\n", __func__);
1668 goto err; 1752 goto err;
@@ -1675,6 +1759,7 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
1675 virt_to_phys(d40d->lli_phy.src), 1759 virt_to_phys(d40d->lli_phy.src),
1676 d40c->src_def_cfg, 1760 d40c->src_def_cfg,
1677 d40c->dma_cfg.src_info.data_width, 1761 d40c->dma_cfg.src_info.data_width,
1762 d40c->dma_cfg.dst_info.data_width,
1678 d40c->dma_cfg.src_info.psize); 1763 d40c->dma_cfg.src_info.psize);
1679 1764
1680 if (res < 0) 1765 if (res < 0)
@@ -1687,6 +1772,7 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
1687 virt_to_phys(d40d->lli_phy.dst), 1772 virt_to_phys(d40d->lli_phy.dst),
1688 d40c->dst_def_cfg, 1773 d40c->dst_def_cfg,
1689 d40c->dma_cfg.dst_info.data_width, 1774 d40c->dma_cfg.dst_info.data_width,
1775 d40c->dma_cfg.src_info.data_width,
1690 d40c->dma_cfg.dst_info.psize); 1776 d40c->dma_cfg.dst_info.psize);
1691 1777
1692 if (res < 0) 1778 if (res < 0)
@@ -1826,7 +1912,6 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
1826 struct d40_chan *d40c = container_of(chan, struct d40_chan, 1912 struct d40_chan *d40c = container_of(chan, struct d40_chan,
1827 chan); 1913 chan);
1828 unsigned long flags; 1914 unsigned long flags;
1829 int err = 0;
1830 1915
1831 if (d40c->phy_chan == NULL) { 1916 if (d40c->phy_chan == NULL) {
1832 dev_err(&d40c->chan.dev->device, 1917 dev_err(&d40c->chan.dev->device,
@@ -1844,6 +1929,15 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
1844 } 1929 }
1845 1930
1846 d40d->txd.flags = dma_flags; 1931 d40d->txd.flags = dma_flags;
1932 d40d->lli_len = d40_size_2_dmalen(size,
1933 d40c->dma_cfg.src_info.data_width,
1934 d40c->dma_cfg.dst_info.data_width);
1935 if (d40d->lli_len < 0) {
1936 dev_err(&d40c->chan.dev->device,
1937 "[%s] Unaligned size\n", __func__);
1938 goto err;
1939 }
1940
1847 1941
1848 dma_async_tx_descriptor_init(&d40d->txd, chan); 1942 dma_async_tx_descriptor_init(&d40d->txd, chan);
1849 1943
@@ -1851,37 +1945,40 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
1851 1945
1852 if (d40c->log_num != D40_PHY_CHAN) { 1946 if (d40c->log_num != D40_PHY_CHAN) {
1853 1947
1854 if (d40_pool_lli_alloc(d40d, 1, true) < 0) { 1948 if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) {
1855 dev_err(&d40c->chan.dev->device, 1949 dev_err(&d40c->chan.dev->device,
1856 "[%s] Out of memory\n", __func__); 1950 "[%s] Out of memory\n", __func__);
1857 goto err; 1951 goto err;
1858 } 1952 }
1859 d40d->lli_len = 1;
1860 d40d->lli_current = 0; 1953 d40d->lli_current = 0;
1861 1954
1862 d40_log_fill_lli(d40d->lli_log.src, 1955 if (d40_log_buf_to_lli(d40d->lli_log.src,
1863 src, 1956 src,
1864 size, 1957 size,
1865 d40c->log_def.lcsp1, 1958 d40c->log_def.lcsp1,
1866 d40c->dma_cfg.src_info.data_width, 1959 d40c->dma_cfg.src_info.data_width,
1867 true); 1960 d40c->dma_cfg.dst_info.data_width,
1961 true) == NULL)
1962 goto err;
1868 1963
1869 d40_log_fill_lli(d40d->lli_log.dst, 1964 if (d40_log_buf_to_lli(d40d->lli_log.dst,
1870 dst, 1965 dst,
1871 size, 1966 size,
1872 d40c->log_def.lcsp3, 1967 d40c->log_def.lcsp3,
1873 d40c->dma_cfg.dst_info.data_width, 1968 d40c->dma_cfg.dst_info.data_width,
1874 true); 1969 d40c->dma_cfg.src_info.data_width,
1970 true) == NULL)
1971 goto err;
1875 1972
1876 } else { 1973 } else {
1877 1974
1878 if (d40_pool_lli_alloc(d40d, 1, false) < 0) { 1975 if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) {
1879 dev_err(&d40c->chan.dev->device, 1976 dev_err(&d40c->chan.dev->device,
1880 "[%s] Out of memory\n", __func__); 1977 "[%s] Out of memory\n", __func__);
1881 goto err; 1978 goto err;
1882 } 1979 }
1883 1980
1884 err = d40_phy_fill_lli(d40d->lli_phy.src, 1981 if (d40_phy_buf_to_lli(d40d->lli_phy.src,
1885 src, 1982 src,
1886 size, 1983 size,
1887 d40c->dma_cfg.src_info.psize, 1984 d40c->dma_cfg.src_info.psize,
@@ -1889,11 +1986,11 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
1889 d40c->src_def_cfg, 1986 d40c->src_def_cfg,
1890 true, 1987 true,
1891 d40c->dma_cfg.src_info.data_width, 1988 d40c->dma_cfg.src_info.data_width,
1892 false); 1989 d40c->dma_cfg.dst_info.data_width,
1893 if (err) 1990 false) == NULL)
1894 goto err_fill_lli; 1991 goto err;
1895 1992
1896 err = d40_phy_fill_lli(d40d->lli_phy.dst, 1993 if (d40_phy_buf_to_lli(d40d->lli_phy.dst,
1897 dst, 1994 dst,
1898 size, 1995 size,
1899 d40c->dma_cfg.dst_info.psize, 1996 d40c->dma_cfg.dst_info.psize,
@@ -1901,10 +1998,9 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
1901 d40c->dst_def_cfg, 1998 d40c->dst_def_cfg,
1902 true, 1999 true,
1903 d40c->dma_cfg.dst_info.data_width, 2000 d40c->dma_cfg.dst_info.data_width,
1904 false); 2001 d40c->dma_cfg.src_info.data_width,
1905 2002 false) == NULL)
1906 if (err) 2003 goto err;
1907 goto err_fill_lli;
1908 2004
1909 (void) dma_map_single(d40c->base->dev, d40d->lli_phy.src, 2005 (void) dma_map_single(d40c->base->dev, d40d->lli_phy.src,
1910 d40d->lli_pool.size, DMA_TO_DEVICE); 2006 d40d->lli_pool.size, DMA_TO_DEVICE);
@@ -1913,9 +2009,6 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
1913 spin_unlock_irqrestore(&d40c->lock, flags); 2009 spin_unlock_irqrestore(&d40c->lock, flags);
1914 return &d40d->txd; 2010 return &d40d->txd;
1915 2011
1916err_fill_lli:
1917 dev_err(&d40c->chan.dev->device,
1918 "[%s] Failed filling in PHY LLI\n", __func__);
1919err: 2012err:
1920 if (d40d) 2013 if (d40d)
1921 d40_desc_free(d40c, d40d); 2014 d40_desc_free(d40c, d40d);
@@ -1945,13 +2038,21 @@ static int d40_prep_slave_sg_log(struct d40_desc *d40d,
1945 dma_addr_t dev_addr = 0; 2038 dma_addr_t dev_addr = 0;
1946 int total_size; 2039 int total_size;
1947 2040
1948 if (d40_pool_lli_alloc(d40d, sg_len, true) < 0) { 2041 d40d->lli_len = d40_sg_2_dmalen(sgl, sg_len,
2042 d40c->dma_cfg.src_info.data_width,
2043 d40c->dma_cfg.dst_info.data_width);
2044 if (d40d->lli_len < 0) {
2045 dev_err(&d40c->chan.dev->device,
2046 "[%s] Unaligned size\n", __func__);
2047 return -EINVAL;
2048 }
2049
2050 if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) {
1949 dev_err(&d40c->chan.dev->device, 2051 dev_err(&d40c->chan.dev->device,
1950 "[%s] Out of memory\n", __func__); 2052 "[%s] Out of memory\n", __func__);
1951 return -ENOMEM; 2053 return -ENOMEM;
1952 } 2054 }
1953 2055
1954 d40d->lli_len = sg_len;
1955 d40d->lli_current = 0; 2056 d40d->lli_current = 0;
1956 2057
1957 if (direction == DMA_FROM_DEVICE) 2058 if (direction == DMA_FROM_DEVICE)
@@ -1993,13 +2094,21 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
1993 dma_addr_t dst_dev_addr; 2094 dma_addr_t dst_dev_addr;
1994 int res; 2095 int res;
1995 2096
1996 if (d40_pool_lli_alloc(d40d, sgl_len, false) < 0) { 2097 d40d->lli_len = d40_sg_2_dmalen(sgl, sgl_len,
2098 d40c->dma_cfg.src_info.data_width,
2099 d40c->dma_cfg.dst_info.data_width);
2100 if (d40d->lli_len < 0) {
2101 dev_err(&d40c->chan.dev->device,
2102 "[%s] Unaligned size\n", __func__);
2103 return -EINVAL;
2104 }
2105
2106 if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) {
1997 dev_err(&d40c->chan.dev->device, 2107 dev_err(&d40c->chan.dev->device,
1998 "[%s] Out of memory\n", __func__); 2108 "[%s] Out of memory\n", __func__);
1999 return -ENOMEM; 2109 return -ENOMEM;
2000 } 2110 }
2001 2111
2002 d40d->lli_len = sgl_len;
2003 d40d->lli_current = 0; 2112 d40d->lli_current = 0;
2004 2113
2005 if (direction == DMA_FROM_DEVICE) { 2114 if (direction == DMA_FROM_DEVICE) {
@@ -2024,6 +2133,7 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
2024 virt_to_phys(d40d->lli_phy.src), 2133 virt_to_phys(d40d->lli_phy.src),
2025 d40c->src_def_cfg, 2134 d40c->src_def_cfg,
2026 d40c->dma_cfg.src_info.data_width, 2135 d40c->dma_cfg.src_info.data_width,
2136 d40c->dma_cfg.dst_info.data_width,
2027 d40c->dma_cfg.src_info.psize); 2137 d40c->dma_cfg.src_info.psize);
2028 if (res < 0) 2138 if (res < 0)
2029 return res; 2139 return res;
@@ -2035,6 +2145,7 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
2035 virt_to_phys(d40d->lli_phy.dst), 2145 virt_to_phys(d40d->lli_phy.dst),
2036 d40c->dst_def_cfg, 2146 d40c->dst_def_cfg,
2037 d40c->dma_cfg.dst_info.data_width, 2147 d40c->dma_cfg.dst_info.data_width,
2148 d40c->dma_cfg.src_info.data_width,
2038 d40c->dma_cfg.dst_info.psize); 2149 d40c->dma_cfg.dst_info.psize);
2039 if (res < 0) 2150 if (res < 0)
2040 return res; 2151 return res;
@@ -2244,6 +2355,8 @@ static void d40_set_runtime_config(struct dma_chan *chan,
2244 psize = STEDMA40_PSIZE_PHY_8; 2355 psize = STEDMA40_PSIZE_PHY_8;
2245 else if (config_maxburst >= 4) 2356 else if (config_maxburst >= 4)
2246 psize = STEDMA40_PSIZE_PHY_4; 2357 psize = STEDMA40_PSIZE_PHY_4;
2358 else if (config_maxburst >= 2)
2359 psize = STEDMA40_PSIZE_PHY_2;
2247 else 2360 else
2248 psize = STEDMA40_PSIZE_PHY_1; 2361 psize = STEDMA40_PSIZE_PHY_1;
2249 } 2362 }