#include <linux/init.h>
#include <linux/list.h>
#include <linux/wait.h>
+#include <linux/percpu.h>
+#include <linux/timer.h>
+
struct hrtimer_clock_base;
struct hrtimer_cpu_base;
* Mode arguments of xxx_hrtimer functions:
*/
enum hrtimer_mode {
- HRTIMER_MODE_ABS, /* Time value is absolute */
- HRTIMER_MODE_REL, /* Time value is relative to now */
+ HRTIMER_MODE_ABS = 0x0, /* Time value is absolute */
+ HRTIMER_MODE_REL = 0x1, /* Time value is relative to now */
+ HRTIMER_MODE_PINNED = 0x02, /* Timer is bound to CPU */
+ HRTIMER_MODE_ABS_PINNED = 0x02,
+ HRTIMER_MODE_REL_PINNED = 0x03,
};
/*
};
/*
- * hrtimer callback modes:
- *
- * HRTIMER_CB_SOFTIRQ: Callback must run in softirq context
- * HRTIMER_CB_IRQSAFE: Callback may run in hardirq context
- * HRTIMER_CB_IRQSAFE_NO_RESTART: Callback may run in hardirq context and
- * does not restart the timer
- * HRTIMER_CB_IRQSAFE_NO_SOFTIRQ: Callback must run in hardirq context
- * Special mode for tick emultation
- */
-enum hrtimer_cb_mode {
- HRTIMER_CB_SOFTIRQ,
- HRTIMER_CB_IRQSAFE,
- HRTIMER_CB_IRQSAFE_NO_RESTART,
- HRTIMER_CB_IRQSAFE_NO_SOFTIRQ,
-};
-
-/*
* Values to track state of the timer
*
* Possible states:
* 0x00 inactive
* 0x01 enqueued into rbtree
* 0x02 callback function running
- * 0x04 callback pending (high resolution mode)
*
- * Special case:
+ * Special cases:
* 0x03 callback function running and enqueued
* (was requeued on another CPU)
+ * 0x09 timer was migrated on CPU hotunplug
* The "callback function running and enqueued" status is only possible on
* SMP. It happens for example when a posix timer expired and the callback
* queued a signal. Between dropping the lock which protects the posix timer
#define HRTIMER_STATE_INACTIVE 0x00
#define HRTIMER_STATE_ENQUEUED 0x01
#define HRTIMER_STATE_CALLBACK 0x02
-#define HRTIMER_STATE_PENDING 0x04
+#define HRTIMER_STATE_MIGRATE 0x04
/**
* struct hrtimer - the basic hrtimer structure
* @node: red black tree node for time ordered insertion
- * @expires: the absolute expiry time in the hrtimers internal
+ * @_expires: the absolute expiry time in the hrtimers internal
* representation. The time is related to the clock on
- * which the timer is based.
+ * which the timer is based. Is setup by adding
+ * slack to the _softexpires value. For non range timers
+ * identical to _softexpires.
+ * @_softexpires: the absolute earliest expiry time of the hrtimer.
+ * The time which was given as expiry time when the timer
+ * was armed.
* @function: timer expiry callback function
* @base: pointer to the timer base (per cpu and per clock)
* @state: state information (See bit values above)
- * @cb_mode: high resolution timer feature to select the callback execution
- * mode
- * @cb_entry: list head to enqueue an expired timer into the callback list
* @start_site: timer statistics field to store the site where the timer
* was started
* @start_comm: timer statistics field to store the name of the process which
enum hrtimer_restart (*function)(struct hrtimer *);
struct hrtimer_clock_base *base;
unsigned long state;
- enum hrtimer_cb_mode cb_mode;
- struct list_head cb_entry;
#ifdef CONFIG_TIMER_STATS
+ int start_pid;
void *start_site;
char start_comm[16];
- int start_pid;
#endif
};
* @first: pointer to the timer node which expires first
* @resolution: the resolution of the clock, in nanoseconds
* @get_time: function to retrieve the current time of the clock
- * @get_softirq_time: function to retrieve the current time from the softirq
* @softirq_time: the time when running the hrtimer queue in the softirq
* @offset: offset of this clock to the monotonic base
- * @reprogram: function to reprogram the timer event
*/
struct hrtimer_clock_base {
struct hrtimer_cpu_base *cpu_base;
struct rb_node *first;
ktime_t resolution;
ktime_t (*get_time)(void);
- ktime_t (*get_softirq_time)(void);
ktime_t softirq_time;
#ifdef CONFIG_HIGH_RES_TIMERS
ktime_t offset;
- int (*reprogram)(struct hrtimer *t,
- struct hrtimer_clock_base *b,
- ktime_t n);
#endif
};
* @check_clocks: Indictator, when set evaluate time source and clock
* event devices whether high resolution mode can be
* activated.
- * @cb_pending: Expired timers are moved from the rbtree to this
- * list in the timer interrupt. The list is processed
- * in the softirq.
* @nr_events: Total number of timer interrupt events
*/
struct hrtimer_cpu_base {
spinlock_t lock;
struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES];
- struct list_head cb_pending;
#ifdef CONFIG_HIGH_RES_TIMERS
ktime_t expires_next;
int hres_active;
#endif
};
-#ifdef CONFIG_HIGH_RES_TIMERS
-struct clock_event_device;
-
-extern void clock_was_set(void);
-extern void hres_timers_resume(void);
-extern void hrtimer_interrupt(struct clock_event_device *dev);
-
-/*
- * In high resolution mode the time reference must be read accurate
- */
-static inline ktime_t hrtimer_cb_get_time(struct hrtimer *timer)
-{
- return timer->base->get_time();
-}
-
-static inline int hrtimer_is_hres_active(struct hrtimer *timer)
-{
- return timer->base->cpu_base->hres_active;
-}
-
static inline void hrtimer_set_expires(struct hrtimer *timer, ktime_t time)
{
timer->_expires = time;
timer->_softexpires = ktime_add_safe(timer->_softexpires, time);
}
-static inline void hrtimer_add_expires_ns(struct hrtimer *timer, unsigned long ns)
+static inline void hrtimer_add_expires_ns(struct hrtimer *timer, u64 ns)
{
timer->_expires = ktime_add_ns(timer->_expires, ns);
timer->_softexpires = ktime_add_ns(timer->_softexpires, ns);
return ktime_sub(timer->_expires, timer->base->get_time());
}
+#ifdef CONFIG_HIGH_RES_TIMERS
+struct clock_event_device;
+
+extern void clock_was_set(void);
+extern void hres_timers_resume(void);
+extern void hrtimer_interrupt(struct clock_event_device *dev);
+
+/*
+ * In high resolution mode the time reference must be read accurate
+ */
+static inline ktime_t hrtimer_cb_get_time(struct hrtimer *timer)
+{
+ return timer->base->get_time();
+}
+
+static inline int hrtimer_is_hres_active(struct hrtimer *timer)
+{
+ return timer->base->cpu_base->hres_active;
+}
+
+extern void hrtimer_peek_ahead_timers(void);
+
/*
* The resolution of the clocks. The resolution value is returned in
* the clock_getres() system call to give application programmers an
* is expired in the next softirq when the clock was advanced.
*/
static inline void clock_was_set(void) { }
+static inline void hrtimer_peek_ahead_timers(void) { }
static inline void hres_timers_resume(void) { }
extern ktime_t ktime_get(void);
extern ktime_t ktime_get_real(void);
+
+DECLARE_PER_CPU(struct tick_device, tick_cpu_device);
+
+
/* Exported timer functions: */
/* Initialize timers: */
/* Basic timer operations: */
extern int hrtimer_start(struct hrtimer *timer, ktime_t tim,
const enum hrtimer_mode mode);
+extern int hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
+ unsigned long range_ns, const enum hrtimer_mode mode);
+extern int
+__hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
+ unsigned long delta_ns,
+ const enum hrtimer_mode mode, int wakeup);
+
extern int hrtimer_cancel(struct hrtimer *timer);
extern int hrtimer_try_to_cancel(struct hrtimer *timer);
static inline int hrtimer_start_expires(struct hrtimer *timer,
enum hrtimer_mode mode)
{
- return hrtimer_start(timer, hrtimer_get_expires(timer), mode);
+ unsigned long delta;
+ ktime_t soft, hard;
+ soft = hrtimer_get_softexpires(timer);
+ hard = hrtimer_get_expires(timer);
+ delta = ktime_to_ns(ktime_sub(hard, soft));
+ return hrtimer_start_range_ns(timer, soft, delta, mode);
}
static inline int hrtimer_restart(struct hrtimer *timer)
*/
static inline int hrtimer_is_queued(struct hrtimer *timer)
{
- return timer->state &
- (HRTIMER_STATE_ENQUEUED | HRTIMER_STATE_PENDING);
+ return timer->state & HRTIMER_STATE_ENQUEUED;
}
/*
static inline void timer_stats_account_hrtimer(struct hrtimer *timer)
{
+ if (likely(!timer->start_site))
+ return;
timer_stats_update_stats(timer, timer->start_pid, timer->start_site,
timer->function, timer->start_comm, 0);
}
static inline void timer_stats_hrtimer_set_start_info(struct hrtimer *timer)
{
+ if (likely(!timer_stats_active))
+ return;
__timer_stats_hrtimer_set_start_info(timer, __builtin_return_address(0));
}