Skip to content

Commit 0dbb186

Browse files
Amadeusz Sławińskibroonie
authored andcommitted
ASoC: Intel: avs: Update stream status in a separate thread
Function snd_pcm_period_elapsed() is part of sequence servicing HDAudio stream IRQs. It's called under Global Interrupt Enable (GIE) disabled - no HDAudio interrupts will be raised. At the same time, the function may end up calling __snd_pcm_xrun() or snd_pcm_drain_done(). On the avs-driver side, this translates to IPCs and as GIE is disabled, these will never complete successfully. Improve system stability by scheduling stream-IRQ handling in a separate thread. Signed-off-by: Amadeusz Sławiński <[email protected]> Reviewed-by: Cezary Rojewski <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 8380dbf commit 0dbb186

File tree

3 files changed

+37
-1
lines changed

3 files changed

+37
-1
lines changed

sound/soc/intel/avs/core.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "avs.h"
2929
#include "cldma.h"
3030
#include "messages.h"
31+
#include "pcm.h"
3132

3233
static u32 pgctl_mask = AZX_PGCTL_LSRMD_MASK;
3334
module_param(pgctl_mask, uint, 0444);
@@ -247,7 +248,7 @@ static void hdac_stream_update_pos(struct hdac_stream *stream, u64 buffer_size)
247248
static void hdac_update_stream(struct hdac_bus *bus, struct hdac_stream *stream)
248249
{
249250
if (stream->substream) {
250-
snd_pcm_period_elapsed(stream->substream);
251+
avs_period_elapsed(stream->substream);
251252
} else if (stream->cstream) {
252253
u64 buffer_size = stream->cstream->runtime->buffer_size;
253254

sound/soc/intel/avs/pcm.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <sound/soc-component.h>
1717
#include "avs.h"
1818
#include "path.h"
19+
#include "pcm.h"
1920
#include "topology.h"
2021
#include "../../codecs/hda.h"
2122

@@ -30,6 +31,7 @@ struct avs_dma_data {
3031
struct hdac_ext_stream *host_stream;
3132
};
3233

34+
struct work_struct period_elapsed_work;
3335
struct snd_pcm_substream *substream;
3436
};
3537

@@ -56,6 +58,22 @@ avs_dai_find_path_template(struct snd_soc_dai *dai, bool is_fe, int direction)
5658
return dw->priv;
5759
}
5860

61+
static void avs_period_elapsed_work(struct work_struct *work)
62+
{
63+
struct avs_dma_data *data = container_of(work, struct avs_dma_data, period_elapsed_work);
64+
65+
snd_pcm_period_elapsed(data->substream);
66+
}
67+
68+
void avs_period_elapsed(struct snd_pcm_substream *substream)
69+
{
70+
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
71+
struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0);
72+
struct avs_dma_data *data = snd_soc_dai_get_dma_data(dai, substream);
73+
74+
schedule_work(&data->period_elapsed_work);
75+
}
76+
5977
static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
6078
{
6179
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
@@ -77,6 +95,7 @@ static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_d
7795
data->substream = substream;
7896
data->template = template;
7997
data->adev = adev;
98+
INIT_WORK(&data->period_elapsed_work, avs_period_elapsed_work);
8099
snd_soc_dai_set_dma_data(dai, substream, data);
81100

82101
if (rtd->dai_link->ignore_suspend)

sound/soc/intel/avs/pcm.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright(c) 2024 Intel Corporation
4+
*
5+
* Authors: Cezary Rojewski <[email protected]>
6+
* Amadeusz Slawinski <[email protected]>
7+
*/
8+
9+
#ifndef __SOUND_SOC_INTEL_AVS_PCM_H
10+
#define __SOUND_SOC_INTEL_AVS_PCM_H
11+
12+
#include <sound/pcm.h>
13+
14+
void avs_period_elapsed(struct snd_pcm_substream *substream);
15+
16+
#endif

0 commit comments

Comments
 (0)