From 56c61845152050bad8e93f2e7decf04dfcedda34 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 31 Oct 2017 14:26:23 +0800 Subject: [PATCH] BACKPORT: UPSTREAM: mmc: dw_mmc: Fix the CTO timeout calculation In the commit 03de19212ea3 ("mmc: dw_mmc: introduce timer for broken command transfer over scheme") we tried to calculate the expected hardware command timeout value. Unfortunately that calculation isn't quite correct in all cases. It used "bus_hz" but, as far as I can tell, it's supposed to use the card clock. Let's account for the div value, which is documented as 2x the value stored in the register, or 1 if the register is 0. NOTE: It's not expected that this will actually fix anything important since the 10 ms margin added by the function will pretty much dwarf any calculations. The card clock should be 100 kHz at minimum and: 1000 ms/s * (255 * 2) / 100000 Hz. Gives us 5.1 ms. ...so really the point of this patch is just to make the code more "correct" in case anyone ever tries to remove the 10 ms buffer. Change-Id: Ie5d902edb3a5bdfb9dc9233eb46edbbee334994c Fixes: 03de19212ea3 ("mmc: dw_mmc: introduce timer for broken command transfer over scheme") Tested-by: Emil Renner Berthing Reviewed-by: Shawn Lin Signed-off-by: Douglas Anderson Signed-off-by: Ulf Hansson Signed-off-by: Shawn Lin (cherry picked from https://patchwork.kernel.org/patch/10002775/) --- drivers/mmc/host/dw_mmc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 7d6a9af68ff3..8e2304a8b857 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -367,10 +367,14 @@ static void dw_mci_wait_while_busy(struct dw_mci *host, u32 cmd_flags) static inline void dw_mci_set_cto(struct dw_mci *host) { unsigned int cto_clks; + unsigned int cto_div; unsigned int cto_ms; cto_clks = mci_readl(host, TMOUT) & 0xff; - cto_ms = DIV_ROUND_UP(cto_clks, host->bus_hz / 1000); + cto_div = (mci_readl(host, CLKDIV) & 0xff) * 2; + if (cto_div == 0) + cto_div = 1; + cto_ms = DIV_ROUND_UP(MSEC_PER_SEC * cto_clks * cto_div, host->bus_hz); /* add a bit spare time */ cto_ms += 10;