diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 5fa8c40de5d9a1..fc487d8dcdac8b 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -696,6 +696,12 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) mutex_init(&sdev->client_event_handler_mutex); mutex_init(&sdev->dsp_fw_boot_mutex); + /* Create high-priority workqueue for PCM period elapsed work */ + sdev->pcm_period_wq = alloc_workqueue("sof_pcm_wq", WQ_HIGHPRI | WQ_UNBOUND, 0); + if (!sdev->pcm_period_wq) { + dev_err(dev, "error: failed to create sof_pcm_wq\n"); + } + /* set default timeouts if none provided */ if (plat_data->desc->ipc_timeout == 0) sdev->ipc_timeout = TIMEOUT_DEFAULT_IPC_MS; @@ -797,6 +803,12 @@ int snd_sof_device_remove(struct device *dev) /* release firmware */ snd_sof_fw_unload(sdev); + /* Destroy the PCM workqueue */ + if (sdev->pcm_period_wq) { + destroy_workqueue(sdev->pcm_period_wq); + sdev->pcm_period_wq = NULL; + } + return 0; } EXPORT_SYMBOL(snd_sof_device_remove); diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index b2071edeaea62e..f34b2919711f68 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -45,6 +45,7 @@ void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; spcm = snd_sof_find_spcm_dai(component, rtd); @@ -62,7 +63,12 @@ void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream) * To avoid sending IPC before the previous IPC is handled, we * schedule delayed work here to call the snd_pcm_period_elapsed(). */ - schedule_work(&spcm->stream[substream->stream].period_elapsed_work); + if (sdev->pcm_period_wq) { + queue_work(sdev->pcm_period_wq, &spcm->stream[substream->stream].period_elapsed_work); + } else { + // Fallback to system workqueue + schedule_work(&spcm->stream[substream->stream].period_elapsed_work); + } } EXPORT_SYMBOL(snd_sof_pcm_period_elapsed); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 3b6ec134d37988..49e7489820b1a8 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -701,6 +701,8 @@ struct snd_sof_dev { /* used to store the FW filename and path passed from userspace for DSP ops testing */ struct sof_loadable_file_profile test_profile; + struct workqueue_struct *pcm_period_wq; /* WQ for PCM period elapsed */ + void *private; /* core does not touch this */ };