sync_debug.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Sync File validation framework and debug information
  4. *
  5. * Copyright (C) 2012 Google, Inc.
  6. */
  7. #include <linux/debugfs.h>
  8. #include "sync_debug.h"
  9. static struct dentry *dbgfs;
  10. static LIST_HEAD(sync_timeline_list_head);
  11. static DEFINE_SPINLOCK(sync_timeline_list_lock);
  12. static LIST_HEAD(sync_file_list_head);
  13. static DEFINE_SPINLOCK(sync_file_list_lock);
  14. void sync_timeline_debug_add(struct sync_timeline *obj)
  15. {
  16. unsigned long flags;
  17. spin_lock_irqsave(&sync_timeline_list_lock, flags);
  18. list_add_tail(&obj->sync_timeline_list, &sync_timeline_list_head);
  19. spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
  20. }
  21. void sync_timeline_debug_remove(struct sync_timeline *obj)
  22. {
  23. unsigned long flags;
  24. spin_lock_irqsave(&sync_timeline_list_lock, flags);
  25. list_del(&obj->sync_timeline_list);
  26. spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
  27. }
  28. void sync_file_debug_add(struct sync_file *sync_file)
  29. {
  30. unsigned long flags;
  31. spin_lock_irqsave(&sync_file_list_lock, flags);
  32. list_add_tail(&sync_file->sync_file_list, &sync_file_list_head);
  33. spin_unlock_irqrestore(&sync_file_list_lock, flags);
  34. }
  35. void sync_file_debug_remove(struct sync_file *sync_file)
  36. {
  37. unsigned long flags;
  38. spin_lock_irqsave(&sync_file_list_lock, flags);
  39. list_del(&sync_file->sync_file_list);
  40. spin_unlock_irqrestore(&sync_file_list_lock, flags);
  41. }
  42. static const char *sync_status_str(int status)
  43. {
  44. if (status < 0)
  45. return "error";
  46. if (status > 0)
  47. return "signaled";
  48. return "active";
  49. }
  50. static void sync_print_fence(struct seq_file *s,
  51. struct dma_fence *fence, bool show)
  52. {
  53. struct sync_timeline *parent = dma_fence_parent(fence);
  54. int status;
  55. status = dma_fence_get_status_locked(fence);
  56. seq_printf(s, " %s%sfence %s",
  57. show ? parent->name : "",
  58. show ? "_" : "",
  59. sync_status_str(status));
  60. if (test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags)) {
  61. struct timespec64 ts64 =
  62. ktime_to_timespec64(fence->timestamp);
  63. seq_printf(s, "@%lld.%09ld", (s64)ts64.tv_sec, ts64.tv_nsec);
  64. }
  65. if (fence->ops->timeline_value_str &&
  66. fence->ops->fence_value_str) {
  67. char value[64];
  68. bool success;
  69. fence->ops->fence_value_str(fence, value, sizeof(value));
  70. success = strlen(value);
  71. if (success) {
  72. seq_printf(s, ": %s", value);
  73. fence->ops->timeline_value_str(fence, value,
  74. sizeof(value));
  75. if (strlen(value))
  76. seq_printf(s, " / %s", value);
  77. }
  78. }
  79. seq_putc(s, '\n');
  80. }
  81. static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj)
  82. {
  83. struct list_head *pos;
  84. seq_printf(s, "%s: %d\n", obj->name, obj->value);
  85. spin_lock_irq(&obj->lock);
  86. list_for_each(pos, &obj->pt_list) {
  87. struct sync_pt *pt = container_of(pos, struct sync_pt, link);
  88. sync_print_fence(s, &pt->base, false);
  89. }
  90. spin_unlock_irq(&obj->lock);
  91. }
  92. static void sync_print_sync_file(struct seq_file *s,
  93. struct sync_file *sync_file)
  94. {
  95. char buf[128];
  96. int i;
  97. seq_printf(s, "[%p] %s: %s\n", sync_file,
  98. sync_file_get_name(sync_file, buf, sizeof(buf)),
  99. sync_status_str(dma_fence_get_status(sync_file->fence)));
  100. if (dma_fence_is_array(sync_file->fence)) {
  101. struct dma_fence_array *array = to_dma_fence_array(sync_file->fence);
  102. for (i = 0; i < array->num_fences; ++i)
  103. sync_print_fence(s, array->fences[i], true);
  104. } else {
  105. sync_print_fence(s, sync_file->fence, true);
  106. }
  107. }
  108. static int sync_info_debugfs_show(struct seq_file *s, void *unused)
  109. {
  110. struct list_head *pos;
  111. seq_puts(s, "objs:\n--------------\n");
  112. spin_lock_irq(&sync_timeline_list_lock);
  113. list_for_each(pos, &sync_timeline_list_head) {
  114. struct sync_timeline *obj =
  115. container_of(pos, struct sync_timeline,
  116. sync_timeline_list);
  117. sync_print_obj(s, obj);
  118. seq_putc(s, '\n');
  119. }
  120. spin_unlock_irq(&sync_timeline_list_lock);
  121. seq_puts(s, "fences:\n--------------\n");
  122. spin_lock_irq(&sync_file_list_lock);
  123. list_for_each(pos, &sync_file_list_head) {
  124. struct sync_file *sync_file =
  125. container_of(pos, struct sync_file, sync_file_list);
  126. sync_print_sync_file(s, sync_file);
  127. seq_putc(s, '\n');
  128. }
  129. spin_unlock_irq(&sync_file_list_lock);
  130. return 0;
  131. }
  132. DEFINE_SHOW_ATTRIBUTE(sync_info_debugfs);
  133. static __init int sync_debugfs_init(void)
  134. {
  135. dbgfs = debugfs_create_dir("sync", NULL);
  136. /*
  137. * The debugfs files won't ever get removed and thus, there is
  138. * no need to protect it against removal races. The use of
  139. * debugfs_create_file_unsafe() is actually safe here.
  140. */
  141. debugfs_create_file_unsafe("info", 0444, dbgfs, NULL,
  142. &sync_info_debugfs_fops);
  143. debugfs_create_file_unsafe("sw_sync", 0644, dbgfs, NULL,
  144. &sw_sync_debugfs_fops);
  145. return 0;
  146. }
  147. late_initcall(sync_debugfs_init);