@@ -37,6 +37,25 @@ struct sof_ipc4_timestamp_info {
3737 snd_pcm_sframes_t delay ;
3838};
3939
40+ /**
41+ * struct sof_ipc4_pcm_stream_priv - IPC4 specific private data
42+ * @time_info: pointer to time info struct if it is supported, otherwise NULL
43+ * @chain_dma_allocated: indicates the ChainDMA allocation state
44+ */
45+ struct sof_ipc4_pcm_stream_priv {
46+ struct sof_ipc4_timestamp_info * time_info ;
47+
48+ bool chain_dma_allocated ;
49+ };
50+
51+ static inline struct sof_ipc4_timestamp_info *
52+ sof_ipc4_sps_to_time_info (struct snd_sof_pcm_stream * sps )
53+ {
54+ struct sof_ipc4_pcm_stream_priv * stream_priv = sps -> private ;
55+
56+ return stream_priv -> time_info ;
57+ }
58+
4059static int sof_ipc4_set_multi_pipeline_state (struct snd_sof_dev * sdev , u32 state ,
4160 struct ipc4_pipeline_set_state_data * trigger_list )
4261{
@@ -253,14 +272,17 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd,
253272 */
254273
255274static int sof_ipc4_chain_dma_trigger (struct snd_sof_dev * sdev ,
256- int direction ,
275+ struct snd_sof_pcm * spcm , int direction ,
257276 struct snd_sof_pcm_stream_pipeline_list * pipeline_list ,
258277 int state , int cmd )
259278{
260279 struct sof_ipc4_fw_data * ipc4_data = sdev -> private ;
280+ struct sof_ipc4_pcm_stream_priv * stream_priv ;
261281 bool allocate , enable , set_fifo_size ;
262282 struct sof_ipc4_msg msg = {{ 0 }};
263- int i ;
283+ int ret , i ;
284+
285+ stream_priv = spcm -> stream [direction ].private ;
264286
265287 switch (state ) {
266288 case SOF_IPC4_PIPE_RUNNING : /* Allocate and start chained dma */
@@ -281,6 +303,11 @@ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev,
281303 set_fifo_size = false;
282304 break ;
283305 case SOF_IPC4_PIPE_RESET : /* Disable and free chained DMA. */
306+
307+ /* ChainDMA can only be reset if it has been allocated */
308+ if (!stream_priv -> chain_dma_allocated )
309+ return 0 ;
310+
284311 allocate = false;
285312 enable = false;
286313 set_fifo_size = false;
@@ -338,7 +365,12 @@ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev,
338365 if (enable )
339366 msg .primary |= SOF_IPC4_GLB_CHAIN_DMA_ENABLE_MASK ;
340367
341- return sof_ipc_tx_message_no_reply (sdev -> ipc , & msg , 0 );
368+ ret = sof_ipc_tx_message_no_reply (sdev -> ipc , & msg , 0 );
369+ /* Update the ChainDMA allocation state */
370+ if (!ret )
371+ stream_priv -> chain_dma_allocated = allocate ;
372+
373+ return ret ;
342374}
343375
344376static int sof_ipc4_trigger_pipelines (struct snd_soc_component * component ,
@@ -378,7 +410,7 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
378410 * trigger function that handles the rest for the substream.
379411 */
380412 if (pipeline -> use_chain_dma )
381- return sof_ipc4_chain_dma_trigger (sdev , substream -> stream ,
413+ return sof_ipc4_chain_dma_trigger (sdev , spcm , substream -> stream ,
382414 pipeline_list , state , cmd );
383415
384416 /* allocate memory for the pipeline data */
@@ -452,7 +484,7 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
452484 * Invalidate the stream_start_offset to make sure that it is
453485 * going to be updated if the stream resumes
454486 */
455- time_info = spcm -> stream [substream -> stream ]. private ;
487+ time_info = sof_ipc4_sps_to_time_info ( & spcm -> stream [substream -> stream ]) ;
456488 if (time_info )
457489 time_info -> stream_start_offset = SOF_IPC4_INVALID_STREAM_POSITION ;
458490
@@ -706,12 +738,16 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
706738static void sof_ipc4_pcm_free (struct snd_sof_dev * sdev , struct snd_sof_pcm * spcm )
707739{
708740 struct snd_sof_pcm_stream_pipeline_list * pipeline_list ;
741+ struct sof_ipc4_pcm_stream_priv * stream_priv ;
709742 int stream ;
710743
711744 for_each_pcm_streams (stream ) {
712745 pipeline_list = & spcm -> stream [stream ].pipeline_list ;
713746 kfree (pipeline_list -> pipelines );
714747 pipeline_list -> pipelines = NULL ;
748+
749+ stream_priv = spcm -> stream [stream ].private ;
750+ kfree (stream_priv -> time_info );
715751 kfree (spcm -> stream [stream ].private );
716752 spcm -> stream [stream ].private = NULL ;
717753 }
@@ -721,7 +757,8 @@ static int sof_ipc4_pcm_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm
721757{
722758 struct snd_sof_pcm_stream_pipeline_list * pipeline_list ;
723759 struct sof_ipc4_fw_data * ipc4_data = sdev -> private ;
724- struct sof_ipc4_timestamp_info * stream_info ;
760+ struct sof_ipc4_pcm_stream_priv * stream_priv ;
761+ struct sof_ipc4_timestamp_info * time_info ;
725762 bool support_info = true;
726763 u32 abi_version ;
727764 u32 abi_offset ;
@@ -749,33 +786,41 @@ static int sof_ipc4_pcm_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm
749786 return - ENOMEM ;
750787 }
751788
789+ stream_priv = kzalloc (sizeof (* stream_priv ), GFP_KERNEL );
790+ if (!stream_priv ) {
791+ sof_ipc4_pcm_free (sdev , spcm );
792+ return - ENOMEM ;
793+ }
794+
795+ spcm -> stream [stream ].private = stream_priv ;
796+
752797 if (!support_info )
753798 continue ;
754799
755- stream_info = kzalloc (sizeof (* stream_info ), GFP_KERNEL );
756- if (!stream_info ) {
800+ time_info = kzalloc (sizeof (* time_info ), GFP_KERNEL );
801+ if (!time_info ) {
757802 sof_ipc4_pcm_free (sdev , spcm );
758803 return - ENOMEM ;
759804 }
760805
761- spcm -> stream [ stream ]. private = stream_info ;
806+ stream_priv -> time_info = time_info ;
762807 }
763808
764809 return 0 ;
765810}
766811
767- static void sof_ipc4_build_time_info (struct snd_sof_dev * sdev , struct snd_sof_pcm_stream * spcm )
812+ static void sof_ipc4_build_time_info (struct snd_sof_dev * sdev , struct snd_sof_pcm_stream * sps )
768813{
769814 struct sof_ipc4_copier * host_copier = NULL ;
770815 struct sof_ipc4_copier * dai_copier = NULL ;
771816 struct sof_ipc4_llp_reading_slot llp_slot ;
772- struct sof_ipc4_timestamp_info * info ;
817+ struct sof_ipc4_timestamp_info * time_info ;
773818 struct snd_soc_dapm_widget * widget ;
774819 struct snd_sof_dai * dai ;
775820 int i ;
776821
777822 /* find host & dai to locate info in memory window */
778- for_each_dapm_widgets (spcm -> list , i , widget ) {
823+ for_each_dapm_widgets (sps -> list , i , widget ) {
779824 struct snd_sof_widget * swidget = widget -> dobj .private ;
780825
781826 if (!swidget )
@@ -795,44 +840,44 @@ static void sof_ipc4_build_time_info(struct snd_sof_dev *sdev, struct snd_sof_pc
795840 return ;
796841 }
797842
798- info = spcm -> private ;
799- info -> host_copier = host_copier ;
800- info -> dai_copier = dai_copier ;
801- info -> llp_offset = offsetof(struct sof_ipc4_fw_registers , llp_gpdma_reading_slots ) +
802- sdev -> fw_info_box .offset ;
843+ time_info = sof_ipc4_sps_to_time_info ( sps ) ;
844+ time_info -> host_copier = host_copier ;
845+ time_info -> dai_copier = dai_copier ;
846+ time_info -> llp_offset = offsetof(struct sof_ipc4_fw_registers ,
847+ llp_gpdma_reading_slots ) + sdev -> fw_info_box .offset ;
803848
804849 /* find llp slot used by current dai */
805850 for (i = 0 ; i < SOF_IPC4_MAX_LLP_GPDMA_READING_SLOTS ; i ++ ) {
806- sof_mailbox_read (sdev , info -> llp_offset , & llp_slot , sizeof (llp_slot ));
851+ sof_mailbox_read (sdev , time_info -> llp_offset , & llp_slot , sizeof (llp_slot ));
807852 if (llp_slot .node_id == dai_copier -> data .gtw_cfg .node_id )
808853 break ;
809854
810- info -> llp_offset += sizeof (llp_slot );
855+ time_info -> llp_offset += sizeof (llp_slot );
811856 }
812857
813858 if (i < SOF_IPC4_MAX_LLP_GPDMA_READING_SLOTS )
814859 return ;
815860
816861 /* if no llp gpdma slot is used, check aggregated sdw slot */
817- info -> llp_offset = offsetof(struct sof_ipc4_fw_registers , llp_sndw_reading_slots ) +
818- sdev -> fw_info_box .offset ;
862+ time_info -> llp_offset = offsetof(struct sof_ipc4_fw_registers ,
863+ llp_sndw_reading_slots ) + sdev -> fw_info_box .offset ;
819864 for (i = 0 ; i < SOF_IPC4_MAX_LLP_SNDW_READING_SLOTS ; i ++ ) {
820- sof_mailbox_read (sdev , info -> llp_offset , & llp_slot , sizeof (llp_slot ));
865+ sof_mailbox_read (sdev , time_info -> llp_offset , & llp_slot , sizeof (llp_slot ));
821866 if (llp_slot .node_id == dai_copier -> data .gtw_cfg .node_id )
822867 break ;
823868
824- info -> llp_offset += sizeof (llp_slot );
869+ time_info -> llp_offset += sizeof (llp_slot );
825870 }
826871
827872 if (i < SOF_IPC4_MAX_LLP_SNDW_READING_SLOTS )
828873 return ;
829874
830875 /* check EVAD slot */
831- info -> llp_offset = offsetof(struct sof_ipc4_fw_registers , llp_evad_reading_slot ) +
832- sdev -> fw_info_box .offset ;
833- sof_mailbox_read (sdev , info -> llp_offset , & llp_slot , sizeof (llp_slot ));
876+ time_info -> llp_offset = offsetof(struct sof_ipc4_fw_registers ,
877+ llp_evad_reading_slot ) + sdev -> fw_info_box .offset ;
878+ sof_mailbox_read (sdev , time_info -> llp_offset , & llp_slot , sizeof (llp_slot ));
834879 if (llp_slot .node_id != dai_copier -> data .gtw_cfg .node_id )
835- info -> llp_offset = 0 ;
880+ time_info -> llp_offset = 0 ;
836881}
837882
838883static int sof_ipc4_pcm_hw_params (struct snd_soc_component * component ,
@@ -849,7 +894,7 @@ static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component,
849894 if (!spcm )
850895 return - EINVAL ;
851896
852- time_info = spcm -> stream [substream -> stream ]. private ;
897+ time_info = sof_ipc4_sps_to_time_info ( & spcm -> stream [substream -> stream ]) ;
853898 /* delay calculation is not supported by current fw_reg ABI */
854899 if (!time_info )
855900 return 0 ;
@@ -864,7 +909,7 @@ static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component,
864909
865910static int sof_ipc4_get_stream_start_offset (struct snd_sof_dev * sdev ,
866911 struct snd_pcm_substream * substream ,
867- struct snd_sof_pcm_stream * stream ,
912+ struct snd_sof_pcm_stream * sps ,
868913 struct sof_ipc4_timestamp_info * time_info )
869914{
870915 struct sof_ipc4_copier * host_copier = time_info -> host_copier ;
@@ -918,7 +963,7 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
918963 struct sof_ipc4_timestamp_info * time_info ;
919964 struct sof_ipc4_llp_reading_slot llp ;
920965 snd_pcm_uframes_t head_cnt , tail_cnt ;
921- struct snd_sof_pcm_stream * stream ;
966+ struct snd_sof_pcm_stream * sps ;
922967 u64 dai_cnt , host_cnt , host_ptr ;
923968 struct snd_sof_pcm * spcm ;
924969 int ret ;
@@ -927,8 +972,8 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
927972 if (!spcm )
928973 return - EOPNOTSUPP ;
929974
930- stream = & spcm -> stream [substream -> stream ];
931- time_info = stream -> private ;
975+ sps = & spcm -> stream [substream -> stream ];
976+ time_info = sof_ipc4_sps_to_time_info ( sps ) ;
932977 if (!time_info )
933978 return - EOPNOTSUPP ;
934979
@@ -938,7 +983,7 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
938983 * the statistics is complete. And it will not change after the first initiailization.
939984 */
940985 if (time_info -> stream_start_offset == SOF_IPC4_INVALID_STREAM_POSITION ) {
941- ret = sof_ipc4_get_stream_start_offset (sdev , substream , stream , time_info );
986+ ret = sof_ipc4_get_stream_start_offset (sdev , substream , sps , time_info );
942987 if (ret < 0 )
943988 return - EOPNOTSUPP ;
944989 }
@@ -1030,15 +1075,13 @@ static snd_pcm_sframes_t sof_ipc4_pcm_delay(struct snd_soc_component *component,
10301075{
10311076 struct snd_soc_pcm_runtime * rtd = snd_soc_substream_to_rtd (substream );
10321077 struct sof_ipc4_timestamp_info * time_info ;
1033- struct snd_sof_pcm_stream * stream ;
10341078 struct snd_sof_pcm * spcm ;
10351079
10361080 spcm = snd_sof_find_spcm_dai (component , rtd );
10371081 if (!spcm )
10381082 return 0 ;
10391083
1040- stream = & spcm -> stream [substream -> stream ];
1041- time_info = stream -> private ;
1084+ time_info = sof_ipc4_sps_to_time_info (& spcm -> stream [substream -> stream ]);
10421085 /*
10431086 * Report the stored delay value calculated in the pointer callback.
10441087 * In the unlikely event that the calculation was skipped/aborted, the
0 commit comments