mali_kbase_dma_fence.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. /*
  2. *
  3. * (C) COPYRIGHT 2011-2016 ARM Limited. All rights reserved.
  4. *
  5. * This program is free software and is provided to you under the terms of the
  6. * GNU General Public License version 2 as published by the Free Software
  7. * Foundation, and any use by you of this program is subject to the terms
  8. * of such GNU licence.
  9. *
  10. * A copy of the licence is included with the program, and can also be obtained
  11. * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  12. * Boston, MA 02110-1301, USA.
  13. *
  14. */
  15. /* Include mali_kbase_dma_fence.h before checking for CONFIG_MALI_DMA_FENCE as
  16. * it will be set there.
  17. */
  18. #include "mali_kbase_dma_fence.h"
  19. #include <linux/atomic.h>
  20. #include <linux/dma-fence.h>
  21. #include <linux/list.h>
  22. #include <linux/lockdep.h>
  23. #include <linux/mutex.h>
  24. #include <linux/reservation.h>
  25. #include <linux/slab.h>
  26. #include <linux/spinlock.h>
  27. #include <linux/workqueue.h>
  28. #include <linux/ww_mutex.h>
  29. #include <mali_kbase.h>
  30. /* Spin lock protecting all Mali fences as fence->lock. */
  31. static DEFINE_SPINLOCK(kbase_dma_fence_lock);
  32. static void
  33. kbase_dma_fence_waiters_add(struct kbase_jd_atom *katom)
  34. {
  35. struct kbase_context *kctx = katom->kctx;
  36. list_add_tail(&katom->queue, &kctx->dma_fence.waiting_resource);
  37. }
  38. void
  39. kbase_dma_fence_waiters_remove(struct kbase_jd_atom *katom)
  40. {
  41. list_del(&katom->queue);
  42. }
  43. static const char *
  44. kbase_dma_fence_get_driver_name(struct dma_fence *fence)
  45. {
  46. return "mali";
  47. }
  48. static const char *
  49. kbase_dma_fence_get_timeline_name(struct dma_fence *fence)
  50. {
  51. return "mali.timeline";
  52. }
  53. static bool
  54. kbase_dma_fence_enable_signaling(struct dma_fence *fence)
  55. {
  56. /* If in the future we need to add code here remember to
  57. * to get a reference to the fence and release it when signaling
  58. * as stated in fence.h
  59. */
  60. return true;
  61. }
  62. static void
  63. kbase_dma_fence_fence_value_str(struct dma_fence *fence, char *str, int size)
  64. {
  65. snprintf(str, size, "%u", fence->seqno);
  66. }
  67. static const struct dma_fence_ops kbase_dma_fence_ops = {
  68. .get_driver_name = kbase_dma_fence_get_driver_name,
  69. .get_timeline_name = kbase_dma_fence_get_timeline_name,
  70. .enable_signaling = kbase_dma_fence_enable_signaling,
  71. /* Use the default wait */
  72. .wait = dma_fence_default_wait,
  73. .fence_value_str = kbase_dma_fence_fence_value_str,
  74. };
  75. static struct dma_fence *
  76. kbase_dma_fence_new(unsigned int context, unsigned int seqno)
  77. {
  78. struct dma_fence *fence;
  79. fence = kzalloc(sizeof(*fence), GFP_KERNEL);
  80. if (!fence)
  81. return NULL;
  82. dma_fence_init(fence,
  83. &kbase_dma_fence_ops,
  84. &kbase_dma_fence_lock,
  85. context,
  86. seqno);
  87. return fence;
  88. }
  89. static int
  90. kbase_dma_fence_lock_reservations(struct kbase_dma_fence_resv_info *info,
  91. struct ww_acquire_ctx *ctx)
  92. {
  93. struct reservation_object *content_res = NULL;
  94. unsigned int content_res_idx = 0;
  95. unsigned int r;
  96. int err;
  97. ww_acquire_init(ctx, &reservation_ww_class);
  98. retry:
  99. for (r = 0; r < info->dma_fence_resv_count; r++) {
  100. if (info->resv_objs[r] == content_res) {
  101. content_res = NULL;
  102. continue;
  103. }
  104. err = ww_mutex_lock(&info->resv_objs[r]->lock, ctx);
  105. if (err)
  106. goto error;
  107. }
  108. ww_acquire_done(ctx);
  109. return err;
  110. error:
  111. content_res_idx = r;
  112. /* Unlock the locked one ones */
  113. for (r--; r >= 0; r--)
  114. ww_mutex_unlock(&info->resv_objs[r]->lock);
  115. if (content_res)
  116. ww_mutex_unlock(&content_res->lock);
  117. /* If we deadlock try with lock_slow and retry */
  118. if (err == -EDEADLK) {
  119. content_res = info->resv_objs[content_res_idx];
  120. ww_mutex_lock_slow(&content_res->lock, ctx);
  121. goto retry;
  122. }
  123. /* If we are here the function failed */
  124. ww_acquire_fini(ctx);
  125. return err;
  126. }
  127. static void
  128. kbase_dma_fence_unlock_reservations(struct kbase_dma_fence_resv_info *info,
  129. struct ww_acquire_ctx *ctx)
  130. {
  131. unsigned int r;
  132. for (r = 0; r < info->dma_fence_resv_count; r++)
  133. ww_mutex_unlock(&info->resv_objs[r]->lock);
  134. ww_acquire_fini(ctx);
  135. }
  136. /**
  137. * kbase_dma_fence_free_callbacks - Free dma-fence callbacks on a katom
  138. * @katom: Pointer to katom
  139. *
  140. * This function will free all fence callbacks on the katom's list of
  141. * callbacks. Callbacks that have not yet been called, because their fence
  142. * hasn't yet signaled, will first be removed from the fence.
  143. *
  144. * Locking: katom->dma_fence.callbacks list assumes jctx.lock is held.
  145. */
  146. static void
  147. kbase_dma_fence_free_callbacks(struct kbase_jd_atom *katom)
  148. {
  149. struct kbase_dma_fence_cb *cb, *tmp;
  150. lockdep_assert_held(&katom->kctx->jctx.lock);
  151. /* Clean up and free callbacks. */
  152. list_for_each_entry_safe(cb, tmp, &katom->dma_fence.callbacks, node) {
  153. bool ret;
  154. /* Cancel callbacks that hasn't been called yet. */
  155. ret = dma_fence_remove_callback(cb->fence, &cb->fence_cb);
  156. if (ret) {
  157. /* Fence had not signaled, clean up after
  158. * canceling.
  159. */
  160. atomic_dec(&katom->dma_fence.dep_count);
  161. }
  162. dma_fence_put(cb->fence);
  163. list_del(&cb->node);
  164. kfree(cb);
  165. }
  166. }
  167. /**
  168. * kbase_dma_fence_cancel_atom() - Cancels waiting on an atom
  169. * @katom: Katom to cancel
  170. *
  171. * Locking: katom->dma_fence.callbacks list assumes jctx.lock is held.
  172. */
  173. static void
  174. kbase_dma_fence_cancel_atom(struct kbase_jd_atom *katom)
  175. {
  176. lockdep_assert_held(&katom->kctx->jctx.lock);
  177. /* Cancel callbacks and clean up. */
  178. kbase_dma_fence_free_callbacks(katom);
  179. KBASE_DEBUG_ASSERT(atomic_read(&katom->dma_fence.dep_count) == 0);
  180. /* Mark the atom as handled in case all fences signaled just before
  181. * canceling the callbacks and the worker was queued.
  182. */
  183. atomic_set(&katom->dma_fence.dep_count, -1);
  184. /* Prevent job_done_nolock from being called twice on an atom when
  185. * there is a race between job completion and cancellation.
  186. */
  187. if (katom->status == KBASE_JD_ATOM_STATE_QUEUED) {
  188. /* Wait was cancelled - zap the atom */
  189. katom->event_code = BASE_JD_EVENT_JOB_CANCELLED;
  190. if (jd_done_nolock(katom, NULL))
  191. kbase_js_sched_all(katom->kctx->kbdev);
  192. }
  193. }
  194. /**
  195. * kbase_dma_fence_work() - Worker thread called when a fence is signaled
  196. * @pwork: work_struct containing a pointer to a katom
  197. *
  198. * This function will clean and mark all dependencies as satisfied
  199. */
  200. static void
  201. kbase_dma_fence_work(struct work_struct *pwork)
  202. {
  203. struct kbase_jd_atom *katom;
  204. struct kbase_jd_context *ctx;
  205. katom = container_of(pwork, struct kbase_jd_atom, work);
  206. ctx = &katom->kctx->jctx;
  207. mutex_lock(&ctx->lock);
  208. if (atomic_read(&katom->dma_fence.dep_count) != 0)
  209. goto out;
  210. atomic_set(&katom->dma_fence.dep_count, -1);
  211. /* Remove atom from list of dma-fence waiting atoms. */
  212. kbase_dma_fence_waiters_remove(katom);
  213. /* Cleanup callbacks. */
  214. kbase_dma_fence_free_callbacks(katom);
  215. /* Queue atom on GPU. */
  216. kbase_jd_dep_clear_locked(katom);
  217. out:
  218. mutex_unlock(&ctx->lock);
  219. }
  220. static int
  221. kbase_dma_fence_add_callback(struct kbase_jd_atom *katom,
  222. struct dma_fence *fence,
  223. dma_fence_func_t callback)
  224. {
  225. int err = 0;
  226. struct kbase_dma_fence_cb *kbase_fence_cb;
  227. kbase_fence_cb = kmalloc(sizeof(*kbase_fence_cb), GFP_KERNEL);
  228. if (!kbase_fence_cb)
  229. return -ENOMEM;
  230. dma_fence_get(fence);
  231. kbase_fence_cb->fence = fence;
  232. kbase_fence_cb->katom = katom;
  233. INIT_LIST_HEAD(&kbase_fence_cb->node);
  234. err = dma_fence_add_callback(fence, &kbase_fence_cb->fence_cb, callback);
  235. if (err == -ENOENT) {
  236. /* Fence signaled, clear the error and return */
  237. err = 0;
  238. kbase_fence_cb->fence = NULL;
  239. dma_fence_put(fence);
  240. kfree(kbase_fence_cb);
  241. } else if (err) {
  242. /* Do nothing, just return the error */
  243. dma_fence_put(fence);
  244. kfree(kbase_fence_cb);
  245. } else {
  246. atomic_inc(&katom->dma_fence.dep_count);
  247. /* Add callback to katom's list of callbacks */
  248. list_add(&katom->dma_fence.callbacks, &kbase_fence_cb->node);
  249. }
  250. return err;
  251. }
  252. static void
  253. kbase_dma_fence_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
  254. {
  255. struct kbase_dma_fence_cb *kcb = container_of(cb,
  256. struct kbase_dma_fence_cb,
  257. fence_cb);
  258. struct kbase_jd_atom *katom = kcb->katom;
  259. struct kbase_context *kctx = katom->kctx;
  260. /* If the atom is zapped dep_count will be forced to a negative number
  261. * preventing this callback from ever scheduling work. Which in turn
  262. * would reschedule the atom.
  263. */
  264. if (atomic_dec_and_test(&katom->dma_fence.dep_count)) {
  265. bool ret;
  266. INIT_WORK(&katom->work, kbase_dma_fence_work);
  267. ret = queue_work(kctx->dma_fence.wq, &katom->work);
  268. /* Warn if work was already queued, that should not happen. */
  269. WARN_ON(!ret);
  270. }
  271. }
  272. static int
  273. kbase_dma_fence_add_reservation_callback(struct kbase_jd_atom *katom,
  274. struct reservation_object *resv,
  275. bool exclusive)
  276. {
  277. struct dma_fence *excl_fence = NULL;
  278. struct dma_fence **shared_fences = NULL;
  279. unsigned int shared_count = 0;
  280. int err, i;
  281. err = reservation_object_get_fences_rcu(resv,
  282. &excl_fence,
  283. &shared_count,
  284. &shared_fences);
  285. if (err)
  286. return err;
  287. if (excl_fence) {
  288. err = kbase_dma_fence_add_callback(katom,
  289. excl_fence,
  290. kbase_dma_fence_cb);
  291. if (err)
  292. goto error;
  293. }
  294. if (exclusive) {
  295. for (i = 0; i < shared_count; i++) {
  296. err = kbase_dma_fence_add_callback(katom,
  297. shared_fences[i],
  298. kbase_dma_fence_cb);
  299. if (err)
  300. goto error;
  301. }
  302. }
  303. kfree(shared_fences);
  304. return err;
  305. error:
  306. /* Cancel and clean up all callbacks that was set up before the error.
  307. */
  308. kbase_dma_fence_free_callbacks(katom);
  309. kfree(shared_fences);
  310. return err;
  311. }
  312. void kbase_dma_fence_add_reservation(struct reservation_object *resv,
  313. struct kbase_dma_fence_resv_info *info,
  314. bool exclusive)
  315. {
  316. unsigned int i;
  317. for (i = 0; i < info->dma_fence_resv_count; i++) {
  318. /* Duplicate resource, ignore */
  319. if (info->resv_objs[i] == resv)
  320. return;
  321. }
  322. info->resv_objs[info->dma_fence_resv_count] = resv;
  323. if (exclusive)
  324. set_bit(info->dma_fence_resv_count,
  325. info->dma_fence_excl_bitmap);
  326. (info->dma_fence_resv_count)++;
  327. }
  328. int kbase_dma_fence_wait(struct kbase_jd_atom *katom,
  329. struct kbase_dma_fence_resv_info *info)
  330. {
  331. int err, i;
  332. struct dma_fence *fence;
  333. struct ww_acquire_ctx ww_ctx;
  334. lockdep_assert_held(&katom->kctx->jctx.lock);
  335. atomic_set(&katom->dma_fence.dep_count, 1);
  336. fence = kbase_dma_fence_new(katom->dma_fence.context,
  337. atomic_inc_return(&katom->dma_fence.seqno));
  338. if (!fence) {
  339. err = -ENOMEM;
  340. dev_err(katom->kctx->kbdev->dev,
  341. "Error %d creating fence.\n", err);
  342. return err;
  343. }
  344. katom->dma_fence.fence = fence;
  345. err = kbase_dma_fence_lock_reservations(info, &ww_ctx);
  346. if (err) {
  347. dev_err(katom->kctx->kbdev->dev,
  348. "Error %d locking reservations.\n", err);
  349. return err;
  350. }
  351. for (i = 0; i < info->dma_fence_resv_count; i++) {
  352. struct reservation_object *obj = info->resv_objs[i];
  353. if (!test_bit(i, info->dma_fence_excl_bitmap)) {
  354. err = reservation_object_reserve_shared(obj);
  355. if (err) {
  356. dev_err(katom->kctx->kbdev->dev,
  357. "Error %d reserving space for shared fence.\n", err);
  358. goto end;
  359. }
  360. err = kbase_dma_fence_add_reservation_callback(katom, obj, false);
  361. if (err) {
  362. dev_err(katom->kctx->kbdev->dev,
  363. "Error %d adding reservation to callback.\n", err);
  364. goto end;
  365. }
  366. reservation_object_add_shared_fence(obj, katom->dma_fence.fence);
  367. } else {
  368. err = kbase_dma_fence_add_reservation_callback(katom, obj, true);
  369. if (err) {
  370. dev_err(katom->kctx->kbdev->dev,
  371. "Error %d adding reservation to callback.\n", err);
  372. goto end;
  373. }
  374. reservation_object_add_excl_fence(obj, katom->dma_fence.fence);
  375. }
  376. }
  377. end:
  378. kbase_dma_fence_unlock_reservations(info, &ww_ctx);
  379. if (!err) {
  380. /* Test if the callbacks are already triggered */
  381. if (atomic_dec_and_test(&katom->dma_fence.dep_count)) {
  382. atomic_set(&katom->dma_fence.dep_count, -1);
  383. kbase_dma_fence_free_callbacks(katom);
  384. } else {
  385. /* Add katom to the list of dma-buf fence waiting atoms
  386. * only if it is still waiting.
  387. */
  388. kbase_dma_fence_waiters_add(katom);
  389. }
  390. }
  391. return err;
  392. }
  393. void kbase_dma_fence_cancel_all_atoms(struct kbase_context *kctx)
  394. {
  395. struct kbase_jd_atom *katom, *katom_tmp;
  396. list_for_each_entry_safe(katom, katom_tmp,
  397. &kctx->dma_fence.waiting_resource, queue) {
  398. kbase_dma_fence_waiters_remove(katom);
  399. kbase_dma_fence_cancel_atom(katom);
  400. }
  401. }
  402. void kbase_dma_fence_cancel_callbacks(struct kbase_jd_atom *katom)
  403. {
  404. /* Cancel callbacks and clean up. */
  405. kbase_dma_fence_free_callbacks(katom);
  406. }
  407. void kbase_dma_fence_signal(struct kbase_jd_atom *katom)
  408. {
  409. if (!katom->dma_fence.fence)
  410. return;
  411. KBASE_DEBUG_ASSERT(atomic_read(&katom->dma_fence.dep_count) == -1);
  412. /* Signal the atom's fence. */
  413. dma_fence_signal(katom->dma_fence.fence);
  414. dma_fence_put(katom->dma_fence.fence);
  415. katom->dma_fence.fence = NULL;
  416. kbase_dma_fence_free_callbacks(katom);
  417. }
  418. void kbase_dma_fence_term(struct kbase_context *kctx)
  419. {
  420. destroy_workqueue(kctx->dma_fence.wq);
  421. kctx->dma_fence.wq = NULL;
  422. }
  423. int kbase_dma_fence_init(struct kbase_context *kctx)
  424. {
  425. INIT_LIST_HEAD(&kctx->dma_fence.waiting_resource);
  426. kctx->dma_fence.wq = alloc_workqueue("mali-fence-%d",
  427. WQ_UNBOUND, 1, kctx->pid);
  428. if (!kctx->dma_fence.wq)
  429. return -ENOMEM;
  430. return 0;
  431. }