mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-08-09 06:14:34 +02:00
Uwe Kleine-König reported this build breakage caused by a recent commit
which provides arch specific kcpustat_field_idle()/kcpustat_field_iowait()
functions:
ERROR: modpost: "arch_kcpustat_field_idle" [drivers/leds/trigger/ledtrig-activity.ko] undefined!
ERROR: modpost: "arch_kcpustat_field_iowait" [drivers/leds/trigger/ledtrig-activity.ko] undefined!
Fix this by adding the missing EXPORT_SYMBOL_GPL().
Fixes: 670e057744 ("s390/idle: Provide arch specific kcpustat_field_idle()/kcpustat_field_iowait()")
Reported-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Closes: https://lore.kernel.org/r/ajKsG0JP6qTssQBX@monoceros
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Tested-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
160 lines
3.8 KiB
C
160 lines
3.8 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Idle functions for s390.
|
|
*
|
|
* Copyright IBM Corp. 2014
|
|
*
|
|
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/kernel_stat.h>
|
|
#include <linux/sched/stat.h>
|
|
#include <linux/notifier.h>
|
|
#include <linux/init.h>
|
|
#include <linux/cpu.h>
|
|
#include <linux/export.h>
|
|
#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>
|
|
|
|
DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
|
|
|
|
static __always_inline void __account_idle_time_irq(void)
|
|
{
|
|
struct s390_idle_data *idle = this_cpu_ptr(&s390_idle);
|
|
unsigned long idle_time;
|
|
|
|
idle_time = idle->clock_idle_exit.tod - idle->clock_idle_enter.tod;
|
|
account_idle_time(cputime_to_nsecs(idle_time));
|
|
}
|
|
|
|
static __always_inline void __account_idle_time_setup(void)
|
|
{
|
|
struct s390_idle_data *idle = this_cpu_ptr(&s390_idle);
|
|
|
|
store_tod_clock_ext(&idle->clock_idle_enter);
|
|
idle->timer_idle_enter = get_cpu_timer();
|
|
idle->clock_idle_exit = idle->clock_idle_enter;
|
|
}
|
|
|
|
#ifdef CONFIG_NO_HZ_COMMON
|
|
|
|
static u64 arch_cpu_in_idle_time(int cpu)
|
|
{
|
|
struct s390_idle_data *idle = &per_cpu(s390_idle, cpu);
|
|
union tod_clock now;
|
|
u64 idle_time;
|
|
|
|
if (!idle->in_idle)
|
|
return 0;
|
|
store_tod_clock_ext(&now);
|
|
if (tod_after(idle->clock_idle_exit.tod, idle->clock_idle_enter.tod))
|
|
idle_time = idle->clock_idle_exit.tod - idle->clock_idle_enter.tod;
|
|
else
|
|
idle_time = now.tod - idle->clock_idle_enter.tod;
|
|
return cputime_to_nsecs(idle_time);
|
|
}
|
|
|
|
static u64 arch_cpu_idle_time(int cpu, enum cpu_usage_stat idx, bool compute_delta)
|
|
{
|
|
struct kernel_cpustat *kc = &kcpustat_cpu(cpu);
|
|
u64 *cpustat = kc->cpustat;
|
|
unsigned int seq;
|
|
u64 idle_time;
|
|
|
|
/*
|
|
* The open coded seqcount writer in entry.S relies on the
|
|
* raw counting mechanism without any writer protection.
|
|
*/
|
|
typecheck(typeof(kc->idle_sleeptime_seq), seqcount_t);
|
|
do {
|
|
seq = read_seqcount_begin(&kc->idle_sleeptime_seq);
|
|
idle_time = cpustat[idx];
|
|
if (compute_delta)
|
|
idle_time += arch_cpu_in_idle_time(cpu);
|
|
} while (read_seqcount_retry(&kc->idle_sleeptime_seq, seq));
|
|
return idle_time;
|
|
}
|
|
|
|
u64 arch_kcpustat_field_idle(int cpu)
|
|
{
|
|
return arch_cpu_idle_time(cpu, CPUTIME_IDLE, !nr_iowait_cpu(cpu));
|
|
}
|
|
EXPORT_SYMBOL_GPL(arch_kcpustat_field_idle);
|
|
|
|
u64 arch_kcpustat_field_iowait(int cpu)
|
|
{
|
|
return arch_cpu_idle_time(cpu, CPUTIME_IOWAIT, nr_iowait_cpu(cpu));
|
|
}
|
|
EXPORT_SYMBOL_GPL(arch_kcpustat_field_iowait);
|
|
|
|
void account_idle_time_irq(void)
|
|
{
|
|
struct s390_idle_data *idle = this_cpu_ptr(&s390_idle);
|
|
struct kernel_cpustat *kc = kcpustat_this_cpu;
|
|
|
|
write_seqcount_begin(&kc->idle_sleeptime_seq);
|
|
idle->in_idle = false;
|
|
__account_idle_time_irq();
|
|
write_seqcount_end(&kc->idle_sleeptime_seq);
|
|
}
|
|
|
|
static __always_inline void account_idle_time_setup(void)
|
|
{
|
|
struct s390_idle_data *idle = this_cpu_ptr(&s390_idle);
|
|
struct kernel_cpustat *kc = kcpustat_this_cpu;
|
|
|
|
raw_write_seqcount_begin(&kc->idle_sleeptime_seq);
|
|
idle->in_idle = true;
|
|
__account_idle_time_setup();
|
|
raw_write_seqcount_end(&kc->idle_sleeptime_seq);
|
|
}
|
|
|
|
#else /* CONFIG_NO_HZ_COMMON */
|
|
|
|
void account_idle_time_irq(void)
|
|
{
|
|
__account_idle_time_irq();
|
|
}
|
|
|
|
static __always_inline void account_idle_time_setup(void)
|
|
{
|
|
__account_idle_time_setup();
|
|
}
|
|
|
|
#endif /* CONFIG_NO_HZ_COMMON */
|
|
|
|
void noinstr arch_cpu_idle(void)
|
|
{
|
|
struct s390_idle_data *idle = this_cpu_ptr(&s390_idle);
|
|
unsigned long psw_mask;
|
|
|
|
/* Wait for external, I/O or machine check interrupt. */
|
|
psw_mask = PSW_KERNEL_BITS | PSW_MASK_WAIT |
|
|
PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK;
|
|
clear_cpu_flag(CIF_NOHZ_DELAY);
|
|
set_cpu_flag(CIF_ENABLED_WAIT);
|
|
if (smp_cpu_mtid)
|
|
stcctm(MT_DIAG, smp_cpu_mtid, (u64 *)&idle->mt_cycles_enter);
|
|
account_idle_time_setup();
|
|
bpon();
|
|
__load_psw_mask(psw_mask);
|
|
}
|
|
|
|
void arch_cpu_idle_enter(void)
|
|
{
|
|
}
|
|
|
|
void arch_cpu_idle_exit(void)
|
|
{
|
|
}
|
|
|
|
void __noreturn arch_cpu_idle_dead(void)
|
|
{
|
|
cpu_die();
|
|
}
|