Commit d4a2fbce authored by Takashi Iwai's avatar Takashi Iwai

Merge tag 'asoc-fix-v4.11-rc7' of...

Merge tag 'asoc-fix-v4.11-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus

ASoC: Fixes for v4.11

A few last minute fixes for v4.11, the STI fix is relatively large but
driver specific and has been cooking in -next for a little while now:

 - A fix from Takashi for some suspend/resume related crashes in the
   Intel drivers.
 - A fix from Mousumi Jana for issues with incorrectly created
   enumeration controls generated from topology files which could cause
   problems for userspace.
 - Fixes from Arnaud Pouliquen for some crashes due to races with the
   interrupt handler in the STI driver.
parents dfb00a56 dc9617cb
...@@ -621,7 +621,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { ...@@ -621,7 +621,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = {
.codec_dai_name = "snd-soc-dummy-dai", .codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy", .codec_name = "snd-soc-dummy",
.platform_name = "sst-mfld-platform", .platform_name = "sst-mfld-platform",
.ignore_suspend = 1, .nonatomic = true,
.dynamic = 1, .dynamic = 1,
.dpcm_playback = 1, .dpcm_playback = 1,
.dpcm_capture = 1, .dpcm_capture = 1,
...@@ -634,7 +634,6 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { ...@@ -634,7 +634,6 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = {
.codec_dai_name = "snd-soc-dummy-dai", .codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy", .codec_name = "snd-soc-dummy",
.platform_name = "sst-mfld-platform", .platform_name = "sst-mfld-platform",
.ignore_suspend = 1,
.nonatomic = true, .nonatomic = true,
.dynamic = 1, .dynamic = 1,
.dpcm_playback = 1, .dpcm_playback = 1,
...@@ -661,6 +660,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { ...@@ -661,6 +660,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = {
| SND_SOC_DAIFMT_CBS_CFS, | SND_SOC_DAIFMT_CBS_CFS,
.be_hw_params_fixup = byt_rt5640_codec_fixup, .be_hw_params_fixup = byt_rt5640_codec_fixup,
.ignore_suspend = 1, .ignore_suspend = 1,
.nonatomic = true,
.dpcm_playback = 1, .dpcm_playback = 1,
.dpcm_capture = 1, .dpcm_capture = 1,
.init = byt_rt5640_init, .init = byt_rt5640_init,
......
...@@ -235,7 +235,6 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { ...@@ -235,7 +235,6 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = {
.codec_dai_name = "snd-soc-dummy-dai", .codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy", .codec_name = "snd-soc-dummy",
.platform_name = "sst-mfld-platform", .platform_name = "sst-mfld-platform",
.ignore_suspend = 1,
.nonatomic = true, .nonatomic = true,
.dynamic = 1, .dynamic = 1,
.dpcm_playback = 1, .dpcm_playback = 1,
...@@ -249,7 +248,6 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { ...@@ -249,7 +248,6 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = {
.codec_dai_name = "snd-soc-dummy-dai", .codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy", .codec_name = "snd-soc-dummy",
.platform_name = "sst-mfld-platform", .platform_name = "sst-mfld-platform",
.ignore_suspend = 1,
.nonatomic = true, .nonatomic = true,
.dynamic = 1, .dynamic = 1,
.dpcm_playback = 1, .dpcm_playback = 1,
......
...@@ -933,6 +933,7 @@ static int soc_tplg_denum_create_texts(struct soc_enum *se, ...@@ -933,6 +933,7 @@ static int soc_tplg_denum_create_texts(struct soc_enum *se,
} }
} }
se->texts = (const char * const *)se->dobj.control.dtexts;
return 0; return 0;
err: err:
......
...@@ -1299,6 +1299,7 @@ struct uniperif { ...@@ -1299,6 +1299,7 @@ struct uniperif {
int ver; /* IP version, used by register access macros */ int ver; /* IP version, used by register access macros */
struct regmap_field *clk_sel; struct regmap_field *clk_sel;
struct regmap_field *valid_sel; struct regmap_field *valid_sel;
spinlock_t irq_lock; /* use to prevent race condition with IRQ */
/* capabilities */ /* capabilities */
const struct snd_pcm_hardware *hw; const struct snd_pcm_hardware *hw;
......
...@@ -65,10 +65,13 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) ...@@ -65,10 +65,13 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
unsigned int status; unsigned int status;
unsigned int tmp; unsigned int tmp;
if (player->state == UNIPERIF_STATE_STOPPED) { spin_lock(&player->irq_lock);
/* Unexpected IRQ: do nothing */ if (!player->substream)
return IRQ_NONE; goto irq_spin_unlock;
}
snd_pcm_stream_lock(player->substream);
if (player->state == UNIPERIF_STATE_STOPPED)
goto stream_unlock;
/* Get interrupt status & clear them immediately */ /* Get interrupt status & clear them immediately */
status = GET_UNIPERIF_ITS(player); status = GET_UNIPERIF_ITS(player);
...@@ -88,9 +91,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) ...@@ -88,9 +91,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(player); SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(player);
/* Stop the player */ /* Stop the player */
snd_pcm_stream_lock(player->substream);
snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
snd_pcm_stream_unlock(player->substream);
} }
ret = IRQ_HANDLED; ret = IRQ_HANDLED;
...@@ -104,9 +105,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) ...@@ -104,9 +105,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player); SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player);
/* Stop the player */ /* Stop the player */
snd_pcm_stream_lock(player->substream);
snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
snd_pcm_stream_unlock(player->substream);
ret = IRQ_HANDLED; ret = IRQ_HANDLED;
} }
...@@ -116,7 +115,8 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) ...@@ -116,7 +115,8 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
if (!player->underflow_enabled) { if (!player->underflow_enabled) {
dev_err(player->dev, dev_err(player->dev,
"unexpected Underflow recovering\n"); "unexpected Underflow recovering\n");
return -EPERM; ret = -EPERM;
goto stream_unlock;
} }
/* Read the underflow recovery duration */ /* Read the underflow recovery duration */
tmp = GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(player); tmp = GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(player);
...@@ -138,13 +138,16 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) ...@@ -138,13 +138,16 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
dev_err(player->dev, "Underflow recovery failed\n"); dev_err(player->dev, "Underflow recovery failed\n");
/* Stop the player */ /* Stop the player */
snd_pcm_stream_lock(player->substream);
snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
snd_pcm_stream_unlock(player->substream);
ret = IRQ_HANDLED; ret = IRQ_HANDLED;
} }
stream_unlock:
snd_pcm_stream_unlock(player->substream);
irq_spin_unlock:
spin_unlock(&player->irq_lock);
return ret; return ret;
} }
...@@ -588,6 +591,7 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol, ...@@ -588,6 +591,7 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol,
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *player = priv->dai_data.uni; struct uniperif *player = priv->dai_data.uni;
struct snd_aes_iec958 *iec958 = &player->stream_settings.iec958; struct snd_aes_iec958 *iec958 = &player->stream_settings.iec958;
unsigned long flags;
mutex_lock(&player->ctrl_lock); mutex_lock(&player->ctrl_lock);
iec958->status[0] = ucontrol->value.iec958.status[0]; iec958->status[0] = ucontrol->value.iec958.status[0];
...@@ -596,12 +600,14 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol, ...@@ -596,12 +600,14 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol,
iec958->status[3] = ucontrol->value.iec958.status[3]; iec958->status[3] = ucontrol->value.iec958.status[3];
mutex_unlock(&player->ctrl_lock); mutex_unlock(&player->ctrl_lock);
spin_lock_irqsave(&player->irq_lock, flags);
if (player->substream && player->substream->runtime) if (player->substream && player->substream->runtime)
uni_player_set_channel_status(player, uni_player_set_channel_status(player,
player->substream->runtime); player->substream->runtime);
else else
uni_player_set_channel_status(player, NULL); uni_player_set_channel_status(player, NULL);
spin_unlock_irqrestore(&player->irq_lock, flags);
return 0; return 0;
} }
...@@ -686,9 +692,12 @@ static int uni_player_startup(struct snd_pcm_substream *substream, ...@@ -686,9 +692,12 @@ static int uni_player_startup(struct snd_pcm_substream *substream,
{ {
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *player = priv->dai_data.uni; struct uniperif *player = priv->dai_data.uni;
unsigned long flags;
int ret; int ret;
spin_lock_irqsave(&player->irq_lock, flags);
player->substream = substream; player->substream = substream;
spin_unlock_irqrestore(&player->irq_lock, flags);
player->clk_adj = 0; player->clk_adj = 0;
...@@ -986,12 +995,15 @@ static void uni_player_shutdown(struct snd_pcm_substream *substream, ...@@ -986,12 +995,15 @@ static void uni_player_shutdown(struct snd_pcm_substream *substream,
{ {
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *player = priv->dai_data.uni; struct uniperif *player = priv->dai_data.uni;
unsigned long flags;
spin_lock_irqsave(&player->irq_lock, flags);
if (player->state != UNIPERIF_STATE_STOPPED) if (player->state != UNIPERIF_STATE_STOPPED)
/* Stop the player */ /* Stop the player */
uni_player_stop(player); uni_player_stop(player);
player->substream = NULL; player->substream = NULL;
spin_unlock_irqrestore(&player->irq_lock, flags);
} }
static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, static int uni_player_parse_dt_audio_glue(struct platform_device *pdev,
...@@ -1096,6 +1108,7 @@ int uni_player_init(struct platform_device *pdev, ...@@ -1096,6 +1108,7 @@ int uni_player_init(struct platform_device *pdev,
} }
mutex_init(&player->ctrl_lock); mutex_init(&player->ctrl_lock);
spin_lock_init(&player->irq_lock);
/* Ensure that disabled by default */ /* Ensure that disabled by default */
SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(player); SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(player);
......
...@@ -46,10 +46,15 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id) ...@@ -46,10 +46,15 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id)
struct uniperif *reader = dev_id; struct uniperif *reader = dev_id;
unsigned int status; unsigned int status;
spin_lock(&reader->irq_lock);
if (!reader->substream)
goto irq_spin_unlock;
snd_pcm_stream_lock(reader->substream);
if (reader->state == UNIPERIF_STATE_STOPPED) { if (reader->state == UNIPERIF_STATE_STOPPED) {
/* Unexpected IRQ: do nothing */ /* Unexpected IRQ: do nothing */
dev_warn(reader->dev, "unexpected IRQ\n"); dev_warn(reader->dev, "unexpected IRQ\n");
return IRQ_HANDLED; goto stream_unlock;
} }
/* Get interrupt status & clear them immediately */ /* Get interrupt status & clear them immediately */
...@@ -60,13 +65,16 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id) ...@@ -60,13 +65,16 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id)
if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) { if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) {
dev_err(reader->dev, "FIFO error detected\n"); dev_err(reader->dev, "FIFO error detected\n");
snd_pcm_stream_lock(reader->substream);
snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN); snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN);
snd_pcm_stream_unlock(reader->substream);
return IRQ_HANDLED; ret = IRQ_HANDLED;
} }
stream_unlock:
snd_pcm_stream_unlock(reader->substream);
irq_spin_unlock:
spin_unlock(&reader->irq_lock);
return ret; return ret;
} }
...@@ -347,9 +355,12 @@ static int uni_reader_startup(struct snd_pcm_substream *substream, ...@@ -347,9 +355,12 @@ static int uni_reader_startup(struct snd_pcm_substream *substream,
{ {
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *reader = priv->dai_data.uni; struct uniperif *reader = priv->dai_data.uni;
unsigned long flags;
int ret; int ret;
spin_lock_irqsave(&reader->irq_lock, flags);
reader->substream = substream; reader->substream = substream;
spin_unlock_irqrestore(&reader->irq_lock, flags);
if (!UNIPERIF_TYPE_IS_TDM(reader)) if (!UNIPERIF_TYPE_IS_TDM(reader))
return 0; return 0;
...@@ -375,12 +386,15 @@ static void uni_reader_shutdown(struct snd_pcm_substream *substream, ...@@ -375,12 +386,15 @@ static void uni_reader_shutdown(struct snd_pcm_substream *substream,
{ {
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *reader = priv->dai_data.uni; struct uniperif *reader = priv->dai_data.uni;
unsigned long flags;
spin_lock_irqsave(&reader->irq_lock, flags);
if (reader->state != UNIPERIF_STATE_STOPPED) { if (reader->state != UNIPERIF_STATE_STOPPED) {
/* Stop the reader */ /* Stop the reader */
uni_reader_stop(reader); uni_reader_stop(reader);
} }
reader->substream = NULL; reader->substream = NULL;
spin_unlock_irqrestore(&reader->irq_lock, flags);
} }
static const struct snd_soc_dai_ops uni_reader_dai_ops = { static const struct snd_soc_dai_ops uni_reader_dai_ops = {
...@@ -415,6 +429,8 @@ int uni_reader_init(struct platform_device *pdev, ...@@ -415,6 +429,8 @@ int uni_reader_init(struct platform_device *pdev,
return -EBUSY; return -EBUSY;
} }
spin_lock_init(&reader->irq_lock);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(uni_reader_init); EXPORT_SYMBOL_GPL(uni_reader_init);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment