Open
Conversation
Signed-off-by: Lesley Rossouw <lesley.rossouw@unsw.edu.au> wip Added universal time conversion to common timer driver logic, inc. memoisation. Tested, works well! Only added to imx and apb_timer for now Signed-off-by: Lesley Rossouw <lesley.rossouw@unsw.edu.au> Minor changes to timer common API for clarity + exposing raw API, added support for all timer drivers Signed-off-by: Lesley Rossouw <lesley.rossouw@unsw.edu.au>
Signed-off-by: Lesley Rossouw <lesley.rossouw@unsw.edu.au>
Signed-off-by: Lesley Rossouw <lesley.rossouw@unsw.edu.au>
Signed-off-by: Lesley Rossouw <lesley.rossouw@unsw.edu.au>
Signed-off-by: Lesley Rossouw <lesley.rossouw@unsw.edu.au>
Signed-off-by: Lesley Rossouw <lesley.rossouw@unsw.edu.au>
Signed-off-by: Lesley Rossouw <lesley.rossouw@unsw.edu.au>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This change adds a universal time conversion module for our timer driver. The design goals are as follows:
I based the method on Linux's method of calculating a multiple and shift to miminise integer division error for arbitrary frequencies. Originally, this was optimal as I made the common code work entirely with 64-bit arithmetic, but I needed to add 128 bit calls for devices like the TSC which go to many GHz. As a result, there is arguably a discussion to be had here re: bothering with this method. We could simply do in-place 128 bit division to calculate the frequency and not worry about error, but we should probably do the math to work out how much error occurs.
Common time conversion logic
Previously, every timer driver tried to do its own frequency conversion math. Unfortunately, most of them did it in ways that are either wrong, cannot run for a long enough time, or both. Given the complexity of the math required and the significant room for error in performing the integer arithmetic with a wide range of possible clock frequencies, I have added a common time conversion module for all drivers to use in
time_conv.c.This function uses a method heavily based on Linux's time conversion method. Rather than calculating terms like
ns = (ticks * freq) / NS_IN_Sdirectly, this method converts all such fractions into a multiply-and-shift operation representing the fraction more precisely for (efficient) integer arithmetic.Rather than manually defining conversions to certain time units as needed, we instead model all jiffy-to-time conversions as a shift of frequencies. For example, rather than converting "to nanoseconds", we can instead convert the number of periods at some frequency
f_ato the number of periods in another frequency,f_b. Iff_bis 1GHz, a period is equal to exactly 1 nanosecond. This means that we can have a single robust method that handles the conversion in both directions, for all frequencies. If we say the number of periods inf_aist_aand the number of periods inf_bist_b, the algebra looks as follows, where we want to findt_bgivenf_a, f_bandt_a`.To avoid loss in integer division, we convert the equation into the following shape:
Where
MandSare arbitrary numbers encoding the value off_aandf_bby effectively moving everything butf_b's factor of 2 to the numerator of the expression. In the code, we evaluate this expression as... returning
t_b, since we can find a division by 2 to the power of S with a left shift.This method of conversion should guarantee about 100 years of time conversions accurately for any frequency in Hz that can be stored in 32 bits.
An iterative method is used to calculate the mult and shift, where we effectively test a bunch of possible shift values and settle on one that gives the desired accuracy. This should find an optimal set of magic numbers for all frequencies that fit in 32 bits (up to ~4.2GHz) for 100 years of runtime.
Common time cached time conversion logic
To make the above mult-shift operation more friendly, I have added
timer_common.c, a file implementing two methods:These methods take in the two required frequencies and do all conversions necessary transparently. The mult and shift used for ns->ticks and ticks-> ns are cached for efficiency. Timer drivers are not forced to use this logic - they may want to use their own method if they do something complex like dynamically reprogramming the prescaler. For all ten of the existing drivers however, the caching behaviour is optimal and should be used.
Why hide state / supply these methods commonly?
Time conversion in particular has proven itself to be very capable of confusing contributors to the sDDF. The mult-shift interface is not particularly friendly or intuitive, and extracting the cached mult-shift values to the front of the interface is likely to be error prone since the significance of these values may not be obvious at a glance. Using this common logic is "fool proof" and will provide optimal behaviour in all cases, and as a result I think it's a suitable compromise to have internal caching, since this is the only way we can provide a "convert to ticks" and "convert to nanoseconds" API efficiently and without risking confusion if we use the Linux-style runtime optimisation. If we decide to drop the runtime-optimising time conversion the common module is obviously irrelevant and we can drop it.