pvr_fw_trace.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. // SPDX-License-Identifier: GPL-2.0-only OR MIT
  2. /* Copyright (c) 2023 Imagination Technologies Ltd. */
  3. #include "pvr_device.h"
  4. #include "pvr_gem.h"
  5. #include "pvr_rogue_fwif.h"
  6. #include "pvr_rogue_fwif_sf.h"
  7. #include "pvr_fw_trace.h"
  8. #include <drm/drm_drv.h>
  9. #include <drm/drm_file.h>
  10. #include <linux/build_bug.h>
  11. #include <linux/dcache.h>
  12. #include <linux/debugfs.h>
  13. #include <linux/sysfs.h>
  14. #include <linux/types.h>
  15. static void
  16. tracebuf_ctrl_init(void *cpu_ptr, void *priv)
  17. {
  18. struct rogue_fwif_tracebuf *tracebuf_ctrl = cpu_ptr;
  19. struct pvr_fw_trace *fw_trace = priv;
  20. u32 thread_nr;
  21. tracebuf_ctrl->tracebuf_size_in_dwords = ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS;
  22. tracebuf_ctrl->tracebuf_flags = 0;
  23. if (fw_trace->group_mask)
  24. tracebuf_ctrl->log_type = fw_trace->group_mask | ROGUE_FWIF_LOG_TYPE_TRACE;
  25. else
  26. tracebuf_ctrl->log_type = ROGUE_FWIF_LOG_TYPE_NONE;
  27. for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) {
  28. struct rogue_fwif_tracebuf_space *tracebuf_space =
  29. &tracebuf_ctrl->tracebuf[thread_nr];
  30. struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr];
  31. pvr_fw_object_get_fw_addr(trace_buffer->buf_obj,
  32. &tracebuf_space->trace_buffer_fw_addr);
  33. tracebuf_space->trace_buffer = trace_buffer->buf;
  34. tracebuf_space->trace_pointer = 0;
  35. }
  36. }
  37. int pvr_fw_trace_init(struct pvr_device *pvr_dev)
  38. {
  39. struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace;
  40. struct drm_device *drm_dev = from_pvr_device(pvr_dev);
  41. u32 thread_nr;
  42. int err;
  43. for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) {
  44. struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr];
  45. trace_buffer->buf =
  46. pvr_fw_object_create_and_map(pvr_dev,
  47. ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS *
  48. sizeof(*trace_buffer->buf),
  49. PVR_BO_FW_FLAGS_DEVICE_UNCACHED |
  50. PVR_BO_FW_NO_CLEAR_ON_RESET,
  51. NULL, NULL, &trace_buffer->buf_obj);
  52. if (IS_ERR(trace_buffer->buf)) {
  53. drm_err(drm_dev, "Unable to allocate trace buffer\n");
  54. err = PTR_ERR(trace_buffer->buf);
  55. trace_buffer->buf = NULL;
  56. goto err_free_buf;
  57. }
  58. }
  59. /* TODO: Provide control of group mask. */
  60. fw_trace->group_mask = 0;
  61. fw_trace->tracebuf_ctrl =
  62. pvr_fw_object_create_and_map(pvr_dev,
  63. sizeof(*fw_trace->tracebuf_ctrl),
  64. PVR_BO_FW_FLAGS_DEVICE_UNCACHED |
  65. PVR_BO_FW_NO_CLEAR_ON_RESET,
  66. tracebuf_ctrl_init, fw_trace,
  67. &fw_trace->tracebuf_ctrl_obj);
  68. if (IS_ERR(fw_trace->tracebuf_ctrl)) {
  69. drm_err(drm_dev, "Unable to allocate trace buffer control structure\n");
  70. err = PTR_ERR(fw_trace->tracebuf_ctrl);
  71. goto err_free_buf;
  72. }
  73. BUILD_BUG_ON(ARRAY_SIZE(fw_trace->tracebuf_ctrl->tracebuf) !=
  74. ARRAY_SIZE(fw_trace->buffers));
  75. for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) {
  76. struct rogue_fwif_tracebuf_space *tracebuf_space =
  77. &fw_trace->tracebuf_ctrl->tracebuf[thread_nr];
  78. struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr];
  79. trace_buffer->tracebuf_space = tracebuf_space;
  80. }
  81. return 0;
  82. err_free_buf:
  83. for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) {
  84. struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr];
  85. if (trace_buffer->buf)
  86. pvr_fw_object_unmap_and_destroy(trace_buffer->buf_obj);
  87. }
  88. return err;
  89. }
  90. void pvr_fw_trace_fini(struct pvr_device *pvr_dev)
  91. {
  92. struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace;
  93. u32 thread_nr;
  94. for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) {
  95. struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr];
  96. pvr_fw_object_unmap_and_destroy(trace_buffer->buf_obj);
  97. }
  98. pvr_fw_object_unmap_and_destroy(fw_trace->tracebuf_ctrl_obj);
  99. }
  100. #if defined(CONFIG_DEBUG_FS)
  101. /**
  102. * update_logtype() - Send KCCB command to trigger FW to update logtype
  103. * @pvr_dev: Target PowerVR device
  104. * @group_mask: New log group mask.
  105. *
  106. * Returns:
  107. * * 0 on success,
  108. * * Any error returned by pvr_kccb_send_cmd(), or
  109. * * -%EIO if the device is lost.
  110. */
  111. static int
  112. update_logtype(struct pvr_device *pvr_dev, u32 group_mask)
  113. {
  114. struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace;
  115. struct rogue_fwif_kccb_cmd cmd;
  116. int idx;
  117. int err;
  118. if (group_mask)
  119. fw_trace->tracebuf_ctrl->log_type = ROGUE_FWIF_LOG_TYPE_TRACE | group_mask;
  120. else
  121. fw_trace->tracebuf_ctrl->log_type = ROGUE_FWIF_LOG_TYPE_NONE;
  122. fw_trace->group_mask = group_mask;
  123. down_read(&pvr_dev->reset_sem);
  124. if (!drm_dev_enter(from_pvr_device(pvr_dev), &idx)) {
  125. err = -EIO;
  126. goto err_up_read;
  127. }
  128. cmd.cmd_type = ROGUE_FWIF_KCCB_CMD_LOGTYPE_UPDATE;
  129. cmd.kccb_flags = 0;
  130. err = pvr_kccb_send_cmd(pvr_dev, &cmd, NULL);
  131. drm_dev_exit(idx);
  132. err_up_read:
  133. up_read(&pvr_dev->reset_sem);
  134. return err;
  135. }
  136. struct pvr_fw_trace_seq_data {
  137. /** @buffer: Pointer to copy of trace data. */
  138. u32 *buffer;
  139. /** @start_offset: Starting offset in trace data, as reported by FW. */
  140. u32 start_offset;
  141. /** @idx: Current index into trace data. */
  142. u32 idx;
  143. /** @assert_buf: Trace assert buffer, as reported by FW. */
  144. struct rogue_fwif_file_info_buf assert_buf;
  145. };
  146. static u32 find_sfid(u32 id)
  147. {
  148. u32 i;
  149. for (i = 0; i < ARRAY_SIZE(stid_fmts); i++) {
  150. if (stid_fmts[i].id == id)
  151. return i;
  152. }
  153. return ROGUE_FW_SF_LAST;
  154. }
  155. static u32 read_fw_trace(struct pvr_fw_trace_seq_data *trace_seq_data, u32 offset)
  156. {
  157. u32 idx;
  158. idx = trace_seq_data->idx + offset;
  159. if (idx >= ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS)
  160. return 0;
  161. idx = (idx + trace_seq_data->start_offset) % ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS;
  162. return trace_seq_data->buffer[idx];
  163. }
  164. /**
  165. * fw_trace_get_next() - Advance trace index to next entry
  166. * @trace_seq_data: Trace sequence data.
  167. *
  168. * Returns:
  169. * * %true if trace index is now pointing to a valid entry, or
  170. * * %false if trace index is pointing to an invalid entry, or has hit the end
  171. * of the trace.
  172. */
  173. static bool fw_trace_get_next(struct pvr_fw_trace_seq_data *trace_seq_data)
  174. {
  175. u32 id, sf_id;
  176. while (trace_seq_data->idx < ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) {
  177. id = read_fw_trace(trace_seq_data, 0);
  178. trace_seq_data->idx++;
  179. if (!ROGUE_FW_LOG_VALIDID(id))
  180. continue;
  181. if (id == ROGUE_FW_SF_MAIN_ASSERT_FAILED) {
  182. /* Assertion failure marks the end of the trace. */
  183. return false;
  184. }
  185. sf_id = find_sfid(id);
  186. if (sf_id == ROGUE_FW_SF_FIRST)
  187. continue;
  188. if (sf_id == ROGUE_FW_SF_LAST) {
  189. /*
  190. * Could not match with an ID in the SF table, trace is
  191. * most likely corrupt from this point.
  192. */
  193. return false;
  194. }
  195. /* Skip over the timestamp, and any parameters. */
  196. trace_seq_data->idx += 2 + ROGUE_FW_SF_PARAMNUM(id);
  197. /* Ensure index is now pointing to a valid trace entry. */
  198. id = read_fw_trace(trace_seq_data, 0);
  199. if (!ROGUE_FW_LOG_VALIDID(id))
  200. continue;
  201. return true;
  202. }
  203. /* Hit end of trace data. */
  204. return false;
  205. }
  206. /**
  207. * fw_trace_get_first() - Find first valid entry in trace
  208. * @trace_seq_data: Trace sequence data.
  209. *
  210. * Skips over invalid (usually zero) and ROGUE_FW_SF_FIRST entries.
  211. *
  212. * If the trace has no valid entries, this function will exit with the trace
  213. * index pointing to the end of the trace. trace_seq_show() will return an error
  214. * in this state.
  215. */
  216. static void fw_trace_get_first(struct pvr_fw_trace_seq_data *trace_seq_data)
  217. {
  218. trace_seq_data->idx = 0;
  219. while (trace_seq_data->idx < ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) {
  220. u32 id = read_fw_trace(trace_seq_data, 0);
  221. if (ROGUE_FW_LOG_VALIDID(id)) {
  222. u32 sf_id = find_sfid(id);
  223. if (sf_id != ROGUE_FW_SF_FIRST)
  224. break;
  225. }
  226. trace_seq_data->idx++;
  227. }
  228. }
  229. static void *fw_trace_seq_start(struct seq_file *s, loff_t *pos)
  230. {
  231. struct pvr_fw_trace_seq_data *trace_seq_data = s->private;
  232. u32 i;
  233. /* Reset trace index, then advance to *pos. */
  234. fw_trace_get_first(trace_seq_data);
  235. for (i = 0; i < *pos; i++) {
  236. if (!fw_trace_get_next(trace_seq_data))
  237. return NULL;
  238. }
  239. return (trace_seq_data->idx < ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) ? pos : NULL;
  240. }
  241. static void *fw_trace_seq_next(struct seq_file *s, void *v, loff_t *pos)
  242. {
  243. struct pvr_fw_trace_seq_data *trace_seq_data = s->private;
  244. (*pos)++;
  245. if (!fw_trace_get_next(trace_seq_data))
  246. return NULL;
  247. return (trace_seq_data->idx < ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) ? pos : NULL;
  248. }
  249. static void fw_trace_seq_stop(struct seq_file *s, void *v)
  250. {
  251. }
  252. static int fw_trace_seq_show(struct seq_file *s, void *v)
  253. {
  254. struct pvr_fw_trace_seq_data *trace_seq_data = s->private;
  255. u64 timestamp;
  256. u32 id;
  257. u32 sf_id;
  258. if (trace_seq_data->idx >= ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS)
  259. return -EINVAL;
  260. id = read_fw_trace(trace_seq_data, 0);
  261. /* Index is not pointing at a valid entry. */
  262. if (!ROGUE_FW_LOG_VALIDID(id))
  263. return -EINVAL;
  264. sf_id = find_sfid(id);
  265. /* Index is not pointing at a valid entry. */
  266. if (sf_id == ROGUE_FW_SF_LAST)
  267. return -EINVAL;
  268. timestamp = ((u64)read_fw_trace(trace_seq_data, 1) << 32) |
  269. read_fw_trace(trace_seq_data, 2);
  270. timestamp = (timestamp & ~ROGUE_FWT_TIMESTAMP_TIME_CLRMSK) >>
  271. ROGUE_FWT_TIMESTAMP_TIME_SHIFT;
  272. seq_printf(s, "[%llu] : ", timestamp);
  273. if (id == ROGUE_FW_SF_MAIN_ASSERT_FAILED) {
  274. seq_printf(s, "ASSERTION %s failed at %s:%u",
  275. trace_seq_data->assert_buf.info,
  276. trace_seq_data->assert_buf.path,
  277. trace_seq_data->assert_buf.line_num);
  278. } else {
  279. seq_printf(s, stid_fmts[sf_id].name,
  280. read_fw_trace(trace_seq_data, 3),
  281. read_fw_trace(trace_seq_data, 4),
  282. read_fw_trace(trace_seq_data, 5),
  283. read_fw_trace(trace_seq_data, 6),
  284. read_fw_trace(trace_seq_data, 7),
  285. read_fw_trace(trace_seq_data, 8),
  286. read_fw_trace(trace_seq_data, 9),
  287. read_fw_trace(trace_seq_data, 10),
  288. read_fw_trace(trace_seq_data, 11),
  289. read_fw_trace(trace_seq_data, 12),
  290. read_fw_trace(trace_seq_data, 13),
  291. read_fw_trace(trace_seq_data, 14),
  292. read_fw_trace(trace_seq_data, 15),
  293. read_fw_trace(trace_seq_data, 16),
  294. read_fw_trace(trace_seq_data, 17),
  295. read_fw_trace(trace_seq_data, 18),
  296. read_fw_trace(trace_seq_data, 19),
  297. read_fw_trace(trace_seq_data, 20),
  298. read_fw_trace(trace_seq_data, 21),
  299. read_fw_trace(trace_seq_data, 22));
  300. }
  301. seq_puts(s, "\n");
  302. return 0;
  303. }
  304. static const struct seq_operations pvr_fw_trace_seq_ops = {
  305. .start = fw_trace_seq_start,
  306. .next = fw_trace_seq_next,
  307. .stop = fw_trace_seq_stop,
  308. .show = fw_trace_seq_show
  309. };
  310. static int fw_trace_open(struct inode *inode, struct file *file)
  311. {
  312. struct pvr_fw_trace_buffer *trace_buffer = inode->i_private;
  313. struct rogue_fwif_tracebuf_space *tracebuf_space =
  314. trace_buffer->tracebuf_space;
  315. struct pvr_fw_trace_seq_data *trace_seq_data;
  316. int err;
  317. trace_seq_data = kzalloc(sizeof(*trace_seq_data), GFP_KERNEL);
  318. if (!trace_seq_data)
  319. return -ENOMEM;
  320. trace_seq_data->buffer = kcalloc(ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS,
  321. sizeof(*trace_seq_data->buffer), GFP_KERNEL);
  322. if (!trace_seq_data->buffer) {
  323. err = -ENOMEM;
  324. goto err_free_data;
  325. }
  326. /*
  327. * Take a local copy of the trace buffer, as firmware may still be
  328. * writing to it. This will exist as long as this file is open.
  329. */
  330. memcpy(trace_seq_data->buffer, trace_buffer->buf,
  331. ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS * sizeof(u32));
  332. trace_seq_data->start_offset = READ_ONCE(tracebuf_space->trace_pointer);
  333. trace_seq_data->assert_buf = tracebuf_space->assert_buf;
  334. fw_trace_get_first(trace_seq_data);
  335. err = seq_open(file, &pvr_fw_trace_seq_ops);
  336. if (err)
  337. goto err_free_buffer;
  338. ((struct seq_file *)file->private_data)->private = trace_seq_data;
  339. return 0;
  340. err_free_buffer:
  341. kfree(trace_seq_data->buffer);
  342. err_free_data:
  343. kfree(trace_seq_data);
  344. return err;
  345. }
  346. static int fw_trace_release(struct inode *inode, struct file *file)
  347. {
  348. struct pvr_fw_trace_seq_data *trace_seq_data =
  349. ((struct seq_file *)file->private_data)->private;
  350. seq_release(inode, file);
  351. kfree(trace_seq_data->buffer);
  352. kfree(trace_seq_data);
  353. return 0;
  354. }
  355. static const struct file_operations pvr_fw_trace_fops = {
  356. .owner = THIS_MODULE,
  357. .open = fw_trace_open,
  358. .read = seq_read,
  359. .llseek = seq_lseek,
  360. .release = fw_trace_release,
  361. };
  362. void
  363. pvr_fw_trace_mask_update(struct pvr_device *pvr_dev, u32 old_mask, u32 new_mask)
  364. {
  365. if (old_mask != new_mask)
  366. update_logtype(pvr_dev, new_mask);
  367. }
  368. void
  369. pvr_fw_trace_debugfs_init(struct pvr_device *pvr_dev, struct dentry *dir)
  370. {
  371. struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace;
  372. u32 thread_nr;
  373. static_assert(ARRAY_SIZE(fw_trace->buffers) <= 10,
  374. "The filename buffer is only large enough for a single-digit thread count");
  375. for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); ++thread_nr) {
  376. char filename[8];
  377. snprintf(filename, ARRAY_SIZE(filename), "trace_%u", thread_nr);
  378. debugfs_create_file(filename, 0400, dir,
  379. &fw_trace->buffers[thread_nr],
  380. &pvr_fw_trace_fops);
  381. }
  382. }
  383. #endif