diff mbox series

mtd: rawnand: Ensure nand_soft_waitrdy wait period is enough

Message ID 20200116135431.17480-1-devik@eaxlabs.cz
State Accepted
Headers show
Series mtd: rawnand: Ensure nand_soft_waitrdy wait period is enough | expand

Commit Message

Martin Devera Jan. 16, 2020, 1:54 p.m. UTC
The used way to compute jiffies timeout brokes when
jiffie difference is 1.
Assume that nand_soft_waitrdy is called with timeout_ms==1.
Jiffies are 1000 for example (assume something more like 1000.99
- just before incrementing to 1001).
We compute timeout_ms = 1000+msecs_to_jiffies(1) = 1001.
nand_read_data_op is called for the first time and returns 0.
During the call jiffies changes to 1001 thus "while loop" ends
here (wrongly). Notice that routine was called with expected timeout
1ms but actual timeout used was something between 0...1ms.

Fixes STM32MP1 FMC2 NAND controller which sometimes failed
exactly in this way.

Signed-off-by: Martin Devera <devik@eaxlabs.cz>
---
 drivers/mtd/nand/raw/nand_base.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

Comments

Miquel Raynal March 10, 2020, 6:34 p.m. UTC | #1
On Thu, 2020-01-16 at 13:54:31 UTC, Martin Devera wrote:
> The used way to compute jiffies timeout brokes when
> jiffie difference is 1.
> Assume that nand_soft_waitrdy is called with timeout_ms==1.
> Jiffies are 1000 for example (assume something more like 1000.99
> - just before incrementing to 1001).
> We compute timeout_ms = 1000+msecs_to_jiffies(1) = 1001.
> nand_read_data_op is called for the first time and returns 0.
> During the call jiffies changes to 1001 thus "while loop" ends
> here (wrongly). Notice that routine was called with expected timeout
> 1ms but actual timeout used was something between 0...1ms.
> 
> Fixes STM32MP1 FMC2 NAND controller which sometimes failed
> exactly in this way.
> 
> Signed-off-by: Martin Devera <devik@eaxlabs.cz>

Applied to https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git nand/next, thanks.

Miquel
diff mbox series

Patch

diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index d527e448ce19..9a7e09c8d8be 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -721,7 +721,12 @@  int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms)
 	if (ret)
 		return ret;
 
-	timeout_ms = jiffies + msecs_to_jiffies(timeout_ms);
+	/*
+	 * +1 below is necessary because if we are now in the last fraction
+	 * of jiffy and msecs_to_jiffies is 1 then we will wait only that
+	 * small jiffy fraction - possibly leading to false timeout
+	 */
+	timeout_ms = jiffies + msecs_to_jiffies(timeout_ms) + 1;
 	do {
 		ret = nand_read_data_op(chip, &status, sizeof(status), true);
 		if (ret)