Commit 05c58a66 authored by Vasily Gorbik's avatar Vasily Gorbik
Browse files

Merge branch 'idle-vtime-fixes-cleanups' into fixes



Pull a small idle/vtime series with two cputime accounting fixes plus
related cleanups and minor improvements.

* idle-vtime-fixes-cleanups:
  s390/idle: Remove psw_idle() prototype
  s390/vtime: Use lockdep_assert_irqs_disabled() instead of BUG_ON()
  s390/vtime: Use __this_cpu_read() / get rid of READ_ONCE()
  s390/irq/idle: Remove psw bits early
  s390/idle: Inline update_timer_idle()
  s390/idle: Slightly optimize idle time accounting
  s390/idle: Add comment for non obvious code
  s390/vtime: Fix virtual timer forwarding
  s390/idle: Fix cpu idle exit cpu time accounting

Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parents 6de23f81 acbc0437
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -19,9 +19,9 @@ struct s390_idle_data {
	unsigned long mt_cycles_enter[8];
};

DECLARE_PER_CPU(struct s390_idle_data, s390_idle);

extern struct device_attribute dev_attr_idle_count;
extern struct device_attribute dev_attr_idle_time_us;

void psw_idle(struct s390_idle_data *data, unsigned long psw_mask);

#endif /* _S390_IDLE_H */
+34 −0
Original line number Diff line number Diff line
@@ -2,6 +2,12 @@
#ifndef _S390_VTIME_H
#define _S390_VTIME_H

#include <asm/lowcore.h>
#include <asm/cpu_mf.h>
#include <asm/idle.h>

DECLARE_PER_CPU(u64, mt_cycles[8]);

static inline void update_timer_sys(void)
{
	struct lowcore *lc = get_lowcore();
@@ -20,4 +26,32 @@ static inline void update_timer_mcck(void)
	lc->last_update_timer = lc->mcck_enter_timer;
}

static inline void update_timer_idle(void)
{
	struct s390_idle_data *idle = this_cpu_ptr(&s390_idle);
	struct lowcore *lc = get_lowcore();
	u64 cycles_new[8];
	int i, mtid;

	mtid = smp_cpu_mtid;
	if (mtid) {
		stcctm(MT_DIAG, mtid, cycles_new);
		for (i = 0; i < mtid; i++)
			__this_cpu_add(mt_cycles[i], cycles_new[i] - idle->mt_cycles_enter[i]);
	}
	/*
	 * This is a bit subtle: Forward last_update_clock so it excludes idle
	 * time. For correct steal time calculation in do_account_vtime() add
	 * passed wall time before idle_enter to steal_timer:
	 * During the passed wall time before idle_enter CPU time may have
	 * been accounted to system, hardirq, softirq, etc. lowcore fields.
	 * The accounted CPU times will be subtracted again from steal_timer
	 * when accumulated steal time is calculated in do_account_vtime().
	 */
	lc->steal_timer += idle->clock_idle_enter - lc->last_update_clock;
	lc->last_update_clock = lc->int_clock;
	lc->system_timer += lc->last_update_timer - idle->timer_idle_enter;
	lc->last_update_timer = lc->sys_enter_timer;
}

#endif /* _S390_VTIME_H */
+0 −2
Original line number Diff line number Diff line
@@ -56,8 +56,6 @@ long sys_s390_pci_mmio_write(unsigned long, const void __user *, size_t);
long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t);
long sys_s390_sthyi(unsigned long function_code, void __user *buffer, u64 __user *return_code, unsigned long flags);

DECLARE_PER_CPU(u64, mt_cycles[8]);

unsigned long stack_alloc(void);
void stack_free(unsigned long stack);

+5 −20
Original line number Diff line number Diff line
@@ -15,37 +15,22 @@
#include <trace/events/power.h>
#include <asm/cpu_mf.h>
#include <asm/cputime.h>
#include <asm/idle.h>
#include <asm/nmi.h>
#include <asm/smp.h>
#include "entry.h"

static DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
DEFINE_PER_CPU(struct s390_idle_data, s390_idle);

