diff options
Diffstat (limited to 'drivers/dma/fsldma.c')
-rw-r--r-- | drivers/dma/fsldma.c | 108 |
1 files changed, 46 insertions, 62 deletions
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 526579df6033..d300de456c90 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c | |||
@@ -882,65 +882,15 @@ static void fsldma_cleanup_descriptor(struct fsldma_chan *chan, | |||
882 | } | 882 | } |
883 | 883 | ||
884 | /** | 884 | /** |
885 | * fsl_chan_ld_cleanup - Clean up link descriptors | ||
886 | * @chan : Freescale DMA channel | ||
887 | * | ||
888 | * This function is run after the queue of running descriptors has been | ||
889 | * executed by the DMA engine. It will run any callbacks, and then free | ||
890 | * the descriptors. | ||
891 | * | ||
892 | * HARDWARE STATE: idle | ||
893 | */ | ||
894 | static void fsl_chan_ld_cleanup(struct fsldma_chan *chan) | ||
895 | { | ||
896 | struct fsl_desc_sw *desc, *_desc; | ||
897 | LIST_HEAD(ld_cleanup); | ||
898 | unsigned long flags; | ||
899 | |||
900 | spin_lock_irqsave(&chan->desc_lock, flags); | ||
901 | |||
902 | /* update the cookie if we have some descriptors to cleanup */ | ||
903 | if (!list_empty(&chan->ld_running)) { | ||
904 | dma_cookie_t cookie; | ||
905 | |||
906 | desc = to_fsl_desc(chan->ld_running.prev); | ||
907 | cookie = desc->async_tx.cookie; | ||
908 | |||
909 | chan->completed_cookie = cookie; | ||
910 | chan_dbg(chan, "completed cookie=%d\n", cookie); | ||
911 | } | ||
912 | |||
913 | /* | ||
914 | * move the descriptors to a temporary list so we can drop the lock | ||
915 | * during the entire cleanup operation | ||
916 | */ | ||
917 | list_splice_tail_init(&chan->ld_running, &ld_cleanup); | ||
918 | |||
919 | spin_unlock_irqrestore(&chan->desc_lock, flags); | ||
920 | |||
921 | /* Run the callback for each descriptor, in order */ | ||
922 | list_for_each_entry_safe(desc, _desc, &ld_cleanup, node) { | ||
923 | |||
924 | /* Remove from the list of transactions */ | ||
925 | list_del(&desc->node); | ||
926 | |||
927 | /* Run all cleanup for this descriptor */ | ||
928 | fsldma_cleanup_descriptor(chan, desc); | ||
929 | } | ||
930 | } | ||
931 | |||
932 | /** | ||
933 | * fsl_chan_xfer_ld_queue - transfer any pending transactions | 885 | * fsl_chan_xfer_ld_queue - transfer any pending transactions |
934 | * @chan : Freescale DMA channel | 886 | * @chan : Freescale DMA channel |
935 | * | 887 | * |
936 | * HARDWARE STATE: idle | 888 | * HARDWARE STATE: idle |
889 | * LOCKING: must hold chan->desc_lock | ||
937 | */ | 890 | */ |
938 | static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) | 891 | static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) |
939 | { | 892 | { |
940 | struct fsl_desc_sw *desc; | 893 | struct fsl_desc_sw *desc; |
941 | unsigned long flags; | ||
942 | |||
943 | spin_lock_irqsave(&chan->desc_lock, flags); | ||
944 | 894 | ||
945 | /* | 895 | /* |
946 | * If the list of pending descriptors is empty, then we | 896 | * If the list of pending descriptors is empty, then we |
@@ -948,7 +898,7 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) | |||
948 | */ | 898 | */ |
949 | if (list_empty(&chan->ld_pending)) { | 899 | if (list_empty(&chan->ld_pending)) { |
950 | chan_dbg(chan, "no pending LDs\n"); | 900 | chan_dbg(chan, "no pending LDs\n"); |
951 | goto out_unlock; | 901 | return; |
952 | } | 902 | } |
953 | 903 | ||
954 | /* | 904 | /* |
@@ -958,7 +908,7 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) | |||
958 | */ | 908 | */ |
959 | if (!chan->idle) { | 909 | if (!chan->idle) { |
960 | chan_dbg(chan, "DMA controller still busy\n"); | 910 | chan_dbg(chan, "DMA controller still busy\n"); |
961 | goto out_unlock; | 911 | return; |
962 | } | 912 | } |
963 | 913 | ||
964 | /* | 914 | /* |
@@ -996,9 +946,6 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) | |||
996 | 946 | ||
997 | dma_start(chan); | 947 | dma_start(chan); |
998 | chan->idle = false; | 948 | chan->idle = false; |
999 | |||
1000 | out_unlock: | ||
1001 | spin_unlock_irqrestore(&chan->desc_lock, flags); | ||
1002 | } | 949 | } |
1003 | 950 | ||
1004 | /** | 951 | /** |
@@ -1008,7 +955,11 @@ out_unlock: | |||
1008 | static void fsl_dma_memcpy_issue_pending(struct dma_chan *dchan) | 955 | static void fsl_dma_memcpy_issue_pending(struct dma_chan *dchan) |
1009 | { | 956 | { |
1010 | struct fsldma_chan *chan = to_fsl_chan(dchan); | 957 | struct fsldma_chan *chan = to_fsl_chan(dchan); |
958 | unsigned long flags; | ||
959 | |||
960 | spin_lock_irqsave(&chan->desc_lock, flags); | ||
1011 | fsl_chan_xfer_ld_queue(chan); | 961 | fsl_chan_xfer_ld_queue(chan); |
962 | spin_unlock_irqrestore(&chan->desc_lock, flags); | ||
1012 | } | 963 | } |
1013 | 964 | ||
1014 | /** | 965 | /** |
@@ -1109,20 +1060,53 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data) | |||
1109 | static void dma_do_tasklet(unsigned long data) | 1060 | static void dma_do_tasklet(unsigned long data) |
1110 | { | 1061 | { |
1111 | struct fsldma_chan *chan = (struct fsldma_chan *)data; | 1062 | struct fsldma_chan *chan = (struct fsldma_chan *)data; |
1063 | struct fsl_desc_sw *desc, *_desc; | ||
1064 | LIST_HEAD(ld_cleanup); | ||
1112 | unsigned long flags; | 1065 | unsigned long flags; |
1113 | 1066 | ||
1114 | chan_dbg(chan, "tasklet entry\n"); | 1067 | chan_dbg(chan, "tasklet entry\n"); |
1115 | 1068 | ||
1116 | /* run all callbacks, free all used descriptors */ | ||
1117 | fsl_chan_ld_cleanup(chan); | ||
1118 | |||
1119 | /* the channel is now idle */ | ||
1120 | spin_lock_irqsave(&chan->desc_lock, flags); | 1069 | spin_lock_irqsave(&chan->desc_lock, flags); |
1070 | |||
1071 | /* update the cookie if we have some descriptors to cleanup */ | ||
1072 | if (!list_empty(&chan->ld_running)) { | ||
1073 | dma_cookie_t cookie; | ||
1074 | |||
1075 | desc = to_fsl_desc(chan->ld_running.prev); | ||
1076 | cookie = desc->async_tx.cookie; | ||
1077 | |||
1078 | chan->completed_cookie = cookie; | ||
1079 | chan_dbg(chan, "completed_cookie=%d\n", cookie); | ||
1080 | } | ||
1081 | |||
1082 | /* | ||
1083 | * move the descriptors to a temporary list so we can drop the lock | ||
1084 | * during the entire cleanup operation | ||
1085 | */ | ||
1086 | list_splice_tail_init(&chan->ld_running, &ld_cleanup); | ||
1087 | |||
1088 | /* the hardware is now idle and ready for more */ | ||
1121 | chan->idle = true; | 1089 | chan->idle = true; |
1122 | spin_unlock_irqrestore(&chan->desc_lock, flags); | ||
1123 | 1090 | ||
1124 | /* start any pending transactions automatically */ | 1091 | /* |
1092 | * Start any pending transactions automatically | ||
1093 | * | ||
1094 | * In the ideal case, we keep the DMA controller busy while we go | ||
1095 | * ahead and free the descriptors below. | ||
1096 | */ | ||
1125 | fsl_chan_xfer_ld_queue(chan); | 1097 | fsl_chan_xfer_ld_queue(chan); |
1098 | spin_unlock_irqrestore(&chan->desc_lock, flags); | ||
1099 | |||
1100 | /* Run the callback for each descriptor, in order */ | ||
1101 | list_for_each_entry_safe(desc, _desc, &ld_cleanup, node) { | ||
1102 | |||
1103 | /* Remove from the list of transactions */ | ||
1104 | list_del(&desc->node); | ||
1105 | |||
1106 | /* Run all cleanup for this descriptor */ | ||
1107 | fsldma_cleanup_descriptor(chan, desc); | ||
1108 | } | ||
1109 | |||
1126 | chan_dbg(chan, "tasklet exit\n"); | 1110 | chan_dbg(chan, "tasklet exit\n"); |
1127 | } | 1111 | } |
1128 | 1112 | ||