From e9d5e7a983b43e1bd4789098d4279c25f8ff7078 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 27 Jun 2018 21:54:28 -0700 Subject: common: clock: Sample time before poller_call() Change is_timeout() to sample current time before invoking poller infrascructure to avoid occasional false timeout conditions. Consider the following timeout loop (can be found in wait_on_timeout): while (!(condition)) { if (is_timeout(...)) { return -ETIMEDOUT; } } ... in the original logic of is_timeout() it was possible to end up in the following situation: 1. Immediate check of of "condition" yeilds false (not enough time for it to become true has passed yet) 2. is_timeout is called which, in turn, calls poller_call() 3. All registerd pollers take more than specified timeout time to execute. 4. Sometime during poller_call() "contition" becomes true 5. As a result of #3 is_timeout() returns "true" 6. Code bails out with -ETIMEDOUT early even though timeout condition didn't really occur. One concrete example of this problem was discovered on ZII RDU1 board (poller_call() is long due to a serdev) when doing large data transfers over SPI to attached DataFlash chip. This commit changes is_timeout() to sample the value of time before calling poller_call(). This way first call to is_timeout() will almost always return false thus checking the condition at least twice before declaring a timeout. Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- common/clock.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common/clock.c b/common/clock.c index f98176dd52..904bee0b46 100644 --- a/common/clock.c +++ b/common/clock.c @@ -181,10 +181,12 @@ EXPORT_SYMBOL(is_timeout_non_interruptible); int is_timeout(uint64_t start_ns, uint64_t time_offset_ns) { + int ret = is_timeout_non_interruptible(start_ns, time_offset_ns); + if (time_offset_ns >= 100 * USECOND) poller_call(); - return is_timeout_non_interruptible(start_ns, time_offset_ns); + return ret; } EXPORT_SYMBOL(is_timeout); -- cgit v1.2.3