Re: Re: [PATCH V2] mmc: omap_hsmmc: Fix sleep too long in ISR context.
On Wednesday 21 August 2013 12:22 AM, Hein Tibosch wrote: Hi, [ added some people from TI ] On 8/7/2013 6:05 PM, majianpeng wrote: V2: clean up code. V1: www.mail-archive.com/linux-omap@vger.../msg93239.html We found a problem when we removed a working sd card that the irqaction of omap_hsmmc can sleep to 3.6s. This cause our watchdog to work. In func omap_hsmmc_reset_controller_fsm, it should watch a 0-1 transition.But avoiding endless waiting, it used loops_per_jiffy as the timer. Tried on a OMAP4460: This can easily be replicated: just withdraw an SD-card and the kernel will get blocked during more than 3 seconds. Calling OMAP_HSMMC_READ() in this loop makes it last so long. The function waits for a 0=1, followed by a 1=0 transition. The value of 1 always comes, but in most cases the code is just too slow to detect it. The first loop will only stop when (i == limit) The code is: while ((!(OMAP_HSMMC_READ(host-base, SYSCTL) bit)) (i++ limit)) cpu_relax(); But generanly loops_per_jiffy as a timer,it should like: while(i++ limit) cpu_relax(); I found for the long time case, the while-opeation stoped because 'i == limit'. Because added some code, so the duration became too longer than MMC_TIMEOU_US(20ms). The software can't monitor the transition of hardware for thi case. Becasue those codes in ISR context, it can't use timer_before/after. I divived the time into 1ms and used udelay(1) to instead. It will cause do additional udelay(1).But from my test,it looks good. Reported-by: Yuzheng Ma mayuzh...@kedacom.com Tested-by: Yuzheng Ma mayuzh...@kedacom.com Reviewed-by: Hein Tibosch hein_tibo...@yahoo.es Signed-off-by: Jianpeng Ma majianp...@gmail.com --- drivers/mmc/host/omap_hsmmc.c | 25 +++-- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 1865321..bbda5ed 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -973,9 +973,8 @@ static inline void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host, static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host, unsigned long bit) { - unsigned long i = 0; - unsigned long limit = (loops_per_jiffy * - msecs_to_jiffies(MMC_TIMEOUT_MS)); + /*change to 1ms,so we can use udelay(1)*/ + unsigned long limit = MMC_TIMEOUT_MS * 1000; OMAP_HSMMC_WRITE(host-base, SYSCTL, OMAP_HSMMC_READ(host-base, SYSCTL) | bit); Checked here: the SRC-bit indeed becomes high. After the test 'features HSMMC_HAS_UPDATED_RESET', the bit has become low again already. Changing to order of statements worked for me, but for Jianpeng Ma this didn't work (timings are 'on the edge'). I think 1-0 transition is missed sometimes and waiting until timeout, Jianpeng Ma, which SoC are you testing ? Hi, my sos is DM8107. Thanks! Jianpeng Ma!
[PATCH V2] mmc: omap_hsmmc: Fix sleep too long in ISR context.
V2: clean up code. V1: www.mail-archive.com/linux-omap@vger.../msg93239.html We found a problem when we removed a working sd card that the irqaction of omap_hsmmc can sleep to 3.6s. This cause our watchdog to work. In func omap_hsmmc_reset_controller_fsm, it should watch a 0-1 transition.But avoiding endless waiting, it used loops_per_jiffy as the timer. The code is: while ((!(OMAP_HSMMC_READ(host-base, SYSCTL) bit)) (i++ limit)) cpu_relax(); But generanly loops_per_jiffy as a timer,it should like: while(i++ limit) cpu_relax(); I found for the long time case, the while-opeation stoped because 'i == limit'. Because added some code, so the duration became too longer than MMC_TIMEOU_US(20ms). The software can't monitor the transition of hardware for thi case. Becasue those codes in ISR context, it can't use timer_before/after. I divived the time into 1ms and used udelay(1) to instead. It will cause do additional udelay(1).But from my test,it looks good. Reported-by: Yuzheng Ma mayuzh...@kedacom.com Tested-by: Yuzheng Ma mayuzh...@kedacom.com Reviewed-by: Hein Tibosch hein_tibo...@yahoo.es Signed-off-by: Jianpeng Ma majianp...@gmail.com --- drivers/mmc/host/omap_hsmmc.c | 25 +++-- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 1865321..bbda5ed 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -973,9 +973,8 @@ static inline void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host, static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host, unsigned long bit) { - unsigned long i = 0; - unsigned long limit = (loops_per_jiffy * - msecs_to_jiffies(MMC_TIMEOUT_MS)); + /*change to 1ms,so we can use udelay(1)*/ + unsigned long limit = MMC_TIMEOUT_MS * 1000; OMAP_HSMMC_WRITE(host-base, SYSCTL, OMAP_HSMMC_READ(host-base, SYSCTL) | bit); @@ -984,17 +983,15 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host, * OMAP4 ES2 and greater has an updated reset logic. * Monitor a 0-1 transition first */ - if (mmc_slot(host).features HSMMC_HAS_UPDATED_RESET) { - while ((!(OMAP_HSMMC_READ(host-base, SYSCTL) bit)) -(i++ limit)) - cpu_relax(); - } - i = 0; - - while ((OMAP_HSMMC_READ(host-base, SYSCTL) bit) - (i++ limit)) - cpu_relax(); - + if (mmc_slot(host).features HSMMC_HAS_UPDATED_RESET) + while (!(OMAP_HSMMC_READ(host-base, SYSCTL) bit) +limit--) + udelay(1); + + limit = MMC_TIMEOUT_MS * 1000; + while ((OMAP_HSMMC_READ(host-base, SYSCTL) bit) limit--) + udelay(1); + if (OMAP_HSMMC_READ(host-base, SYSCTL) bit) dev_err(mmc_dev(host-mmc), Timeout waiting on controller reset in %s\n, -- 1.8.1.2
Re: Re: [PATCH] mmc: omap_hsmmc: Fix sleep too long in ISR context.
Hi Jianpeng Ma, On 8/1/2013 10:18 AM, majianpeng wrote: We found a problem when we removed a working sd card that the irqaction of omap_hsmmc can sleep to 3.6s. This cause our watchdog to work. In func omap_hsmmc_reset_controller_fsm, it should watch a 0-1 transition.It used loops_per_jiffy as the timer. The code is: while ((!(OMAP_HSMMC_READ(host-base, SYSCTL) bit)) (i++ limit)) cpu_relax(); But the loops_per_jiffy is: while(i++ limit) cpu_relax(); It add some codes so the time became long. Becasue those codes in ISR context, it can't use timer_before/after. I divived the time into 1ms and used udelay(1) to instead. It will cause do additional udelay(1).But from my test,it looks good. Reported-by: Yuzheng Ma mayuzh...@kedacom.com Tested-by: Yuzheng Ma mayuzh...@kedacom.com Signed-off-by: Jianpeng Ma majianp...@gmail.com --- drivers/mmc/host/omap_hsmmc.c | 20 +--- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 1865321..96daca1 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -977,6 +977,8 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host, unsigned long limit = (loops_per_jiffy * msecs_to_jiffies(MMC_TIMEOUT_MS)); +/*Divided time into us for unit 1,we can use udelay(1)*/ +i = limit / (MMC_TIMEOUT_MS * 1000); 'limit' is a number of loops, which you now divide by 20,000? To get uS, you could just change: - unsigned long limit = (loops_per_jiffy * - msecs_to_jiffies(MMC_TIMEOUT_MS)); + unsigned long limit = 1000 * MMC_TIMEOUT_MS; Yes, you are right. and make this amount of loops using udelay(). OMAP_HSMMC_WRITE(host-base, SYSCTL, OMAP_HSMMC_READ(host-base, SYSCTL) | bit); @@ -985,15 +987,19 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host, * Monitor a 0-1 transition first */ if (mmc_slot(host).features HSMMC_HAS_UPDATED_RESET) { -while ((!(OMAP_HSMMC_READ(host-base, SYSCTL) bit)) - (i++ limit)) -cpu_relax(); I still don't see why any of these loops could last 3.6 seconds? Yes the __raw_readl() will add some time, but so much? I'd like to see which value you get for 'limit' on your machine Would PM play a role? Or cpu-freq, and 'loops_per_jiffy' isn't updated on time? From my test, i found it don't monitor a 0-1 transtion.That is the last result is 'i = limit'. The later while opertion stop also because 'i = limit'. The basic reason is the hardware. It write bit and monitor 1--0---1---0.But we start monitor we only got 0 and the value don't change. Maybe the transition is 1--0.So the monitor can't work but still waste cpu. +while (i--) { +if ((OMAP_HSMMC_READ(host-base, SYSCTL) bit)) +break; +udelay(1); In earlier threads, the use of udelay was disliked because it's a waste of cpu cycles. The desired bit in SYSCTL will change, while udelay() is still making many useless loops. Yes, but it at most wast 1us. Jianpeng Ma +} } -i = 0; -while ((OMAP_HSMMC_READ(host-base, SYSCTL) bit) -(i++ limit)) -cpu_relax(); +i = limit / (MMC_TIMEOUT_MS * 1000); +while (i--) { +if (!(OMAP_HSMMC_READ(host-base, SYSCTL) bit)) +break; +udealy(1); +} if (OMAP_HSMMC_READ(host-base, SYSCTL) bit) dev_err(mmc_dev(host-mmc), Hein Thanks! Jianpeng Ma Hi Jianpeng Ma, On 8/1/2013 10:18 AM, majianpeng wrote: We found a problem when we removed a working sd card that the irqaction of omap_hsmmc can sleep to 3.6s. This cause our watchdog to work. In func omap_hsmmc_reset_controller_fsm, it should watch a 0-1 transition.It used loops_per_jiffy as the timer. The code is: while ((!(OMAP_HSMMC_READ(host-base, SYSCTL) bit)) (i++ limit)) cpu_relax(); But the loops_per_jiffy is: while(i++ limit) cpu_relax(); It add some codes so the time became long. Becasue those codes in ISR context, it can't use timer_before/after. I divived the time into 1ms and used udelay(1) to instead. It will cause do additional udelay(1).But from my test,it looks good. Reported-by: Yuzheng Ma mayuzh...@kedacom.com Tested-by: Yuzheng Ma mayuzh...@kedacom.com Signed-off-by: Jianpeng Ma majianp...@gmail.com --- drivers/mmc/host/omap_hsmmc.c | 20 +--- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 1865321..96daca1 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host
[PATCH] mmc: omap_hsmmc: Fix sleep too long in ISR context.
We found a problem when we removed a working sd card that the irqaction of omap_hsmmc can sleep to 3.6s. This cause our watchdog to work. In func omap_hsmmc_reset_controller_fsm, it should watch a 0-1 transition.It used loops_per_jiffy as the timer. The code is: while ((!(OMAP_HSMMC_READ(host-base, SYSCTL) bit)) (i++ limit)) cpu_relax(); But the loops_per_jiffy is: while(i++ limit) cpu_relax(); It add some codes so the time became long. Becasue those codes in ISR context, it can't use timer_before/after. I divived the time into 1ms and used udelay(1) to instead. It will cause do additional udelay(1).But from my test,it looks good. Reported-by: Yuzheng Ma mayuzh...@kedacom.com Tested-by: Yuzheng Ma mayuzh...@kedacom.com Signed-off-by: Jianpeng Ma majianp...@gmail.com --- drivers/mmc/host/omap_hsmmc.c | 20 +--- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 1865321..96daca1 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -977,6 +977,8 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host, unsigned long limit = (loops_per_jiffy * msecs_to_jiffies(MMC_TIMEOUT_MS)); + /*Divided time into us for unit 1,we can use udelay(1)*/ + i = limit / (MMC_TIMEOUT_MS * 1000); OMAP_HSMMC_WRITE(host-base, SYSCTL, OMAP_HSMMC_READ(host-base, SYSCTL) | bit); @@ -985,15 +987,19 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host, * Monitor a 0-1 transition first */ if (mmc_slot(host).features HSMMC_HAS_UPDATED_RESET) { - while ((!(OMAP_HSMMC_READ(host-base, SYSCTL) bit)) -(i++ limit)) - cpu_relax(); + while (i--) { + if ((OMAP_HSMMC_READ(host-base, SYSCTL) bit)) + break; + udelay(1); + } } - i = 0; - while ((OMAP_HSMMC_READ(host-base, SYSCTL) bit) - (i++ limit)) - cpu_relax(); + i = limit / (MMC_TIMEOUT_MS * 1000); + while (i--) { + if (!(OMAP_HSMMC_READ(host-base, SYSCTL) bit)) + break; + udealy(1); + } if (OMAP_HSMMC_READ(host-base, SYSCTL) bit) dev_err(mmc_dev(host-mmc), -- 1.8.1.2 Thanks! Jianpeng MaN�Р骒r��yb�X�肚�v�^�)藓{.n�+�伐�{雹f��{ay��,j��f"�h���z��wア� ⒎�j:+v���w�j�m��赙zZ+�茛j��!�i
About omap2 mmc host close too long irq in irqaction.
Hi all, Now i worked on omp2 and met a probelm which someplace close_irq for 3.6second. The kernel version is 2.6.37. I used trace to find in irq_action:omap_hsmmc_irq. This problem occured by removed the sdcard when there are io operations. I found the read problem is in omap_hsmmc_reset_controller_fsm. In omap_hsmmc_reset_controller_fsm: static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host, unsigned long bit) { unsigned long i = 0; unsigned long limit = (loops_per_jiffy * msecs_to_jiffies(MMC_TIMEOUT_MS)); OMAP_HSMMC_WRITE(host-base, SYSCTL, OMAP_HSMMC_READ(host-base, SYSCTL) | bit); /* * OMAP4 ES2 and greater has an updated reset logic. * Monitor a 0-1 transition first */ if (mmc_slot(host).features HSMMC_HAS_UPDATED_RESET) { while ((!(OMAP_HSMMC_READ(host-base, SYSCTL) bit)) (i++ limit)) cpu_relax(); } In func, it used loops_per_jiffy in order to avoid do many time exceed MMC_TIMEOUT_MS. In face oops_per_jiify is like: while(i++ loops_per_jiffy) cpu_relax(); But actually, it used as follow: while ((!(OMAP_HSMMC_READ(host-base, SYSCTL) bit)) (i++ limit)) it add some operations like: read regisger, , . So the time may exceed MMC_TIMEOUT_MS. I used those code to test and found it's ok: for (i = 0 ; i 10; i++){ if (!(OMAP_HSMMC_READ(host-base, SYSCTL) bit)) break; j = limit/10; while(j--) cpu_relax(); } Using this the problom can't occur. Am i missing something? Thanks! Jianpeng Ma