1414#include <linux/debugfs.h>
1515#include <linux/io.h>
1616#include <linux/pm_runtime.h>
17+ #include <sound/sof/debug.h>
1718#include "sof-priv.h"
1819#include "ops.h"
1920
@@ -626,6 +627,118 @@ int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev,
626627}
627628EXPORT_SYMBOL_GPL (snd_sof_debugfs_buf_item );
628629
630+ static int memory_info_update (struct snd_sof_dev * sdev , char * buf , size_t buff_size )
631+ {
632+ struct sof_ipc_cmd_hdr msg = {
633+ .size = sizeof (struct sof_ipc_cmd_hdr ),
634+ .cmd = SOF_IPC_GLB_DEBUG | SOF_IPC_DEBUG_MEM_USAGE ,
635+ };
636+ struct sof_ipc_dbg_mem_usage * reply ;
637+ int len = 0 ;
638+ int ret ;
639+ int i ;
640+
641+ reply = kmalloc (SOF_IPC_MSG_MAX_SIZE , GFP_KERNEL );
642+ if (!reply )
643+ return - ENOMEM ;
644+
645+ ret = pm_runtime_get_sync (sdev -> dev );
646+ if (ret < 0 && ret != - EACCES ) {
647+ pm_runtime_put_noidle (sdev -> dev );
648+ dev_err (sdev -> dev , "error: enabling device failed: %d\n" , ret );
649+ goto error ;
650+ }
651+
652+ ret = sof_ipc_tx_message (sdev -> ipc , msg .cmd , & msg , msg .size , reply , SOF_IPC_MSG_MAX_SIZE );
653+ pm_runtime_mark_last_busy (sdev -> dev );
654+ pm_runtime_put_autosuspend (sdev -> dev );
655+ if (ret < 0 || reply -> rhdr .error < 0 ) {
656+ ret = min (ret , reply -> rhdr .error );
657+ dev_err (sdev -> dev , "error: reading memory info failed, %d\n" , ret );
658+ goto error ;
659+ }
660+
661+ if (struct_size (reply , elems , reply -> num_elems ) != reply -> rhdr .hdr .size ) {
662+ dev_err (sdev -> dev , "error: invalid memory info ipc struct size, %d\n" ,
663+ reply -> rhdr .hdr .size );
664+ ret = - EINVAL ;
665+ goto error ;
666+ }
667+
668+ for (i = 0 ; i < reply -> num_elems ; i ++ ) {
669+ ret = snprintf (buf + len , buff_size - len , "zone %d.%d used %#8x free %#8x\n" ,
670+ reply -> elems [i ].zone , reply -> elems [i ].id ,
671+ reply -> elems [i ].used , reply -> elems [i ].free );
672+ if (ret < 0 )
673+ goto error ;
674+ len += ret ;
675+ }
676+
677+ return len ;
678+ error :
679+ kfree (reply );
680+ return ret ;
681+ }
682+
683+ static ssize_t memory_info_read (struct file * file , char __user * to , size_t count , loff_t * ppos )
684+ {
685+ struct snd_sof_dfsentry * dfse = file -> private_data ;
686+ struct snd_sof_dev * sdev = dfse -> sdev ;
687+ int ret ;
688+
689+ /* allocate buffer memory only in first function run */
690+ if (!sdev -> memory_info_buf ) {
691+ sdev -> memory_info_buf = devm_kmalloc (sdev -> dev , dfse -> size , GFP_KERNEL );
692+ if (!sdev -> memory_info_buf )
693+ return - ENOMEM ;
694+ }
695+
696+ /* read memory info from FW only once for each file read */
697+ if (!* ppos ) {
698+ sdev -> memory_info_len = memory_info_update (sdev , sdev -> memory_info_buf , dfse -> size );
699+ if (sdev -> memory_info_len < 0 )
700+ return sdev -> memory_info_len ;
701+ }
702+
703+ ret = simple_read_from_buffer (to , count , ppos , sdev -> memory_info_buf ,
704+ sdev -> memory_info_len );
705+
706+ return ret ;
707+ }
708+
709+ static const struct file_operations memory_info_fops = {
710+ .open = simple_open ,
711+ .read = memory_info_read ,
712+ .llseek = default_llseek ,
713+ };
714+
715+ int snd_sof_dbg_memory_info_init (struct snd_sof_dev * sdev )
716+ {
717+ struct snd_sof_dfsentry * dfse ;
718+ size_t size = 512 ;
719+
720+ dfse = devm_kzalloc (sdev -> dev , sizeof (* dfse ), GFP_KERNEL );
721+ if (!dfse )
722+ goto error ;
723+
724+ dfse -> type = SOF_DFSENTRY_TYPE_BUF ;
725+ dfse -> sdev = sdev ;
726+
727+ dfse -> size = size ;
728+ dfse -> buf = devm_kmalloc (sdev -> dev , size , GFP_KERNEL );
729+ if (!dfse -> buf )
730+ goto error ;
731+
732+ debugfs_create_file ("memory_info" , 0444 , sdev -> debugfs_root , dfse , & memory_info_fops );
733+
734+ /* add to dfsentry list */
735+ list_add (& dfse -> list , & sdev -> dfsentry_list );
736+ return 0 ;
737+ error :
738+ kfree (dfse );
739+ return - ENOMEM ;
740+ }
741+
629742int snd_sof_dbg_init (struct snd_sof_dev * sdev )
630743{
631744 const struct snd_sof_dsp_ops * ops = sof_ops (sdev );
@@ -651,6 +764,11 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev)
651764 return err ;
652765 }
653766
767+ /* create read-only memory_info debugfs entry */
768+ err = snd_sof_dbg_memory_info_init (sdev );
769+ if (err < 0 )
770+ return err ;
771+
654772#if IS_ENABLED (CONFIG_SND_SOC_SOF_DEBUG_PROBES )
655773 err = snd_sof_debugfs_probe_item (sdev , "probe_points" ,
656774 0644 , & probe_points_fops );
0 commit comments