Re: [U-Boot] [PATCH v2] mmc: omap: timeout counter fix
On 10/25/2010 11:01 PM, Reinhard Meyer wrote: Dear Wolfgang Denk, Dear Reinhard Meyer, In message4cc66a67.4000...@emk-elektronik.de you wrote: It fails in case the timer wraps around. Assume 32 bit counters, start time = 0xFFF0, delay = 0x20. It will compute end = 0x10, the while codition is immediately false, and you don't have any delay at all, which most probably generates a false error condition. I used and assumed a 64 bit counter, that will not wrap around while our civilization still exists... The code is still wrong, and as a simple correct implementation exists there is no excuse for using such incorrect code. Please fix that! Agreed here. People are invited to dig through u-boot and find all those places. If get_ticks() is only 32 bits worth, both methods will misbehave at a 32 bit wrap over. No. start = time(); while ((time() - start)delay) ... This works much better (assuming unsigned arithmetics). True, provided the underlying timer is really 64 bits, otherwise this fails, too... You are wrong. Try for example this: - snip --- #includestdio.h int main(void) { unsigned int time = 0xFFF0; unsigned int delay = 0x20; unsigned int start; You are wrong here, because you take it out of context. My demo is using the (declared as) 64 bit function get_ticks(). I mentioned above that this function MUST be truly returning 64 bits worth of (incrementing) value to make any version work. If get_ticks() just returns a 32 bit counter value neither method will work reliably. Just check all implementations that this function is implemented correctly. Hi All, I have wondered for quite some time about the rush to make get_ticks() return a 64 bit value. For any reasonable purpose, like waiting a few seconds for something to complete, a 32 bit timebase is plenty adequate. If the number of ticks per second is 10, i.e. a 1 GHz clock rate, the clock wraps in a 32 bit word about every five seconds. The trick is that time always moves forward, so a current get_ticks() - a previous get_ticks() is ALWAYS a positive number. It is necessary to check the clock more often than (0X1 - your_timeout) times per second, but unless your timeout is very near the maximum time that fits into 32 bits, this won't be a problem. Most CPUs have a counter that count at a reasonable rate. Some CPUs also have a cycle counter that runs at the CPU clock rate. These counters are useful to determine exactly how many machine cycles a certain process took, and therefore they have high resolution. Timers for simple delays neither need nor want such resolution. If the only counter available on you CPU runs at several GHz, and is 64 bits long, just shift it right a few bits to reduce the resolution to a reasonable resolution and return a 32 bit value. There is no need for a bunch of long long variables and extra code running around to process simple timeouts. It may be that we need a different routine for precision timing measurements with high resolution, but it needn't, and probably shouldn't IMHO be get_ticks(). Best Regards, Bill Campbell ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
Re: [U-Boot] [PATCH v2] mmc: omap: timeout counter fix
Dear Reinhard Meyer, In message 4cc66eca.9000...@emk-elektronik.de you wrote: Agreed here. People are invited to dig through u-boot and find all those places. You know the ones you added best :-) int main(void) { unsigned int time = 0xFFF0; unsigned int delay = 0x20; unsigned int start; You are wrong here, because you take it out of context. I am not wrong. Feel free to replace unsigned int by unsigned long long, and 0xFFF0 by 0xFFF0ULL, and the %X by %llX. My demo is using the (declared as) 64 bit function get_ticks(). I mentioned above that this function MUST be truly returning 64 bits worth of (incrementing) value to make any version work. What's the difference? It is inherently wrong to believe an overflow would never occur just because the precision of a number is long enough. Remeber y2k issues. Remember the time overflog for UNIX systems in 2038, etc. etc. If get_ticks() just returns a 32 bit counter value neither method will work reliably. Just check all implementations that this function is implemented correctly. No, the code is still WRONG. It'ss just that the problem is less likely to hit. BTW - who says the timer starts counting at 0 ? Best regards, Wolfgang Denk -- DENX Software Engineering GmbH, MD: Wolfgang Denk Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: w...@denx.de Lack of skill dictates economy of style.- Joey Ramone ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
Re: [U-Boot] [PATCH v2] mmc: omap: timeout counter fix
Dear Wolfgang Denk, Dear Reinhard Meyer, In message 4cc66eca.9000...@emk-elektronik.de you wrote: Agreed here. People are invited to dig through u-boot and find all those places. You know the ones you added best :-) int main(void) { unsigned int time = 0xFFF0; unsigned int delay = 0x20; unsigned int start; You are wrong here, because you take it out of context. I am not wrong. Feel free to replace unsigned int by unsigned long long, and 0xFFF0 by 0xFFF0ULL, and the %X by %llX. My demo is using the (declared as) 64 bit function get_ticks(). I mentioned above that this function MUST be truly returning 64 bits worth of (incrementing) value to make any version work. What's the difference? It is inherently wrong to believe an overflow would never occur just because the precision of a number is long enough. Remeber y2k issues. Remember the time overflog for UNIX systems in 2038, etc. etc. If get_ticks() just returns a 32 bit counter value neither method will work reliably. Just check all implementations that this function is implemented correctly. You should really try to understand what I am saying here: IF get_timer() returns 0x to 0x and wraps back to 0x (thats how it is or was implemented in SOME architectures) neither mine (agreed to be wrong) nor your code would work if it uses 64 bits vars. Reinhard ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
Re: [U-Boot] [PATCH v2] mmc: omap: timeout counter fix
Ghorai, Sukumar had written, on 10/26/2010 12:34 AM, the following: [...] [Ghorai] Thanks.. This is the best approach. Otherwise udelay() will increase the boot time. Please define increase the boot time with the context to the patch where you think the increase of boot time will be? In my experience, it has not. the iterations are such that: while (condition_not_met) udelay(10); This is reasonable enough to wait till the condition is met. a) u-boot boot logic is not invoked until mmc part 0 is invoked - u-boot boot time does not change b) the actual fatload by itself will only incur minor latency addition - IMHO - necessary addition - in cases where the check conditions are not met. would be great if you can illustrate within the patch areas which need continuous checks Vs the ones that do not need continuous checks. -- Regards, Nishanth Menon ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2] mmc: omap: timeout counter fix
Having a loop with a counter is no timing guarentee for timing accuracy or compiler optimizations. For e.g. the same loop counter which runs when the MPU is running at 600MHz will timeout in around half the time when running at 1GHz. or the example where GCC 4.5 compiles with different optimization compared to GCC 4.4. use a udelay(10) to ensure we have a predictable delay. use an emperical number - 10 uSec ~= 1sec for a worst case timeout. This should never happen, and is adequate imaginary condition for us to fail with timeout. Signed-off-by: Nishanth Menon n...@ti.com --- V2: additional cleanups + made MAX_RETRY a macro for reuse throughout the file. tested on PandaBoard with 1GHz boot frequency and GCC4.5 on u-boot 2010.09 + mmc patches. Requesting testing on other platforms V1: http://www.mail-archive.com/u-boot@lists.denx.de/msg40969.html drivers/mmc/omap_hsmmc.c | 114 +++--- 1 files changed, 97 insertions(+), 17 deletions(-) diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index 9271470..f7bdfe9 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -30,6 +30,7 @@ #include twl4030.h #include asm/io.h #include asm/arch/mmc_host_def.h +#define MAX_RETRY 10 static int mmc_read_data(hsmmc_t *mmc_base, char *buf, unsigned int size); static int mmc_write_data(hsmmc_t *mmc_base, const char *buf, unsigned int siz); @@ -70,18 +71,32 @@ unsigned char mmc_board_init(hsmmc_t *mmc_base) void mmc_init_stream(hsmmc_t *mmc_base) { + int retry = MAX_RETRY; writel(readl(mmc_base-con) | INIT_INITSTREAM, mmc_base-con); writel(MMC_CMD0, mmc_base-cmd); - while (!(readl(mmc_base-stat) CC_MASK)) - ; + while (!(readl(mmc_base-stat) CC_MASK)) { + retry--; + udelay(10); + if (!retry) { + printf(%s: timedout waiting for cc!\n, __func__); + return; + } + } writel(CC_MASK, mmc_base-stat) ; writel(MMC_CMD0, mmc_base-cmd) ; - while (!(readl(mmc_base-stat) CC_MASK)) - ; + retry = MAX_RETRY; + while (!(readl(mmc_base-stat) CC_MASK)) { + retry--; + udelay(10); + if (!retry) { + printf(%s: timedout waiting for cc2!\n, __func__); + return; + } + } writel(readl(mmc_base-con) ~INIT_INITSTREAM, mmc_base-con); } @@ -91,16 +106,31 @@ static int mmc_init_setup(struct mmc *mmc) hsmmc_t *mmc_base = (hsmmc_t *)mmc-priv; unsigned int reg_val; unsigned int dsor; + int retry = MAX_RETRY; mmc_board_init(mmc_base); writel(readl(mmc_base-sysconfig) | MMC_SOFTRESET, mmc_base-sysconfig); - while ((readl(mmc_base-sysstatus) RESETDONE) == 0) - ; + while ((readl(mmc_base-sysstatus) RESETDONE) == 0) { + retry--; + udelay(10); + if (!retry) { + printf(%s: timedout waiting for cc2!\n, __func__); + return TIMEOUT; + } + } writel(readl(mmc_base-sysctl) | SOFTRESETALL, mmc_base-sysctl); - while ((readl(mmc_base-sysctl) SOFTRESETALL) != 0x0) - ; + retry = MAX_RETRY; + while ((readl(mmc_base-sysctl) SOFTRESETALL) != 0x0) { + retry--; + udelay(10); + if (!retry) { + printf(%s: timedout waiting for softresetall!\n, + __func__); + return TIMEOUT; + } + } writel(DTW_1_BITMODE | SDBP_PWROFF | SDVS_3V0, mmc_base-hctl); writel(readl(mmc_base-capa) | VS30_3V0SUP | VS18_1V8SUP, mmc_base-capa); @@ -116,8 +146,15 @@ static int mmc_init_setup(struct mmc *mmc) (ICE_STOP | DTO_15THDTO | CEN_DISABLE)); mmc_reg_out(mmc_base-sysctl, ICE_MASK | CLKD_MASK, (dsor CLKD_OFFSET) | ICE_OSCILLATE); - while ((readl(mmc_base-sysctl) ICS_MASK) == ICS_NOTREADY) - ; + retry = MAX_RETRY; + while ((readl(mmc_base-sysctl) ICS_MASK) == ICS_NOTREADY) { + retry--; + udelay(10); + if (!retry) { + printf(%s: timedout waiting for ics!\n, __func__); + return TIMEOUT; + } + } writel(readl(mmc_base-sysctl) | CEN_ENABLE, mmc_base-sysctl); writel(readl(mmc_base-hctl) | SDBP_PWRON, mmc_base-hctl); @@ -137,14 +174,27 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, { hsmmc_t *mmc_base = (hsmmc_t *)mmc-priv; unsigned int flags, mmc_stat; - unsigned int retry = 0x10; + int retry = MAX_RETRY; -
Re: [U-Boot] [PATCH v2] mmc: omap: timeout counter fix
Dear Nishanth Menon, Having a loop with a counter is no timing guarentee for timing accuracy or compiler optimizations. For e.g. the same loop counter which runs when the MPU is running at 600MHz will timeout in around half the time when running at 1GHz. or the example where GCC 4.5 compiles with different optimization compared to GCC 4.4. use a udelay(10) to ensure we have a predictable delay. use an emperical number - 10 uSec ~= 1sec for a worst case timeout. This should never happen, and is adequate imaginary condition for us to fail with timeout. In such cases I prefer to use: uint64_t etime; ... etime = get_ticks() + get_tbclk(); /* 1 second */ do { whatever; udelay (xx); } while (condition get_ticks() = etime); That is far more accurate than calling udelay() 10 times. (depending on implementation and granularity udelay of a few usecs might be rounded significantly) You can still call udelay inside the loop if you don't want to poll the condition too tightly... Best Regards, Reinhard ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
Re: [U-Boot] [PATCH v2] mmc: omap: timeout counter fix
Reinhard Meyer had written, on 10/25/2010 08:14 PM, the following: Dear Nishanth Menon, Having a loop with a counter is no timing guarentee for timing accuracy or compiler optimizations. For e.g. the same loop counter which runs when the MPU is running at 600MHz will timeout in around half the time when running at 1GHz. or the example where GCC 4.5 compiles with different optimization compared to GCC 4.4. use a udelay(10) to ensure we have a predictable delay. use an emperical number - 10 uSec ~= 1sec for a worst case timeout. This should never happen, and is adequate imaginary condition for us to fail with timeout. In such cases I prefer to use: uint64_t etime; ... etime = get_ticks() + get_tbclk(); /* 1 second */ do { whatever; udelay (xx); } while (condition get_ticks() = etime); That is far more accurate than calling udelay() 10 times. (depending on implementation and granularity udelay of a few usecs might be rounded significantly) You can still call udelay inside the loop if you don't want to poll the condition too tightly... hmmm.. almost like the jiffies in kernel ;).. timing wise, I see that the only benefit is that the approach gives a little more accuracy to the timeout delay - the other benefit is option to loop continuously instead of delaying with udelays - overall, at least the segments I saw had no reason to hit the registers so hard (alright we dont have much else to do.. but still).. I am very open to options from Sukumar(original author) as well.. -- Regards, Nishanth Menon ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
Re: [U-Boot] [PATCH v2] mmc: omap: timeout counter fix
-Original Message- From: u-boot-boun...@lists.denx.de [mailto:u-boot-boun...@lists.denx.de] On Behalf Of Wolfgang Denk Sent: Tuesday, October 26, 2010 10:06 AM To: Menon, Nishanth Cc: u-boot Subject: Re: [U-Boot] [PATCH v2] mmc: omap: timeout counter fix Dear Nishanth Menon, In message 1288054924-24989-1-git-send-email...@ti.com you wrote: Having a loop with a counter is no timing guarentee for timing accuracy or compiler optimizations. For e.g. the same loop counter which runs when the MPU is running at 600MHz will timeout in around half the time when running at 1GHz. or the example where GCC 4.5 compiles with different optimization compared to GCC 4.4. use a udelay(10) to ensure we have a predictable delay. use an emperical number - 10 uSec ~= 1sec for a worst case timeout. Hm... 10 usec = 0.1 sec only... Guess you mean 100,000 x 10 usec = 1 sec ? Best regards, Wolfgang Denk [..snip..] [Menon, Nishanth] - overall, at least the segments I saw had no reason to hit the registers so hard (alright we dont have much else to do.. but still).. I am very open to options from Sukumar(original author) as well.. [Ghorai] I am agreeing with the part where it's looks while(1) loop. And can add retry counter too. otherwise I feel I will increase the boot time. ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
Re: [U-Boot] [PATCH v2] mmc: omap: timeout counter fix
Dear Reinhard Meyer, In message 4cc62b6c.30...@emk-elektronik.de you wrote: In such cases I prefer to use: uint64_t etime; ... etime = get_ticks() + get_tbclk(); /* 1 second */ do { whatever; udelay (xx); } while (condition get_ticks() = etime); That is far more accurate than calling udelay() 10 times. It may be more accuratre, but it may also be HORRIBLY WRONG!! Do NOT do that!! NEVER implement such a delay loop as end = time() + delay; while (time() end) ... It fails in case the timer wraps around. Assume 32 bit counters, start time = 0xFFF0, delay = 0x20. It will compute end = 0x10, the while codition is immediately false, and you don't have any delay at all, which most probably generates a false error condition. Correct implementation of a timeout like that should always look like that: start = time(); while ((time() - start) delay) ... This works much better (assuming unsigned arithmetics). Best regards, Wolfgang Denk -- DENX Software Engineering GmbH, MD: Wolfgang Denk Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: w...@denx.de Ein weiser Herrscher kann in einem großen Land mehr Gutes bewirken als in einem kleinen - ein dummer Herrscher aber auch viel mehr Un- fug. Da weise Herrscher seltener sind als dumme, war ich schon immer gegen große Reiche skeptisch. - Herbert Rosendorfer ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
Re: [U-Boot] [PATCH v2] mmc: omap: timeout counter fix
Dear Nishanth Menon, In message 4cc62c81.8000...@ti.com you wrote: You can still call udelay inside the loop if you don't want to poll the condition too tightly... hmmm.. almost like the jiffies in kernel ;).. timing wise, I see that Yes, except for the bugs... ;-) Best regards, Wolfgang Denk -- DENX Software Engineering GmbH, MD: Wolfgang Denk Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: w...@denx.de Der Horizont vieler Menschen ist ein Kreis mit Radius Null -- und das nennen sie ihren Standpunkt. ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
Re: [U-Boot] [PATCH v2] mmc: omap: timeout counter fix
-Original Message- From: u-boot-boun...@lists.denx.de [mailto:u-boot-boun...@lists.denx.de] On Behalf Of Wolfgang Denk Sent: Tuesday, October 26, 2010 10:59 AM To: Reinhard Meyer Cc: Menon, Nishanth; u-boot Subject: Re: [U-Boot] [PATCH v2] mmc: omap: timeout counter fix Dear Reinhard Meyer, In message 4cc62b6c.30...@emk-elektronik.de you wrote: In such cases I prefer to use: uint64_t etime; ... etime = get_ticks() + get_tbclk(); /* 1 second */ do { whatever; udelay (xx); } while (condition get_ticks() = etime); That is far more accurate than calling udelay() 10 times. It may be more accuratre, but it may also be HORRIBLY WRONG!! Do NOT do that!! NEVER implement such a delay loop as end = time() + delay; while (time() end) ... It fails in case the timer wraps around. Assume 32 bit counters, start time = 0xFFF0, delay = 0x20. It will compute end = 0x10, the while codition is immediately false, and you don't have any delay at all, which most probably generates a false error condition. Correct implementation of a timeout like that should always look like that: start = time(); while ((time() - start) delay) ... This works much better (assuming unsigned arithmetics). [Ghorai] Thanks.. This is the best approach. Otherwise udelay() will increase the boot time. Best regards, Wolfgang Denk -- DENX Software Engineering GmbH, MD: Wolfgang Denk Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: w...@denx.de Ein weiser Herrscher kann in einem großen Land mehr Gutes bewirken als in einem kleinen - ein dummer Herrscher aber auch viel mehr Un- fug. Da weise Herrscher seltener sind als dumme, war ich schon immer gegen große Reiche skeptisch. - Herbert Rosendorfer ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
Re: [U-Boot] [PATCH v2] mmc: omap: timeout counter fix
Dear Wolfgang Denk, In message4cc62b6c.30...@emk-elektronik.de you wrote: In such cases I prefer to use: uint64_t etime; ... etime = get_ticks() + get_tbclk(); /* 1 second */ do { whatever; udelay (xx); } while (condition get_ticks()= etime); That is far more accurate than calling udelay() 10 times. It may be more accuratre, but it may also be HORRIBLY WRONG!! Do NOT do that!! NEVER implement such a delay loop as end = time() + delay; while (time() end) ... It fails in case the timer wraps around. Assume 32 bit counters, start time = 0xFFF0, delay = 0x20. It will compute end = 0x10, the while codition is immediately false, and you don't have any delay at all, which most probably generates a false error condition. I used and assumed a 64 bit counter, that will not wrap around while our civilization still exists... If get_ticks() is only 32 bits worth, both methods will misbehave at a 32 bit wrap over. Correct implementation of a timeout like that should always look like that: start = time(); while ((time() - start) delay) ... This works much better (assuming unsigned arithmetics). True, provided the underlying timer is really 64 bits, otherwise this fails, too... Best would be to assign get_ticks() to a 32 bit unsigned and use 32 bit vars for start and delay as well. The original udelay() implementation in AT91 would have failed at a 32 bit wrap over, too (fixed in mainline). I hope other implementations are done right, too... Best regards, Reinhard ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot