kgsl_eventlog.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2021, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #include <linux/sched.h>
  7. #include <linux/sched/clock.h>
  8. #include <linux/slab.h>
  9. #include <linux/spinlock.h>
  10. #include "kgsl_device.h"
  11. #include "kgsl_eventlog.h"
  12. #include "kgsl_snapshot.h"
  13. #include "kgsl_util.h"
  14. #define EVENTLOG_SIZE (SZ_64K + SZ_32K)
  15. #define MAGIC 0xabbaabba
  16. #define LOG_FENCE_NAME_LEN 74
  17. #define KGSL_SNAPSHOT_EVENTLOG_TYPE 0x1
  18. #define KGSL_SNAPSHOT_EVENTLOG_VERSION 0x0
  19. /*
  20. * This an internal event used to skip empty space at the bottom of the
  21. * ringbuffer
  22. */
  23. #define LOG_SKIP 1
  24. #define LOG_FIRE_EVENT 2
  25. #define LOG_CMDBATCH_SUBMITTED_EVENT 3
  26. #define LOG_CMDBATCH_RETIRED_EVENT 4
  27. #define LOG_SYNCPOINT_FENCE_EVENT 5
  28. #define LOG_SYNCPOINT_FENCE_EXPIRE_EVENT 6
  29. #define LOG_TIMELINE_FENCE_ALLOC_EVENT 7
  30. #define LOG_TIMELINE_FENCE_RELEASE_EVENT 8
  31. static spinlock_t lock;
  32. static void *kgsl_eventlog;
  33. static int eventlog_wptr;
  34. struct kgsl_log_header {
  35. /** @magic: Magic value to identify header */
  36. u32 magic;
  37. /** @pid: : PID of the process */
  38. int pid;
  39. /** @time: System time in nanoseconds */
  40. u64 time;
  41. /** @event: bits[0:15] specify the event ID. bits[16:31] specify event version */
  42. u32 event;
  43. /** @size: Size of the event data in bytes */
  44. u32 size;
  45. };
  46. /* Add a marker to skip the rest of the eventlog and start over fresh */
  47. static void add_skip_header(u32 offset)
  48. {
  49. struct kgsl_log_header *header = kgsl_eventlog + offset;
  50. header->magic = MAGIC;
  51. header->time = local_clock();
  52. header->pid = 0;
  53. header->event = FIELD_PREP(GENMASK(15, 0), LOG_SKIP);
  54. header->size = EVENTLOG_SIZE - sizeof(*header) - offset;
  55. }
  56. static void *kgsl_eventlog_alloc(u16 eventid, u32 size)
  57. {
  58. struct kgsl_log_header *header;
  59. u32 datasize = size + sizeof(*header);
  60. unsigned long flags;
  61. void *data;
  62. if (!kgsl_eventlog)
  63. return NULL;
  64. spin_lock_irqsave(&lock, flags);
  65. if (eventlog_wptr + datasize > (EVENTLOG_SIZE - sizeof(*header))) {
  66. add_skip_header(eventlog_wptr);
  67. eventlog_wptr = datasize;
  68. data = kgsl_eventlog;
  69. } else {
  70. data = kgsl_eventlog + eventlog_wptr;
  71. eventlog_wptr += datasize;
  72. }
  73. spin_unlock_irqrestore(&lock, flags);
  74. header = data;
  75. header->magic = MAGIC;
  76. header->time = local_clock();
  77. header->pid = current->pid;
  78. header->event = FIELD_PREP(GENMASK(15, 0), eventid);
  79. header->size = size;
  80. return data + sizeof(*header);
  81. }
  82. void kgsl_eventlog_init(void)
  83. {
  84. kgsl_eventlog = kzalloc(EVENTLOG_SIZE, GFP_KERNEL);
  85. eventlog_wptr = 0;
  86. spin_lock_init(&lock);
  87. kgsl_add_to_minidump("KGSL_EVENTLOG", (u64) kgsl_eventlog,
  88. __pa(kgsl_eventlog), EVENTLOG_SIZE);
  89. }
  90. void kgsl_eventlog_exit(void)
  91. {
  92. kgsl_remove_from_minidump("KGSL_EVENTLOG", (u64) kgsl_eventlog,
  93. __pa(kgsl_eventlog), EVENTLOG_SIZE);
  94. kfree(kgsl_eventlog);
  95. kgsl_eventlog = NULL;
  96. eventlog_wptr = 0;
  97. }
  98. void log_kgsl_fire_event(u32 id, u32 ts, u32 type, u32 age)
  99. {
  100. struct {
  101. u32 id;
  102. u32 ts;
  103. u32 type;
  104. u32 age;
  105. } *entry;
  106. entry = kgsl_eventlog_alloc(LOG_FIRE_EVENT, sizeof(*entry));
  107. if (!entry)
  108. return;
  109. entry->id = id;
  110. entry->ts = ts;
  111. entry->type = type;
  112. entry->age = age;
  113. }
  114. void log_kgsl_cmdbatch_submitted_event(u32 id, u32 ts, u32 prio, u64 flags)
  115. {
  116. struct {
  117. u32 id;
  118. u32 ts;
  119. u32 prio;
  120. u64 flags;
  121. } *entry;
  122. entry = kgsl_eventlog_alloc(LOG_CMDBATCH_SUBMITTED_EVENT, sizeof(*entry));
  123. if (!entry)
  124. return;
  125. entry->id = id;
  126. entry->ts = ts;
  127. entry->prio = prio;
  128. entry->flags = flags;
  129. }
  130. void log_kgsl_cmdbatch_retired_event(u32 id, u32 ts, u32 prio, u64 flags,
  131. u64 start, u64 retire)
  132. {
  133. struct {
  134. u32 id;
  135. u32 ts;
  136. u32 prio;
  137. u64 flags;
  138. u64 start;
  139. u64 retire;
  140. } *entry;
  141. entry = kgsl_eventlog_alloc(LOG_CMDBATCH_RETIRED_EVENT, sizeof(*entry));
  142. if (!entry)
  143. return;
  144. entry->id = id;
  145. entry->ts = ts;
  146. entry->prio = prio;
  147. entry->flags = flags;
  148. entry->start = start;
  149. entry->retire = retire;
  150. }
  151. void log_kgsl_syncpoint_fence_event(u32 id, char *fence_name)
  152. {
  153. struct {
  154. u32 id;
  155. char name[LOG_FENCE_NAME_LEN];
  156. } *entry;
  157. entry = kgsl_eventlog_alloc(LOG_SYNCPOINT_FENCE_EVENT, sizeof(*entry));
  158. if (!entry)
  159. return;
  160. entry->id = id;
  161. memset(entry->name, 0, sizeof(entry->name));
  162. strscpy(entry->name, fence_name, sizeof(entry->name));
  163. }
  164. void log_kgsl_syncpoint_fence_expire_event(u32 id, char *fence_name)
  165. {
  166. struct {
  167. u32 id;
  168. char name[LOG_FENCE_NAME_LEN];
  169. } *entry;
  170. entry = kgsl_eventlog_alloc(LOG_SYNCPOINT_FENCE_EXPIRE_EVENT, sizeof(*entry));
  171. if (!entry)
  172. return;
  173. entry->id = id;
  174. memset(entry->name, 0, sizeof(entry->name));
  175. strscpy(entry->name, fence_name, sizeof(entry->name));
  176. }
  177. void log_kgsl_timeline_fence_alloc_event(u32 id, u64 seqno)
  178. {
  179. struct {
  180. u32 id;
  181. u64 seqno;
  182. } *entry;
  183. entry = kgsl_eventlog_alloc(LOG_TIMELINE_FENCE_ALLOC_EVENT, sizeof(*entry));
  184. if (!entry)
  185. return;
  186. entry->id = id;
  187. entry->seqno = seqno;
  188. }
  189. void log_kgsl_timeline_fence_release_event(u32 id, u64 seqno)
  190. {
  191. struct {
  192. u32 id;
  193. u64 seqno;
  194. } *entry;
  195. entry = kgsl_eventlog_alloc(LOG_TIMELINE_FENCE_RELEASE_EVENT, sizeof(*entry));
  196. if (!entry)
  197. return;
  198. entry->id = id;
  199. entry->seqno = seqno;
  200. }
  201. size_t kgsl_snapshot_eventlog_buffer(struct kgsl_device *device,
  202. u8 *buf, size_t remain, void *priv)
  203. {
  204. struct kgsl_snapshot_eventlog *hdr =
  205. (struct kgsl_snapshot_eventlog *)buf;
  206. u32 *data = (u32 *)(buf + sizeof(*hdr));
  207. if (!kgsl_eventlog)
  208. return 0;
  209. if (remain < EVENTLOG_SIZE + sizeof(*hdr)) {
  210. dev_err(device->dev,
  211. "snapshot: Not enough memory for eventlog\n");
  212. return 0;
  213. }
  214. hdr->size = EVENTLOG_SIZE;
  215. hdr->type = KGSL_SNAPSHOT_EVENTLOG_TYPE;
  216. hdr->version = KGSL_SNAPSHOT_EVENTLOG_VERSION;
  217. memcpy(data, kgsl_eventlog, EVENTLOG_SIZE);
  218. return EVENTLOG_SIZE + sizeof(*hdr);
  219. }