On Tue, Nov 10, 2026 at 8:08 PM Stefan Ghetu <[email protected]> wrote: > > hw_params() can be called again without hw_free() in between, and > hw_free() is also called after a failed hw_params(). > > fsl_asrc_request_pair() always takes a new pair, so a second hw_params() > leaves the stream in two asrc->pair[] entries. Only one is released, and > after close the other points to freed memory, which is dereferenced by > fsl_asrc_isr() and fsl_asrc_m2m_suspend(). After a failed hw_params(), > fsl_asrc_release_pair() releases a stale index that may belong to > another running stream. > > Keep the owned pair and only update its channels when it is requested > again, and ignore a pair the stream does not own on release. > > Fixes: 3117bb3109dc ("ASoC: fsl_asrc: Add ASRC ASoC CPU DAI and platform > drivers") > Signed-off-by: Stefan Ghetu <[email protected]>
Reviewed-by: Shengjiu Wang <[email protected]> best regards shengjiu Wang > --- > sound/soc/fsl/fsl_asrc.c | 22 ++++++++++++++++++++++ > 1 file changed, 22 insertions(+) > > diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c > index faf348dd582d..5d97789b5c36 100644 > --- a/sound/soc/fsl/fsl_asrc.c > +++ b/sound/soc/fsl/fsl_asrc.c > @@ -216,6 +216,8 @@ static void fsl_asrc_sel_proc(int inrate, int outrate, > * It assigns pair by the order of A->C->B because allocation of pair B, > * within range [ANCA, ANCA+ANCB-1], depends on the channels of pair A > * while pair A and pair C are comparatively independent. > + * > + * If @pair already owns a pair, it is kept and only its channels are > updated. > */ > static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) > { > @@ -226,6 +228,19 @@ static int fsl_asrc_request_pair(int channels, struct > fsl_asrc_pair *pair) > > guard(spinlock_irqsave)(&asrc->lock); > > + if (asrc->pair[pair->index] == pair) { > + if (asrc->channel_avail + pair->channels < channels) { > + dev_err(dev, "can't afford required channels: %d\n", > channels); > + return -EINVAL; > + } > + > + asrc->channel_avail += pair->channels; > + asrc->channel_avail -= channels; > + pair->channels = channels; > + > + return 0; > + } > + > for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) { > if (asrc->pair[i] != NULL) > continue; > @@ -257,12 +272,19 @@ static int fsl_asrc_request_pair(int channels, struct > fsl_asrc_pair *pair) > * @pair: pair to release > * > * It clears the resource from asrc and releases the occupied channels. > + * Nothing is done if @pair does not own a pair. > */ > static void fsl_asrc_release_pair(struct fsl_asrc_pair *pair) > { > struct fsl_asrc *asrc = pair->asrc; > enum asrc_pair_index index = pair->index; > > + /* Only the owner clears its entry, so it cannot change after this > check */ > + scoped_guard(spinlock_irqsave, &asrc->lock) { > + if (asrc->pair[index] != pair) > + return; > + } > + > /* Make sure the pair is disabled */ > regmap_update_bits(asrc->regmap, REG_ASRCTR, > ASRCTR_ASRCEi_MASK(index), 0); > -- > 2.53.0 >
