012-dmaengine-Add-transfer-termination-synchronization-s.patch 12 KB

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