mali_kbase_sync.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*
  2. *
  3. * (C) COPYRIGHT 2012-2015 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. #ifdef CONFIG_SYNC
  16. #include <linux/seq_file.h>
  17. #include "sync.h"
  18. #include <mali_kbase.h>
  19. #include <mali_kbase_sync.h>
  20. struct mali_sync_timeline {
  21. struct sync_timeline timeline;
  22. atomic_t counter;
  23. atomic_t signalled;
  24. };
  25. struct mali_sync_pt {
  26. struct sync_pt pt;
  27. int order;
  28. int result;
  29. };
  30. static struct mali_sync_timeline *to_mali_sync_timeline(struct sync_timeline *timeline)
  31. {
  32. return container_of(timeline, struct mali_sync_timeline, timeline);
  33. }
  34. static struct mali_sync_pt *to_mali_sync_pt(struct sync_pt *pt)
  35. {
  36. return container_of(pt, struct mali_sync_pt, pt);
  37. }
  38. static struct sync_pt *timeline_dup(struct sync_pt *pt)
  39. {
  40. struct mali_sync_pt *mpt = to_mali_sync_pt(pt);
  41. struct mali_sync_pt *new_mpt;
  42. struct sync_pt *new_pt = sync_pt_create(sync_pt_parent(pt), sizeof(struct mali_sync_pt));
  43. if (!new_pt)
  44. return NULL;
  45. new_mpt = to_mali_sync_pt(new_pt);
  46. new_mpt->order = mpt->order;
  47. new_mpt->result = mpt->result;
  48. return new_pt;
  49. }
  50. static int timeline_has_signaled(struct sync_pt *pt)
  51. {
  52. struct mali_sync_pt *mpt = to_mali_sync_pt(pt);
  53. struct mali_sync_timeline *mtl = to_mali_sync_timeline(sync_pt_parent(pt));
  54. int result = mpt->result;
  55. int diff = atomic_read(&mtl->signalled) - mpt->order;
  56. if (diff >= 0)
  57. return (result < 0) ? result : 1;
  58. return 0;
  59. }
  60. static int timeline_compare(struct sync_pt *a, struct sync_pt *b)
  61. {
  62. struct mali_sync_pt *ma = container_of(a, struct mali_sync_pt, pt);
  63. struct mali_sync_pt *mb = container_of(b, struct mali_sync_pt, pt);
  64. int diff = ma->order - mb->order;
  65. if (diff == 0)
  66. return 0;
  67. return (diff < 0) ? -1 : 1;
  68. }
  69. static void timeline_value_str(struct sync_timeline *timeline, char *str,
  70. int size)
  71. {
  72. struct mali_sync_timeline *mtl = to_mali_sync_timeline(timeline);
  73. snprintf(str, size, "%d", atomic_read(&mtl->signalled));
  74. }
  75. static void pt_value_str(struct sync_pt *pt, char *str, int size)
  76. {
  77. struct mali_sync_pt *mpt = to_mali_sync_pt(pt);
  78. snprintf(str, size, "%d(%d)", mpt->order, mpt->result);
  79. }
  80. static struct sync_timeline_ops mali_timeline_ops = {
  81. .driver_name = "Mali",
  82. .dup = timeline_dup,
  83. .has_signaled = timeline_has_signaled,
  84. .compare = timeline_compare,
  85. .timeline_value_str = timeline_value_str,
  86. .pt_value_str = pt_value_str,
  87. };
  88. int kbase_sync_timeline_is_ours(struct sync_timeline *timeline)
  89. {
  90. return timeline->ops == &mali_timeline_ops;
  91. }
  92. struct sync_timeline *kbase_sync_timeline_alloc(const char *name)
  93. {
  94. struct sync_timeline *tl;
  95. struct mali_sync_timeline *mtl;
  96. tl = sync_timeline_create(&mali_timeline_ops, sizeof(struct mali_sync_timeline), name);
  97. if (!tl)
  98. return NULL;
  99. /* Set the counter in our private struct */
  100. mtl = to_mali_sync_timeline(tl);
  101. atomic_set(&mtl->counter, 0);
  102. atomic_set(&mtl->signalled, 0);
  103. return tl;
  104. }
  105. struct sync_pt *kbase_sync_pt_alloc(struct sync_timeline *parent)
  106. {
  107. struct sync_pt *pt = sync_pt_create(parent, sizeof(struct mali_sync_pt));
  108. struct mali_sync_timeline *mtl = to_mali_sync_timeline(parent);
  109. struct mali_sync_pt *mpt;
  110. if (!pt)
  111. return NULL;
  112. mpt = to_mali_sync_pt(pt);
  113. mpt->order = atomic_inc_return(&mtl->counter);
  114. mpt->result = 0;
  115. return pt;
  116. }
  117. void kbase_sync_signal_pt(struct sync_pt *pt, int result)
  118. {
  119. struct mali_sync_pt *mpt = to_mali_sync_pt(pt);
  120. struct mali_sync_timeline *mtl = to_mali_sync_timeline(sync_pt_parent(pt));
  121. int signalled;
  122. int diff;
  123. mpt->result = result;
  124. do {
  125. signalled = atomic_read(&mtl->signalled);
  126. diff = signalled - mpt->order;
  127. if (diff > 0) {
  128. /* The timeline is already at or ahead of this point.
  129. * This should not happen unless userspace has been
  130. * signalling fences out of order, so warn but don't
  131. * violate the sync_pt API.
  132. * The warning is only in debug builds to prevent
  133. * a malicious user being able to spam dmesg.
  134. */
  135. #ifdef CONFIG_MALI_DEBUG
  136. pr_err("Fences were triggered in a different order to allocation!");
  137. #endif
  138. return;
  139. }
  140. } while (atomic_cmpxchg(&mtl->signalled, signalled, mpt->order) != signalled);
  141. }
  142. #endif // ifdef CONFIG_SYNC