Skip to content

Commit f23e8f3

Browse files
committed
ASoC: SOF: ipc4-pcm: Do not reset ChainDMA if it is
Merge series from Peter Ujfalusi <[email protected]>: The current code will reset the ChainDMA on release unconditionally which can result the following error when the CHainDMA is not allocated: ipc tx : 0xe040000|0x0: GLB_CHAIN_DMA ipc tx reply: 0x2e000007|0x0: GLB_CHAIN_DMA FW reported error: 7 - Unsupported operation requested ipc error for msg 0xe040000|0x0 sof_pcm_stream_free: pcm_ops hw_free failed -22 Background: Pulseaudio and Pipewire on startup opens all available streams and closes them without triggering a start (after probing it's capabilities).
2 parents a93830a + 7211814 commit f23e8f3

File tree

1 file changed

+79
-36
lines changed

1 file changed

+79
-36
lines changed

sound/soc/sof/ipc4-pcm.c

Lines changed: 79 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
4059
static 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

255274
static 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

344376
static 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,
706738
static 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

838883
static 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

865910
static 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

Comments
 (0)