dma-fence-unwrap.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * dma-fence-util: misc functions for dma_fence objects
  4. *
  5. * Copyright (C) 2022 Advanced Micro Devices, Inc.
  6. * Authors:
  7. * Christian König <[email protected]>
  8. */
  9. #include <linux/dma-fence.h>
  10. #include <linux/dma-fence-array.h>
  11. #include <linux/dma-fence-chain.h>
  12. #include <linux/dma-fence-unwrap.h>
  13. #include <linux/slab.h>
  14. /* Internal helper to start new array iteration, don't use directly */
  15. static struct dma_fence *
  16. __dma_fence_unwrap_array(struct dma_fence_unwrap *cursor)
  17. {
  18. cursor->array = dma_fence_chain_contained(cursor->chain);
  19. cursor->index = 0;
  20. return dma_fence_array_first(cursor->array);
  21. }
  22. /**
  23. * dma_fence_unwrap_first - return the first fence from fence containers
  24. * @head: the entrypoint into the containers
  25. * @cursor: current position inside the containers
  26. *
  27. * Unwraps potential dma_fence_chain/dma_fence_array containers and return the
  28. * first fence.
  29. */
  30. struct dma_fence *dma_fence_unwrap_first(struct dma_fence *head,
  31. struct dma_fence_unwrap *cursor)
  32. {
  33. cursor->chain = dma_fence_get(head);
  34. return __dma_fence_unwrap_array(cursor);
  35. }
  36. EXPORT_SYMBOL_GPL(dma_fence_unwrap_first);
  37. /**
  38. * dma_fence_unwrap_next - return the next fence from a fence containers
  39. * @cursor: current position inside the containers
  40. *
  41. * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return
  42. * the next fence from them.
  43. */
  44. struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
  45. {
  46. struct dma_fence *tmp;
  47. ++cursor->index;
  48. tmp = dma_fence_array_next(cursor->array, cursor->index);
  49. if (tmp)
  50. return tmp;
  51. cursor->chain = dma_fence_chain_walk(cursor->chain);
  52. return __dma_fence_unwrap_array(cursor);
  53. }
  54. EXPORT_SYMBOL_GPL(dma_fence_unwrap_next);
  55. /* Implementation for the dma_fence_merge() marco, don't use directly */
  56. struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
  57. struct dma_fence **fences,
  58. struct dma_fence_unwrap *iter)
  59. {
  60. struct dma_fence_array *result;
  61. struct dma_fence *tmp, **array;
  62. ktime_t timestamp;
  63. unsigned int i;
  64. size_t count;
  65. count = 0;
  66. timestamp = ns_to_ktime(0);
  67. for (i = 0; i < num_fences; ++i) {
  68. dma_fence_unwrap_for_each(tmp, &iter[i], fences[i]) {
  69. if (!dma_fence_is_signaled(tmp)) {
  70. ++count;
  71. } else {
  72. ktime_t t = dma_fence_timestamp(tmp);
  73. if (ktime_after(t, timestamp))
  74. timestamp = t;
  75. }
  76. }
  77. }
  78. /*
  79. * If we couldn't find a pending fence just return a private signaled
  80. * fence with the timestamp of the last signaled one.
  81. */
  82. if (count == 0)
  83. return dma_fence_allocate_private_stub(timestamp);
  84. array = kmalloc_array(count, sizeof(*array), GFP_KERNEL);
  85. if (!array)
  86. return NULL;
  87. /*
  88. * This trashes the input fence array and uses it as position for the
  89. * following merge loop. This works because the dma_fence_merge()
  90. * wrapper macro is creating this temporary array on the stack together
  91. * with the iterators.
  92. */
  93. for (i = 0; i < num_fences; ++i)
  94. fences[i] = dma_fence_unwrap_first(fences[i], &iter[i]);
  95. count = 0;
  96. do {
  97. unsigned int sel;
  98. restart:
  99. tmp = NULL;
  100. for (i = 0; i < num_fences; ++i) {
  101. struct dma_fence *next;
  102. while (fences[i] && dma_fence_is_signaled(fences[i]))
  103. fences[i] = dma_fence_unwrap_next(&iter[i]);
  104. next = fences[i];
  105. if (!next)
  106. continue;
  107. /*
  108. * We can't guarantee that inpute fences are ordered by
  109. * context, but it is still quite likely when this
  110. * function is used multiple times. So attempt to order
  111. * the fences by context as we pass over them and merge
  112. * fences with the same context.
  113. */
  114. if (!tmp || tmp->context > next->context) {
  115. tmp = next;
  116. sel = i;
  117. } else if (tmp->context < next->context) {
  118. continue;
  119. } else if (dma_fence_is_later(tmp, next)) {
  120. fences[i] = dma_fence_unwrap_next(&iter[i]);
  121. goto restart;
  122. } else {
  123. fences[sel] = dma_fence_unwrap_next(&iter[sel]);
  124. goto restart;
  125. }
  126. }
  127. if (tmp) {
  128. array[count++] = dma_fence_get(tmp);
  129. fences[sel] = dma_fence_unwrap_next(&iter[sel]);
  130. }
  131. } while (tmp);
  132. if (count == 0) {
  133. tmp = dma_fence_allocate_private_stub(ktime_get());
  134. goto return_tmp;
  135. }
  136. if (count == 1) {
  137. tmp = array[0];
  138. goto return_tmp;
  139. }
  140. result = dma_fence_array_create(count, array,
  141. dma_fence_context_alloc(1),
  142. 1, false);
  143. if (!result) {
  144. tmp = NULL;
  145. goto return_tmp;
  146. }
  147. return &result->base;
  148. return_tmp:
  149. kfree(array);
  150. return tmp;
  151. }
  152. EXPORT_SYMBOL_GPL(__dma_fence_unwrap_merge);