mvebu: remove linux 4.4 support
[openwrt/staging/lynxis/omap.git] / target / linux / apm821xx / patches-4.4 / 012-dmaengine-Add-transfer-termination-synchronization-s.patch
1 From b36f09c3c441a6e59eab9315032e7d546571de3f Mon Sep 17 00:00:00 2001
2 From: Lars-Peter Clausen <lars@metafoo.de>
3 Date: Tue, 20 Oct 2015 11:46:28 +0200
4 Subject: [PATCH] dmaengine: Add transfer termination synchronization support
5
6 The DMAengine API has a long standing race condition that is inherent to
7 the API itself. Calling dmaengine_terminate_all() is supposed to stop and
8 abort any pending or active transfers that have previously been submitted.
9 Unfortunately it is possible that this operation races against a currently
10 running (or with some drivers also scheduled) completion callback.
11
12 Since the API allows dmaengine_terminate_all() to be called from atomic
13 context as well as from within a completion callback it is not possible to
14 synchronize to the execution of the completion callback from within
15 dmaengine_terminate_all() itself.
16
17 This means that a user of the DMAengine API does not know when it is safe
18 to free resources used in the completion callback, which can result in a
19 use-after-free race condition.
20
21 This patch addresses the issue by introducing an explicit synchronization
22 primitive to the DMAengine API called dmaengine_synchronize().
23
24 The existing dmaengine_terminate_all() is deprecated in favor of
25 dmaengine_terminate_sync() and dmaengine_terminate_async(). The former
26 aborts all pending and active transfers and synchronizes to the current
27 context, meaning it will wait until all running completion callbacks have
28 finished. This means it is only possible to call this function from
29 non-atomic context. The later function does not synchronize, but can still
30 be used in atomic context or from within a complete callback. It has to be
31 followed up by dmaengine_synchronize() before a client can free the
32 resources used in a completion callback.
33
34 In addition to this the semantics of the device_terminate_all() callback
35 are slightly relaxed by this patch. It is now OK for a driver to only
36 schedule the termination of the active transfer, but does not necessarily
37 have to wait until the DMA controller has completely stopped. The driver
38 must ensure though that the controller has stopped and no longer accesses
39 any memory when the device_synchronize() callback returns.
40
41 This was in part done since most drivers do not pay attention to this
42 anyway at the moment and to emphasize that this needs to be done when the
43 device_synchronize() callback is implemented. But it also helps with
44 implementing support for devices where stopping the controller can require
45 operations that may sleep.
46
47 Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
48 Signed-off-by: Vinod Koul <vinod.koul@intel.com>
49 ---
50 Documentation/dmaengine/client.txt | 38 ++++++++++++++-
51 Documentation/dmaengine/provider.txt | 20 +++++++-
52 drivers/dma/dmaengine.c | 5 +-
53 include/linux/dmaengine.h | 90 ++++++++++++++++++++++++++++++++++++
54 4 files changed, 148 insertions(+), 5 deletions(-)
55
56 --- a/Documentation/dmaengine/client.txt
57 +++ b/Documentation/dmaengine/client.txt
58 @@ -117,7 +117,7 @@ The slave DMA usage consists of followin
59 transaction.
60
61 For cyclic DMA, a callback function may wish to terminate the
62 - DMA via dmaengine_terminate_all().
63 + DMA via dmaengine_terminate_async().
64
65 Therefore, it is important that DMA engine drivers drop any
66 locks before calling the callback function which may cause a
67 @@ -155,12 +155,29 @@ The slave DMA usage consists of followin
68
69 Further APIs:
70
71 -1. int dmaengine_terminate_all(struct dma_chan *chan)
72 +1. int dmaengine_terminate_sync(struct dma_chan *chan)
73 + int dmaengine_terminate_async(struct dma_chan *chan)
74 + int dmaengine_terminate_all(struct dma_chan *chan) /* DEPRECATED */
75
76 This causes all activity for the DMA channel to be stopped, and may
77 discard data in the DMA FIFO which hasn't been fully transferred.
78 No callback functions will be called for any incomplete transfers.
79
80 + Two variants of this function are available.
81 +
82 + dmaengine_terminate_async() might not wait until the DMA has been fully
83 + stopped or until any running complete callbacks have finished. But it is
84 + possible to call dmaengine_terminate_async() from atomic context or from
85 + within a complete callback. dmaengine_synchronize() must be called before it
86 + is safe to free the memory accessed by the DMA transfer or free resources
87 + accessed from within the complete callback.
88 +
89 + dmaengine_terminate_sync() will wait for the transfer and any running
90 + complete callbacks to finish before it returns. But the function must not be
91 + called from atomic context or from within a complete callback.
92 +
93 + dmaengine_terminate_all() is deprecated and should not be used in new code.
94 +
95 2. int dmaengine_pause(struct dma_chan *chan)
96
97 This pauses activity on the DMA channel without data loss.
98 @@ -186,3 +203,20 @@ Further APIs:
99 a running DMA channel. It is recommended that DMA engine users
100 pause or stop (via dmaengine_terminate_all()) the channel before
101 using this API.
102 +
103 +5. void dmaengine_synchronize(struct dma_chan *chan)
104 +
105 + Synchronize the termination of the DMA channel to the current context.
106 +
107 + This function should be used after dmaengine_terminate_async() to synchronize
108 + the termination of the DMA channel to the current context. The function will
109 + wait for the transfer and any running complete callbacks to finish before it
110 + returns.
111 +
112 + If dmaengine_terminate_async() is used to stop the DMA channel this function
113 + must be called before it is safe to free memory accessed by previously
114 + submitted descriptors or to free any resources accessed within the complete
115 + callback of previously submitted descriptors.
116 +
117 + The behavior of this function is undefined if dma_async_issue_pending() has
118 + been called between dmaengine_terminate_async() and this function.
119 --- a/Documentation/dmaengine/provider.txt
120 +++ b/Documentation/dmaengine/provider.txt
121 @@ -327,8 +327,24 @@ supported.
122
123 * device_terminate_all
124 - Aborts all the pending and ongoing transfers on the channel
125 - - This command should operate synchronously on the channel,
126 - terminating right away all the channels
127 + - For aborted transfers the complete callback should not be called
128 + - Can be called from atomic context or from within a complete
129 + callback of a descriptor. Must not sleep. Drivers must be able
130 + to handle this correctly.
131 + - Termination may be asynchronous. The driver does not have to
132 + wait until the currently active transfer has completely stopped.
133 + See device_synchronize.
134 +
135 + * device_synchronize
136 + - Must synchronize the termination of a channel to the current
137 + context.
138 + - Must make sure that memory for previously submitted
139 + descriptors is no longer accessed by the DMA controller.
140 + - Must make sure that all complete callbacks for previously
141 + submitted descriptors have finished running and none are
142 + scheduled to run.
143 + - May sleep.
144 +
145
146 Misc notes (stuff that should be documented, but don't really know
147 where to put them)
148 --- a/drivers/dma/dmaengine.c
149 +++ b/drivers/dma/dmaengine.c
150 @@ -266,8 +266,11 @@ static void dma_chan_put(struct dma_chan
151 module_put(dma_chan_to_owner(chan));
152
153 /* This channel is not in use anymore, free it */
154 - if (!chan->client_count && chan->device->device_free_chan_resources)
155 + if (!chan->client_count && chan->device->device_free_chan_resources) {
156 + /* Make sure all operations have completed */
157 + dmaengine_synchronize(chan);
158 chan->device->device_free_chan_resources(chan);
159 + }
160
161 /* If the channel is used via a DMA request router, free the mapping */
162 if (chan->router && chan->router->route_free) {
163 --- a/include/linux/dmaengine.h
164 +++ b/include/linux/dmaengine.h
165 @@ -681,6 +681,8 @@ struct dma_filter {
166 * paused. Returns 0 or an error code
167 * @device_terminate_all: Aborts all transfers on a channel. Returns 0
168 * or an error code
169 + * @device_synchronize: Synchronizes the termination of a transfers to the
170 + * current context.
171 * @device_tx_status: poll for transaction completion, the optional
172 * txstate parameter can be supplied with a pointer to get a
173 * struct with auxiliary transfer status information, otherwise the call
174 @@ -765,6 +767,7 @@ struct dma_device {
175 int (*device_pause)(struct dma_chan *chan);
176 int (*device_resume)(struct dma_chan *chan);
177 int (*device_terminate_all)(struct dma_chan *chan);
178 + void (*device_synchronize)(struct dma_chan *chan);
179
180 enum dma_status (*device_tx_status)(struct dma_chan *chan,
181 dma_cookie_t cookie,
182 @@ -856,6 +859,13 @@ static inline struct dma_async_tx_descri
183 src_sg, src_nents, flags);
184 }
185
186 +/**
187 + * dmaengine_terminate_all() - Terminate all active DMA transfers
188 + * @chan: The channel for which to terminate the transfers
189 + *
190 + * This function is DEPRECATED use either dmaengine_terminate_sync() or
191 + * dmaengine_terminate_async() instead.
192 + */
193 static inline int dmaengine_terminate_all(struct dma_chan *chan)
194 {
195 if (chan->device->device_terminate_all)
196 @@ -864,6 +874,86 @@ static inline int dmaengine_terminate_al
197 return -ENOSYS;
198 }
199
200 +/**
201 + * dmaengine_terminate_async() - Terminate all active DMA transfers
202 + * @chan: The channel for which to terminate the transfers
203 + *
204 + * Calling this function will terminate all active and pending descriptors
205 + * that have previously been submitted to the channel. It is not guaranteed
206 + * though that the transfer for the active descriptor has stopped when the
207 + * function returns. Furthermore it is possible the complete callback of a
208 + * submitted transfer is still running when this function returns.
209 + *
210 + * dmaengine_synchronize() needs to be called before it is safe to free
211 + * any memory that is accessed by previously submitted descriptors or before
212 + * freeing any resources accessed from within the completion callback of any
213 + * perviously submitted descriptors.
214 + *
215 + * This function can be called from atomic context as well as from within a
216 + * complete callback of a descriptor submitted on the same channel.
217 + *
218 + * If none of the two conditions above apply consider using
219 + * dmaengine_terminate_sync() instead.
220 + */
221 +static inline int dmaengine_terminate_async(struct dma_chan *chan)
222 +{
223 + if (chan->device->device_terminate_all)
224 + return chan->device->device_terminate_all(chan);
225 +
226 + return -EINVAL;
227 +}
228 +
229 +/**
230 + * dmaengine_synchronize() - Synchronize DMA channel termination
231 + * @chan: The channel to synchronize
232 + *
233 + * Synchronizes to the DMA channel termination to the current context. When this
234 + * function returns it is guaranteed that all transfers for previously issued
235 + * descriptors have stopped and and it is safe to free the memory assoicated
236 + * with them. Furthermore it is guaranteed that all complete callback functions
237 + * for a previously submitted descriptor have finished running and it is safe to
238 + * free resources accessed from within the complete callbacks.
239 + *
240 + * The behavior of this function is undefined if dma_async_issue_pending() has
241 + * been called between dmaengine_terminate_async() and this function.
242 + *
243 + * This function must only be called from non-atomic context and must not be
244 + * called from within a complete callback of a descriptor submitted on the same
245 + * channel.
246 + */
247 +static inline void dmaengine_synchronize(struct dma_chan *chan)
248 +{
249 + if (chan->device->device_synchronize)
250 + chan->device->device_synchronize(chan);
251 +}
252 +
253 +/**
254 + * dmaengine_terminate_sync() - Terminate all active DMA transfers
255 + * @chan: The channel for which to terminate the transfers
256 + *
257 + * Calling this function will terminate all active and pending transfers
258 + * that have previously been submitted to the channel. It is similar to
259 + * dmaengine_terminate_async() but guarantees that the DMA transfer has actually
260 + * stopped and that all complete callbacks have finished running when the
261 + * function returns.
262 + *
263 + * This function must only be called from non-atomic context and must not be
264 + * called from within a complete callback of a descriptor submitted on the same
265 + * channel.
266 + */
267 +static inline int dmaengine_terminate_sync(struct dma_chan *chan)
268 +{
269 + int ret;
270 +
271 + ret = dmaengine_terminate_async(chan);
272 + if (ret)
273 + return ret;
274 +
275 + dmaengine_synchronize(chan);
276 +
277 + return 0;
278 +}
279 +
280 static inline int dmaengine_pause(struct dma_chan *chan)
281 {
282 if (chan->device->device_pause)