diff options
| -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 | ||
