[U-Boot] [PATCH v1 (WIP) 00/16] [Timer]API Rewrite

Wolfgang Denk wd at denx.de
Tue Jul 12 15:10:42 CEST 2011


Dear Graeme Russ,

In message <4E1C23B8.6020101 at gmail.com> you wrote:
> 
> So how do we deal with Nios2? It is what caused such a deep investigation
> into the timer API. We have three choices I can think of off the top of my
> head:
> 
>  1. Move the whole timer API up to the architecture level and replicate
> code everywhere
>  2. Make the whole timer API weak
>  3. Fundamentally allow the timer API to handle arbitrary timer resolutions
> 
> 1. Way ugly. We already have this, and that is why we are here today
> 2. Well, you know what will happen - Someone will be unhappy with the
> generic API and rewrite a completely different one (timer_masked anyone!)
> 3. Why is this so evil?

The big disadvantage of 3) is that you cannot make any reasonable
assumptions any more in the code.  If I place a "udelay(10)" in some
device driver, I am probably aware that we don't have exact times, and
that the actual delay may be 10 or 12 or eventually even 20 micro-
seconds.  We should make sure that the delay never takes less than 10 us,
but we also have to guarantee that it does not take - for example -
10 milliseconds.


What exactly is the reason that we cannot have better timer
resolutions in NIOS?  I'm anything but a NIOS export, but skimming
through the "Altera Embedded Peripherals IP User Guide", section "28.
Interval Timer Core" I see that we can have "32-bit and 64-bit
counters", "Two count modes: count down once and continuous
count-down", and the example in section "Configuration: Timeout
Period" on p. 28-3 reads:

        For example, if the associated system clock has a frequency
        of 30 ns, and the specified Timeout Period value is 1 µs, the
        true timeout period will be 1.020 microseconds.

Well, if I understand this correctly, we can have a continuously
running 64 bit counter with microsecond resolution.

There are other sections that describe configurations that might
probably be used as well, for example in "HAL System Library Support":

	Timestamp Driver
	The interval timer core may be used as a timestamp device ...

Also, the "Nios II Software Developer's Handbook" says in "Chapter 6:
Developing Programs Using the Hardware Abstraction Layer - Using
Timer Devices" on o. 6-16:

	The HAL API provides two types of timer device drivers:
        - System clock driver--Supports alarms, such as you would use
          in a scheduler.
        - Timestamp driver--Supports high-resolution time
          measurement.
	...
        You can obtain the rate at which the timestamp counter
        increments by calling the function alt_timestamp_freq(). This
        rate is typically the hardware frequency of the Nios II
        processor system--usually millions of cycles per second. The
        timestamp drivers are defined in the alt_timestamp.h header
        file.

High-resolution time measurement?  Isn't this what we are looking for?

Or am I missing something?

Scott, maybe you can comment here?


> I'm open to other options if you have any

At the moment I'm trying to understand if we really have a problem on
NIOS2 that cannot be fixed in a way that is compatible with our
current plans.

> 1) Get the current time

Agreed. That's time().

> 2) Report the minimum time elapsed since an arbitrary epoch
> 3) Report the maximum time elapsed since an arbitrary epoch

I don't understand why we would need this.

> 4) Delay for an arbitrary period of time
> 
> 4 is a derivative of 2 - Just loop until at least the required time has
> elapsed.

Right.  Both delays and timeouts work like that, the difference being
that delays are "blocking", i. e. there is no other code running
inbetween, and you can just sit in a tight spinning loop.

I have not seen any requirement yet for 3.

> And you then suggest bringing in no less than 6 functions from Linux

It's just macros.  And we don't need to use them all.  Actually
time_after() is all that's needed to satisfy our current usage.

> Done - I will reject the current series and rebase/repost the patches you
> have already ack'd and assign them to you in patchwork - I'll leave it up
> to you to pull them in

Don't reject them - just mark them as RFC.


> Provided you have access to an incrementing value which increments at a
> fixed rate and you know the rate, the rest is architecture independent

We also have to deal with decrementing counters, but this is just aan
unimportant detail.  And it appears that we actually can have this,
even on NIOS.

> > We could also say this is all we need. If we have a working high
> > precision TOD timestamp, we can derive all other things we need from
> > that.
> 
> So you want to look at bringing in the Linux TOD API as well? That means we

No, I don't.

> > See my previous comments. And the longer I think about it, the more I
> > think we should just use
> > 
> > 	u64 time(void)
> > 
> > as core of this new code.
> 
> Agreed - As said before (for the time being) the return value of any
> arbitrary call to time() means nothing. It _may_ mean the number of
> nanoseconds since power-up, but this is by no means guaranteed.

True.  But it is also garanteet to be usable in constructs as the
aforementioned

	u64 then = time() + number_of_nanoseconds;
	...
	if (time_after(time(), then))
		...

> But what about delays (no-brainer - ndelay, udelay, mdelay) and 'elapsed time'

Well, like this:

void udelay(u32 usec)
{
	u64 then = time() + (u64)usec * (u64)1000;

	while (!time_after(time(), then))
		... do something, like trigger watchdogs etc ...
}

For 'elapsed time' it should be sufficient to store the start value of
time() as early as possible in the (architecture specific) code.

> > Well, here I think we should have a look at Linux again here. In
> > include/linux/jiffies.h they provide a nice set of inlines, which in
> > our case would reuse directly:
> > 
> > 	time_after()
> > 	time_after_eq()
> > 	time_before()
> > 	time_before_eq()
> > 	time_in_range()
> > 	time_in_range_open()
> > 	
> 
> When would we use time_in_range and time_in_range_open? I don't think we

I don;t suggest that we need to use all of these.  As mentioned,
currently I only see use for time_after() (and/or time_after_eq(), it
if should make a difference).

> > The classic timeout code then becomes:
> > 
> > 	u64 then = time() + TIMEOUT;
> > 	...
> > 	if (time_after(time(), then)) {
> > 		/* handle timeout */
> > 	}
> 
> Arrrgh - Sorry, but we have been around and around and around this. There
> are sooooo many way to do this - The two big contenders have been:

Yes, and both of them do the compare in local code. This is what we
should get rid of.

> And now we throw a third into the mix.

Please read the comments for the implementation of the time_after()
macro.  It makes sense to do it this way.

> time_since and future_time are designed to take into account the underlying
> resolution of the hardware timer/counter. The big thing to remember is that
> we _must_ handle the case where the underlying timer is too coarse

Do we?  What exactly is the needed resolution of the underlying
hardware timer?  So far, it appears sufficient to have it ticking with
1000 Hz or more.  Are there really systems that cannot provide that?
The only architecture I remember that seemed prolematic was NIOS - but
then the NIOS documentation suggests that this might actually be
solvable.

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: wd at denx.de
Immortality consists largely of boredom.
	-- Zefrem Cochrane, "Metamorphosis", stardate 3219.8


More information about the U-Boot mailing list