PageRenderTime 54ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/gpu/arm/bifrost/debug/mali_kbase_debug_ktrace.c

https://gitlab.com/buktemirlnk/mirrors
C | 356 lines | 239 code | 69 blank | 48 comment | 20 complexity | c26d1a553086f34a7fc55b2fd880094c MD5 | raw file
  1. /*
  2. *
  3. * (C) COPYRIGHT 2020 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. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, you can access it online at
  17. * http://www.gnu.org/licenses/gpl-2.0.html.
  18. *
  19. * SPDX-License-Identifier: GPL-2.0
  20. *
  21. */
  22. #include <mali_kbase.h>
  23. #include "debug/mali_kbase_debug_ktrace_internal.h"
  24. int kbase_ktrace_init(struct kbase_device *kbdev)
  25. {
  26. #if KBASE_KTRACE_TARGET_RBUF
  27. struct kbase_ktrace_msg *rbuf;
  28. rbuf = kmalloc_array(KBASE_KTRACE_SIZE, sizeof(*rbuf), GFP_KERNEL);
  29. if (!rbuf)
  30. return -EINVAL;
  31. kbdev->ktrace.rbuf = rbuf;
  32. spin_lock_init(&kbdev->ktrace.lock);
  33. #endif /* KBASE_KTRACE_TARGET_RBUF */
  34. return 0;
  35. }
  36. void kbase_ktrace_term(struct kbase_device *kbdev)
  37. {
  38. #if KBASE_KTRACE_TARGET_RBUF
  39. kfree(kbdev->ktrace.rbuf);
  40. #endif /* KBASE_KTRACE_TARGET_RBUF */
  41. }
  42. void kbase_ktrace_hook_wrapper(void *param)
  43. {
  44. struct kbase_device *kbdev = (struct kbase_device *)param;
  45. KBASE_KTRACE_DUMP(kbdev);
  46. }
  47. #if KBASE_KTRACE_TARGET_RBUF
  48. static const char * const kbasep_ktrace_code_string[] = {
  49. /*
  50. * IMPORTANT: USE OF SPECIAL #INCLUDE OF NON-STANDARD HEADER FILE
  51. * THIS MUST BE USED AT THE START OF THE ARRAY
  52. */
  53. #define KBASE_KTRACE_CODE_MAKE_CODE(X) # X
  54. #include "debug/mali_kbase_debug_ktrace_codes.h"
  55. #undef KBASE_KTRACE_CODE_MAKE_CODE
  56. };
  57. static void kbasep_ktrace_format_header(char *buffer, int sz, s32 written)
  58. {
  59. written += MAX(snprintf(buffer + written, MAX(sz - written, 0),
  60. "secs,thread_id,cpu,code,kctx,"), 0);
  61. kbasep_ktrace_backend_format_header(buffer, sz, &written);
  62. written += MAX(snprintf(buffer + written, MAX(sz - written, 0),
  63. ",info_val,ktrace_version=%u.%u",
  64. KBASE_KTRACE_VERSION_MAJOR,
  65. KBASE_KTRACE_VERSION_MINOR), 0);
  66. buffer[sz - 1] = 0;
  67. }
  68. static void kbasep_ktrace_format_msg(struct kbase_ktrace_msg *trace_msg,
  69. char *buffer, int sz)
  70. {
  71. s32 written = 0;
  72. /* Initial part of message:
  73. *
  74. * secs,thread_id,cpu,code,
  75. */
  76. written += MAX(snprintf(buffer + written, MAX(sz - written, 0),
  77. "%d.%.6d,%d,%d,%s,",
  78. (int)trace_msg->timestamp.tv_sec,
  79. (int)(trace_msg->timestamp.tv_nsec / 1000),
  80. trace_msg->thread_id, trace_msg->cpu,
  81. kbasep_ktrace_code_string[trace_msg->backend.code]), 0);
  82. /* kctx part: */
  83. if (trace_msg->kctx_tgid) {
  84. written += MAX(snprintf(buffer + written, MAX(sz - written, 0),
  85. "%d_%u",
  86. trace_msg->kctx_tgid, trace_msg->kctx_id), 0);
  87. }
  88. /* Trailing comma */
  89. written += MAX(snprintf(buffer + written, MAX(sz - written, 0),
  90. ","), 0);
  91. /* Backend parts */
  92. kbasep_ktrace_backend_format_msg(trace_msg, buffer, sz,
  93. &written);
  94. /* Rest of message:
  95. *
  96. * ,info_val
  97. *
  98. * Note that the last column is empty, it's simply to hold the ktrace
  99. * version in the header
  100. */
  101. written += MAX(snprintf(buffer + written, MAX(sz - written, 0),
  102. ",0x%.16llx",
  103. (unsigned long long)trace_msg->info_val), 0);
  104. buffer[sz - 1] = 0;
  105. }
  106. static void kbasep_ktrace_dump_msg(struct kbase_device *kbdev,
  107. struct kbase_ktrace_msg *trace_msg)
  108. {
  109. char buffer[KTRACE_DUMP_MESSAGE_SIZE];
  110. lockdep_assert_held(&kbdev->ktrace.lock);
  111. kbasep_ktrace_format_msg(trace_msg, buffer, sizeof(buffer));
  112. dev_dbg(kbdev->dev, "%s", buffer);
  113. }
  114. struct kbase_ktrace_msg *kbasep_ktrace_reserve(struct kbase_ktrace *ktrace)
  115. {
  116. struct kbase_ktrace_msg *trace_msg;
  117. lockdep_assert_held(&ktrace->lock);
  118. trace_msg = &ktrace->rbuf[ktrace->next_in];
  119. /* Update the ringbuffer indices */
  120. ktrace->next_in = (ktrace->next_in + 1) & KBASE_KTRACE_MASK;
  121. if (ktrace->next_in == ktrace->first_out)
  122. ktrace->first_out = (ktrace->first_out + 1) & KBASE_KTRACE_MASK;
  123. return trace_msg;
  124. }
  125. void kbasep_ktrace_msg_init(struct kbase_ktrace *ktrace,
  126. struct kbase_ktrace_msg *trace_msg, enum kbase_ktrace_code code,
  127. struct kbase_context *kctx, kbase_ktrace_flag_t flags,
  128. u64 info_val)
  129. {
  130. lockdep_assert_held(&ktrace->lock);
  131. trace_msg->thread_id = task_pid_nr(current);
  132. trace_msg->cpu = task_cpu(current);
  133. ktime_get_real_ts64(&trace_msg->timestamp);
  134. /* No need to store a flag about whether there was a kctx, tgid==0 is
  135. * sufficient
  136. */
  137. if (kctx) {
  138. trace_msg->kctx_tgid = kctx->tgid;
  139. trace_msg->kctx_id = kctx->id;
  140. } else {
  141. trace_msg->kctx_tgid = 0;
  142. trace_msg->kctx_id = 0;
  143. }
  144. trace_msg->info_val = info_val;
  145. trace_msg->backend.code = code;
  146. trace_msg->backend.flags = flags;
  147. }
  148. void kbasep_ktrace_add(struct kbase_device *kbdev, enum kbase_ktrace_code code,
  149. struct kbase_context *kctx, kbase_ktrace_flag_t flags,
  150. u64 info_val)
  151. {
  152. unsigned long irqflags;
  153. struct kbase_ktrace_msg *trace_msg;
  154. WARN_ON((flags & ~KBASE_KTRACE_FLAG_COMMON_ALL));
  155. spin_lock_irqsave(&kbdev->ktrace.lock, irqflags);
  156. /* Reserve and update indices */
  157. trace_msg = kbasep_ktrace_reserve(&kbdev->ktrace);
  158. /* Fill the common part of the message (including backend.flags) */
  159. kbasep_ktrace_msg_init(&kbdev->ktrace, trace_msg, code, kctx, flags,
  160. info_val);
  161. /* Done */
  162. spin_unlock_irqrestore(&kbdev->ktrace.lock, irqflags);
  163. }
  164. static void kbasep_ktrace_clear_locked(struct kbase_device *kbdev)
  165. {
  166. lockdep_assert_held(&kbdev->ktrace.lock);
  167. kbdev->ktrace.first_out = kbdev->ktrace.next_in;
  168. }
  169. void kbasep_ktrace_clear(struct kbase_device *kbdev)
  170. {
  171. unsigned long flags;
  172. spin_lock_irqsave(&kbdev->ktrace.lock, flags);
  173. kbasep_ktrace_clear_locked(kbdev);
  174. spin_unlock_irqrestore(&kbdev->ktrace.lock, flags);
  175. }
  176. void kbasep_ktrace_dump(struct kbase_device *kbdev)
  177. {
  178. unsigned long flags;
  179. u32 start;
  180. u32 end;
  181. char buffer[KTRACE_DUMP_MESSAGE_SIZE] = "Dumping trace:\n";
  182. kbasep_ktrace_format_header(buffer, sizeof(buffer), strlen(buffer));
  183. dev_dbg(kbdev->dev, "%s", buffer);
  184. spin_lock_irqsave(&kbdev->ktrace.lock, flags);
  185. start = kbdev->ktrace.first_out;
  186. end = kbdev->ktrace.next_in;
  187. while (start != end) {
  188. struct kbase_ktrace_msg *trace_msg = &kbdev->ktrace.rbuf[start];
  189. kbasep_ktrace_dump_msg(kbdev, trace_msg);
  190. start = (start + 1) & KBASE_KTRACE_MASK;
  191. }
  192. dev_dbg(kbdev->dev, "TRACE_END");
  193. kbasep_ktrace_clear_locked(kbdev);
  194. spin_unlock_irqrestore(&kbdev->ktrace.lock, flags);
  195. }
  196. #ifdef CONFIG_DEBUG_FS
  197. struct trace_seq_state {
  198. struct kbase_ktrace_msg trace_buf[KBASE_KTRACE_SIZE];
  199. u32 start;
  200. u32 end;
  201. };
  202. static void *kbasep_ktrace_seq_start(struct seq_file *s, loff_t *pos)
  203. {
  204. struct trace_seq_state *state = s->private;
  205. int i;
  206. if (*pos == 0)
  207. /* See Documentation/filesystems/seq_file.txt */
  208. return SEQ_START_TOKEN;
  209. if (*pos > KBASE_KTRACE_SIZE)
  210. return NULL;
  211. i = state->start + *pos;
  212. if ((state->end >= state->start && i >= state->end) ||
  213. i >= state->end + KBASE_KTRACE_SIZE)
  214. return NULL;
  215. i &= KBASE_KTRACE_MASK;
  216. return &state->trace_buf[i];
  217. }
  218. static void kbasep_ktrace_seq_stop(struct seq_file *s, void *data)
  219. {
  220. }
  221. static void *kbasep_ktrace_seq_next(struct seq_file *s, void *data, loff_t *pos)
  222. {
  223. struct trace_seq_state *state = s->private;
  224. int i;
  225. if (data != SEQ_START_TOKEN)
  226. (*pos)++;
  227. i = (state->start + *pos) & KBASE_KTRACE_MASK;
  228. if (i == state->end)
  229. return NULL;
  230. return &state->trace_buf[i];
  231. }
  232. static int kbasep_ktrace_seq_show(struct seq_file *s, void *data)
  233. {
  234. struct kbase_ktrace_msg *trace_msg = data;
  235. char buffer[KTRACE_DUMP_MESSAGE_SIZE];
  236. /* If this is the start, print a header */
  237. if (data == SEQ_START_TOKEN)
  238. kbasep_ktrace_format_header(buffer, sizeof(buffer), 0);
  239. else
  240. kbasep_ktrace_format_msg(trace_msg, buffer, sizeof(buffer));
  241. seq_printf(s, "%s\n", buffer);
  242. return 0;
  243. }
  244. static const struct seq_operations kbasep_ktrace_seq_ops = {
  245. .start = kbasep_ktrace_seq_start,
  246. .next = kbasep_ktrace_seq_next,
  247. .stop = kbasep_ktrace_seq_stop,
  248. .show = kbasep_ktrace_seq_show,
  249. };
  250. static int kbasep_ktrace_debugfs_open(struct inode *inode, struct file *file)
  251. {
  252. struct kbase_device *kbdev = inode->i_private;
  253. unsigned long flags;
  254. struct trace_seq_state *state;
  255. state = __seq_open_private(file, &kbasep_ktrace_seq_ops,
  256. sizeof(*state));
  257. if (!state)
  258. return -ENOMEM;
  259. spin_lock_irqsave(&kbdev->ktrace.lock, flags);
  260. state->start = kbdev->ktrace.first_out;
  261. state->end = kbdev->ktrace.next_in;
  262. memcpy(state->trace_buf, kbdev->ktrace.rbuf, sizeof(state->trace_buf));
  263. spin_unlock_irqrestore(&kbdev->ktrace.lock, flags);
  264. return 0;
  265. }
  266. static const struct file_operations kbasep_ktrace_debugfs_fops = {
  267. .owner = THIS_MODULE,
  268. .open = kbasep_ktrace_debugfs_open,
  269. .read = seq_read,
  270. .llseek = seq_lseek,
  271. .release = seq_release_private,
  272. };
  273. void kbase_ktrace_debugfs_init(struct kbase_device *kbdev)
  274. {
  275. debugfs_create_file("mali_trace", 0444,
  276. kbdev->mali_debugfs_directory, kbdev,
  277. &kbasep_ktrace_debugfs_fops);
  278. }
  279. #endif /* CONFIG_DEBUG_FS */
  280. #else /* KBASE_KTRACE_TARGET_RBUF */
  281. #ifdef CONFIG_DEBUG_FS
  282. void kbase_ktrace_debugfs_init(struct kbase_device *kbdev)
  283. {
  284. CSTD_UNUSED(kbdev);
  285. }
  286. #endif /* CONFIG_DEBUG_FS */
  287. #endif /* KBASE_KTRACE_TARGET_RBUF */