void account_idle_time_irq(void)
{
	struct s390_idle_data *idle = this_cpu_ptr(&s390_idle);
	struct lowcore *lc = get_lowcore();
	unsigned long idle_time;
	u64 cycles_new[8];
	int i;

	if (smp_cpu_mtid) {
		stcctm(MT_DIAG, smp_cpu_mtid, cycles_new);
		for (i = 0; i < smp_cpu_mtid; i++)
			this_cpu_add(mt_cycles[i], cycles_new[i] - idle->mt_cycles_enter[i]);
	}

	idle_time = lc->int_clock - idle->clock_idle_enter;

	lc->steal_timer += idle->clock_idle_enter - lc->last_update_clock;
	lc->last_update_clock = lc->int_clock;

	lc->system_timer += lc->last_update_timer - idle->timer_idle_enter;
	lc->last_update_timer = lc->sys_enter_timer;
	idle_time = get_lowcore()->int_clock - idle->clock_idle_enter;

	/* Account time spent with enabled wait psw loaded as idle time. */
	WRITE_ONCE(idle->idle_time, READ_ONCE(idle->idle_time) + idle_time);
	WRITE_ONCE(idle->idle_count, READ_ONCE(idle->idle_count) + 1);
	__atomic64_add(idle_time, &idle->idle_time);
	__atomic64_add_const(1, &idle->idle_count);
	account_idle_time(cputime_to_nsecs(idle_time));
}

+12 −8
Original line number Diff line number Diff line
@@ -146,6 +146,12 @@ void noinstr do_io_irq(struct pt_regs *regs)
	struct pt_regs *old_regs = set_irq_regs(regs);
	bool from_idle;

	from_idle = test_and_clear_cpu_flag(CIF_ENABLED_WAIT);
	if (from_idle) {
		update_timer_idle();
		regs->psw.mask &= ~(PSW_MASK_EXT | PSW_MASK_IO | PSW_MASK_WAIT);
	}

	irq_enter_rcu();

	if (user_mode(regs)) {
@@ -154,7 +160,6 @@ void noinstr do_io_irq(struct pt_regs *regs)
			current->thread.last_break = regs->last_break;
	}

	from_idle = test_and_clear_cpu_flag(CIF_ENABLED_WAIT);
	if (from_idle)
		account_idle_time_irq();

@@ -171,9 +176,6 @@ void noinstr do_io_irq(struct pt_regs *regs)

	set_irq_regs(old_regs);
	irqentry_exit(regs, state);

	if (from_idle)
		regs->psw.mask &= ~(PSW_MASK_EXT | PSW_MASK_IO | PSW_MASK_WAIT);
}

void noinstr do_ext_irq(struct pt_regs *regs)
@@ -182,6 +184,12 @@ void noinstr do_ext_irq(struct pt_regs *regs)
	struct pt_regs *old_regs = set_irq_regs(regs);
	bool from_idle;

	from_idle = test_and_clear_cpu_flag(CIF_ENABLED_WAIT);
	if (from_idle) {
		update_timer_idle();
		regs->psw.mask &= ~(PSW_MASK_EXT | PSW_MASK_IO | PSW_MASK_WAIT);
	}

	irq_enter_rcu();

	if (user_mode(regs)) {
@@ -194,7 +202,6 @@ void noinstr do_ext_irq(struct pt_regs *regs)
	regs->int_parm = get_lowcore()->ext_params;
	regs->int_parm_long = get_lowcore()->ext_params2;

	from_idle = test_and_clear_cpu_flag(CIF_ENABLED_WAIT);
	if (from_idle)
		account_idle_time_irq();

@@ -203,9 +210,6 @@ void noinstr do_ext_irq(struct pt_regs *regs)
	irq_exit_rcu();
	set_irq_regs(old_regs);
	irqentry_exit(regs, state);

	if (from_idle)
		regs->psw.mask &= ~(PSW_MASK_EXT | PSW_MASK_IO | PSW_MASK_WAIT);
}

static void show_msi_interrupt(struct seq_file *p, int irq)
Loading