summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormillerliang <millerliang@google.com>2023-07-10 19:48:48 +0800
committerMiller Liang <millerliang@google.com>2023-07-19 06:14:59 +0000
commit1ec0334c0041fccab7248c8c7c17e6febb48bde9 (patch)
treea486159b3453cf2d5689051ca5a62f4934056c93
parent509a9573ada096ff90812243669896902ed35523 (diff)
downloadaoc-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.h3
-rw-r--r--alsa/aoc_alsa_incall.c24
-rw-r--r--alsa/aoc_alsa_pcm.c26
-rw-r--r--alsa/aoc_alsa_voip.c22
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)) {