Commit 5d6cbeafb80c52af322a45985aa7b41f9b9ec66c

Authored by Shengjiu Wang
1 parent 7a0078775f

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;