1414#include <linux/debugfs.h>
1515#include <linux/io.h>
1616#include <linux/pm_runtime.h>
17+ #include <sound/sof/ext_manifest.h>
18+ #include <sound/sof/debug.h>
1719#include "sof-priv.h"
1820#include "ops.h"
1921
@@ -626,10 +628,120 @@ int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev,
626628}
627629EXPORT_SYMBOL_GPL (snd_sof_debugfs_buf_item );
628630
631+ static int memory_info_update (struct snd_sof_dev * sdev , char * buf , size_t buff_size )
632+ {
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 ,
636+ };
637+ struct sof_ipc_dbg_mem_usage * reply ;
638+ int len ;
639+ int ret ;
640+ int i ;
641+
642+ reply = kmalloc (SOF_IPC_MSG_MAX_SIZE , GFP_KERNEL );
643+ if (!reply )
644+ return - ENOMEM ;
645+
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 );
650+ goto error ;
651+ }
652+
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 );
659+ goto error ;
660+ }
661+
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 );
665+ ret = - EINVAL ;
666+ goto error ;
667+ }
668+
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 );
673+ if (ret < 0 )
674+ goto error ;
675+ len += ret ;
676+ }
677+
678+ return len ;
679+ error :
680+ kfree (reply );
681+ return ret ;
682+ }
683+
684+ static ssize_t memory_info_read (struct file * file , char __user * to , size_t count , loff_t * ppos )
685+ {
686+ struct snd_sof_dfsentry * dfse = file -> private_data ;
687+ struct snd_sof_dev * sdev = dfse -> sdev ;
688+ int data_length ;
689+
690+ /* allocate buffer memory only in first function run, to save memory when unused */
691+ if (!dfse -> buf ) {
692+ dfse -> size = PAGE_SIZE ;
693+ dfse -> buf = devm_kmalloc (sdev -> dev , dfse -> size , GFP_KERNEL );
694+ if (!dfse -> buf ) {
695+ dfse -> size = 0 ;
696+ return - ENOMEM ;
697+ }
698+ }
699+
700+ /* read memory info from FW only once for each file read */
701+ if (!* ppos ) {
702+ dfse -> buf_data_size = 0 ;
703+ data_length = memory_info_update (sdev , dfse -> buf , dfse -> size );
704+ if (data_length < 0 )
705+ return data_length ;
706+ dfse -> buf_data_size = data_length ;
707+ }
708+
709+ return simple_read_from_buffer (to , count , ppos , dfse -> buf , dfse -> buf_data_size );
710+ }
711+
712+ static const struct file_operations memory_info_fops = {
713+ .open = simple_open ,
714+ .read = memory_info_read ,
715+ .llseek = default_llseek ,
716+ };
717+
718+ static int snd_sof_dbg_memory_info_init (struct snd_sof_dev * sdev )
719+ {
720+ struct snd_sof_dfsentry * dfse ;
721+
722+ dfse = devm_kzalloc (sdev -> dev , sizeof (* dfse ), GFP_KERNEL );
723+ if (!dfse )
724+ goto error ;
725+
726+ /* don't allocate buffer before first usage, to save memory when unused */
727+ dfse -> type = SOF_DFSENTRY_TYPE_BUF ;
728+ dfse -> sdev = sdev ;
729+
730+ debugfs_create_file ("memory_info" , 0444 , sdev -> debugfs_root , dfse , & memory_info_fops );
731+
732+ /* add to dfsentry list */
733+ list_add (& dfse -> list , & sdev -> dfsentry_list );
734+ return 0 ;
735+ error :
736+ kfree (dfse );
737+ return - ENOMEM ;
738+ }
739+
629740int snd_sof_dbg_init (struct snd_sof_dev * sdev )
630741{
631742 const struct snd_sof_dsp_ops * ops = sof_ops (sdev );
632743 const struct snd_sof_debugfs_map * map ;
744+ uint32_t memory_scan_en ;
633745 int i ;
634746 int err ;
635747
@@ -651,6 +763,14 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev)
651763 return err ;
652764 }
653765
766+ /* create read-only memory_info debugfs entry */
767+ err = snd_sof_get_config_value (sdev , EXT_MAN_CONFIG_MEMORY_USAGE_SCAN , & memory_scan_en );
768+ if (!err && memory_scan_en ) {
769+ err = snd_sof_dbg_memory_info_init (sdev );
770+ if (err < 0 )
771+ return err ;
772+ }
773+
654774#if IS_ENABLED (CONFIG_SND_SOC_SOF_DEBUG_PROBES )
655775 err = snd_sof_debugfs_probe_item (sdev , "probe_points" ,
656776 0644 , & probe_points_fops );
0 commit comments