Unverified Commit 0dbb186c authored by Amadeusz Sławiński's avatar Amadeusz Sławiński Committed by Mark Brown
Browse files

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: default avatarAmadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Reviewed-by: default avatarCezary Rojewski <cezary.rojewski@intel.com>
Link: https://patch.msgid.link/20241008083758.756578-1-amadeuszx.slawinski@linux.intel.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 8380dbf1
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include "avs.h"
#include "cldma.h"
#include "messages.h"
#include "pcm.h"

static u32 pgctl_mask = AZX_PGCTL_LSRMD_MASK;
module_param(pgctl_mask, uint, 0444);
@@ -247,7 +248,7 @@ static void hdac_stream_update_pos(struct hdac_stream *stream, u64 buffer_size)
static void hdac_update_stream(struct hdac_bus *bus, struct hdac_stream *stream)
{
	if (stream->substream) {
		snd_pcm_period_elapsed(stream->substream);
		avs_period_elapsed(stream->substream);
	} else if (stream->cstream) {
		u64 buffer_size = stream->cstream->runtime->buffer_size;

+19 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <sound/soc-component.h>
#include "avs.h"
#include "path.h"
#include "pcm.h"
#include "topology.h"
#include "../../codecs/hda.h"

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

	struct work_struct period_elapsed_work;
	struct snd_pcm_substream *substream;
};

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

static void avs_period_elapsed_work(struct work_struct *work)
{
	struct avs_dma_data *data = container_of(work, struct avs_dma_data, period_elapsed_work);

	snd_pcm_period_elapsed(data->substream);
}

void avs_period_elapsed(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
	struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0);
	struct avs_dma_data *data = snd_soc_dai_get_dma_data(dai, substream);

	schedule_work(&data->period_elapsed_work);
}

static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
	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
	data->substream = substream;
	data->template = template;
	data->adev = adev;
	INIT_WORK(&data->period_elapsed_work, avs_period_elapsed_work);
	snd_soc_dai_set_dma_data(dai, substream, data);

	if (rtd->dai_link->ignore_suspend)
+16 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright(c) 2024 Intel Corporation
 *
 * Authors: Cezary Rojewski <cezary.rojewski@intel.com>
 *          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
 */

#ifndef __SOUND_SOC_INTEL_AVS_PCM_H
#define __SOUND_SOC_INTEL_AVS_PCM_H

#include <sound/pcm.h>

void avs_period_elapsed(struct snd_pcm_substream *substream);

#endif