@@ -65,10 +65,13 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
6565 unsigned int status ;
6666 unsigned int tmp ;
6767
68- if (player -> state == UNIPERIF_STATE_STOPPED ) {
69- /* Unexpected IRQ: do nothing */
70- return IRQ_NONE ;
71- }
68+ spin_lock (& player -> irq_lock );
69+ if (!player -> substream )
70+ goto irq_spin_unlock ;
71+
72+ snd_pcm_stream_lock (player -> substream );
73+ if (player -> state == UNIPERIF_STATE_STOPPED )
74+ goto stream_unlock ;
7275
7376 /* Get interrupt status & clear them immediately */
7477 status = GET_UNIPERIF_ITS (player );
@@ -88,9 +91,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
8891 SET_UNIPERIF_ITM_BCLR_FIFO_ERROR (player );
8992
9093 /* Stop the player */
91- snd_pcm_stream_lock (player -> substream );
9294 snd_pcm_stop (player -> substream , SNDRV_PCM_STATE_XRUN );
93- snd_pcm_stream_unlock (player -> substream );
9495 }
9596
9697 ret = IRQ_HANDLED ;
@@ -104,9 +105,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
104105 SET_UNIPERIF_ITM_BCLR_DMA_ERROR (player );
105106
106107 /* Stop the player */
107- snd_pcm_stream_lock (player -> substream );
108108 snd_pcm_stop (player -> substream , SNDRV_PCM_STATE_XRUN );
109- snd_pcm_stream_unlock (player -> substream );
110109
111110 ret = IRQ_HANDLED ;
112111 }
@@ -116,7 +115,8 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
116115 if (!player -> underflow_enabled ) {
117116 dev_err (player -> dev ,
118117 "unexpected Underflow recovering\n" );
119- return - EPERM ;
118+ ret = - EPERM ;
119+ goto stream_unlock ;
120120 }
121121 /* Read the underflow recovery duration */
122122 tmp = GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION (player );
@@ -138,13 +138,16 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
138138 dev_err (player -> dev , "Underflow recovery failed\n" );
139139
140140 /* Stop the player */
141- snd_pcm_stream_lock (player -> substream );
142141 snd_pcm_stop (player -> substream , SNDRV_PCM_STATE_XRUN );
143- snd_pcm_stream_unlock (player -> substream );
144142
145143 ret = IRQ_HANDLED ;
146144 }
147145
146+ stream_unlock :
147+ snd_pcm_stream_unlock (player -> substream );
148+ irq_spin_unlock :
149+ spin_unlock (& player -> irq_lock );
150+
148151 return ret ;
149152}
150153
@@ -588,6 +591,7 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol,
588591 struct sti_uniperiph_data * priv = snd_soc_dai_get_drvdata (dai );
589592 struct uniperif * player = priv -> dai_data .uni ;
590593 struct snd_aes_iec958 * iec958 = & player -> stream_settings .iec958 ;
594+ unsigned long flags ;
591595
592596 mutex_lock (& player -> ctrl_lock );
593597 iec958 -> status [0 ] = ucontrol -> value .iec958 .status [0 ];
@@ -596,12 +600,14 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol,
596600 iec958 -> status [3 ] = ucontrol -> value .iec958 .status [3 ];
597601 mutex_unlock (& player -> ctrl_lock );
598602
603+ spin_lock_irqsave (& player -> irq_lock , flags );
599604 if (player -> substream && player -> substream -> runtime )
600605 uni_player_set_channel_status (player ,
601606 player -> substream -> runtime );
602607 else
603608 uni_player_set_channel_status (player , NULL );
604609
610+ spin_unlock_irqrestore (& player -> irq_lock , flags );
605611 return 0 ;
606612}
607613
@@ -686,9 +692,12 @@ static int uni_player_startup(struct snd_pcm_substream *substream,
686692{
687693 struct sti_uniperiph_data * priv = snd_soc_dai_get_drvdata (dai );
688694 struct uniperif * player = priv -> dai_data .uni ;
695+ unsigned long flags ;
689696 int ret ;
690697
698+ spin_lock_irqsave (& player -> irq_lock , flags );
691699 player -> substream = substream ;
700+ spin_unlock_irqrestore (& player -> irq_lock , flags );
692701
693702 player -> clk_adj = 0 ;
694703
@@ -986,12 +995,15 @@ static void uni_player_shutdown(struct snd_pcm_substream *substream,
986995{
987996 struct sti_uniperiph_data * priv = snd_soc_dai_get_drvdata (dai );
988997 struct uniperif * player = priv -> dai_data .uni ;
998+ unsigned long flags ;
989999
1000+ spin_lock_irqsave (& player -> irq_lock , flags );
9901001 if (player -> state != UNIPERIF_STATE_STOPPED )
9911002 /* Stop the player */
9921003 uni_player_stop (player );
9931004
9941005 player -> substream = NULL ;
1006+ spin_unlock_irqrestore (& player -> irq_lock , flags );
9951007}
9961008
9971009static int uni_player_parse_dt_audio_glue (struct platform_device * pdev ,
@@ -1096,6 +1108,7 @@ int uni_player_init(struct platform_device *pdev,
10961108 }
10971109
10981110 mutex_init (& player -> ctrl_lock );
1111+ spin_lock_init (& player -> irq_lock );
10991112
11001113 /* Ensure that disabled by default */
11011114 SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE (player );
0 commit comments