diff mbox

[2/2] mmc: mxs: Use the spinlock irq variants

Message ID 1477594672-31611-2-git-send-email-festevam@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Fabio Estevam Oct. 27, 2016, 6:57 p.m. UTC
From: Fabio Estevam <fabio.estevam@nxp.com>

Inside an interrupt handler we should use the spin_lock_irqsave()/
spin_unlock_irqrestore() variants, so fix it accordingly.

Signed-off-by: Fabio Estevam <fabio.estevam@nxp.com>
---
 drivers/mmc/host/mxs-mmc.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

Comments

Marek Vasut Oct. 27, 2016, 7:09 p.m. UTC | #1
On 10/27/2016 08:57 PM, Fabio Estevam wrote:
> From: Fabio Estevam <fabio.estevam@nxp.com>
> 
> Inside an interrupt handler we should use the spin_lock_irqsave()/
> spin_unlock_irqrestore() variants, so fix it accordingly.
> 
> Signed-off-by: Fabio Estevam <fabio.estevam@nxp.com>

Reviewed-by: Marek Vasut <marex@denx.de>
Jisheng Zhang Oct. 28, 2016, 2:23 a.m. UTC | #2
On Thu, 27 Oct 2016 16:57:52 -0200 Fabio Estevam wrote:

> From: Fabio Estevam <fabio.estevam@nxp.com>
> 
> Inside an interrupt handler we should use the spin_lock_irqsave()/
> spin_unlock_irqrestore() variants, so fix it accordingly.

hmm, in interrupt handler the irq is disabled, so IMHO there's no need to
use irqsave/irqrestore spinlock variants.

Thanks,
Jisheng

> 
> Signed-off-by: Fabio Estevam <fabio.estevam@nxp.com>
> ---
>  drivers/mmc/host/mxs-mmc.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
> index 44ecebd..14b7548 100644
> --- a/drivers/mmc/host/mxs-mmc.c
> +++ b/drivers/mmc/host/mxs-mmc.c
> @@ -189,15 +189,16 @@ static irqreturn_t mxs_mmc_irq_handler(int irq, void *dev_id)
>  	struct mmc_command *cmd = host->cmd;
>  	struct mmc_data *data = host->data;
>  	struct mxs_ssp *ssp = &host->ssp;
> +	unsigned long flags;
>  	u32 stat;
>  
> -	spin_lock(&host->lock);
> +	spin_lock_irqsave(&host->lock, flags);
>  
>  	stat = readl(ssp->base + HW_SSP_CTRL1(ssp));
>  	writel(stat & MXS_MMC_IRQ_BITS,
>  	       ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_CLR);
>  
> -	spin_unlock(&host->lock);
> +	spin_unlock_irqrestore(&host->lock, flags);
>  
>  	if ((stat & BM_SSP_CTRL1_SDIO_IRQ) && (stat & BM_SSP_CTRL1_SDIO_IRQ_EN))
>  		mmc_signal_sdio_irq(host->mmc);

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Fabio Estevam Oct. 28, 2016, 11:40 a.m. UTC | #3
Hi Jisheng,

On Fri, Oct 28, 2016 at 12:23 AM, Jisheng Zhang <jszhang@marvell.com> wrote:

> hmm, in interrupt handler the irq is disabled, so IMHO there's no need to
> use irqsave/irqrestore spinlock variants.

Please check Documentation/locking/spinlocks.txt:

"IFF you know that the spinlocks are
never used in interrupt handlers, you can use the non-irq versions:"
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jisheng Zhang Oct. 28, 2016, 11:49 a.m. UTC | #4
Hi Fabio,

On Fri, 28 Oct 2016 09:40:29 -0200 Fabio Estevam wrote:

> Hi Jisheng,
> 
> On Fri, Oct 28, 2016 at 12:23 AM, Jisheng Zhang <jszhang@marvell.com> wrote:
> 
> > hmm, in interrupt handler the irq is disabled, so IMHO there's no need to
> > use irqsave/irqrestore spinlock variants.  
> 
> Please check Documentation/locking/spinlocks.txt:
> 
> "IFF you know that the spinlocks are
> never used in interrupt handlers, you can use the non-irq versions:"

This is not the key. The key here is: 

