Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions sound/soc/sof/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you describe how this can happen?
If the system workqueue is that much congested then how can anything work?

We use threaded irq as well and that is also using system queue afaik, I'm not sure how this helps.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "congestion" we observed is relative to audio's strict timing requirements. Most system tasks handled by the system workqueue (e.g., input events, network stack processing, or disk I/O) are relatively tolerant of latencies in the range of 20-50ms. However, audio streams with small periods (e.g., 10ms in SOF) are extremely sensitive to such delays.

In our traces, we found that under heavy load (e.g., stressapptest), the kworker thread responsible for snd_sof_pcm_period_elapsed_work was delayed by 25ms to 100ms because it was competing with other SCHED_OTHER tasks at the same priority (120/nice 0). While the rest of the system remains functional, this delay is enough to cause audio underruns, especially for applications using the poll/pcm_wait mechanism.

Not sure which threaded IRQs you mentioned. I think standard threaded IRQs (created via request_threaded_irq) are typically handled by dedicated kernel threads (irq/N-name) that run with SCHED_FIFO (real-time) priority. They do not use the shared system_wq and are therefore protected from this type of congestion.

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;
Expand Down Expand Up @@ -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);
Expand Down
8 changes: 7 additions & 1 deletion sound/soc/sof/pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);

Expand Down
2 changes: 2 additions & 0 deletions sound/soc/sof/sof-priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
};

Expand Down
Loading