|
@@ -345,7 +345,9 @@ void open_softirq(int nr, void (*action)(struct softirq_action *))
|
|
|
softirq_vec[nr].action = action;
|
|
|
}
|
|
|
|
|
|
-/* Tasklets */
|
|
|
+/*
|
|
|
+ * Tasklets
|
|
|
+ */
|
|
|
struct tasklet_head
|
|
|
{
|
|
|
struct tasklet_struct *head;
|
|
@@ -493,6 +495,66 @@ void tasklet_kill(struct tasklet_struct *t)
|
|
|
|
|
|
EXPORT_SYMBOL(tasklet_kill);
|
|
|
|
|
|
+/*
|
|
|
+ * tasklet_hrtimer
|
|
|
+ */
|
|
|
+
|
|
|
+/*
|
|
|
+ * The trampoline is called when the hrtimer expires. If this is
|
|
|
+ * called from the hrtimer interrupt then we schedule the tasklet as
|
|
|
+ * the timer callback function expects to run in softirq context. If
|
|
|
+ * it's called in softirq context anyway (i.e. high resolution timers
|
|
|
+ * disabled) then the hrtimer callback is called right away.
|
|
|
+ */
|
|
|
+static enum hrtimer_restart __hrtimer_tasklet_trampoline(struct hrtimer *timer)
|
|
|
+{
|
|
|
+ struct tasklet_hrtimer *ttimer =
|
|
|
+ container_of(timer, struct tasklet_hrtimer, timer);
|
|
|
+
|
|
|
+ if (hrtimer_is_hres_active(timer)) {
|
|
|
+ tasklet_hi_schedule(&ttimer->tasklet);
|
|
|
+ return HRTIMER_NORESTART;
|
|
|
+ }
|
|
|
+ return ttimer->function(timer);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Helper function which calls the hrtimer callback from
|
|
|
+ * tasklet/softirq context
|
|
|
+ */
|
|
|
+static void __tasklet_hrtimer_trampoline(unsigned long data)
|
|
|
+{
|
|
|
+ struct tasklet_hrtimer *ttimer = (void *)data;
|
|
|
+ enum hrtimer_restart restart;
|
|
|
+
|
|
|
+ restart = ttimer->function(&ttimer->timer);
|
|
|
+ if (restart != HRTIMER_NORESTART)
|
|
|
+ hrtimer_restart(&ttimer->timer);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * tasklet_hrtimer_init - Init a tasklet/hrtimer combo for softirq callbacks
|
|
|
+ * @ttimer: tasklet_hrtimer which is initialized
|
|
|
+ * @function: hrtimer callback funtion which gets called from softirq context
|
|
|
+ * @which_clock: clock id (CLOCK_MONOTONIC/CLOCK_REALTIME)
|
|
|
+ * @mode: hrtimer mode (HRTIMER_MODE_ABS/HRTIMER_MODE_REL)
|
|
|
+ */
|
|
|
+void tasklet_hrtimer_init(struct tasklet_hrtimer *ttimer,
|
|
|
+ enum hrtimer_restart (*function)(struct hrtimer *),
|
|
|
+ clockid_t which_clock, enum hrtimer_mode mode)
|
|
|
+{
|
|
|
+ hrtimer_init(&ttimer->timer, which_clock, mode);
|
|
|
+ ttimer->timer.function = __hrtimer_tasklet_trampoline;
|
|
|
+ tasklet_init(&ttimer->tasklet, __tasklet_hrtimer_trampoline,
|
|
|
+ (unsigned long)ttimer);
|
|
|
+ ttimer->function = function;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(tasklet_hrtimer_init);
|
|
|
+
|
|
|
+/*
|
|
|
+ * Remote softirq bits
|
|
|
+ */
|
|
|
+
|
|
|
DEFINE_PER_CPU(struct list_head [NR_SOFTIRQS], softirq_work_list);
|
|
|
EXPORT_PER_CPU_SYMBOL(softirq_work_list);
|
|
|
|