diff options
author | Maxime Ripard <maxime.ripard@free-electrons.com> | 2015-09-15 09:29:27 -0400 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2015-09-30 22:00:33 -0400 |
commit | 4e5385784e69e448efca0998aa188404d5e8d313 (patch) | |
tree | 34c1f6bf05ca1f71ed0167c4a7109e06a32f9fe7 /drivers/dma/at_xdmac.c | |
parent | 1a492ac2b87b05c8a175478e79d3c74511c74921 (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.c | 104 |
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; |