X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=include%2Flinux%2Fclocksource.h;h=55e434feec993d9656ccf6bcd31964005daa9667;hb=ad826e22c1343ceca76d814539a6fc94dd474def;hp=4bc94282c364ff7ef5e89aef3817cbe12bba6e95;hpb=7f9f303aa33c7acc7b4aa9ebea25cbd990bc707b;p=safe%2Fjmp%2Flinux-2.6 diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 4bc9428..55e434f 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -12,11 +12,14 @@ #include #include #include +#include +#include #include #include /* clocksource cycle base type */ typedef u64 cycle_t; +struct clocksource; /** * struct clocksource - hardware abstraction for a free running counter @@ -44,12 +47,16 @@ typedef u64 cycle_t; * subtraction of non 64 bit counters * @mult: cycle to nanosecond multiplier * @shift: cycle to nanosecond divisor (power of two) - * @update_callback: called when safe to alter clocksource values - * @is_continuous: defines if clocksource is free-running. - * @interval_cycles: Used internally by timekeeping core, please ignore. - * @interval_snsecs: Used internally by timekeeping core, please ignore. + * @flags: flags describing special properties + * @vread: vsyscall based read + * @resume: resume function for the clocksource, if necessary + * @cycle_interval: Used internally by timekeeping core, please ignore. + * @xtime_interval: Used internally by timekeeping core, please ignore. */ struct clocksource { + /* + * First part of structure is read mostly + */ char *name; struct list_head list; int rating; @@ -57,16 +64,48 @@ struct clocksource { cycle_t mask; u32 mult; u32 shift; - int (*update_callback)(void); - int is_continuous; + unsigned long flags; + cycle_t (*vread)(void); + void (*resume)(void); +#ifdef CONFIG_IA64 + void *fsys_mmio; /* used by fsyscall asm code */ +#define CLKSRC_FSYS_MMIO_SET(mmio, addr) ((mmio) = (addr)) +#else +#define CLKSRC_FSYS_MMIO_SET(mmio, addr) do { } while (0) +#endif /* timekeeping specific data, ignore */ - cycle_t interval_cycles; - u64 interval_snsecs; + cycle_t cycle_interval; + u64 xtime_interval; + /* + * Second part is written at each timer interrupt + * Keep it in a different cache line to dirty no + * more than one cache line. + */ + cycle_t cycle_last ____cacheline_aligned_in_smp; + u64 xtime_nsec; + s64 error; + +#ifdef CONFIG_CLOCKSOURCE_WATCHDOG + /* Watchdog related data, used by the framework */ + struct list_head wd_list; + cycle_t wd_last; +#endif }; +extern struct clocksource *clock; /* current clocksource */ + +/* + * Clock source flags bits:: + */ +#define CLOCK_SOURCE_IS_CONTINUOUS 0x01 +#define CLOCK_SOURCE_MUST_VERIFY 0x02 + +#define CLOCK_SOURCE_WATCHDOG 0x10 +#define CLOCK_SOURCE_VALID_FOR_HRES 0x20 + /* simplify initialization of mask field */ -#define CLOCKSOURCE_MASK(bits) (cycle_t)(bits<64 ? ((1ULL<mult/2; do_div(tmp, c->mult); - c->interval_cycles = (cycle_t)tmp; - if(c->interval_cycles == 0) - c->interval_cycles = 1; + c->cycle_interval = (cycle_t)tmp; + if (c->cycle_interval == 0) + c->cycle_interval = 1; - c->interval_snsecs = (u64)c->interval_cycles * c->mult; + c->xtime_interval = (u64)c->cycle_interval * c->mult; } -/** - * error_aproximation - calculates an error adjustment for a given error - * - * @error: Error value (unsigned) - * @unit: Adjustment unit - * - * For a given error value, this function takes the adjustment unit - * and uses binary approximation to return a power of two adjustment value. - * - * This function is only for use by the the make_ntp_adj() function - * and you must hold a write on the xtime_lock when calling. - */ -static inline int error_aproximation(u64 error, u64 unit) +/* used to install a new clocksource */ +extern int clocksource_register(struct clocksource*); +extern void clocksource_unregister(struct clocksource*); +extern void clocksource_touch_watchdog(void); +extern struct clocksource* clocksource_get_next(void); +extern void clocksource_change_rating(struct clocksource *cs, int rating); +extern void clocksource_resume(void); + +#ifdef CONFIG_GENERIC_TIME_VSYSCALL +extern void update_vsyscall(struct timespec *ts, struct clocksource *c); +extern void update_vsyscall_tz(void); +#else +static inline void update_vsyscall(struct timespec *ts, struct clocksource *c) { - static int saved_adj = 0; - u64 adjusted_unit = unit << saved_adj; - - if (error > (adjusted_unit * 2)) { - /* large error, so increment the adjustment factor */ - saved_adj++; - } else if (error > adjusted_unit) { - /* just right, don't touch it */ - } else if (saved_adj) { - /* small error, so drop the adjustment factor */ - saved_adj--; - return 0; - } - - return saved_adj; } - -/** - * make_ntp_adj - Adjusts the specified clocksource for a given error - * - * @clock: Pointer to clock to be adjusted - * @cycles_delta: Current unacounted cycle delta - * @error: Pointer to current error value - * - * Returns clock shifted nanosecond adjustment to be applied against - * the accumulated time value (ie: xtime). - * - * If the error value is large enough, this function calulates the - * (power of two) adjustment value, and adjusts the clock's mult and - * interval_snsecs values accordingly. - * - * However, since there may be some unaccumulated cycles, to avoid - * time inconsistencies we must adjust the accumulation value - * accordingly. - * - * This is not very intuitive, so the following proof should help: - * The basic timeofday algorithm: base + cycle * mult - * Thus: - * new_base + cycle * new_mult = old_base + cycle * old_mult - * new_base = old_base + cycle * old_mult - cycle * new_mult - * new_base = old_base + cycle * (old_mult - new_mult) - * new_base - old_base = cycle * (old_mult - new_mult) - * base_delta = cycle * (old_mult - new_mult) - * base_delta = cycle * (mult_delta) - * - * Where mult_delta is the adjustment value made to mult - * - */ -static inline s64 make_ntp_adj(struct clocksource *clock, - cycles_t cycles_delta, s64* error) +static inline void update_vsyscall_tz(void) { - s64 ret = 0; - if (*error > ((s64)clock->interval_cycles+1)/2) { - /* calculate adjustment value */ - int adjustment = error_aproximation(*error, - clock->interval_cycles); - /* adjust clock */ - clock->mult += 1 << adjustment; - clock->interval_snsecs += clock->interval_cycles << adjustment; - - /* adjust the base and error for the adjustment */ - ret = -(cycles_delta << adjustment); - *error -= clock->interval_cycles << adjustment; - /* XXX adj error for cycle_delta offset? */ - } else if ((-(*error)) > ((s64)clock->interval_cycles+1)/2) { - /* calculate adjustment value */ - int adjustment = error_aproximation(-(*error), - clock->interval_cycles); - /* adjust clock */ - clock->mult -= 1 << adjustment; - clock->interval_snsecs -= clock->interval_cycles << adjustment; - - /* adjust the base and error for the adjustment */ - ret = cycles_delta << adjustment; - *error += clock->interval_cycles << adjustment; - /* XXX adj error for cycle_delta offset? */ - } - return ret; } - - -/* used to install a new clocksource */ -int clocksource_register(struct clocksource*); -void clocksource_reselect(void); -struct clocksource* clocksource_get_next(void); +#endif #endif /* _LINUX_CLOCKSOURCE_H */