Split be_hw_params_fixup function for different codecs as current common
function, leads to crash while trying to get snd_soc_dpcm with
container_of() macro in kabylake_ssp_fixup().
The crash call path looks as below:
soc_pcm_hw_params()
snd_soc_dai_hw_params(codec_dai, substream, &codec_params);
rtd->dai_link->be_hw_params_fixup(rtd, params)
kabylake_ssp_fixup()
In this case, codec_params is just a copy of an internal structure and is
not embedded into struct snd_soc_dpcm thus we cannot use
container_of() on it.
Signed-off-by: Lukasz Majczak <[email protected]>
---
.../intel/boards/kbl_rt5663_rt5514_max98927.c | 68 +++++++++++--------
1 file changed, 39 insertions(+), 29 deletions(-)
diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
index 1b1f8d7a4ea3..2e0ae724122c 100644
--- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
@@ -328,46 +328,55 @@ static const struct snd_soc_ops kabylake_rt5663_fe_ops = {
.startup = kbl_fe_startup,
};
-static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_hw_params *params)
+static void kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params, snd_pcm_format_t pcm_fmt)
{
struct snd_interval *rate = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *chan = hw_param_interval(params,
+ struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
- struct snd_soc_dpcm *dpcm = container_of(
- params, struct snd_soc_dpcm, hw_params);
- struct snd_soc_dai_link *fe_dai_link = dpcm->fe->dai_link;
- struct snd_soc_dai_link *be_dai_link = dpcm->be->dai_link;
/*
* The ADSP will convert the FE rate to 48k, stereo, 24 bit
*/
- if (!strcmp(fe_dai_link->name, "Kbl Audio Port") ||
- !strcmp(fe_dai_link->name, "Kbl Audio Headset Playback") ||
- !strcmp(fe_dai_link->name, "Kbl Audio Capture Port")) {
- rate->min = rate->max = 48000;
- chan->min = chan->max = 2;
- snd_mask_none(fmt);
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
- } else if (!strcmp(fe_dai_link->name, "Kbl Audio DMIC cap")) {
- if (params_channels(params) == 2 ||
- DMIC_CH(dmic_constraints) == 2)
- chan->min = chan->max = 2;
- else
- chan->min = chan->max = 4;
- }
- /*
- * The speaker on the SSP0 supports S16_LE and not S24_LE.
- * thus changing the mask here
- */
- if (!strcmp(be_dai_link->name, "SSP0-Codec"))
- snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, pcm_fmt);
+}
+
+static int kabylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ kabylake_ssp_fixup(rtd, params, SNDRV_PCM_FORMAT_S16_LE);
return 0;
}
+static int kabylake_ssp1_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+
+ kabylake_ssp_fixup(rtd, params, SNDRV_PCM_FORMAT_S24_LE);
+ return 0;
+}
+
+static int kabylake_dmic_cap_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ if (params_channels(params) == 2 ||
+ DMIC_CH(dmic_constraints) == 2)
+ channels->min = channels->max = 2;
+ else
+ channels->min = channels->max = 4;
+
+ return 0;
+}
static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -582,6 +591,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
.dpcm_capture = 1,
.nonatomic = 1,
.dynamic = 1,
+ .be_hw_params_fixup = kabylake_dmic_cap_fixup,
.ops = &kabylake_dmic_ops,
SND_SOC_DAILINK_REG(dmic, dummy, platform),
},
@@ -618,7 +628,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
.ignore_pmdown_time = 1,
- .be_hw_params_fixup = kabylake_ssp_fixup,
+ .be_hw_params_fixup = kabylake_ssp0_fixup,
.dpcm_playback = 1,
.dpcm_capture = 1,
.ops = &kabylake_ssp0_ops,
@@ -632,7 +642,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
.ignore_pmdown_time = 1,
- .be_hw_params_fixup = kabylake_ssp_fixup,
+ .be_hw_params_fixup = kabylake_ssp1_fixup,
.ops = &kabylake_rt5663_ops,
.dpcm_playback = 1,
.dpcm_capture = 1,
--
2.25.1
On 5/13/20 2:20 PM, Lukasz Majczak wrote:
> Split be_hw_params_fixup function for different codecs as current common
> function, leads to crash while trying to get snd_soc_dpcm with
> container_of() macro in kabylake_ssp_fixup().
> The crash call path looks as below:
> soc_pcm_hw_params()
> snd_soc_dai_hw_params(codec_dai, substream, &codec_params);
> rtd->dai_link->be_hw_params_fixup(rtd, params)
> kabylake_ssp_fixup()
> In this case, codec_params is just a copy of an internal structure and is
> not embedded into struct snd_soc_dpcm thus we cannot use
> container_of() on it.
This looks like a nice/welcome change, we've had these unexplained
crashes on KBL since 4.19 (reported by Guenter and me). I thought they
were topology related.
If indeed this fixes the issue, it might be worth applying in to all
stable releases?
Since we have the same code structure for the other kbl drivers, would
it also make sense to apply the same fixes there:
kbl_da7219_max98927.c: struct snd_soc_dpcm *dpcm = container_of(
kbl_rt5663_max98927.c: struct snd_soc_dpcm *dpcm = container_of(
>
> Signed-off-by: Lukasz Majczak <[email protected]>
> ---
> .../intel/boards/kbl_rt5663_rt5514_max98927.c | 68 +++++++++++--------
> 1 file changed, 39 insertions(+), 29 deletions(-)
>
> diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
> index 1b1f8d7a4ea3..2e0ae724122c 100644
> --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
> +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
> @@ -328,46 +328,55 @@ static const struct snd_soc_ops kabylake_rt5663_fe_ops = {
> .startup = kbl_fe_startup,
> };
>
> -static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
> - struct snd_pcm_hw_params *params)
> +static void kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
> + struct snd_pcm_hw_params *params, snd_pcm_format_t pcm_fmt)
> {
> struct snd_interval *rate = hw_param_interval(params,
> SNDRV_PCM_HW_PARAM_RATE);
> - struct snd_interval *chan = hw_param_interval(params,
> + struct snd_interval *channels = hw_param_interval(params,
> SNDRV_PCM_HW_PARAM_CHANNELS);
> struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
> - struct snd_soc_dpcm *dpcm = container_of(
> - params, struct snd_soc_dpcm, hw_params);
> - struct snd_soc_dai_link *fe_dai_link = dpcm->fe->dai_link;
> - struct snd_soc_dai_link *be_dai_link = dpcm->be->dai_link;
>
> /*
> * The ADSP will convert the FE rate to 48k, stereo, 24 bit
> */
> - if (!strcmp(fe_dai_link->name, "Kbl Audio Port") ||
> - !strcmp(fe_dai_link->name, "Kbl Audio Headset Playback") ||
> - !strcmp(fe_dai_link->name, "Kbl Audio Capture Port")) {
> - rate->min = rate->max = 48000;
> - chan->min = chan->max = 2;
> - snd_mask_none(fmt);
> - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
> - } else if (!strcmp(fe_dai_link->name, "Kbl Audio DMIC cap")) {
> - if (params_channels(params) == 2 ||
> - DMIC_CH(dmic_constraints) == 2)
> - chan->min = chan->max = 2;
> - else
> - chan->min = chan->max = 4;
> - }
> - /*
> - * The speaker on the SSP0 supports S16_LE and not S24_LE.
> - * thus changing the mask here
> - */
> - if (!strcmp(be_dai_link->name, "SSP0-Codec"))
> - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
>
> + rate->min = rate->max = 48000;
> + channels->min = channels->max = 2;
> +
> + snd_mask_none(fmt);
> + snd_mask_set_format(fmt, pcm_fmt);
> +}
> +
> +static int kabylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
> + struct snd_pcm_hw_params *params)
> +{
> + kabylake_ssp_fixup(rtd, params, SNDRV_PCM_FORMAT_S16_LE);
> return 0;
> }
>
> +static int kabylake_ssp1_fixup(struct snd_soc_pcm_runtime *rtd,
> + struct snd_pcm_hw_params *params)
> +{
> +
> + kabylake_ssp_fixup(rtd, params, SNDRV_PCM_FORMAT_S24_LE);
> + return 0;
> +}
> +
> +static int kabylake_dmic_cap_fixup(struct snd_soc_pcm_runtime *rtd,
> + struct snd_pcm_hw_params *params)
> +{
> + struct snd_interval *channels = hw_param_interval(params,
> + SNDRV_PCM_HW_PARAM_CHANNELS);
> +
> + if (params_channels(params) == 2 ||
> + DMIC_CH(dmic_constraints) == 2)
> + channels->min = channels->max = 2;
> + else
> + channels->min = channels->max = 4;
> +
> + return 0;
> +}
> static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream,
> struct snd_pcm_hw_params *params)
> {
> @@ -582,6 +591,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
> .dpcm_capture = 1,
> .nonatomic = 1,
> .dynamic = 1,
> + .be_hw_params_fixup = kabylake_dmic_cap_fixup,
> .ops = &kabylake_dmic_ops,
> SND_SOC_DAILINK_REG(dmic, dummy, platform),
> },
> @@ -618,7 +628,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
> SND_SOC_DAIFMT_NB_NF |
> SND_SOC_DAIFMT_CBS_CFS,
> .ignore_pmdown_time = 1,
> - .be_hw_params_fixup = kabylake_ssp_fixup,
> + .be_hw_params_fixup = kabylake_ssp0_fixup,
> .dpcm_playback = 1,
> .dpcm_capture = 1,
> .ops = &kabylake_ssp0_ops,
> @@ -632,7 +642,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
> .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
> SND_SOC_DAIFMT_CBS_CFS,
> .ignore_pmdown_time = 1,
> - .be_hw_params_fixup = kabylake_ssp_fixup,
> + .be_hw_params_fixup = kabylake_ssp1_fixup,
> .ops = &kabylake_rt5663_ops,
> .dpcm_playback = 1,
> .dpcm_capture = 1,
>
On Thu, May 14, 2020 at 5:47 AM Pierre-Louis Bossart
<[email protected]> wrote:
>
>
>
> On 5/13/20 2:20 PM, Lukasz Majczak wrote:
> > Split be_hw_params_fixup function for different codecs as current common
> > function, leads to crash while trying to get snd_soc_dpcm with
> > container_of() macro in kabylake_ssp_fixup().
> > The crash call path looks as below:
> > soc_pcm_hw_params()
> > snd_soc_dai_hw_params(codec_dai, substream, &codec_params);
> > rtd->dai_link->be_hw_params_fixup(rtd, params)
> > kabylake_ssp_fixup()
> > In this case, codec_params is just a copy of an internal structure and is
> > not embedded into struct snd_soc_dpcm thus we cannot use
> > container_of() on it.
>
> This looks like a nice/welcome change, we've had these unexplained
> crashes on KBL since 4.19 (reported by Guenter and me). I thought they
> were topology related.
>
Not entirely unexplained. See
https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1600868,
which fixes the problem for all three affected drivers.
Someone had told me, though, that the problem is no longer seen. Guess
that was wrong.
Guenter
> If indeed this fixes the issue, it might be worth applying in to all
> stable releases?
>
> Since we have the same code structure for the other kbl drivers, would
> it also make sense to apply the same fixes there:
>
> kbl_da7219_max98927.c: struct snd_soc_dpcm *dpcm = container_of(
> kbl_rt5663_max98927.c: struct snd_soc_dpcm *dpcm = container_of(
>
>
> >
> > Signed-off-by: Lukasz Majczak <[email protected]>
> > ---
> > .../intel/boards/kbl_rt5663_rt5514_max98927.c | 68 +++++++++++--------
> > 1 file changed, 39 insertions(+), 29 deletions(-)
> >
> > diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
> > index 1b1f8d7a4ea3..2e0ae724122c 100644
> > --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
> > +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
> > @@ -328,46 +328,55 @@ static const struct snd_soc_ops kabylake_rt5663_fe_ops = {
> > .startup = kbl_fe_startup,
> > };
> >
> > -static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
> > - struct snd_pcm_hw_params *params)
> > +static void kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
> > + struct snd_pcm_hw_params *params, snd_pcm_format_t pcm_fmt)
> > {
> > struct snd_interval *rate = hw_param_interval(params,
> > SNDRV_PCM_HW_PARAM_RATE);
> > - struct snd_interval *chan = hw_param_interval(params,
> > + struct snd_interval *channels = hw_param_interval(params,
> > SNDRV_PCM_HW_PARAM_CHANNELS);
> > struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
> > - struct snd_soc_dpcm *dpcm = container_of(
> > - params, struct snd_soc_dpcm, hw_params);
> > - struct snd_soc_dai_link *fe_dai_link = dpcm->fe->dai_link;
> > - struct snd_soc_dai_link *be_dai_link = dpcm->be->dai_link;
> >
> > /*
> > * The ADSP will convert the FE rate to 48k, stereo, 24 bit
> > */
> > - if (!strcmp(fe_dai_link->name, "Kbl Audio Port") ||
> > - !strcmp(fe_dai_link->name, "Kbl Audio Headset Playback") ||
> > - !strcmp(fe_dai_link->name, "Kbl Audio Capture Port")) {
> > - rate->min = rate->max = 48000;
> > - chan->min = chan->max = 2;
> > - snd_mask_none(fmt);
> > - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
> > - } else if (!strcmp(fe_dai_link->name, "Kbl Audio DMIC cap")) {
> > - if (params_channels(params) == 2 ||
> > - DMIC_CH(dmic_constraints) == 2)
> > - chan->min = chan->max = 2;
> > - else
> > - chan->min = chan->max = 4;
> > - }
> > - /*
> > - * The speaker on the SSP0 supports S16_LE and not S24_LE.
> > - * thus changing the mask here
> > - */
> > - if (!strcmp(be_dai_link->name, "SSP0-Codec"))
> > - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
> >
> > + rate->min = rate->max = 48000;
> > + channels->min = channels->max = 2;
> > +
> > + snd_mask_none(fmt);
> > + snd_mask_set_format(fmt, pcm_fmt);
> > +}
> > +
> > +static int kabylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
> > + struct snd_pcm_hw_params *params)
> > +{
> > + kabylake_ssp_fixup(rtd, params, SNDRV_PCM_FORMAT_S16_LE);
> > return 0;
> > }
> >
> > +static int kabylake_ssp1_fixup(struct snd_soc_pcm_runtime *rtd,
> > + struct snd_pcm_hw_params *params)
> > +{
> > +
> > + kabylake_ssp_fixup(rtd, params, SNDRV_PCM_FORMAT_S24_LE);
> > + return 0;
> > +}
> > +
> > +static int kabylake_dmic_cap_fixup(struct snd_soc_pcm_runtime *rtd,
> > + struct snd_pcm_hw_params *params)
> > +{
> > + struct snd_interval *channels = hw_param_interval(params,
> > + SNDRV_PCM_HW_PARAM_CHANNELS);
> > +
> > + if (params_channels(params) == 2 ||
> > + DMIC_CH(dmic_constraints) == 2)
> > + channels->min = channels->max = 2;
> > + else
> > + channels->min = channels->max = 4;
> > +
> > + return 0;
> > +}
> > static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream,
> > struct snd_pcm_hw_params *params)
> > {
> > @@ -582,6 +591,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
> > .dpcm_capture = 1,
> > .nonatomic = 1,
> > .dynamic = 1,
> > + .be_hw_params_fixup = kabylake_dmic_cap_fixup,
> > .ops = &kabylake_dmic_ops,
> > SND_SOC_DAILINK_REG(dmic, dummy, platform),
> > },
> > @@ -618,7 +628,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
> > SND_SOC_DAIFMT_NB_NF |
> > SND_SOC_DAIFMT_CBS_CFS,
> > .ignore_pmdown_time = 1,
> > - .be_hw_params_fixup = kabylake_ssp_fixup,
> > + .be_hw_params_fixup = kabylake_ssp0_fixup,
> > .dpcm_playback = 1,
> > .dpcm_capture = 1,
> > .ops = &kabylake_ssp0_ops,
> > @@ -632,7 +642,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
> > .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
> > SND_SOC_DAIFMT_CBS_CFS,
> > .ignore_pmdown_time = 1,
> > - .be_hw_params_fixup = kabylake_ssp_fixup,
> > + .be_hw_params_fixup = kabylake_ssp1_fixup,
> > .ops = &kabylake_rt5663_ops,
> > .dpcm_playback = 1,
> > .dpcm_capture = 1,
> >