summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormillerliang <millerliang@google.com>2023-09-06 14:50:47 +0800
committerMiller Liang <millerliang@google.com>2023-09-20 02:04:28 +0000
commit09fa9ec757b637967c9eed486274a9ba9ed8a3e9 (patch)
tree64692e5402e5dff095e4a912bb2e394d5e48ae43
parent897e404fa79ddeeb5a156f40d3bd689d33de5db7 (diff)
downloadaoc-09fa9ec757b637967c9eed486274a9ba9ed8a3e9.tar.gz
alsa: check the consumed data size in irq process functions
The ALSA pcm lib driver assumes one period data was consumed in the snd_pcm_update_hw_ptr0 function when updating the hw_ptr. Update the hw_ptr if the consumed data size is equal to or bigger than one period size. Bug: 295546940 Test: Local test Change-Id: I668c4272dbccb08fe7c46105b3c74b3a64bdd2d5 Signed-off-by: millerliang <millerliang@google.com>
-rw-r--r--alsa/aoc_alsa.h4
-rw-r--r--alsa/aoc_alsa_incall.c16
-rw-r--r--alsa/aoc_alsa_pcm.c49
-rw-r--r--alsa/aoc_alsa_voip.c17
4 files changed, 62 insertions, 24 deletions
diff --git a/alsa/aoc_alsa.h b/alsa/aoc_alsa.h
index a9c30ab..3cc3da9 100644
--- a/alsa/aoc_alsa.h
+++ b/alsa/aoc_alsa.h
@@ -305,6 +305,9 @@ struct aoc_alsa_stream {
unsigned int period_size;
unsigned int buffer_size;
unsigned int pos;
+ unsigned int prev_pos;
+ unsigned int pos_delta;
+ unsigned long prev_buffer_cnt;
unsigned long hw_ptr_base; /* read/write pointers in ring buffer */
unsigned long prev_consumed;
int n_overflow;
@@ -326,6 +329,7 @@ void aoc_timer_restart(struct aoc_alsa_stream *alsa_stream);
void aoc_timer_stop(struct aoc_alsa_stream *alsa_stream);
void aoc_timer_stop_sync(struct aoc_alsa_stream *alsa_stream);
void aoc_pcm_period_work_handler(struct work_struct *work);
+bool aoc_pcm_update_pos(struct aoc_alsa_stream *alsa_stream, unsigned long consumed);
int snd_aoc_new_ctl(struct aoc_chip *chip);
int snd_aoc_new_pcm(struct aoc_chip *chip);
diff --git a/alsa/aoc_alsa_incall.c b/alsa/aoc_alsa_incall.c
index 56a1ac7..eb8be56 100644
--- a/alsa/aoc_alsa_incall.c
+++ b/alsa/aoc_alsa_incall.c
@@ -77,14 +77,10 @@ static enum hrtimer_restart aoc_incall_hifi_irq_process(struct aoc_alsa_stream *
}
alsa_stream->prev_consumed = consumed;
- /* Update the pcm pointer */
- if (unlikely(alsa_stream->n_overflow)) {
- alsa_stream->pos = (consumed + 0x100000000 * alsa_stream->n_overflow -
- alsa_stream->hw_ptr_base) %
- alsa_stream->buffer_size;
- } else {
- alsa_stream->pos = (consumed - alsa_stream->hw_ptr_base) % alsa_stream->buffer_size;
- }
+ if (!aoc_pcm_update_pos(alsa_stream, consumed))
+ return HRTIMER_RESTART;
+
+ alsa_stream->prev_pos = alsa_stream->pos;
/* Do not queue a work if the cancel_work is active */
if (atomic_read(&alsa_stream->cancel_work_active) > 0
@@ -216,6 +212,7 @@ static int snd_aoc_pcm_open(struct snd_soc_component *component,
aoc_ring_bytes_written(dev->service, AOC_UP);
alsa_stream->prev_consumed = alsa_stream->hw_ptr_base;
alsa_stream->n_overflow = 0;
+ alsa_stream->prev_buffer_cnt = 0;
err = aoc_audio_open(alsa_stream);
if (err != 0) {
@@ -409,11 +406,14 @@ static int snd_aoc_pcm_prepare(struct snd_soc_component *component,
alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
alsa_stream->pos = 0;
+ alsa_stream->prev_pos = 0;
+ alsa_stream->pos_delta = 0;
alsa_stream->hw_ptr_base = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
aoc_ring_bytes_read(dev->service, AOC_DOWN) :
aoc_ring_bytes_written(dev->service, AOC_UP);
alsa_stream->prev_consumed = alsa_stream->hw_ptr_base;
alsa_stream->n_overflow = 0;
+ alsa_stream->prev_buffer_cnt = 0;
dev_dbg(component->dev, "pcm prepare: hw_ptr_base = %lu\n", alsa_stream->hw_ptr_base);
diff --git a/alsa/aoc_alsa_pcm.c b/alsa/aoc_alsa_pcm.c
index 1654ca0..14fbf12 100644
--- a/alsa/aoc_alsa_pcm.c
+++ b/alsa/aoc_alsa_pcm.c
@@ -133,6 +133,39 @@ void aoc_timer_stop_sync(struct aoc_alsa_stream *alsa_stream)
}
}
+bool aoc_pcm_update_pos(struct aoc_alsa_stream *alsa_stream, unsigned long consumed)
+{
+ unsigned long buffer_cnt;
+
+ /* Update the pcm pointer */
+ if (unlikely(alsa_stream->n_overflow)) {
+ alsa_stream->pos = (consumed + 0x100000000 * alsa_stream->n_overflow -
+ alsa_stream->hw_ptr_base) %
+ alsa_stream->buffer_size;
+ buffer_cnt = (consumed + 0x100000000 * alsa_stream->n_overflow -
+ alsa_stream->hw_ptr_base) / alsa_stream->buffer_size;
+ } else {
+ alsa_stream->pos = (consumed - alsa_stream->hw_ptr_base) % alsa_stream->buffer_size;
+ buffer_cnt = (consumed - alsa_stream->hw_ptr_base) / alsa_stream->buffer_size;
+ }
+
+ /* Update hw_ptr if the consumed data is equal to or bigger than one period */
+ if (buffer_cnt == alsa_stream->prev_buffer_cnt)
+ alsa_stream->pos_delta = alsa_stream->pos - alsa_stream->prev_pos;
+ else {
+ alsa_stream->pos_delta = (alsa_stream->pos + alsa_stream->buffer_size *
+ (buffer_cnt - alsa_stream->prev_buffer_cnt)) -
+ alsa_stream->prev_pos;
+ if ((buffer_cnt - alsa_stream->prev_buffer_cnt) != 1)
+ pr_warn("idx(%d): buffer_cnt %ld, prev_buffer_cnt %ld, pos_delta = %d\n",
+ alsa_stream->idx, buffer_cnt, alsa_stream->prev_buffer_cnt,
+ alsa_stream->pos_delta);
+ alsa_stream->prev_buffer_cnt = buffer_cnt;
+ }
+
+ return (alsa_stream->pos_delta >= alsa_stream->period_size) ? true : false;
+}
+
/* Hardware definition
* TODO: different pcm may have different hardware setup,
* considering deep buffer and compressed offload buffer
@@ -198,14 +231,10 @@ static enum hrtimer_restart aoc_pcm_irq_process(struct aoc_alsa_stream *alsa_str
}
alsa_stream->prev_consumed = consumed;
- /* Update the pcm pointer */
- if (unlikely(alsa_stream->n_overflow)) {
- alsa_stream->pos = (consumed + 0x100000000 * alsa_stream->n_overflow -
- alsa_stream->hw_ptr_base) %
- alsa_stream->buffer_size;
- } else {
- alsa_stream->pos = (consumed - alsa_stream->hw_ptr_base) % alsa_stream->buffer_size;
- }
+ if (!aoc_pcm_update_pos(alsa_stream, consumed))
+ return HRTIMER_RESTART;
+
+ alsa_stream->prev_pos = alsa_stream->pos;
/* Do not queue a work if the cancel_work is active */
if (atomic_read(&alsa_stream->cancel_work_active) > 0 || alsa_stream->pcm_period_wq == NULL)
@@ -343,6 +372,7 @@ static int snd_aoc_pcm_open(struct snd_soc_component *component,
aoc_ring_bytes_written(dev->service, AOC_UP);
alsa_stream->prev_consumed = alsa_stream->hw_ptr_base;
alsa_stream->n_overflow = 0;
+ alsa_stream->prev_buffer_cnt = 0;
err = aoc_audio_open(alsa_stream);
if (err != 0) {
@@ -558,11 +588,14 @@ static int snd_aoc_pcm_prepare(struct snd_soc_component *component,
alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
alsa_stream->pos = 0;
+ alsa_stream->prev_pos = 0;
+ alsa_stream->pos_delta = 0;
alsa_stream->hw_ptr_base = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
aoc_ring_bytes_read(dev->service, AOC_DOWN) :
aoc_ring_bytes_written(dev->service, AOC_UP);
alsa_stream->prev_consumed = alsa_stream->hw_ptr_base;
alsa_stream->n_overflow = 0;
+ alsa_stream->prev_buffer_cnt = 0;
pr_debug("pcm prepare: hw_ptr_base = %lu\n", alsa_stream->hw_ptr_base);
diff --git a/alsa/aoc_alsa_voip.c b/alsa/aoc_alsa_voip.c
index f6200dd..f9f85ba 100644
--- a/alsa/aoc_alsa_voip.c
+++ b/alsa/aoc_alsa_voip.c
@@ -76,14 +76,10 @@ static enum hrtimer_restart aoc_voip_irq_process(struct aoc_alsa_stream *alsa_st
}
alsa_stream->prev_consumed = consumed;
- /* Update the pcm pointer */
- if (unlikely(alsa_stream->n_overflow)) {
- alsa_stream->pos = (consumed + 0x100000000 * alsa_stream->n_overflow -
- alsa_stream->hw_ptr_base) %
- alsa_stream->buffer_size;
- } else {
- alsa_stream->pos = (consumed - alsa_stream->hw_ptr_base) % alsa_stream->buffer_size;
- }
+ if (!aoc_pcm_update_pos(alsa_stream, consumed))
+ return HRTIMER_RESTART;
+
+ alsa_stream->prev_pos = alsa_stream->pos;
/* Do not queue a work if the cancel_work is active */
if (atomic_read(&alsa_stream->cancel_work_active) > 0
@@ -212,6 +208,7 @@ static int snd_aoc_pcm_open(struct snd_soc_component *component,
aoc_ring_bytes_written(dev->service, AOC_UP);
alsa_stream->prev_consumed = alsa_stream->hw_ptr_base;
alsa_stream->n_overflow = 0;
+ alsa_stream->prev_buffer_cnt = 0;
err = aoc_audio_open(alsa_stream);
if (err != 0) {
@@ -400,11 +397,15 @@ static int snd_aoc_pcm_prepare(struct snd_soc_component *component,
alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
alsa_stream->pos = 0;
+ alsa_stream->prev_pos = 0;
+ alsa_stream->pos_delta = 0;
+
alsa_stream->hw_ptr_base = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
aoc_ring_bytes_written(dev->service, AOC_DOWN) :
aoc_ring_bytes_written(dev->service, AOC_UP);
alsa_stream->prev_consumed = alsa_stream->hw_ptr_base;
alsa_stream->n_overflow = 0;
+ alsa_stream->prev_buffer_cnt = 0;
pr_notice("Start voip call\n");
err = prepare_voipcall(alsa_stream);