ASoC: Intel: avs: Rule invalid buffer and period sizes out

While HDAudio controller supports buffer packets up to 128 bytes low,
audio format shall be taken into consideration when calculating buffer
and period sizes to avoid undesired xruns.

As *_size in ALSA terms means frames (channels times bit-depth-bytes),
hw_rules can calculate minimal buffer and period sizes solely from
sample rate and the number of milliseconds commonly used on the
AudioDSP firmware side.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
Link: https://msgid.link/r/20240405090929.1184068-14-cezary.rojewski@intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Cezary Rojewski 2024-04-05 11:09:29 +02:00 committed by Mark Brown
parent c2b10acb62
commit 9a38599350
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0

View File

@ -457,6 +457,26 @@ static const struct snd_pcm_hw_constraint_list hw_rates = {
const struct snd_soc_dai_ops avs_dai_fe_ops;
static int hw_rule_param_size(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
{
struct snd_interval *interval = hw_param_interval(params, rule->var);
struct snd_interval to;
snd_interval_any(&to);
to.integer = interval->integer;
to.max = interval->max;
/*
* Commonly 2ms buffer size is used in HDA scenarios whereas 4ms is used
* when streaming through GPDMA. Align to the latter to account for both.
*/
to.min = params_rate(params) / 1000 * 4;
if (rule->var == SNDRV_PCM_HW_PARAM_PERIOD_SIZE)
to.min /= params_periods(params);
return snd_interval_refine(interval, &to);
}
static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@ -492,6 +512,14 @@ static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_so
if (ret < 0)
goto err;
/* Adjust buffer and period size based on the audio format. */
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, hw_rule_param_size, NULL,
SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_CHANNELS,
SNDRV_PCM_HW_PARAM_RATE, -1);
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, hw_rule_param_size, NULL,
SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_CHANNELS,
SNDRV_PCM_HW_PARAM_RATE, -1);
snd_pcm_set_sync(substream);
dev_dbg(dai->dev, "%s fe STARTUP tag %d str %p",