aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/at_xdmac.c
diff options
context:
space:
mode:
authorMaxime Ripard <maxime.ripard@free-electrons.com>2015-09-15 09:29:27 -0400
committerVinod Koul <vinod.koul@intel.com>2015-09-30 22:00:33 -0400
commit4e5385784e69e448efca0998aa188404d5e8d313 (patch)
tree34c1f6bf05ca1f71ed0167c4a7109e06a32f9fe7 /drivers/dma/at_xdmac.c
parent1a492ac2b87b05c8a175478e79d3c74511c74921 (diff)
dmaengine: at_xdmac: handle numf > 1
Handle 'numf > 1' case for interleaved mode. Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma/at_xdmac.c')
-rw-r--r--drivers/dma/at_xdmac.c104
1 files changed, 50 insertions, 54 deletions
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index a165b4bfd330..0190d1ca3004 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -929,13 +929,19 @@ at_xdmac_prep_interleaved(struct dma_chan *chan,
929{ 929{
930 struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); 930 struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
931 struct at_xdmac_desc *prev = NULL, *first = NULL; 931 struct at_xdmac_desc *prev = NULL, *first = NULL;
932 struct data_chunk *chunk, *prev_chunk = NULL;
933 dma_addr_t dst_addr, src_addr; 932 dma_addr_t dst_addr, src_addr;
934 size_t dst_skip, src_skip, len = 0; 933 size_t src_skip = 0, dst_skip = 0, len = 0;
935 size_t prev_dst_icg = 0, prev_src_icg = 0; 934 struct data_chunk *chunk;
936 int i; 935 int i;
937 936
938 if (!xt || (xt->numf != 1) || (xt->dir != DMA_MEM_TO_MEM)) 937 if (!xt || !xt->numf || (xt->dir != DMA_MEM_TO_MEM))
938 return NULL;
939
940 /*
941 * TODO: Handle the case where we have to repeat a chain of
942 * descriptors...
943 */
944 if ((xt->numf > 1) && (xt->frame_size > 1))
939 return NULL; 945 return NULL;
940 946
941 dev_dbg(chan2dev(chan), "%s: src=0x%08x, dest=0x%08x, numf=%d, frame_size=%d, flags=0x%lx\n", 947 dev_dbg(chan2dev(chan), "%s: src=0x%08x, dest=0x%08x, numf=%d, frame_size=%d, flags=0x%lx\n",
@@ -945,66 +951,56 @@ at_xdmac_prep_interleaved(struct dma_chan *chan,
945 src_addr = xt->src_start; 951 src_addr = xt->src_start;
946 dst_addr = xt->dst_start; 952 dst_addr = xt->dst_start;
947 953
948 for (i = 0; i < xt->frame_size; i++) { 954 if (xt->numf > 1) {
949 struct at_xdmac_desc *desc; 955 first = at_xdmac_interleaved_queue_desc(chan, atchan,
950 size_t src_icg, dst_icg; 956 NULL,
951 957 src_addr, dst_addr,
952 chunk = xt->sgl + i; 958 xt, xt->sgl);
959 for (i = 0; i < xt->numf; i++)
960 at_xdmac_increment_block_count(chan, first);
961 } else {
962 for (i = 0; i < xt->frame_size; i++) {
963 size_t src_icg = 0, dst_icg = 0;
964 struct at_xdmac_desc *desc;
953 965
954 dst_icg = dmaengine_get_dst_icg(xt, chunk); 966 chunk = xt->sgl + i;
955 src_icg = dmaengine_get_src_icg(xt, chunk);
956 967
957 src_skip = chunk->size + src_icg; 968 dst_icg = dmaengine_get_dst_icg(xt, chunk);
958 dst_skip = chunk->size + dst_icg; 969 src_icg = dmaengine_get_src_icg(xt, chunk);
959 970
960 dev_dbg(chan2dev(chan), 971 src_skip = chunk->size + src_icg;
961 "%s: chunk size=%d, src icg=%d, dst icg=%d\n", 972 dst_skip = chunk->size + dst_icg;
962 __func__, chunk->size, src_icg, dst_icg);
963 973
964 /*
965 * Handle the case where we just have the same
966 * transfer to setup, we can just increase the
967 * block number and reuse the same descriptor.
968 */
969 if (prev_chunk && prev &&
970 (prev_chunk->size == chunk->size) &&
971 (prev_src_icg == src_icg) &&
972 (prev_dst_icg == dst_icg)) {
973 dev_dbg(chan2dev(chan), 974 dev_dbg(chan2dev(chan),
974 "%s: same configuration that the previous chunk, merging the descriptors...\n", 975 "%s: chunk size=%d, src icg=%d, dst icg=%d\n",
975 __func__); 976 __func__, chunk->size, src_icg, dst_icg);
976 at_xdmac_increment_block_count(chan, prev); 977
977 continue; 978 desc = at_xdmac_interleaved_queue_desc(chan, atchan,
978 } 979 prev,
979 980 src_addr, dst_addr,
980 desc = at_xdmac_interleaved_queue_desc(chan, atchan, 981 xt, chunk);
981 prev, 982 if (!desc) {
982 src_addr, dst_addr, 983 list_splice_init(&first->descs_list,
983 xt, chunk); 984 &atchan->free_descs_list);
984 if (!desc) { 985 return NULL;
985 list_splice_init(&first->descs_list, 986 }
986 &atchan->free_descs_list);
987 return NULL;
988 }
989 987
990 if (!first) 988 if (!first)
991 first = desc; 989 first = desc;
992 990
993 dev_dbg(chan2dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n", 991 dev_dbg(chan2dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n",
994 __func__, desc, first); 992 __func__, desc, first);
995 list_add_tail(&desc->desc_node, &first->descs_list); 993 list_add_tail(&desc->desc_node, &first->descs_list);
996 994
997 if (xt->src_sgl) 995 if (xt->src_sgl)
998 src_addr += src_skip; 996 src_addr += src_skip;
999 997
1000 if (xt->dst_sgl) 998 if (xt->dst_sgl)
1001 dst_addr += dst_skip; 999 dst_addr += dst_skip;
1002 1000
1003 len += chunk->size; 1001 len += chunk->size;
1004 prev_chunk = chunk; 1002 prev = desc;
1005 prev_dst_icg = dst_icg; 1003 }
1006 prev_src_icg = src_icg;
1007 prev = desc;
1008 } 1004 }
1009 1005
1010 first->tx_dma_desc.cookie = -EBUSY; 1006 first->tx_dma_desc.cookie = -EBUSY;