1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
3 // This file is provided under a dual BSD/GPLv2 license. When using or
4 // redistributing this file, you may do so under either license.
6 // Copyright(c) 2018 Intel Corporation. All rights reserved.
8 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
10 // Generic debug routines used to export DSP MMIO and memories to userspace
11 // for firmware debugging.
14 #include <linux/debugfs.h>
16 #include <linux/pm_runtime.h>
17 #include <sound/sof/ext_manifest.h>
18 #include <sound/sof/debug.h>
22 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
26 * strsplit_u32 - Split string into sequence of u32 tokens
27 * @buf: String to split into tokens.
28 * @delim: String containing delimiter characters.
29 * @tkns: Returned u32 sequence pointer.
30 * @num_tkns: Returned number of tokens obtained.
33 strsplit_u32(char **buf
, const char *delim
, u32
**tkns
, size_t *num_tkns
)
43 data
= kcalloc(cap
, sizeof(*data
), GFP_KERNEL
);
47 while ((s
= strsep(buf
, delim
)) != NULL
) {
48 ret
= kstrtouint(s
, 0, data
+ count
);
53 tmp
= krealloc(data
, cap
* sizeof(*data
), GFP_KERNEL
);
64 *tkns
= kmemdup(data
, count
* sizeof(*data
), GFP_KERNEL
);
76 static int tokenize_input(const char __user
*from
, size_t count
,
77 loff_t
*ppos
, u32
**tkns
, size_t *num_tkns
)
82 buf
= kmalloc(count
+ 1, GFP_KERNEL
);
86 ret
= simple_write_to_buffer(buf
, count
, ppos
, from
, count
);
88 ret
= ret
>= 0 ? -EIO
: ret
;
93 ret
= strsplit_u32((char **)&buf
, ",", tkns
, num_tkns
);
99 static ssize_t
probe_points_read(struct file
*file
,
100 char __user
*to
, size_t count
, loff_t
*ppos
)
102 struct snd_sof_dfsentry
*dfse
= file
->private_data
;
103 struct snd_sof_dev
*sdev
= dfse
->sdev
;
104 struct sof_probe_point_desc
*desc
;
105 size_t num_desc
, len
= 0;
109 if (sdev
->extractor_stream_tag
== SOF_PROBE_INVALID_NODE_ID
) {
110 dev_warn(sdev
->dev
, "no extractor stream running\n");
114 buf
= kzalloc(PAGE_SIZE
, GFP_KERNEL
);
118 ret
= sof_ipc_probe_points_info(sdev
, &desc
, &num_desc
);
122 for (i
= 0; i
< num_desc
; i
++) {
123 ret
= snprintf(buf
+ len
, PAGE_SIZE
- len
,
124 "Id: %#010x Purpose: %d Node id: %#x\n",
125 desc
[i
].buffer_id
, desc
[i
].purpose
, desc
[i
].stream_tag
);
131 ret
= simple_read_from_buffer(to
, count
, ppos
, buf
, len
);
139 static ssize_t
probe_points_write(struct file
*file
,
140 const char __user
*from
, size_t count
, loff_t
*ppos
)
142 struct snd_sof_dfsentry
*dfse
= file
->private_data
;
143 struct snd_sof_dev
*sdev
= dfse
->sdev
;
144 struct sof_probe_point_desc
*desc
;
145 size_t num_tkns
, bytes
;
149 if (sdev
->extractor_stream_tag
== SOF_PROBE_INVALID_NODE_ID
) {
150 dev_warn(sdev
->dev
, "no extractor stream running\n");
154 ret
= tokenize_input(from
, count
, ppos
, &tkns
, &num_tkns
);
157 bytes
= sizeof(*tkns
) * num_tkns
;
158 if (!num_tkns
|| (bytes
% sizeof(*desc
))) {
163 desc
= (struct sof_probe_point_desc
*)tkns
;
164 ret
= sof_ipc_probe_points_add(sdev
,
165 desc
, bytes
/ sizeof(*desc
));
173 static const struct file_operations probe_points_fops
= {
175 .read
= probe_points_read
,
176 .write
= probe_points_write
,
177 .llseek
= default_llseek
,
180 static ssize_t
probe_points_remove_write(struct file
*file
,
181 const char __user
*from
, size_t count
, loff_t
*ppos
)
183 struct snd_sof_dfsentry
*dfse
= file
->private_data
;
184 struct snd_sof_dev
*sdev
= dfse
->sdev
;
189 if (sdev
->extractor_stream_tag
== SOF_PROBE_INVALID_NODE_ID
) {
190 dev_warn(sdev
->dev
, "no extractor stream running\n");
194 ret
= tokenize_input(from
, count
, ppos
, &tkns
, &num_tkns
);
202 ret
= sof_ipc_probe_points_remove(sdev
, tkns
, num_tkns
);
210 static const struct file_operations probe_points_remove_fops
= {
212 .write
= probe_points_remove_write
,
213 .llseek
= default_llseek
,
216 static int snd_sof_debugfs_probe_item(struct snd_sof_dev
*sdev
,
217 const char *name
, mode_t mode
,
218 const struct file_operations
*fops
)
220 struct snd_sof_dfsentry
*dfse
;
222 dfse
= devm_kzalloc(sdev
->dev
, sizeof(*dfse
), GFP_KERNEL
);
226 dfse
->type
= SOF_DFSENTRY_TYPE_BUF
;
229 debugfs_create_file(name
, mode
, sdev
->debugfs_root
, dfse
, fops
);
230 /* add to dfsentry list */
231 list_add(&dfse
->list
, &sdev
->dfsentry_list
);
237 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST)
238 #define MAX_IPC_FLOOD_DURATION_MS 1000
239 #define MAX_IPC_FLOOD_COUNT 10000
240 #define IPC_FLOOD_TEST_RESULT_LEN 512
242 static int sof_debug_ipc_flood_test(struct snd_sof_dev
*sdev
,
243 struct snd_sof_dfsentry
*dfse
,
244 bool flood_duration_test
,
245 unsigned long ipc_duration_ms
,
246 unsigned long ipc_count
)
248 struct sof_ipc_cmd_hdr hdr
;
249 struct sof_ipc_reply reply
;
250 u64 min_response_time
= U64_MAX
;
251 ktime_t start
, end
, test_end
;
252 u64 avg_response_time
= 0;
253 u64 max_response_time
= 0;
254 u64 ipc_response_time
;
258 /* configure test IPC */
259 hdr
.cmd
= SOF_IPC_GLB_TEST_MSG
| SOF_IPC_TEST_IPC_FLOOD
;
260 hdr
.size
= sizeof(hdr
);
262 /* set test end time for duration flood test */
263 if (flood_duration_test
)
264 test_end
= ktime_get_ns() + ipc_duration_ms
* NSEC_PER_MSEC
;
266 /* send test IPC's */
269 ret
= sof_ipc_tx_message(sdev
->ipc
, hdr
.cmd
, &hdr
, hdr
.size
,
270 &reply
, sizeof(reply
));
276 /* compute min and max response times */
277 ipc_response_time
= ktime_to_ns(ktime_sub(end
, start
));
278 min_response_time
= min(min_response_time
, ipc_response_time
);
279 max_response_time
= max(max_response_time
, ipc_response_time
);
281 /* sum up response times */
282 avg_response_time
+= ipc_response_time
;
286 if (flood_duration_test
) {
287 if (ktime_to_ns(end
) >= test_end
)
297 "error: ipc flood test failed at %d iterations\n", i
);
299 /* return if the first IPC fails */
303 /* compute average response time */
304 do_div(avg_response_time
, i
);
306 /* clear previous test output */
307 memset(dfse
->cache_buf
, 0, IPC_FLOOD_TEST_RESULT_LEN
);
309 if (flood_duration_test
) {
310 dev_dbg(sdev
->dev
, "IPC Flood test duration: %lums\n",
312 snprintf(dfse
->cache_buf
, IPC_FLOOD_TEST_RESULT_LEN
,
313 "IPC Flood test duration: %lums\n", ipc_duration_ms
);
317 "IPC Flood count: %d, Avg response time: %lluns\n",
318 i
, avg_response_time
);
319 dev_dbg(sdev
->dev
, "Max response time: %lluns\n",
321 dev_dbg(sdev
->dev
, "Min response time: %lluns\n",
324 /* format output string */
325 snprintf(dfse
->cache_buf
+ strlen(dfse
->cache_buf
),
326 IPC_FLOOD_TEST_RESULT_LEN
- strlen(dfse
->cache_buf
),
327 "IPC Flood count: %d\nAvg response time: %lluns\n",
328 i
, avg_response_time
);
330 snprintf(dfse
->cache_buf
+ strlen(dfse
->cache_buf
),
331 IPC_FLOOD_TEST_RESULT_LEN
- strlen(dfse
->cache_buf
),
332 "Max response time: %lluns\nMin response time: %lluns\n",
333 max_response_time
, min_response_time
);
339 static ssize_t
sof_dfsentry_write(struct file
*file
, const char __user
*buffer
,
340 size_t count
, loff_t
*ppos
)
342 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST)
343 struct snd_sof_dfsentry
*dfse
= file
->private_data
;
344 struct snd_sof_dev
*sdev
= dfse
->sdev
;
345 unsigned long ipc_duration_ms
= 0;
346 bool flood_duration_test
= false;
347 unsigned long ipc_count
= 0;
348 struct dentry
*dentry
;
355 string
= kzalloc(count
, GFP_KERNEL
);
359 size
= simple_write_to_buffer(string
, count
, ppos
, buffer
, count
);
362 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST)
364 * write op is only supported for ipc_flood_count or
365 * ipc_flood_duration_ms debugfs entries atm.
366 * ipc_flood_count floods the DSP with the number of IPC's specified.
367 * ipc_duration_ms test floods the DSP for the time specified
368 * in the debugfs entry.
370 dentry
= file
->f_path
.dentry
;
371 if (strcmp(dentry
->d_name
.name
, "ipc_flood_count") &&
372 strcmp(dentry
->d_name
.name
, "ipc_flood_duration_ms")) {
377 if (!strcmp(dentry
->d_name
.name
, "ipc_flood_duration_ms"))
378 flood_duration_test
= true;
380 /* test completion criterion */
381 if (flood_duration_test
)
382 ret
= kstrtoul(string
, 0, &ipc_duration_ms
);
384 ret
= kstrtoul(string
, 0, &ipc_count
);
388 /* limit max duration/ipc count for flood test */
389 if (flood_duration_test
) {
390 if (!ipc_duration_ms
) {
395 /* find the minimum. min() is not used to avoid warnings */
396 if (ipc_duration_ms
> MAX_IPC_FLOOD_DURATION_MS
)
397 ipc_duration_ms
= MAX_IPC_FLOOD_DURATION_MS
;
404 /* find the minimum. min() is not used to avoid warnings */
405 if (ipc_count
> MAX_IPC_FLOOD_COUNT
)
406 ipc_count
= MAX_IPC_FLOOD_COUNT
;
409 ret
= pm_runtime_get_sync(sdev
->dev
);
410 if (ret
< 0 && ret
!= -EACCES
) {
411 dev_err_ratelimited(sdev
->dev
,
412 "error: debugfs write failed to resume %d\n",
414 pm_runtime_put_noidle(sdev
->dev
);
419 ret
= sof_debug_ipc_flood_test(sdev
, dfse
, flood_duration_test
,
420 ipc_duration_ms
, ipc_count
);
422 pm_runtime_mark_last_busy(sdev
->dev
);
423 err
= pm_runtime_put_autosuspend(sdev
->dev
);
425 dev_err_ratelimited(sdev
->dev
,
426 "error: debugfs write failed to idle %d\n",
429 /* return size if test is successful */
438 static ssize_t
sof_dfsentry_read(struct file
*file
, char __user
*buffer
,
439 size_t count
, loff_t
*ppos
)
441 struct snd_sof_dfsentry
*dfse
= file
->private_data
;
442 struct snd_sof_dev
*sdev
= dfse
->sdev
;
449 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST)
450 struct dentry
*dentry
;
452 dentry
= file
->f_path
.dentry
;
453 if ((!strcmp(dentry
->d_name
.name
, "ipc_flood_count") ||
454 !strcmp(dentry
->d_name
.name
, "ipc_flood_duration_ms")) &&
459 count
= strlen(dfse
->cache_buf
);
460 size_ret
= copy_to_user(buffer
, dfse
->cache_buf
, count
);
470 /* validate position & count */
473 if (pos
>= size
|| !count
)
475 /* find the minimum. min() is not used since it adds sparse warnings */
476 if (count
> size
- pos
)
479 /* align io read start to u32 multiple */
480 pos
= ALIGN_DOWN(pos
, 4);
482 /* intermediate buffer size must be u32 multiple */
483 size
= ALIGN(count
, 4);
485 /* if start position is unaligned, read extra u32 */
486 if (unlikely(pos
!= *ppos
)) {
488 if (pos
+ size
+ 4 < dfse
->size
)
492 buf
= kzalloc(size
, GFP_KERNEL
);
496 if (dfse
->type
== SOF_DFSENTRY_TYPE_IOMEM
) {
497 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
499 * If the DSP is active: copy from IO.
500 * If the DSP is suspended:
501 * - Copy from IO if the memory is always accessible.
502 * - Otherwise, copy from cached buffer.
504 if (pm_runtime_active(sdev
->dev
) ||
505 dfse
->access_type
== SOF_DEBUGFS_ACCESS_ALWAYS
) {
506 memcpy_fromio(buf
, dfse
->io_mem
+ pos
, size
);
509 "Copying cached debugfs data\n");
510 memcpy(buf
, dfse
->cache_buf
+ pos
, size
);
513 /* if the DSP is in D3 */
514 if (!pm_runtime_active(sdev
->dev
) &&
515 dfse
->access_type
== SOF_DEBUGFS_ACCESS_D0_ONLY
) {
517 "error: debugfs entry cannot be read in DSP D3\n");
522 memcpy_fromio(buf
, dfse
->io_mem
+ pos
, size
);
525 memcpy(buf
, ((u8
*)(dfse
->buf
) + pos
), size
);
528 /* copy to userspace */
529 size_ret
= copy_to_user(buffer
, buf
+ skip
, count
);
533 /* update count & position if copy succeeded */
542 static const struct file_operations sof_dfs_fops
= {
544 .read
= sof_dfsentry_read
,
545 .llseek
= default_llseek
,
546 .write
= sof_dfsentry_write
,
549 /* create FS entry for debug files that can expose DSP memories, registers */
550 int snd_sof_debugfs_io_item(struct snd_sof_dev
*sdev
,
551 void __iomem
*base
, size_t size
,
553 enum sof_debugfs_access_type access_type
)
555 struct snd_sof_dfsentry
*dfse
;
560 dfse
= devm_kzalloc(sdev
->dev
, sizeof(*dfse
), GFP_KERNEL
);
564 dfse
->type
= SOF_DFSENTRY_TYPE_IOMEM
;
568 dfse
->access_type
= access_type
;
570 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
572 * allocate cache buffer that will be used to save the mem window
573 * contents prior to suspend
575 if (access_type
== SOF_DEBUGFS_ACCESS_D0_ONLY
) {
576 dfse
->cache_buf
= devm_kzalloc(sdev
->dev
, size
, GFP_KERNEL
);
577 if (!dfse
->cache_buf
)
582 debugfs_create_file(name
, 0444, sdev
->debugfs_root
, dfse
,
585 /* add to dfsentry list */
586 list_add(&dfse
->list
, &sdev
->dfsentry_list
);
590 EXPORT_SYMBOL_GPL(snd_sof_debugfs_io_item
);
592 /* create FS entry for debug files to expose kernel memory */
593 int snd_sof_debugfs_buf_item(struct snd_sof_dev
*sdev
,
594 void *base
, size_t size
,
595 const char *name
, mode_t mode
)
597 struct snd_sof_dfsentry
*dfse
;
602 dfse
= devm_kzalloc(sdev
->dev
, sizeof(*dfse
), GFP_KERNEL
);
606 dfse
->type
= SOF_DFSENTRY_TYPE_BUF
;
611 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST)
613 * cache_buf is unused for SOF_DFSENTRY_TYPE_BUF debugfs entries.
614 * So, use it to save the results of the last IPC flood test.
616 dfse
->cache_buf
= devm_kzalloc(sdev
->dev
, IPC_FLOOD_TEST_RESULT_LEN
,
618 if (!dfse
->cache_buf
)
622 debugfs_create_file(name
, mode
, sdev
->debugfs_root
, dfse
,
624 /* add to dfsentry list */
625 list_add(&dfse
->list
, &sdev
->dfsentry_list
);
629 EXPORT_SYMBOL_GPL(snd_sof_debugfs_buf_item
);
631 static int memory_info_update(struct snd_sof_dev
*sdev
, char *buf
, size_t buff_size
)
633 struct sof_ipc_cmd_hdr msg
= {
634 .size
= sizeof(struct sof_ipc_cmd_hdr
),
635 .cmd
= SOF_IPC_GLB_DEBUG
| SOF_IPC_DEBUG_MEM_USAGE
,
637 struct sof_ipc_dbg_mem_usage
*reply
;
642 reply
= kmalloc(SOF_IPC_MSG_MAX_SIZE
, GFP_KERNEL
);
646 ret
= pm_runtime_get_sync(sdev
->dev
);
647 if (ret
< 0 && ret
!= -EACCES
) {
648 pm_runtime_put_noidle(sdev
->dev
);
649 dev_err(sdev
->dev
, "error: enabling device failed: %d\n", ret
);
653 ret
= sof_ipc_tx_message(sdev
->ipc
, msg
.cmd
, &msg
, msg
.size
, reply
, SOF_IPC_MSG_MAX_SIZE
);
654 pm_runtime_mark_last_busy(sdev
->dev
);
655 pm_runtime_put_autosuspend(sdev
->dev
);
656 if (ret
< 0 || reply
->rhdr
.error
< 0) {
657 ret
= min(ret
, reply
->rhdr
.error
);
658 dev_err(sdev
->dev
, "error: reading memory info failed, %d\n", ret
);
662 if (struct_size(reply
, elems
, reply
->num_elems
) != reply
->rhdr
.hdr
.size
) {
663 dev_err(sdev
->dev
, "error: invalid memory info ipc struct size, %d\n",
664 reply
->rhdr
.hdr
.size
);
669 for (i
= 0, len
= 0; i
< reply
->num_elems
; i
++) {
670 ret
= snprintf(buf
+ len
, buff_size
- len
, "zone %d.%d used %#8x free %#8x\n",
671 reply
->elems
[i
].zone
, reply
->elems
[i
].id
,
672 reply
->elems
[i
].used
, reply
->elems
[i
].free
);
684 static ssize_t
memory_info_read(struct file
*file
, char __user
*to
, size_t count
, loff_t
*ppos
)
686 struct snd_sof_dfsentry
*dfse
= file
->private_data
;
687 struct snd_sof_dev
*sdev
= dfse
->sdev
;
690 /* read memory info from FW only once for each file read */
692 dfse
->buf_data_size
= 0;
693 data_length
= memory_info_update(sdev
, dfse
->buf
, dfse
->size
);
696 dfse
->buf_data_size
= data_length
;
699 return simple_read_from_buffer(to
, count
, ppos
, dfse
->buf
, dfse
->buf_data_size
);
702 static int memory_info_open(struct inode
*inode
, struct file
*file
)
704 struct snd_sof_dfsentry
*dfse
= inode
->i_private
;
705 struct snd_sof_dev
*sdev
= dfse
->sdev
;
707 file
->private_data
= dfse
;
709 /* allocate buffer memory only in first open run, to save memory when unused */
711 dfse
->buf
= devm_kmalloc(sdev
->dev
, PAGE_SIZE
, GFP_KERNEL
);
714 dfse
->size
= PAGE_SIZE
;
720 static const struct file_operations memory_info_fops
= {
721 .open
= memory_info_open
,
722 .read
= memory_info_read
,
723 .llseek
= default_llseek
,
726 int snd_sof_dbg_memory_info_init(struct snd_sof_dev
*sdev
)
728 struct snd_sof_dfsentry
*dfse
;
730 dfse
= devm_kzalloc(sdev
->dev
, sizeof(*dfse
), GFP_KERNEL
);
734 /* don't allocate buffer before first usage, to save memory when unused */
735 dfse
->type
= SOF_DFSENTRY_TYPE_BUF
;
738 debugfs_create_file("memory_info", 0444, sdev
->debugfs_root
, dfse
, &memory_info_fops
);
740 /* add to dfsentry list */
741 list_add(&dfse
->list
, &sdev
->dfsentry_list
);
744 EXPORT_SYMBOL_GPL(snd_sof_dbg_memory_info_init
);
746 int snd_sof_dbg_init(struct snd_sof_dev
*sdev
)
748 const struct snd_sof_dsp_ops
*ops
= sof_ops(sdev
);
749 const struct snd_sof_debugfs_map
*map
;
753 /* use "sof" as top level debugFS dir */
754 sdev
->debugfs_root
= debugfs_create_dir("sof", NULL
);
756 /* init dfsentry list */
757 INIT_LIST_HEAD(&sdev
->dfsentry_list
);
759 /* create debugFS files for platform specific MMIO/DSP memories */
760 for (i
= 0; i
< ops
->debug_map_count
; i
++) {
761 map
= &ops
->debug_map
[i
];
763 err
= snd_sof_debugfs_io_item(sdev
, sdev
->bar
[map
->bar
] +
764 map
->offset
, map
->size
,
765 map
->name
, map
->access_type
);
766 /* errors are only due to memory allocation, not debugfs */
771 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
772 err
= snd_sof_debugfs_probe_item(sdev
, "probe_points",
773 0644, &probe_points_fops
);
776 err
= snd_sof_debugfs_probe_item(sdev
, "probe_points_remove",
777 0200, &probe_points_remove_fops
);
782 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST)
783 /* create read-write ipc_flood_count debugfs entry */
784 err
= snd_sof_debugfs_buf_item(sdev
, NULL
, 0,
785 "ipc_flood_count", 0666);
787 /* errors are only due to memory allocation, not debugfs */
791 /* create read-write ipc_flood_duration_ms debugfs entry */
792 err
= snd_sof_debugfs_buf_item(sdev
, NULL
, 0,
793 "ipc_flood_duration_ms", 0666);
795 /* errors are only due to memory allocation, not debugfs */
802 EXPORT_SYMBOL_GPL(snd_sof_dbg_init
);
804 void snd_sof_free_debug(struct snd_sof_dev
*sdev
)
806 debugfs_remove_recursive(sdev
->debugfs_root
);
808 EXPORT_SYMBOL_GPL(snd_sof_free_debug
);
810 void snd_sof_handle_fw_exception(struct snd_sof_dev
*sdev
)
812 if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT
) ||
813 (sof_core_debug
& SOF_DBG_RETAIN_CTX
)) {
814 /* should we prevent DSP entering D3 ? */
815 dev_info(sdev
->dev
, "info: preventing DSP entering D3 state to preserve context\n");
816 pm_runtime_get_noresume(sdev
->dev
);
819 /* dump vital information to the logs */
820 snd_sof_dsp_dbg_dump(sdev
, SOF_DBG_DUMP_REGS
| SOF_DBG_DUMP_MBOX
);
821 snd_sof_ipc_dump(sdev
);
822 snd_sof_trace_notify_for_error(sdev
);
824 EXPORT_SYMBOL(snd_sof_handle_fw_exception
);