[U-Boot] TIMER cleanup RFC, was: [PATCH 4/4] arm920t/at91/timer: replace bss variables by gd
J. William Campbell
jwilliamcampbell at comcast.net
Tue Nov 30 18:29:52 CET 2010
On 11/30/2010 7:48 AM, Reinhard Meyer wrote:
> Dear J. William Campbell,
>> On 11/30/2010 1:14 AM, Reinhard Meyer wrote:
>>> Dear Wolfgang Denk,
>>>
>>> what we really need is only a 32 bit monotonous free running tick that
>>> increments
>>> at a rate of at least 1 MHz. As someone pointed out a while ago, even
>>> at 1GHz that would
>>> last for four seconds before it rolls over. But a 1HGz counter could
>>> be 64 bit internally
>>> and always be returned as 32 bits when it is shifted right to bring it
>>> into the "few" MHz
>>> range.
>>>
>>> Any architecture should be able to provide such a 32 bit value. On
>>> powerpc that would
>>> simply be tbu|tbl shifted right a few bits.
>>>
>>> An architecture and SoC specific timer should export 3 functions:
>>>
>>> int timer_init(void);
>>> u32 get_tick(void); /* return the current value of the internal free
>>> running counter */
>>> u32 get_tbclk(void); /* return the rate at which that counter
>>> increments (per second) */
>>>
>>> A generic timer function common to *most* architectures and SoCs would
>>> use those two
>>> functions to provice udelay() and reset_timer() and get_timer().
>>> Any other timer functions should not be required in u-boot anymore.
>>>
>>> However get_timer() and reset_timer() are a bit of a functional problem:
>>>
>>> currently reset_timer() does either actually RESET the free running
>>> timer (BAD!) or
>>> remember its current value in another (gd-)static variable which later
>>> is subtracted
>>> when get_timer() is called. That precludes the use of several timers
>>> concurrently.
>>>
>>> Also, since the 1000Hz base for that timer is usually derived from
>>> get_tick() by
>>> dividing it by some value, the resulting 1000Hz base is not exhausting
>>> the 32 bits
>>> before it wraps to zero.
> (###)
Hi All,
A correct method to provide a full 32 bits of resolution at a 1
ms rate is simple. It requires maintaining a software timer in ms. This
timer is updated by converting the difference in the hardware time base
to ms and then adding the correct number of ms to the software timer.
As previously discussed, this only requires calling get_timer once a
second or so. The conversion can be made simply in most cases,
especially if the clock rate is a "nice" number. Even in the worst case,
it is not too hard to "adjust" the saved hardware timer value to contain
any remainder ticks. Yes, if this is done incorrectly, the results are bad.
>>> Therefore I propose two new functions that are to replace
>>> reset_timer() and get_timer():
>>>
>>> u32 init_timeout(u32 timeout_in_ms); /* return the 32 bit tick value
>>> when the timeout will be */
>>> bool is_timeout(u32 reference); /* return true if reference is in the
>>> past */
>>>
>>> A timeout loop would therefore be like:
>>>
>>> u32 t_ref = timeout_init(3000); /* init a 3 second timeout */
>>>
>>> do ... loop ... while (!is_timeout(t_ref));
>>>
>>> coarse sketches of those functions:
>>>
>>> u32 init_timeout(u32 ms)
>>> {
>>> return get_ticks() + ((u64)get_tbclk() * (u64)ms) / (u64)1000;
>>> }
>>>
>>> bool is_timeout(u32 reference)
>>> {
>>> return ((int)get_ticks() - (int)reference)> 0;
>>> }
>>>
>>> Unfortunately this requires to "fix" all uses of get_timer() and
>>> friends, but I see no other
>>> long term solution to the current incoherencies.
>>>
>>> Comments welcome (and I would provide patches)...
>> Hi All,
>> The idea of changing the get_timer interface to the
>> init_timeout/is_timeout pair has the advantage that it is only necessary
>> to change the delay time in ms to an internal timebase once, and after
>> that, only a 32-bit subtraction is required.
> Exactly.
>> I do not however like the
>> idea of using 64 bit math to do so, as on many systems this is quite
>> expensive. However, this is a feature that can be optimized for
>> particular CPUs.
> 64 Bit math is only necessary when get_tbclk() times the maximun anticipated
> timeout (in ms) is larger than 32 bits. This happens easyly when tbclk is a
> few MHz.
What I think you mean to say here is that the delay time fits easily
into 32 bits for all reasonable clock rates. For instance, a 1 GHz clock
rate yields a maximum delay of about 2 seconds in a 32 bit word? For
fast clock rates, it is probably advisable to shift the 64 bit counter
right a few bits to ensure adequate range.
> Besides the current working(!) implementations use 64 bit math
> already.
In ARM perhaps, but I think there are lots of working 32 bit in other
processors(?).
> You can optimize into 32 bits by factoring the timeout_in_ms into
> whole seconds, and the remainder.
True.
>> I also REALLY don't like the idea of having a get_ticks
>> function, because for sure people will use this instead of the desired
>> interface to the timer because it is "better". Then we get back into a
>> mess. Since in most cases get_ticks is one or two instructions, please,
>> let us hide them in init_timeout/is_timeout.
> Agreed. However I intended to split the timer into two sources (read above):
> one hardware dependant part exporting exactly those functions, and one
> generic part using them.
Yes, and that is EXACTLY what I think is a bad idea for the reason I
mentioned. If the get_ticks interface is public, it will be used, and
this will lead to problems (as it already has). Yes, we can say "don't
do that", but people will do it anyway, and eventually it will sneak
into the code base. Since the conversion to/from hardware resolution to
1 ms resolution becomes CPU dependent if any optimization is used, this
operation really needs to be a per CPU thing.
>> An alternate approach, which has the merit of being more like the
>> originally intended interface, simply disallows reset_timer since it is
>> totally unnecessary. The only dis-advantage of the original approach
>> using just get_timer is that the conversion to ms must be considered at
>> each call to get_timer, and will require at a minimum one 32 bit integer
>> to remember the hardware timer value the last time get_timer was called
> "remembering" that inside the timer function is exactly what I want to get
> rid of. And that would not work in case of the usage method (2.) below.
>> (unless the hardware time can be trivially converted to a 32 bit value
>> in ms, which is quite uncommon).
> Indeed.
>> This is not a high price to pay, and
>> matches the current usage. This is probably for Mr. Denk to decide. If
> The "current usages" are mainly those two:
> 1. reset_timer(); ... if (get_timer(0)> TIMEOUT) ...
> --> this is an ab-use, of course, but can be found in u-boot.
Getting rid of reset_reset timer detects all such abuses.
> 2. epoch = get_timer(0); ... if (get_timer(epoch)> TIMEOUT) ...
> --> this is the correct way to use get_timer(), however it has the problem
> of incorrect rollover after 32 bits. See (###) above!
I assume by ### you mean that is get_timer(int x) is not based on a
correct conversion of hardware time to a 1 ms timebase, there is a
problem. 32 bits at 1 ms resolution is 49.7/2 days, so you can't mean
this is the problem.
>> we were just starting now, the init_timeout/is_timeout is simpler, but
>> since we are not, perhaps keeping the current approach has value.
> Finding the current uses of get_timer() is a simple grep, fixing the code
> should not require more than a few minutes per location. Testing, however
> is a problem. But ANY change would require testing.
>> I would really like to help by providing some patches, but I am
>> just way too busy at present.
> Same here. Nevertheless some xmax holidays are coming up, and maybe some
> idle hours in them ;)
I hope so!
Best Regards,
Bill Campbell
> Best Regards,
> Reinhard
>
>
>
>
More information about the U-Boot
mailing list