]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00225534-2 mmc: sdhci: using cancel_work_sync instread of cancel_delayed_work
authorDong Aisheng <b29396@freescale.com>
Fri, 21 Sep 2012 10:33:06 +0000 (18:33 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:35:26 +0000 (08:35 +0200)
We recently met an rarely happened sychronization issue which can cause
mmc timeout during transfer as follows:
[ OK ]onfiguring network interfaces...
[ OK ]ctivating swap...
mmc0: Timeout waiting for hardware interrupt.
mmc0: Timeout waiting for hardware interrupt.
mmc0: Timeout waiting for hardware interrupt.
mmcblk0: error -110 sending status command, retrying
mmcblk0: error -110 sending stop command, original cmd response 0x900, card status 0xd00
mmcblk0: error -110 transferring data, sector 9981952, nr 16, cmd response 0x900, card status 0xc00
end_request: I/O error, dev mmcblk0, sector 9981952

The root cause is that host uses cancel_delayed_work to cancel the delayed
clock disable work to avoid clock to be disabled if a new cmd
transfer request happens.
However, the work callback may already be running during the excution
of cancel_delayed_work which can not be cancelled and causes
the clock probably still to be disabled during cmd transfer,
then cmd timeout happens.

Using cancel_work_sync instead to wait for the completion of clock disable
first then we can make sure the clock can not be disabled during the cmd
transfer.

BTW, although the original code checks if in interrupt context, however,
it's still not interrupt context safe due to the unsafe platform_clk_ctrl,
so it's ok to directly use cancel_work_sync here and sdhci_enable_clk is
simply not allowed to be called in irq context.

Acked-by: Ryan QIAN <b32804@freescale.com>
Signed-off-by: Dong Aisheng <b29396@freescale.com>
drivers/mmc/host/sdhci.c

index d642020810b10a64cc25e15df98f9bf1b87b1b91..3b8340e60cd6addbc24273fe8942ee905294d231 100755 (executable)
@@ -30,7 +30,7 @@
 #include "sdhci.h"
 
 #define DRIVER_NAME "sdhci"
-#define CLK_TIMEOUT    (10 * HZ)
+#define CLK_TIMEOUT    (10 * HZ)
 
 #define DBG(f, x...) \
        pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
@@ -76,11 +76,7 @@ static inline bool sdhci_is_sdio_attached(struct sdhci_host *host)
 static void sdhci_enable_clk(struct sdhci_host *host)
 {
        if (host->clk_mgr_en) {
-               if (!in_interrupt())
-                       cancel_delayed_work(&host->clk_worker);
-               else
-                       __cancel_delayed_work(&host->clk_worker);
-
+               cancel_delayed_work_sync(&host->clk_worker);
                if (!host->clk_status && host->ops->platform_clk_ctrl)
                        host->ops->platform_clk_ctrl(host, true);
        }