]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
s390/time: Prepare to stop elapsing in dynticks-idle
authorFrederic Weisbecker <frederic@kernel.org>
Fri, 8 May 2026 13:16:38 +0000 (15:16 +0200)
committerThomas Gleixner <tglx@kernel.org>
Tue, 2 Jun 2026 19:27:25 +0000 (21:27 +0200)
Currently the tick subsystem stores the idle cputime accounting in private
fields, allowing cohabitation with architecture idle vtime accounting. The
former is fetched on online CPUs, the latter on offline CPUs.

For consolidation purposes, architecture vtime accounting will continue to
account the cputime but will make a break when the idle tick is
stopped. The dyntick cputime accounting will then be relayed by the tick
subsystem so that the idle cputime is still seen advancing coherently even
when the tick isn't there to flush the idle vtime.

Prepare for that and introduce three new APIs which will be used in
subsequent patches:

  - vtime_dynticks_start() is deemed to be called when idle enters in
    dyntick mode. The idle cputime that elapsed so far is accumulated
    and accounted. Also idle time accounting is ignored.

  - vtime_dynticks_stop() is deemed to be called when idle exits from
    dyntick mode. The vtime entry clocks are fast-forward to current time
    so that idle accounting restarts elapsing from now. Also idle time
    accounting is resumed.

  - vtime_reset() is deemed to be called from dynticks idle IRQ entry to
    fast-forward the clock to current time so that the IRQ time is still
    accounted by vtime while nohz cputime is paused.

Also accumulated vtime won't be flushed from dyntick-idle ticks to avoid
accounting twice the idle cputime, along with nohz accounting.

Co-developed-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Tested-by: Shrikanth Hegde <sshegde@linux.ibm.com>
Link: https://patch.msgid.link/20260508131647.43868-7-frederic@kernel.org
arch/s390/include/asm/idle.h
arch/s390/kernel/idle.c
arch/s390/kernel/vtime.c

index 32536ee34aa09896d07575ddb81944e349654beb..e4ad09a22400b4d5c80d3efa2f1e4005af5e53e1 100644 (file)
@@ -8,10 +8,12 @@
 #ifndef _S390_IDLE_H
 #define _S390_IDLE_H
 
+#include <linux/percpu-defs.h>
 #include <linux/types.h>
 #include <linux/device.h>
 
 struct s390_idle_data {
+       bool          idle_dyntick;
        unsigned long idle_count;
        unsigned long idle_time;
        unsigned long clock_idle_enter;
index 1f1b06b6b4efaa0492e4ba7333a01f6d6295edd4..4685d7c5bc5189e04691222c78c425537448bbe3 100644 (file)
@@ -31,7 +31,10 @@ void account_idle_time_irq(void)
        /* Account time spent with enabled wait psw loaded as idle time. */
        __atomic64_add(idle_time, &idle->idle_time);
        __atomic64_add_const(1, &idle->idle_count);
-       account_idle_time(cputime_to_nsecs(idle_time));
+
+       /* Dyntick idle time accounted by nohz/scheduler */
+       if (!idle->idle_dyntick)
+               account_idle_time(cputime_to_nsecs(idle_time));
 }
 
 void noinstr arch_cpu_idle(void)
index bf48744d09123233a38b533c167d4010c73f0b0d..d1102a6f80bda28738f1d41df7443dff8f5e1c07 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/vtimer.h>
 #include <asm/vtime.h>
 #include <asm/cpu_mf.h>
+#include <asm/idle.h>
 #include <asm/smp.h>
 
 #include "entry.h"
@@ -110,6 +111,16 @@ static void account_system_index_scaled(struct task_struct *p, u64 cputime,
        account_system_index_time(p, cputime_to_nsecs(cputime), index);
 }
 
+static inline void vtime_reset_last_update(struct lowcore *lc)
+{
+       asm volatile(
+               "       stpt    %0\n"   /* Store current cpu timer value */
+               "       stckf   %1"     /* Store current tod clock value */
+               : "=Q" (lc->last_update_timer),
+                 "=Q" (lc->last_update_clock)
+               : : "cc");
+}
+
 /*
  * Update process times based on virtual cpu times stored by entry.S
  * to the lowcore fields user_timer, system_timer & steal_clock.
@@ -121,17 +132,16 @@ static int do_account_vtime(struct task_struct *tsk)
 
        timer = lc->last_update_timer;
        clock = lc->last_update_clock;
-       asm volatile(
-               "       stpt    %0\n"   /* Store current cpu timer value */
-               "       stckf   %1"     /* Store current tod clock value */
-               : "=Q" (lc->last_update_timer),
-                 "=Q" (lc->last_update_clock)
-               : : "cc");
+
+       vtime_reset_last_update(lc);
+
        clock = lc->last_update_clock - clock;
        timer -= lc->last_update_timer;
 
        if (hardirq_count())
                lc->hardirq_timer += timer;
+       else if (in_serving_softirq())
+               lc->softirq_timer += timer;
        else
                lc->system_timer += timer;
 
@@ -231,13 +241,62 @@ EXPORT_SYMBOL_GPL(vtime_account_kernel);
 
 void vtime_account_softirq(struct task_struct *tsk)
 {
-       get_lowcore()->softirq_timer += vtime_delta();
+       if (!__this_cpu_read(s390_idle.idle_dyntick))
+               get_lowcore()->softirq_timer += vtime_delta();
+       else
+               vtime_flush(tsk);
 }
 
 void vtime_account_hardirq(struct task_struct *tsk)
 {
-       get_lowcore()->hardirq_timer += vtime_delta();
+       if (!__this_cpu_read(s390_idle.idle_dyntick)) {
+               get_lowcore()->hardirq_timer += vtime_delta();
+       } else {
+               /*
+                * In dynticks mode, the idle cputime is accounted by the nohz
+                * subsystem. Therefore the s390 timer/clocks are reset on IRQ
+                * entry and steal time must be accounted now.
+                */
+               vtime_flush(tsk);
+       }
+}
+
+#ifdef CONFIG_NO_HZ_COMMON
+/**
+ * vtime_reset - Fast forward vtime entry clocks
+ *
+ * Called from dynticks idle IRQ entry to fast-forward the clocks to current time
+ * so that the IRQ time is still accounted by vtime while nohz cputime is paused.
+ */
+void vtime_reset(void)
+{
+       vtime_reset_last_update(get_lowcore());
+}
+
+/**
+ * vtime_dyntick_start - Inform vtime about entry to idle-dynticks
+ *
+ * Called when idle enters in dyntick mode. The idle cputime that elapsed so far
+ * is flushed and the tick subsystem takes over the idle cputime accounting.
+ */
+void vtime_dyntick_start(void)
+{
+       __this_cpu_write(s390_idle.idle_dyntick, true);
+       vtime_flush(current);
+}
+
+/**
+ * vtime_dyntick_stop - Inform vtime about exit from idle-dynticks
+ *
+ * Called when idle exits from dyntick mode. The vtime entry clocks are
+ * fast-forward to current time and idle accounting resumes.
+ */
+void vtime_dyntick_stop(void)
+{
+       vtime_reset_last_update(get_lowcore());
+       __this_cpu_write(s390_idle.idle_dyntick, false);
 }
+#endif /* CONFIG_NO_HZ_COMMON */
 
 /*
  * Sorted add to a list. List is linear searched until first bigger