diff options
| -rw-r--r-- | include/linux/clockchips.h | 7 | ||||
| -rw-r--r-- | include/linux/clocksource.h | 10 | ||||
| -rw-r--r-- | kernel/time/clocksource.c | 53 |
3 files changed, 70 insertions, 0 deletions
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index 3b5841016276..4d438b0bc10a 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h | |||
| @@ -130,6 +130,13 @@ extern int clockevents_program_event(struct clock_event_device *dev, | |||
| 130 | 130 | ||
| 131 | extern void clockevents_handle_noop(struct clock_event_device *dev); | 131 | extern void clockevents_handle_noop(struct clock_event_device *dev); |
| 132 | 132 | ||
| 133 | static inline void | ||
| 134 | clockevents_calc_mult_shift(struct clock_event_device *ce, u32 freq, u32 minsec) | ||
| 135 | { | ||
| 136 | return clocks_calc_mult_shift(&ce->mult, &ce->shift, NSEC_PER_SEC, | ||
| 137 | freq, minsec); | ||
| 138 | } | ||
| 139 | |||
| 133 | #ifdef CONFIG_GENERIC_CLOCKEVENTS | 140 | #ifdef CONFIG_GENERIC_CLOCKEVENTS |
| 134 | extern void clockevents_notify(unsigned long reason, void *arg); | 141 | extern void clockevents_notify(unsigned long reason, void *arg); |
| 135 | #else | 142 | #else |
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 83d2fbd81b93..f57f88250526 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h | |||
| @@ -279,6 +279,16 @@ extern void clocksource_resume(void); | |||
| 279 | extern struct clocksource * __init __weak clocksource_default_clock(void); | 279 | extern struct clocksource * __init __weak clocksource_default_clock(void); |
| 280 | extern void clocksource_mark_unstable(struct clocksource *cs); | 280 | extern void clocksource_mark_unstable(struct clocksource *cs); |
| 281 | 281 | ||
| 282 | extern void | ||
| 283 | clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 minsec); | ||
| 284 | |||
| 285 | static inline void | ||
| 286 | clocksource_calc_mult_shift(struct clocksource *cs, u32 freq, u32 minsec) | ||
| 287 | { | ||
| 288 | return clocks_calc_mult_shift(&cs->mult, &cs->shift, freq, | ||
| 289 | NSEC_PER_SEC, minsec); | ||
| 290 | } | ||
| 291 | |||
| 282 | #ifdef CONFIG_GENERIC_TIME_VSYSCALL | 292 | #ifdef CONFIG_GENERIC_TIME_VSYSCALL |
| 283 | extern void update_vsyscall(struct timespec *ts, struct clocksource *c); | 293 | extern void update_vsyscall(struct timespec *ts, struct clocksource *c); |
| 284 | extern void update_vsyscall_tz(void); | 294 | extern void update_vsyscall_tz(void); |
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 5e18c6ab2c6a..407c0894ef37 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c | |||
| @@ -107,6 +107,59 @@ u64 timecounter_cyc2time(struct timecounter *tc, | |||
| 107 | } | 107 | } |
| 108 | EXPORT_SYMBOL(timecounter_cyc2time); | 108 | EXPORT_SYMBOL(timecounter_cyc2time); |
| 109 | 109 | ||
| 110 | /** | ||
| 111 | * clocks_calc_mult_shift - calculate mult/shift factors for scaled math of clocks | ||
| 112 | * @mult: pointer to mult variable | ||
| 113 | * @shift: pointer to shift variable | ||
| 114 | * @from: frequency to convert from | ||
| 115 | * @to: frequency to convert to | ||
| 116 | * @minsec: guaranteed runtime conversion range in seconds | ||
| 117 | * | ||
| 118 | * The function evaluates the shift/mult pair for the scaled math | ||
| 119 | * operations of clocksources and clockevents. | ||
| 120 | * | ||
| 121 | * @to and @from are frequency values in HZ. For clock sources @to is | ||
| 122 | * NSEC_PER_SEC == 1GHz and @from is the counter frequency. For clock | ||
| 123 | * event @to is the counter frequency and @from is NSEC_PER_SEC. | ||
| 124 | * | ||
| 125 | * The @minsec conversion range argument controls the time frame in | ||
| 126 | * seconds which must be covered by the runtime conversion with the | ||
| 127 | * calculated mult and shift factors. This guarantees that no 64bit | ||
| 128 | * overflow happens when the input value of the conversion is | ||
| 129 | * multiplied with the calculated mult factor. Larger ranges may | ||
| 130 | * reduce the conversion accuracy by chosing smaller mult and shift | ||
| 131 | * factors. | ||
| 132 | */ | ||
| 133 | void | ||
| 134 | clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 minsec) | ||
| 135 | { | ||
| 136 | u64 tmp; | ||
| 137 | u32 sft, sftacc= 32; | ||
| 138 | |||
| 139 | /* | ||
| 140 | * Calculate the shift factor which is limiting the conversion | ||
| 141 | * range: | ||
| 142 | */ | ||
| 143 | tmp = ((u64)minsec * from) >> 32; | ||
| 144 | while (tmp) { | ||
| 145 | tmp >>=1; | ||
| 146 | sftacc--; | ||
| 147 | } | ||
| 148 | |||
| 149 | /* | ||
| 150 | * Find the conversion shift/mult pair which has the best | ||
| 151 | * accuracy and fits the maxsec conversion range: | ||
| 152 | */ | ||
| 153 | for (sft = 32; sft > 0; sft--) { | ||
| 154 | tmp = (u64) to << sft; | ||
| 155 | do_div(tmp, from); | ||
| 156 | if ((tmp >> sftacc) == 0) | ||
| 157 | break; | ||
| 158 | } | ||
| 159 | *mult = tmp; | ||
| 160 | *shift = sft; | ||
| 161 | } | ||
| 162 | |||
| 110 | /*[Clocksource internal variables]--------- | 163 | /*[Clocksource internal variables]--------- |
| 111 | * curr_clocksource: | 164 | * curr_clocksource: |
| 112 | * currently selected clocksource. | 165 | * currently selected clocksource. |
