/* * Copyright (C) 2006,2007 Philippe Gerum . * * Xenomai is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, * or (at your option) any later version. * * Xenomai is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Xenomai; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _COBALT_KERNEL_CLOCK_H #define _COBALT_KERNEL_CLOCK_H #include #include #include #include #include #include /** * @addtogroup cobalt_core_clock * @{ */ struct xnsched; struct xntimerdata; struct __kernel_timex; struct xnclock_gravity { unsigned long irq; unsigned long kernel; unsigned long user; }; struct xnclock { /** (ns) */ xnsticks_t wallclock_offset; /** (ns) */ xnticks_t resolution; /** (raw clock ticks). */ struct xnclock_gravity gravity; /** Clock name. */ const char *name; struct { #ifdef CONFIG_XENO_OPT_EXTCLOCK xnticks_t (*read_raw)(struct xnclock *clock); xnticks_t (*read_monotonic)(struct xnclock *clock); int (*set_time)(struct xnclock *clock, const struct timespec64 *ts); xnsticks_t (*ns_to_ticks)(struct xnclock *clock, xnsticks_t ns); xnsticks_t (*ticks_to_ns)(struct xnclock *clock, xnsticks_t ticks); xnsticks_t (*ticks_to_ns_rounded)(struct xnclock *clock, xnsticks_t ticks); void (*program_local_shot)(struct xnclock *clock, struct xnsched *sched); void (*program_remote_shot)(struct xnclock *clock, struct xnsched *sched); #endif int (*adjust_time)(struct xnclock *clock, struct __kernel_timex *tx); int (*set_gravity)(struct xnclock *clock, const struct xnclock_gravity *p); void (*reset_gravity)(struct xnclock *clock); #ifdef CONFIG_XENO_OPT_VFILE void (*print_status)(struct xnclock *clock, struct xnvfile_regular_iterator *it); #endif } ops; /* Private section. */ struct xntimerdata *timerdata; int id; #ifdef CONFIG_SMP /** Possible CPU affinity of clock beat. */ cpumask_t affinity; #endif #ifdef CONFIG_XENO_OPT_STATS struct xnvfile_snapshot timer_vfile; struct xnvfile_rev_tag timer_revtag; struct list_head timerq; int nrtimers; #endif /* CONFIG_XENO_OPT_STATS */ #ifdef CONFIG_XENO_OPT_VFILE struct xnvfile_regular vfile; #endif }; struct xnclock_ratelimit_state { xnticks_t interval; xnticks_t begin; int burst; int printed; int missed; }; extern struct xnclock nkclock; int xnclock_register(struct xnclock *clock, const cpumask_t *affinity); void xnclock_deregister(struct xnclock *clock); void xnclock_tick(struct xnclock *clock); void xnclock_core_local_shot(struct xnsched *sched); void xnclock_core_remote_shot(struct xnsched *sched); xnsticks_t xnclock_core_ns_to_ticks(xnsticks_t ns); xnsticks_t xnclock_core_ticks_to_ns(xnsticks_t ticks); xnsticks_t xnclock_core_ticks_to_ns_rounded(xnsticks_t ticks); xnticks_t xnclock_core_read_monotonic(void); static inline xnticks_t xnclock_core_read_raw(void) { return pipeline_read_cycle_counter(); } /* We use the Linux defaults */ #define XN_RATELIMIT_INTERVAL 5000000000LL #define XN_RATELIMIT_BURST 10 int __xnclock_ratelimit(struct xnclock_ratelimit_state *rs, const char *func); #define xnclock_ratelimit() ({ \ static struct xnclock_ratelimit_state __state = { \ .interval = XN_RATELIMIT_INTERVAL, \ .burst = XN_RATELIMIT_BURST, \ }; \ __xnclock_ratelimit(&__state, __func__); \ }) #ifdef CONFIG_XENO_OPT_EXTCLOCK static inline void xnclock_program_shot(struct xnclock *clock, struct xnsched *sched) { if (likely(clock == &nkclock)) xnclock_core_local_shot(sched); else if (clock->ops.program_local_shot) clock->ops.program_local_shot(clock, sched); } static inline void xnclock_remote_shot(struct xnclock *clock, struct xnsched *sched) { #ifdef CONFIG_SMP if (likely(clock == &nkclock)) xnclock_core_remote_shot(sched); else if (clock->ops.program_remote_shot) clock->ops.program_remote_shot(clock, sched); #endif } static inline xnticks_t xnclock_read_raw(struct xnclock *clock) { if (likely(clock == &nkclock)) return xnclock_core_read_raw(); return clock->ops.read_raw(clock); } static inline xnsticks_t xnclock_ns_to_ticks(struct xnclock *clock, xnsticks_t ns) { if (likely(clock == &nkclock)) return xnclock_core_ns_to_ticks(ns); return clock->ops.ns_to_ticks(clock, ns); } static inline xnsticks_t xnclock_ticks_to_ns(struct xnclock *clock, xnsticks_t ticks) { if (likely(clock == &nkclock)) return xnclock_core_ticks_to_ns(ticks); return clock->ops.ticks_to_ns(clock, ticks); } static inline xnsticks_t xnclock_ticks_to_ns_rounded(struct xnclock *clock, xnsticks_t ticks) { if (likely(clock == &nkclock)) return xnclock_core_ticks_to_ns_rounded(ticks); return clock->ops.ticks_to_ns_rounded(clock, ticks); } static inline xnticks_t xnclock_read_monotonic(struct xnclock *clock) { if (likely(clock == &nkclock)) return xnclock_core_read_monotonic(); return clock->ops.read_monotonic(clock); } static inline int xnclock_set_time(struct xnclock *clock, const struct timespec64 *ts) { if (likely(clock == &nkclock)) return -EINVAL; return clock->ops.set_time(clock, ts); } #else /* !CONFIG_XENO_OPT_EXTCLOCK */ static inline void xnclock_program_shot(struct xnclock *clock, struct xnsched *sched) { xnclock_core_local_shot(sched); } static inline void xnclock_remote_shot(struct xnclock *clock, struct xnsched *sched) { #ifdef CONFIG_SMP xnclock_core_remote_shot(sched); #endif } static inline xnticks_t xnclock_read_raw(struct xnclock *clock) { return xnclock_core_read_raw(); } static inline xnsticks_t xnclock_ns_to_ticks(struct xnclock *clock, xnsticks_t ns) { return xnclock_core_ns_to_ticks(ns); } static inline xnsticks_t xnclock_ticks_to_ns(struct xnclock *clock, xnsticks_t ticks) { return xnclock_core_ticks_to_ns(ticks); } static inline xnsticks_t xnclock_ticks_to_ns_rounded(struct xnclock *clock, xnsticks_t ticks) { return xnclock_core_ticks_to_ns_rounded(ticks); } static inline xnticks_t xnclock_read_monotonic(struct xnclock *clock) { return xnclock_core_read_monotonic(); } static inline int xnclock_set_time(struct xnclock *clock, const struct timespec64 *ts) { /* * There is no way to change the core clock's idea of time. */ return -EINVAL; } #endif /* !CONFIG_XENO_OPT_EXTCLOCK */ static inline int xnclock_adjust_time(struct xnclock *clock, struct __kernel_timex *tx) { if (clock->ops.adjust_time == NULL) return -EOPNOTSUPP; return clock->ops.adjust_time(clock, tx); } static inline xnticks_t xnclock_get_offset(struct xnclock *clock) { return clock->wallclock_offset; } static inline xnticks_t xnclock_get_resolution(struct xnclock *clock) { return clock->resolution; /* ns */ } static inline void xnclock_set_resolution(struct xnclock *clock, xnticks_t resolution) { clock->resolution = resolution; /* ns */ } static inline int xnclock_set_gravity(struct xnclock *clock, const struct xnclock_gravity *gravity) { if (clock->ops.set_gravity) return clock->ops.set_gravity(clock, gravity); return -EINVAL; } static inline void xnclock_reset_gravity(struct xnclock *clock) { if (clock->ops.reset_gravity) clock->ops.reset_gravity(clock); } #define xnclock_get_gravity(__clock, __type) ((__clock)->gravity.__type) static inline xnticks_t xnclock_read_realtime(struct xnclock *clock) { if (likely(clock == &nkclock)) return pipeline_read_wallclock(); /* * Return an adjusted value of the monotonic time with the * translated system wallclock offset. */ return xnclock_read_monotonic(clock) + xnclock_get_offset(clock); } void xnclock_apply_offset(struct xnclock *clock, xnsticks_t delta_ns); void xnclock_set_wallclock(xnticks_t epoch_ns); unsigned long long xnclock_divrem_billion(unsigned long long value, unsigned long *rem); #ifdef CONFIG_XENO_OPT_VFILE void xnclock_init_proc(void); void xnclock_cleanup_proc(void); static inline void xnclock_print_status(struct xnclock *clock, struct xnvfile_regular_iterator *it) { if (clock->ops.print_status) clock->ops.print_status(clock, it); } #else static inline void xnclock_init_proc(void) { } static inline void xnclock_cleanup_proc(void) { } #endif int xnclock_init(void); void xnclock_cleanup(void); /** @} */ #endif /* !_COBALT_KERNEL_CLOCK_H */