Commit 5d6cbeafb80c52af322a45985aa7b41f9b9ec66c
1 parent
7a0078775f
Exists in
smarc_8mm_imx_4.14.98_2.0.0_ga
and in
4 other branches
MLK-21447: ASoC: fsl_rpmsg_i2s: underrun in m4 for msg delayed
With small buffer size, the resume will be triggered after suspend immediately, if we reserve the period done message to be sent with the next command, one period time later, it will cause underrun in m4 side, for ALSA thought the appl_ptr is updated, but the command won't be sent to M4 immediately, M4 don't have enough data to play. In this patch, we check that if the left size in the buffer is less that one period, the work queue will be triggered to send the period done message immediately. Fixes: 348d47695622 ("MLK-21307: ASoC: fsl_rpmsg_i2s: optimize the message sent to m4") Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com> (cherry picked from commit 3dfecae40765329c0b7de1157f97ade24ecfce6d)
Showing 2 changed files with 33 additions and 1 deletions Side-by-side Diff
sound/soc/fsl/fsl_rpmsg_i2s.c
... | ... | @@ -144,6 +144,7 @@ |
144 | 144 | { |
145 | 145 | struct work_of_rpmsg *work_of_rpmsg; |
146 | 146 | struct i2s_info *i2s_info; |
147 | + bool is_period_done = false; | |
147 | 148 | |
148 | 149 | work_of_rpmsg = container_of(work, struct work_of_rpmsg, work); |
149 | 150 | i2s_info = work_of_rpmsg->i2s_info; |
... | ... | @@ -158,7 +159,13 @@ |
158 | 159 | i2s_info->period_done_msg_enabled[1] = false; |
159 | 160 | } |
160 | 161 | |
161 | - i2s_send_message(&work_of_rpmsg->msg, i2s_info); | |
162 | + if (work_of_rpmsg->msg.send_msg.header.type == I2S_TYPE_C && | |
163 | + (work_of_rpmsg->msg.send_msg.header.cmd == I2S_TX_PERIOD_DONE || | |
164 | + work_of_rpmsg->msg.send_msg.header.cmd == I2S_RX_PERIOD_DONE)) | |
165 | + is_period_done = true; | |
166 | + | |
167 | + if (!is_period_done) | |
168 | + i2s_send_message(&work_of_rpmsg->msg, i2s_info); | |
162 | 169 | |
163 | 170 | i2s_info->work_read_index++; |
164 | 171 | i2s_info->work_read_index %= WORK_MAX_NUM; |
sound/soc/fsl/imx-pcm-rpmsg.c
... | ... | @@ -577,7 +577,10 @@ |
577 | 577 | struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(cpu_dai->dev); |
578 | 578 | struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info; |
579 | 579 | struct i2s_rpmsg *rpmsg; |
580 | + int index = i2s_info->work_write_index; | |
580 | 581 | int buffer_tail = 0; |
582 | + int writen_num = 0; | |
583 | + snd_pcm_sframes_t avail; | |
581 | 584 | |
582 | 585 | if (!rpmsg_i2s->force_lpa) |
583 | 586 | return 0; |
584 | 587 | |
... | ... | @@ -599,10 +602,32 @@ |
599 | 602 | buffer_tail = buffer_tail / snd_pcm_lib_period_bytes(substream); |
600 | 603 | |
601 | 604 | if (buffer_tail != rpmsg->send_msg.param.buffer_tail) { |
605 | + writen_num = buffer_tail - rpmsg->send_msg.param.buffer_tail; | |
606 | + if (writen_num < 0) | |
607 | + writen_num += runtime->periods; | |
608 | + | |
602 | 609 | rpmsg->send_msg.param.buffer_tail = buffer_tail; |
603 | 610 | memcpy(&i2s_info->period_done_msg[substream->stream], rpmsg, |
604 | 611 | sizeof(struct i2s_rpmsg_s)); |
605 | 612 | i2s_info->period_done_msg_enabled[substream->stream] = true; |
613 | + | |
614 | + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | |
615 | + avail = snd_pcm_playback_hw_avail(runtime); | |
616 | + else | |
617 | + avail = snd_pcm_capture_hw_avail(runtime); | |
618 | + | |
619 | + if ((avail - writen_num * runtime->period_size) | |
620 | + <= runtime->period_size) { | |
621 | + if (i2s_info->work_write_index != i2s_info->work_read_index) { | |
622 | + memcpy(&i2s_info->work_list[index].msg, rpmsg, | |
623 | + sizeof(struct i2s_rpmsg_s)); | |
624 | + queue_work(i2s_info->rpmsg_wq, | |
625 | + &i2s_info->work_list[index].work); | |
626 | + i2s_info->work_write_index++; | |
627 | + i2s_info->work_write_index %= WORK_MAX_NUM; | |
628 | + } else | |
629 | + i2s_info->msg_drop_count[substream->stream]++; | |
630 | + } | |
606 | 631 | } |
607 | 632 | |
608 | 633 | return 0; |