diff options
author | Shengjiu Wang <shengjiu.wang@nxp.com> | 2019-04-14 10:55:34 +0800 |
---|---|---|
committer | Shengjiu Wang <shengjiu.wang@nxp.com> | 2019-04-14 16:22:17 +0800 |
commit | 3dfecae40765329c0b7de1157f97ade24ecfce6d (patch) | |
tree | 1c03a1f51ceb45f1f34ae7f7b5d9563692d42edf /sound | |
parent | c2bc1f62ec28981462c9cb5ceac17134931ca19f (diff) |
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>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/fsl/fsl_rpmsg_i2s.c | 9 | ||||
-rw-r--r-- | sound/soc/fsl/imx-pcm-rpmsg.c | 25 |
2 files changed, 33 insertions, 1 deletions
diff --git a/sound/soc/fsl/fsl_rpmsg_i2s.c b/sound/soc/fsl/fsl_rpmsg_i2s.c index f43890a364cd..5a82340c2d6d 100644 --- a/sound/soc/fsl/fsl_rpmsg_i2s.c +++ b/sound/soc/fsl/fsl_rpmsg_i2s.c @@ -144,6 +144,7 @@ static void rpmsg_i2s_work(struct work_struct *work) { struct work_of_rpmsg *work_of_rpmsg; struct i2s_info *i2s_info; + bool is_period_done = false; work_of_rpmsg = container_of(work, struct work_of_rpmsg, work); i2s_info = work_of_rpmsg->i2s_info; @@ -158,7 +159,13 @@ static void rpmsg_i2s_work(struct work_struct *work) i2s_info->period_done_msg_enabled[1] = false; } - i2s_send_message(&work_of_rpmsg->msg, i2s_info); + if (work_of_rpmsg->msg.send_msg.header.type == I2S_TYPE_C && + (work_of_rpmsg->msg.send_msg.header.cmd == I2S_TX_PERIOD_DONE || + work_of_rpmsg->msg.send_msg.header.cmd == I2S_RX_PERIOD_DONE)) + is_period_done = true; + + if (!is_period_done) + i2s_send_message(&work_of_rpmsg->msg, i2s_info); i2s_info->work_read_index++; i2s_info->work_read_index %= WORK_MAX_NUM; diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c index 2a89f9371edb..39b9b62e8303 100644 --- a/sound/soc/fsl/imx-pcm-rpmsg.c +++ b/sound/soc/fsl/imx-pcm-rpmsg.c @@ -577,7 +577,10 @@ int imx_rpmsg_pcm_ack(struct snd_pcm_substream *substream) struct fsl_rpmsg_i2s *rpmsg_i2s = dev_get_drvdata(cpu_dai->dev); struct i2s_info *i2s_info = &rpmsg_i2s->i2s_info; struct i2s_rpmsg *rpmsg; + int index = i2s_info->work_write_index; int buffer_tail = 0; + int writen_num = 0; + snd_pcm_sframes_t avail; if (!rpmsg_i2s->force_lpa) return 0; @@ -599,10 +602,32 @@ int imx_rpmsg_pcm_ack(struct snd_pcm_substream *substream) buffer_tail = buffer_tail / snd_pcm_lib_period_bytes(substream); if (buffer_tail != rpmsg->send_msg.param.buffer_tail) { + writen_num = buffer_tail - rpmsg->send_msg.param.buffer_tail; + if (writen_num < 0) + writen_num += runtime->periods; + rpmsg->send_msg.param.buffer_tail = buffer_tail; memcpy(&i2s_info->period_done_msg[substream->stream], rpmsg, sizeof(struct i2s_rpmsg_s)); i2s_info->period_done_msg_enabled[substream->stream] = true; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + avail = snd_pcm_playback_hw_avail(runtime); + else + avail = snd_pcm_capture_hw_avail(runtime); + + if ((avail - writen_num * runtime->period_size) + <= runtime->period_size) { + if (i2s_info->work_write_index != i2s_info->work_read_index) { + memcpy(&i2s_info->work_list[index].msg, rpmsg, + sizeof(struct i2s_rpmsg_s)); + queue_work(i2s_info->rpmsg_wq, + &i2s_info->work_list[index].work); + i2s_info->work_write_index++; + i2s_info->work_write_index %= WORK_MAX_NUM; + } else + i2s_info->msg_drop_count[substream->stream]++; + } } return 0; |