Commit 75defee0 authored by Kuninori Morimoto's avatar Kuninori Morimoto Committed by Mark Brown

ASoC: rsnd: don't call snd_pcm_period_elapsed() under spin lock

'a9e1ac1a9e4585b5("ASoC: rsnd: spin lock for interrupt handler")'
added spin lock under interrupt handler to solve HW restart issue.

OTOH, current rsnd driver calls snd_pcm_period_elapsed() from
rsnd_dai_pointer_update(). but, it will be called under spin lock
if SSI was PIO mode.

If it was called under spin lock, it will call
snd_pcm_update_state() -> snd_pcm_drain_done().
Then, it calls rsnd_soc_dai_trigger() and will be dead-lock.
This patch doesn't call rsnd_dai_pointer_update() under spin lock
Signed-off-by: default avatarKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Tested-by: default avatarKeita Kobayashi <keita.kobayashi.ym@renesas.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 12927a8f
...@@ -302,7 +302,7 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional) ...@@ -302,7 +302,7 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional)
return pos; return pos;
} }
void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte) bool rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte)
{ {
io->byte_pos += byte; io->byte_pos += byte;
...@@ -319,8 +319,24 @@ void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte) ...@@ -319,8 +319,24 @@ void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte)
io->next_period_byte = io->byte_per_period; io->next_period_byte = io->byte_per_period;
} }
snd_pcm_period_elapsed(substream); return true;
} }
return false;
}
void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io)
{
struct snd_pcm_substream *substream = io->substream;
/*
* this function should be called...
*
* - if rsnd_dai_pointer_update() returns true
* - without spin lock
*/
snd_pcm_period_elapsed(substream);
} }
static void rsnd_dai_stream_init(struct rsnd_dai_stream *io, static void rsnd_dai_stream_init(struct rsnd_dai_stream *io,
......
...@@ -36,7 +36,10 @@ static void rsnd_dmaen_complete(void *data) ...@@ -36,7 +36,10 @@ static void rsnd_dmaen_complete(void *data)
{ {
struct rsnd_dma *dma = (struct rsnd_dma *)data; struct rsnd_dma *dma = (struct rsnd_dma *)data;
struct rsnd_mod *mod = rsnd_dma_to_mod(dma); struct rsnd_mod *mod = rsnd_dma_to_mod(dma);
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
bool elapsed = false;
unsigned long flags;
/* /*
* Renesas sound Gen1 needs 1 DMAC, * Renesas sound Gen1 needs 1 DMAC,
...@@ -49,8 +52,14 @@ static void rsnd_dmaen_complete(void *data) ...@@ -49,8 +52,14 @@ static void rsnd_dmaen_complete(void *data)
* rsnd_dai_pointer_update() will be called twice, * rsnd_dai_pointer_update() will be called twice,
* ant it will breaks io->byte_pos * ant it will breaks io->byte_pos
*/ */
spin_lock_irqsave(&priv->lock, flags);
elapsed = rsnd_dai_pointer_update(io, io->byte_per_period);
spin_unlock_irqrestore(&priv->lock, flags);
rsnd_dai_pointer_update(io, io->byte_per_period); if (elapsed)
rsnd_dai_period_elapsed(io);
} }
static void rsnd_dmaen_stop(struct rsnd_dma *dma) static void rsnd_dmaen_stop(struct rsnd_dma *dma)
......
...@@ -355,7 +355,8 @@ struct rsnd_dai { ...@@ -355,7 +355,8 @@ struct rsnd_dai {
struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id); struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id);
void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); bool rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io);
int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
/* /*
......
...@@ -426,6 +426,7 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) ...@@ -426,6 +426,7 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
int is_dma = rsnd_ssi_is_dma_mode(mod); int is_dma = rsnd_ssi_is_dma_mode(mod);
u32 status; u32 status;
bool elapsed = false;
spin_lock(&priv->lock); spin_lock(&priv->lock);
...@@ -451,7 +452,7 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) ...@@ -451,7 +452,7 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
else else
*buf = rsnd_mod_read(mod, SSIRDR); *buf = rsnd_mod_read(mod, SSIRDR);
rsnd_dai_pointer_update(io, sizeof(*buf)); elapsed = rsnd_dai_pointer_update(io, sizeof(*buf));
} }
/* DMA only */ /* DMA only */
...@@ -476,6 +477,9 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) ...@@ -476,6 +477,9 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
rsnd_ssi_interrupt_out: rsnd_ssi_interrupt_out:
spin_unlock(&priv->lock); spin_unlock(&priv->lock);
if (elapsed)
rsnd_dai_period_elapsed(io);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
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