compared with the non-irq version, the irq-version spin lock does one extra
work: disable the local interrupts. But since we are in interrupt handler, 
the local irq is already disabled, so there's no need for the irq-versions.

I'm not sure I understand the situation, comments are welcome.

Thanks,
Jisheng

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Fabio Estevam Nov. 5, 2016, 6:56 p.m. UTC | #5
Hi Jisheng,

On Fri, Oct 28, 2016 at 9:49 AM, Jisheng Zhang <jszhang@marvell.com> wrote:

> This is not the key. The key here is:
>
> compared with the non-irq version, the irq-version spin lock does one extra
> work: disable the local interrupts. But since we are in interrupt handler,
> the local irq is already disabled, so there's no need for the irq-versions.
>
> I'm not sure I understand the situation, comments are welcome.

Quoting  http://www.xml.com/ldd/chapter/book/ch09.html:

"Many users of spinlocks stick to spin_lock and spin_unlock. If you
are using spinlocks in interrupt handlers, however, you must use the
IRQ-disabling versions (usually spin_lock_irqsave and
spin_unlock_irqsave) in the noninterrupt code. To do otherwise is to
invite a deadlock situation.

It is worth considering an example here. Assume that your driver is
running in its read method, and it obtains a lock with spin_lock.
While the read method is holding the lock, your device interrupts, and
your interrupt handler is executed on the same processor. If it
attempts to use the same lock, it will go into a busy-wait loop, since
your read method already holds the lock. But, since the interrupt
routine has preempted that method, the lock will never be released and
the processor deadlocks, which is probably not what you wanted.

This problem can be avoided by using spin_lock_irqsave to disable
interrupts on the local processor while the lock is held. When in
doubt, use the _irqsave versions of the primitives and you will not
need to worry about deadlocks. Remember, though, that the flags value
from spin_lock_irqsave must not be passed to other functions."

And as I mentioned before Documentation/locking/spinlocks.txt is very
clear about the need of using spin_lock_irqsave inside interrupt
handlers.

Feel free to submit a patch to Documentation/locking/spinlocks.txt if
you think this is incorrect.

Thanks
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Fabio Estevam Nov. 5, 2016, 7:19 p.m. UTC | #6
Hi Jisheng,

On Sat, Nov 5, 2016 at 4:56 PM, Fabio Estevam <festevam@gmail.com> wrote:
> Hi Jisheng,
>
> On Fri, Oct 28, 2016 at 9:49 AM, Jisheng Zhang <jszhang@marvell.com> wrote:
>
>> This is not the key. The key here is:
>>
>> compared with the non-irq version, the irq-version spin lock does one extra
>> work: disable the local interrupts. But since we are in interrupt handler,
>> the local irq is already disabled, so there's no need for the irq-versions.
>>
>> I'm not sure I understand the situation, comments are welcome.
>
> Quoting  http://www.xml.com/ldd/chapter/book/ch09.html:
>
> "Many users of spinlocks stick to spin_lock and spin_unlock. If you
> are using spinlocks in interrupt handlers, however, you must use the
> IRQ-disabling versions (usually spin_lock_irqsave and
> spin_unlock_irqsave) in the noninterrupt code. To do otherwise is to
> invite a deadlock situation.

Ah, after re-reading it several times I agree with you now. It is the
noninterrupt code that needs the irq spinlock versions.

I will resend the series without this patch.

Thanks
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index 44ecebd..14b7548 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -189,15 +189,16 @@  static irqreturn_t mxs_mmc_irq_handler(int irq, void *dev_id)
 	struct mmc_command *cmd = host->cmd;
 	struct mmc_data *data = host->data;
 	struct mxs_ssp *ssp = &host->ssp;
+	unsigned long flags;
 	u32 stat;
 
-	spin_lock(&host->lock);
+	spin_lock_irqsave(&host->lock, flags);
 
 	stat = readl(ssp->base + HW_SSP_CTRL1(ssp));
 	writel(stat & MXS_MMC_IRQ_BITS,
 	       ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_CLR);
 
-	spin_unlock(&host->lock);
+	spin_unlock_irqrestore(&host->lock, flags);
 
 	if ((stat & BM_SSP_CTRL1_SDIO_IRQ) && (stat & BM_SSP_CTRL1_SDIO_IRQ_EN))
 		mmc_signal_sdio_irq(host->mmc);