|
@@ -2377,6 +2377,77 @@ static void rcu_kick_nohz_cpu(int cpu)
|
|
|
|
|
|
#ifdef CONFIG_NO_HZ_FULL_SYSIDLE
|
|
|
|
|
|
+/*
|
|
|
+ * Invoked to note exit from irq or task transition to idle. Note that
|
|
|
+ * usermode execution does -not- count as idle here! After all, we want
|
|
|
+ * to detect full-system idle states, not RCU quiescent states and grace
|
|
|
+ * periods. The caller must have disabled interrupts.
|
|
|
+ */
|
|
|
+static void rcu_sysidle_enter(struct rcu_dynticks *rdtp, int irq)
|
|
|
+{
|
|
|
+ unsigned long j;
|
|
|
+
|
|
|
+ /* Adjust nesting, check for fully idle. */
|
|
|
+ if (irq) {
|
|
|
+ rdtp->dynticks_idle_nesting--;
|
|
|
+ WARN_ON_ONCE(rdtp->dynticks_idle_nesting < 0);
|
|
|
+ if (rdtp->dynticks_idle_nesting != 0)
|
|
|
+ return; /* Still not fully idle. */
|
|
|
+ } else {
|
|
|
+ if ((rdtp->dynticks_idle_nesting & DYNTICK_TASK_NEST_MASK) ==
|
|
|
+ DYNTICK_TASK_NEST_VALUE) {
|
|
|
+ rdtp->dynticks_idle_nesting = 0;
|
|
|
+ } else {
|
|
|
+ rdtp->dynticks_idle_nesting -= DYNTICK_TASK_NEST_VALUE;
|
|
|
+ WARN_ON_ONCE(rdtp->dynticks_idle_nesting < 0);
|
|
|
+ return; /* Still not fully idle. */
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Record start of fully idle period. */
|
|
|
+ j = jiffies;
|
|
|
+ ACCESS_ONCE(rdtp->dynticks_idle_jiffies) = j;
|
|
|
+ smp_mb__before_atomic_inc();
|
|
|
+ atomic_inc(&rdtp->dynticks_idle);
|
|
|
+ smp_mb__after_atomic_inc();
|
|
|
+ WARN_ON_ONCE(atomic_read(&rdtp->dynticks_idle) & 0x1);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Invoked to note entry to irq or task transition from idle. Note that
|
|
|
+ * usermode execution does -not- count as idle here! The caller must
|
|
|
+ * have disabled interrupts.
|
|
|
+ */
|
|
|
+static void rcu_sysidle_exit(struct rcu_dynticks *rdtp, int irq)
|
|
|
+{
|
|
|
+ /* Adjust nesting, check for already non-idle. */
|
|
|
+ if (irq) {
|
|
|
+ rdtp->dynticks_idle_nesting++;
|
|
|
+ WARN_ON_ONCE(rdtp->dynticks_idle_nesting <= 0);
|
|
|
+ if (rdtp->dynticks_idle_nesting != 1)
|
|
|
+ return; /* Already non-idle. */
|
|
|
+ } else {
|
|
|
+ /*
|
|
|
+ * Allow for irq misnesting. Yes, it really is possible
|
|
|
+ * to enter an irq handler then never leave it, and maybe
|
|
|
+ * also vice versa. Handle both possibilities.
|
|
|
+ */
|
|
|
+ if (rdtp->dynticks_idle_nesting & DYNTICK_TASK_NEST_MASK) {
|
|
|
+ rdtp->dynticks_idle_nesting += DYNTICK_TASK_NEST_VALUE;
|
|
|
+ WARN_ON_ONCE(rdtp->dynticks_idle_nesting <= 0);
|
|
|
+ return; /* Already non-idle. */
|
|
|
+ } else {
|
|
|
+ rdtp->dynticks_idle_nesting = DYNTICK_TASK_EXIT_IDLE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Record end of idle period. */
|
|
|
+ smp_mb__before_atomic_inc();
|
|
|
+ atomic_inc(&rdtp->dynticks_idle);
|
|
|
+ smp_mb__after_atomic_inc();
|
|
|
+ WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks_idle) & 0x1));
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Initialize dynticks sysidle state for CPUs coming online.
|
|
|
*/
|
|
@@ -2387,6 +2458,14 @@ static void rcu_sysidle_init_percpu_data(struct rcu_dynticks *rdtp)
|
|
|
|
|
|
#else /* #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */
|
|
|
|
|
|
+static void rcu_sysidle_enter(struct rcu_dynticks *rdtp, int irq)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+static void rcu_sysidle_exit(struct rcu_dynticks *rdtp, int irq)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
static void rcu_sysidle_init_percpu_data(struct rcu_dynticks *rdtp)
|
|
|
{
|
|
|
}
|