diff options
author | millerliang <millerliang@google.com> | 2023-07-10 19:48:48 +0800 |
---|---|---|
committer | Miller Liang <millerliang@google.com> | 2023-07-19 06:14:59 +0000 |
commit | 1ec0334c0041fccab7248c8c7c17e6febb48bde9 (patch) | |
tree | a486159b3453cf2d5689051ca5a62f4934056c93 | |
parent | 509a9573ada096ff90812243669896902ed35523 (diff) | |
download | aoc-1ec0334c0041fccab7248c8c7c17e6febb48bde9.tar.gz |
aoc/alsa: use a single workqueue to update hw_ptr
If other process blocks the cpu too long in the common work queue,
the updating hw_ptr function cannot be executed on time.
Use a single workqueue to avoid it.
Bug: 289577164
Change-Id: I48853bb94ca816d77a5f32c2a1ff0927bc2b04e2
Signed-off-by: millerliang <millerliang@google.com>
(cherry picked from commit 0e40ca7fca8a1a4a31e5f3ef74cbd0cac070a654)
-rw-r--r-- | alsa/aoc_alsa.h | 3 | ||||
-rw-r--r-- | alsa/aoc_alsa_incall.c | 24 | ||||
-rw-r--r-- | alsa/aoc_alsa_pcm.c | 26 | ||||
-rw-r--r-- | alsa/aoc_alsa_voip.c | 22 |
4 files changed, 65 insertions, 10 deletions
diff --git a/alsa/aoc_alsa.h b/alsa/aoc_alsa.h index 9ebd338..a9c30ab 100644 --- a/alsa/aoc_alsa.h +++ b/alsa/aoc_alsa.h @@ -314,6 +314,9 @@ struct aoc_alsa_stream { int wq_busy_count; struct work_struct free_aoc_service_work; + struct workqueue_struct *pcm_period_wq; + struct workqueue_struct *incall_period_wq; + struct workqueue_struct *voip_period_wq; struct work_struct pcm_period_work; }; diff --git a/alsa/aoc_alsa_incall.c b/alsa/aoc_alsa_incall.c index 72a2636..4ee2139 100644 --- a/alsa/aoc_alsa_incall.c +++ b/alsa/aoc_alsa_incall.c @@ -90,7 +90,7 @@ static enum hrtimer_restart aoc_incall_hifi_irq_process(struct aoc_alsa_stream * if (atomic_read(&alsa_stream->cancel_work_active) > 0) return HRTIMER_RESTART; - if (!queue_work(system_highpri_wq, &alsa_stream->pcm_period_work)) { + if (!queue_work(alsa_stream->incall_period_wq, &alsa_stream->pcm_period_work)) { wake_up(&alsa_stream->substream->runtime->sleep); wake_up(&alsa_stream->substream->runtime->tsleep); alsa_stream->wq_busy_count++; @@ -200,6 +200,14 @@ static int snd_aoc_pcm_open(struct snd_soc_component *component, atomic_set(&alsa_stream->cancel_work_active, 0); INIT_WORK(&alsa_stream->pcm_period_work, aoc_pcm_period_work_handler); + alsa_stream->incall_period_wq = + alloc_ordered_workqueue("alsa_incall_period_work", WQ_HIGHPRI); + if (!alsa_stream->incall_period_wq) { + err = -ENOMEM; + pr_err("ERR: fail to alloc workqueue for %s", rtd->dai_link->name); + goto out; + } + /* Ring buffer will be flushed at prepare() before playback/capture */ alsa_stream->hw_ptr_base = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? @@ -237,7 +245,14 @@ static int snd_aoc_pcm_open(struct snd_soc_component *component, return 0; out: - kfree(alsa_stream); + if (alsa_stream) { + if (alsa_stream->incall_period_wq) { + flush_workqueue(alsa_stream->incall_period_wq); + destroy_workqueue(alsa_stream->incall_period_wq); + } + kfree(alsa_stream); + } + if (dev) { free_aoc_audio_service(rtd->dai_link->name, dev); dev = NULL; @@ -262,7 +277,10 @@ static int snd_aoc_pcm_close(struct snd_soc_component *component, aoc_timer_stop_sync(alsa_stream); atomic_set(&alsa_stream->cancel_work_active, 1); audio_free_isr(alsa_stream->dev); - cancel_work_sync(&alsa_stream->pcm_period_work); + if (alsa_stream->incall_period_wq) { + flush_workqueue(alsa_stream->incall_period_wq); + destroy_workqueue(alsa_stream->incall_period_wq); + } atomic_set(&alsa_stream->cancel_work_active, 0); if (mutex_lock_interruptible(&chip->audio_mutex)) { diff --git a/alsa/aoc_alsa_pcm.c b/alsa/aoc_alsa_pcm.c index 2734651..4005fff 100644 --- a/alsa/aoc_alsa_pcm.c +++ b/alsa/aoc_alsa_pcm.c @@ -35,7 +35,10 @@ static void free_aoc_service_work_handler(struct work_struct *work) aoc_timer_stop_sync(alsa_stream); atomic_set(&alsa_stream->cancel_work_active, 1); audio_free_isr(alsa_stream->dev); - cancel_work_sync(&alsa_stream->pcm_period_work); + if (alsa_stream->pcm_period_wq) { + flush_workqueue(alsa_stream->pcm_period_wq); + destroy_workqueue(alsa_stream->pcm_period_wq); + } atomic_set(&alsa_stream->cancel_work_active, 0); if (mutex_lock_interruptible(&chip->audio_mutex)) { @@ -207,7 +210,7 @@ static enum hrtimer_restart aoc_pcm_irq_process(struct aoc_alsa_stream *alsa_str if (atomic_read(&alsa_stream->cancel_work_active) > 0) return HRTIMER_RESTART; - if (!queue_work(system_highpri_wq, &alsa_stream->pcm_period_work)) { + if (!queue_work(alsa_stream->pcm_period_wq, &alsa_stream->pcm_period_work)) { wake_up(&alsa_stream->substream->runtime->sleep); wake_up(&alsa_stream->substream->runtime->tsleep); alsa_stream->wq_busy_count++; @@ -285,6 +288,7 @@ static int snd_aoc_pcm_open(struct snd_soc_component *component, struct aoc_service_dev *dev = NULL; int idx; int err; + char wqname[33]; pr_debug("stream (%d)\n", substream->number); /* Playback or capture */ if (mutex_lock_interruptible(&chip->audio_mutex)) { @@ -314,6 +318,14 @@ static int snd_aoc_pcm_open(struct snd_soc_component *component, INIT_WORK(&alsa_stream->free_aoc_service_work, free_aoc_service_work_handler); INIT_WORK(&alsa_stream->pcm_period_work, aoc_pcm_period_work_handler); + scnprintf(wqname, sizeof(wqname), "alsa_pcm_period_work_%d", alsa_stream->idx); + alsa_stream->pcm_period_wq = + alloc_ordered_workqueue("%s", WQ_HIGHPRI, wqname); + if (!alsa_stream->pcm_period_wq) { + err = -ENOMEM; + pr_err("ERR: fail to alloc workqueue for %s", rtd->dai_link->name); + goto out; + } /* Find the corresponding aoc audio service */ err = alloc_aoc_audio_service(rtd->dai_link->name, &dev, aoc_pcm_reset_handler, @@ -371,7 +383,10 @@ out: if (alsa_stream) { cancel_work_sync(&alsa_stream->free_aoc_service_work); - cancel_work_sync(&alsa_stream->pcm_period_work); + if (alsa_stream->pcm_period_wq) { + flush_workqueue(alsa_stream->pcm_period_wq); + destroy_workqueue(alsa_stream->pcm_period_wq); + } kfree(alsa_stream); } @@ -393,7 +408,10 @@ static int snd_aoc_pcm_close(struct snd_soc_component *component, aoc_timer_stop_sync(alsa_stream); atomic_set(&alsa_stream->cancel_work_active, 1); audio_free_isr(alsa_stream->dev); - cancel_work_sync(&alsa_stream->pcm_period_work); + if (alsa_stream->pcm_period_wq) { + flush_workqueue(alsa_stream->pcm_period_wq); + destroy_workqueue(alsa_stream->pcm_period_wq); + } atomic_set(&alsa_stream->cancel_work_active, 0); if (mutex_lock_interruptible(&chip->audio_mutex)) { diff --git a/alsa/aoc_alsa_voip.c b/alsa/aoc_alsa_voip.c index cf98d16..a1cf17a 100644 --- a/alsa/aoc_alsa_voip.c +++ b/alsa/aoc_alsa_voip.c @@ -89,7 +89,7 @@ static enum hrtimer_restart aoc_voip_irq_process(struct aoc_alsa_stream *alsa_st if (atomic_read(&alsa_stream->cancel_work_active) > 0) return HRTIMER_RESTART; - if (!queue_work(system_highpri_wq, &alsa_stream->pcm_period_work)) { + if (!queue_work(alsa_stream->voip_period_wq, &alsa_stream->pcm_period_work)) { wake_up(&alsa_stream->substream->runtime->sleep); wake_up(&alsa_stream->substream->runtime->tsleep); alsa_stream->wq_busy_count++; @@ -198,6 +198,12 @@ static int snd_aoc_pcm_open(struct snd_soc_component *component, atomic_set(&alsa_stream->cancel_work_active, 0); INIT_WORK(&alsa_stream->pcm_period_work, aoc_pcm_period_work_handler); + alsa_stream->voip_period_wq = alloc_ordered_workqueue("alsa_voip_period_work", WQ_HIGHPRI); + if (!alsa_stream->voip_period_wq) { + err = -ENOMEM; + pr_err("ERR: fail to alloc workqueue for %s", rtd->dai_link->name); + goto out; + } /* Ring buffer will be flushed at prepare() before playback/capture */ alsa_stream->hw_ptr_base = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? @@ -235,7 +241,14 @@ static int snd_aoc_pcm_open(struct snd_soc_component *component, return 0; out: - kfree(alsa_stream); + if (alsa_stream) { + if (alsa_stream->voip_period_wq) { + flush_workqueue(alsa_stream->voip_period_wq); + destroy_workqueue(alsa_stream->voip_period_wq); + } + kfree(alsa_stream); + } + if (dev) { free_aoc_audio_service(rtd->dai_link->name, dev); dev = NULL; @@ -260,7 +273,10 @@ static int snd_aoc_pcm_close(struct snd_soc_component *component, aoc_timer_stop_sync(alsa_stream); atomic_set(&alsa_stream->cancel_work_active, 1); audio_free_isr(alsa_stream->dev); - cancel_work_sync(&alsa_stream->pcm_period_work); + if (alsa_stream->voip_period_wq) { + flush_workqueue(alsa_stream->voip_period_wq); + destroy_workqueue(alsa_stream->voip_period_wq); + } atomic_set(&alsa_stream->cancel_work_active, 0); if (mutex_lock_interruptible(&chip->audio_mutex)) { |