dma-fence-unwrap.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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 <christian.koenig@amd.com>
  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. #include <linux/sort.h>
  15. /* Internal helper to start new array iteration, don't use directly */
  16. static struct dma_fence *
  17. __dma_fence_unwrap_array(struct dma_fence_unwrap *cursor)
  18. {
  19. cursor->array = dma_fence_chain_contained(cursor->chain);
  20. cursor->index = 0;
  21. return dma_fence_array_first(cursor->array);
  22. }
  23. /**
  24. * dma_fence_unwrap_first - return the first fence from fence containers
  25. * @head: the entrypoint into the containers
  26. * @cursor: current position inside the containers
  27. *
  28. * Unwraps potential dma_fence_chain/dma_fence_array containers and return the
  29. * first fence.
  30. */
  31. struct dma_fence *dma_fence_unwrap_first(struct dma_fence *head,
  32. struct dma_fence_unwrap *cursor)
  33. {
  34. cursor->chain = dma_fence_get(head);
  35. return __dma_fence_unwrap_array(cursor);
  36. }
  37. EXPORT_SYMBOL_GPL(dma_fence_unwrap_first);
  38. /**
  39. * dma_fence_unwrap_next - return the next fence from a fence containers
  40. * @cursor: current position inside the containers
  41. *
  42. * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return
  43. * the next fence from them.
  44. */
  45. struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
  46. {
  47. struct dma_fence *tmp;
  48. ++cursor->index;
  49. tmp = dma_fence_array_next(cursor->array, cursor->index);
  50. if (tmp)
  51. return tmp;
  52. cursor->chain = dma_fence_chain_walk(cursor->chain);
  53. return __dma_fence_unwrap_array(cursor);
  54. }
  55. EXPORT_SYMBOL_GPL(dma_fence_unwrap_next);
  56. static int fence_cmp(const void *_a, const void *_b)
  57. {
  58. struct dma_fence *a = *(struct dma_fence **)_a;
  59. struct dma_fence *b = *(struct dma_fence **)_b;
  60. if (a->context < b->context)
  61. return -1;
  62. else if (a->context > b->context)
  63. return 1;
  64. if (dma_fence_is_later(b, a))
  65. return 1;
  66. else if (dma_fence_is_later(a, b))
  67. return -1;
  68. return 0;
  69. }
  70. /**
  71. * dma_fence_dedup_array - Sort and deduplicate an array of dma_fence pointers
  72. * @fences: Array of dma_fence pointers to be deduplicated
  73. * @num_fences: Number of entries in the @fences array
  74. *
  75. * Sorts the input array by context, then removes duplicate
  76. * fences with the same context, keeping only the most recent one.
  77. *
  78. * The array is modified in-place and unreferenced duplicate fences are released
  79. * via dma_fence_put(). The function returns the new number of fences after
  80. * deduplication.
  81. *
  82. * Return: Number of unique fences remaining in the array.
  83. */
  84. int dma_fence_dedup_array(struct dma_fence **fences, int num_fences)
  85. {
  86. int i, j;
  87. sort(fences, num_fences, sizeof(*fences), fence_cmp, NULL);
  88. /*
  89. * Only keep the most recent fence for each context.
  90. */
  91. j = 0;
  92. for (i = 1; i < num_fences; i++) {
  93. if (fences[i]->context == fences[j]->context)
  94. dma_fence_put(fences[i]);
  95. else
  96. fences[++j] = fences[i];
  97. }
  98. return ++j;
  99. }
  100. EXPORT_SYMBOL_GPL(dma_fence_dedup_array);
  101. /* Implementation for the dma_fence_merge() marco, don't use directly */
  102. struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences,
  103. struct dma_fence **fences,
  104. struct dma_fence_unwrap *iter)
  105. {
  106. struct dma_fence *tmp, *unsignaled = NULL, **array;
  107. struct dma_fence_array *result;
  108. ktime_t timestamp;
  109. int i, count;
  110. count = 0;
  111. timestamp = ns_to_ktime(0);
  112. for (i = 0; i < num_fences; ++i) {
  113. dma_fence_unwrap_for_each(tmp, &iter[i], fences[i]) {
  114. if (!dma_fence_is_signaled(tmp)) {
  115. dma_fence_put(unsignaled);
  116. unsignaled = dma_fence_get(tmp);
  117. ++count;
  118. } else {
  119. ktime_t t = dma_fence_timestamp(tmp);
  120. if (ktime_after(t, timestamp))
  121. timestamp = t;
  122. }
  123. }
  124. }
  125. /*
  126. * If we couldn't find a pending fence just return a private signaled
  127. * fence with the timestamp of the last signaled one.
  128. *
  129. * Or if there was a single unsignaled fence left we can return it
  130. * directly and early since that is a major path on many workloads.
  131. */
  132. if (count == 0)
  133. return dma_fence_allocate_private_stub(timestamp);
  134. else if (count == 1)
  135. return unsignaled;
  136. dma_fence_put(unsignaled);
  137. array = kmalloc_objs(*array, count);
  138. if (!array)
  139. return NULL;
  140. count = 0;
  141. for (i = 0; i < num_fences; ++i) {
  142. dma_fence_unwrap_for_each(tmp, &iter[i], fences[i]) {
  143. if (!dma_fence_is_signaled(tmp)) {
  144. array[count++] = dma_fence_get(tmp);
  145. } else {
  146. ktime_t t = dma_fence_timestamp(tmp);
  147. if (ktime_after(t, timestamp))
  148. timestamp = t;
  149. }
  150. }
  151. }
  152. if (count == 0 || count == 1)
  153. goto return_fastpath;
  154. count = dma_fence_dedup_array(array, count);
  155. if (count > 1) {
  156. result = dma_fence_array_create(count, array,
  157. dma_fence_context_alloc(1),
  158. 1, false);
  159. if (!result) {
  160. for (i = 0; i < count; i++)
  161. dma_fence_put(array[i]);
  162. tmp = NULL;
  163. goto return_tmp;
  164. }
  165. return &result->base;
  166. }
  167. return_fastpath:
  168. if (count == 0)
  169. tmp = dma_fence_allocate_private_stub(timestamp);
  170. else
  171. tmp = array[0];
  172. return_tmp:
  173. kfree(array);
  174. return tmp;
  175. }
  176. EXPORT_SYMBOL_GPL(__dma_fence_unwrap_merge);