Commit 39adff5f authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

* 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (23 commits)
  time, s390: Get rid of compile warning
  dw_apb_timer: constify clocksource name
  time: Cleanup old CONFIG_GENERIC_TIME references that snuck in
  time: Change jiffies_to_clock_t() argument type to unsigned long
  alarmtimers: Fix error handling
  clocksource: Make watchdog reset lockless
  posix-cpu-timers: Cure SMP accounting oddities
  s390: Use direct ktime path for s390 clockevent device
  clockevents: Add direct ktime programming function
  clockevents: Make minimum delay adjustments configurable
  nohz: Remove "Switched to NOHz mode" debugging messages
  proc: Consider NO_HZ when printing idle and iowait times
  nohz: Make idle/iowait counter update conditional
  nohz: Fix update_ts_time_stat idle accounting
  cputime: Clean up cputime_to_usecs and usecs_to_cputime macros
  alarmtimers: Rework RTC device selection using class interface
  alarmtimers: Add try_to_cancel functionality
  alarmtimers: Add more refined alarm state tracking
  alarmtimers: Remove period from alarm structure
  alarmtimers: Remove interval cap limit hack
  ...
parents 8a4a8918 e35f95b3
...@@ -346,7 +346,6 @@ config ARCH_GEMINI ...@@ -346,7 +346,6 @@ config ARCH_GEMINI
config ARCH_PRIMA2 config ARCH_PRIMA2
bool "CSR SiRFSoC PRIMA2 ARM Cortex A9 Platform" bool "CSR SiRFSoC PRIMA2 ARM Cortex A9 Platform"
select CPU_V7 select CPU_V7
select GENERIC_TIME
select NO_IOPORT select NO_IOPORT
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select CLKDEV_LOOKUP select CLKDEV_LOOKUP
...@@ -520,7 +519,6 @@ config ARCH_LPC32XX ...@@ -520,7 +519,6 @@ config ARCH_LPC32XX
select ARM_AMBA select ARM_AMBA
select USB_ARCH_HAS_OHCI select USB_ARCH_HAS_OHCI
select CLKDEV_LOOKUP select CLKDEV_LOOKUP
select GENERIC_TIME
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
help help
Support for the NXP LPC32XX family of processors Support for the NXP LPC32XX family of processors
...@@ -599,7 +597,6 @@ config ARCH_TEGRA ...@@ -599,7 +597,6 @@ config ARCH_TEGRA
bool "NVIDIA Tegra" bool "NVIDIA Tegra"
select CLKDEV_LOOKUP select CLKDEV_LOOKUP
select CLKSRC_MMIO select CLKSRC_MMIO
select GENERIC_TIME
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select GENERIC_GPIO select GENERIC_GPIO
select HAVE_CLK select HAVE_CLK
...@@ -914,7 +911,6 @@ config ARCH_VT8500 ...@@ -914,7 +911,6 @@ config ARCH_VT8500
config ARCH_ZYNQ config ARCH_ZYNQ
bool "Xilinx Zynq ARM Cortex A9 Platform" bool "Xilinx Zynq ARM Cortex A9 Platform"
select CPU_V7 select CPU_V7
select GENERIC_TIME
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select CLKDEV_LOOKUP select CLKDEV_LOOKUP
select ARM_GIC select ARM_GIC
......
...@@ -47,9 +47,6 @@ config GENERIC_CMOS_UPDATE ...@@ -47,9 +47,6 @@ config GENERIC_CMOS_UPDATE
config GENERIC_HWEIGHT config GENERIC_HWEIGHT
def_bool y def_bool y
config GENERIC_TIME
def_bool y
config GENERIC_CLOCKEVENTS config GENERIC_CLOCKEVENTS
def_bool y def_bool y
......
...@@ -109,10 +109,14 @@ static void fixup_clock_comparator(unsigned long long delta) ...@@ -109,10 +109,14 @@ static void fixup_clock_comparator(unsigned long long delta)
set_clock_comparator(S390_lowcore.clock_comparator); set_clock_comparator(S390_lowcore.clock_comparator);
} }
static int s390_next_event(unsigned long delta, static int s390_next_ktime(ktime_t expires,
struct clock_event_device *evt) struct clock_event_device *evt)
{ {
S390_lowcore.clock_comparator = get_clock() + delta; u64 nsecs;
nsecs = ktime_to_ns(ktime_sub(expires, ktime_get_monotonic_offset()));
do_div(nsecs, 125);
S390_lowcore.clock_comparator = TOD_UNIX_EPOCH + (nsecs << 9);
set_clock_comparator(S390_lowcore.clock_comparator); set_clock_comparator(S390_lowcore.clock_comparator);
return 0; return 0;
} }
...@@ -137,14 +141,15 @@ void init_cpu_timer(void) ...@@ -137,14 +141,15 @@ void init_cpu_timer(void)
cpu = smp_processor_id(); cpu = smp_processor_id();
cd = &per_cpu(comparators, cpu); cd = &per_cpu(comparators, cpu);
cd->name = "comparator"; cd->name = "comparator";
cd->features = CLOCK_EVT_FEAT_ONESHOT; cd->features = CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_KTIME;
cd->mult = 16777; cd->mult = 16777;
cd->shift = 12; cd->shift = 12;
cd->min_delta_ns = 1; cd->min_delta_ns = 1;
cd->max_delta_ns = LONG_MAX; cd->max_delta_ns = LONG_MAX;
cd->rating = 400; cd->rating = 400;
cd->cpumask = cpumask_of(cpu); cd->cpumask = cpumask_of(cpu);
cd->set_next_event = s390_next_event; cd->set_next_ktime = s390_next_ktime;
cd->set_mode = s390_set_mode; cd->set_mode = s390_set_mode;
clockevents_register_device(cd); clockevents_register_device(cd);
......
...@@ -46,9 +46,6 @@ config NEED_PER_CPU_PAGE_FIRST_CHUNK ...@@ -46,9 +46,6 @@ config NEED_PER_CPU_PAGE_FIRST_CHUNK
config SYS_SUPPORTS_HUGETLBFS config SYS_SUPPORTS_HUGETLBFS
def_bool y def_bool y
config GENERIC_TIME
def_bool y
config GENERIC_CLOCKEVENTS config GENERIC_CLOCKEVENTS
def_bool y def_bool y
......
...@@ -11,7 +11,6 @@ CONFIG_HAVE_ARCH_ALLOC_REMAP=y ...@@ -11,7 +11,6 @@ CONFIG_HAVE_ARCH_ALLOC_REMAP=y
CONFIG_HAVE_SETUP_PER_CPU_AREA=y CONFIG_HAVE_SETUP_PER_CPU_AREA=y
CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
CONFIG_SYS_SUPPORTS_HUGETLBFS=y CONFIG_SYS_SUPPORTS_HUGETLBFS=y
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_DEFAULT_MIGRATION_COST=10000000 CONFIG_DEFAULT_MIGRATION_COST=10000000
......
...@@ -11,7 +11,6 @@ CONFIG_HAVE_ARCH_ALLOC_REMAP=y ...@@ -11,7 +11,6 @@ CONFIG_HAVE_ARCH_ALLOC_REMAP=y
CONFIG_HAVE_SETUP_PER_CPU_AREA=y CONFIG_HAVE_SETUP_PER_CPU_AREA=y
CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
CONFIG_SYS_SUPPORTS_HUGETLBFS=y CONFIG_SYS_SUPPORTS_HUGETLBFS=y
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_DEFAULT_MIGRATION_COST=10000000 CONFIG_DEFAULT_MIGRATION_COST=10000000
......
...@@ -13,7 +13,6 @@ CONFIG_LOCKDEP_SUPPORT=y ...@@ -13,7 +13,6 @@ CONFIG_LOCKDEP_SUPPORT=y
# CONFIG_STACKTRACE_SUPPORT is not set # CONFIG_STACKTRACE_SUPPORT is not set
CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_BUG=y CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_IRQ_RELEASE_METHOD=y CONFIG_IRQ_RELEASE_METHOD=y
CONFIG_HZ=100 CONFIG_HZ=100
......
...@@ -68,6 +68,7 @@ config X86 ...@@ -68,6 +68,7 @@ config X86
select GENERIC_IRQ_PROBE select GENERIC_IRQ_PROBE
select GENERIC_PENDING_IRQ if SMP select GENERIC_PENDING_IRQ if SMP
select GENERIC_IRQ_SHOW select GENERIC_IRQ_SHOW
select GENERIC_CLOCKEVENTS_MIN_ADJUST
select IRQ_FORCED_THREADING select IRQ_FORCED_THREADING
select USE_GENERIC_SMP_HELPERS if SMP select USE_GENERIC_SMP_HELPERS if SMP
select HAVE_BPF_JIT if (X86_64 && NET) select HAVE_BPF_JIT if (X86_64 && NET)
......
...@@ -15,7 +15,6 @@ CONFIG_GENERIC_GPIO=y ...@@ -15,7 +15,6 @@ CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_HAS_ILOG2_U64 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_NO_IOPORT=y CONFIG_NO_IOPORT=y
CONFIG_HZ=100 CONFIG_HZ=100
CONFIG_GENERIC_TIME=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
CONFIG_CONSTRUCTORS=y CONFIG_CONSTRUCTORS=y
......
...@@ -15,7 +15,6 @@ CONFIG_GENERIC_GPIO=y ...@@ -15,7 +15,6 @@ CONFIG_GENERIC_GPIO=y
# CONFIG_ARCH_HAS_ILOG2_U64 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_NO_IOPORT=y CONFIG_NO_IOPORT=y
CONFIG_HZ=100 CONFIG_HZ=100
CONFIG_GENERIC_TIME=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
# #
......
...@@ -348,7 +348,7 @@ static void apbt_restart_clocksource(struct clocksource *cs) ...@@ -348,7 +348,7 @@ static void apbt_restart_clocksource(struct clocksource *cs)
* dw_apb_clocksource_register() as the next step. * dw_apb_clocksource_register() as the next step.
*/ */
struct dw_apb_clocksource * struct dw_apb_clocksource *
dw_apb_clocksource_init(unsigned rating, char *name, void __iomem *base, dw_apb_clocksource_init(unsigned rating, const char *name, void __iomem *base,
unsigned long freq) unsigned long freq)
{ {
struct dw_apb_clocksource *dw_cs = kzalloc(sizeof(*dw_cs), GFP_KERNEL); struct dw_apb_clocksource *dw_cs = kzalloc(sizeof(*dw_cs), GFP_KERNEL);
......
...@@ -120,10 +120,12 @@ static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu, ...@@ -120,10 +120,12 @@ static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu,
static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
{ {
u64 idle_time = get_cpu_idle_time_us(cpu, wall); u64 idle_time = get_cpu_idle_time_us(cpu, NULL);
if (idle_time == -1ULL) if (idle_time == -1ULL)
return get_cpu_idle_time_jiffy(cpu, wall); return get_cpu_idle_time_jiffy(cpu, wall);
else
idle_time += get_cpu_iowait_time_us(cpu, wall);
return idle_time; return idle_time;
} }
......
...@@ -144,10 +144,12 @@ static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu, ...@@ -144,10 +144,12 @@ static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu,
static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
{ {
u64 idle_time = get_cpu_idle_time_us(cpu, wall); u64 idle_time = get_cpu_idle_time_us(cpu, NULL);
if (idle_time == -1ULL) if (idle_time == -1ULL)
return get_cpu_idle_time_jiffy(cpu, wall); return get_cpu_idle_time_jiffy(cpu, wall);
else
idle_time += get_cpu_iowait_time_us(cpu, wall);
return idle_time; return idle_time;
} }
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/time.h> #include <linux/time.h>
#include <linux/irqnr.h> #include <linux/irqnr.h>
#include <asm/cputime.h> #include <asm/cputime.h>
#include <linux/tick.h>
#ifndef arch_irq_stat_cpu #ifndef arch_irq_stat_cpu
#define arch_irq_stat_cpu(cpu) 0 #define arch_irq_stat_cpu(cpu) 0
...@@ -21,6 +22,35 @@ ...@@ -21,6 +22,35 @@
#define arch_idle_time(cpu) 0 #define arch_idle_time(cpu) 0
#endif #endif
static cputime64_t get_idle_time(int cpu)
{
u64 idle_time = get_cpu_idle_time_us(cpu, NULL);
cputime64_t idle;
if (idle_time == -1ULL) {
/* !NO_HZ so we can rely on cpustat.idle */
idle = kstat_cpu(cpu).cpustat.idle;
idle = cputime64_add(idle, arch_idle_time(cpu));
} else
idle = usecs_to_cputime(idle_time);
return idle;
}
static cputime64_t get_iowait_time(int cpu)
{
u64 iowait_time = get_cpu_iowait_time_us(cpu, NULL);
cputime64_t iowait;
if (iowait_time == -1ULL)
/* !NO_HZ so we can rely on cpustat.iowait */
iowait = kstat_cpu(cpu).cpustat.iowait;
else
iowait = usecs_to_cputime(iowait_time);
return iowait;
}
static int show_stat(struct seq_file *p, void *v) static int show_stat(struct seq_file *p, void *v)
{ {
int i, j; int i, j;
...@@ -42,9 +72,8 @@ static int show_stat(struct seq_file *p, void *v) ...@@ -42,9 +72,8 @@ static int show_stat(struct seq_file *p, void *v)
user = cputime64_add(user, kstat_cpu(i).cpustat.user); user = cputime64_add(user, kstat_cpu(i).cpustat.user);
nice = cputime64_add(nice, kstat_cpu(i).cpustat.nice); nice = cputime64_add(nice, kstat_cpu(i).cpustat.nice);
system = cputime64_add(system, kstat_cpu(i).cpustat.system); system = cputime64_add(system, kstat_cpu(i).cpustat.system);
idle = cputime64_add(idle, kstat_cpu(i).cpustat.idle); idle = cputime64_add(idle, get_idle_time(i));
idle = cputime64_add(idle, arch_idle_time(i)); iowait = cputime64_add(iowait, get_iowait_time(i));
iowait = cputime64_add(iowait, kstat_cpu(i).cpustat.iowait);
irq = cputime64_add(irq, kstat_cpu(i).cpustat.irq); irq = cputime64_add(irq, kstat_cpu(i).cpustat.irq);
softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq); softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal); steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
...@@ -76,14 +105,12 @@ static int show_stat(struct seq_file *p, void *v) ...@@ -76,14 +105,12 @@ static int show_stat(struct seq_file *p, void *v)
(unsigned long long)cputime64_to_clock_t(guest), (unsigned long long)cputime64_to_clock_t(guest),
(unsigned long long)cputime64_to_clock_t(guest_nice)); (unsigned long long)cputime64_to_clock_t(guest_nice));
for_each_online_cpu(i) { for_each_online_cpu(i) {
/* Copy values here to work around gcc-2.95.3, gcc-2.96 */ /* Copy values here to work around gcc-2.95.3, gcc-2.96 */
user = kstat_cpu(i).cpustat.user; user = kstat_cpu(i).cpustat.user;
nice = kstat_cpu(i).cpustat.nice; nice = kstat_cpu(i).cpustat.nice;
system = kstat_cpu(i).cpustat.system; system = kstat_cpu(i).cpustat.system;
idle = kstat_cpu(i).cpustat.idle; idle = get_idle_time(i);
idle = cputime64_add(idle, arch_idle_time(i)); iowait = get_iowait_time(i);
iowait = kstat_cpu(i).cpustat.iowait;
irq = kstat_cpu(i).cpustat.irq; irq = kstat_cpu(i).cpustat.irq;
softirq = kstat_cpu(i).cpustat.softirq; softirq = kstat_cpu(i).cpustat.softirq;
steal = kstat_cpu(i).cpustat.steal; steal = kstat_cpu(i).cpustat.steal;
......
...@@ -38,8 +38,8 @@ typedef u64 cputime64_t; ...@@ -38,8 +38,8 @@ typedef u64 cputime64_t;
/* /*
* Convert cputime to microseconds and back. * Convert cputime to microseconds and back.
*/ */
#define cputime_to_usecs(__ct) jiffies_to_usecs(__ct); #define cputime_to_usecs(__ct) jiffies_to_usecs(__ct)
#define usecs_to_cputime(__msecs) usecs_to_jiffies(__msecs); #define usecs_to_cputime(__msecs) usecs_to_jiffies(__msecs)
/* /*
* Convert cputime to seconds and back. * Convert cputime to seconds and back.
......
...@@ -13,6 +13,16 @@ enum alarmtimer_type { ...@@ -13,6 +13,16 @@ enum alarmtimer_type {
ALARM_NUMTYPE, ALARM_NUMTYPE,
}; };
enum alarmtimer_restart {
ALARMTIMER_NORESTART,
ALARMTIMER_RESTART,
};
#define ALARMTIMER_STATE_INACTIVE 0x00
#define ALARMTIMER_STATE_ENQUEUED 0x01
#define ALARMTIMER_STATE_CALLBACK 0x02
/** /**
* struct alarm - Alarm timer structure * struct alarm - Alarm timer structure
* @node: timerqueue node for adding to the event list this value * @node: timerqueue node for adding to the event list this value
...@@ -25,16 +35,45 @@ enum alarmtimer_type { ...@@ -25,16 +35,45 @@ enum alarmtimer_type {
*/ */
struct alarm { struct alarm {
struct timerqueue_node node; struct timerqueue_node node;
ktime_t period; enum alarmtimer_restart (*function)(struct alarm *, ktime_t now);
void (*function)(struct alarm *);
enum alarmtimer_type type; enum alarmtimer_type type;
bool enabled; int state;
void *data; void *data;
}; };
void alarm_init(struct alarm *alarm, enum alarmtimer_type type, void alarm_init(struct alarm *alarm, enum alarmtimer_type type,
void (*function)(struct alarm *)); enum alarmtimer_restart (*function)(struct alarm *, ktime_t));
void alarm_start(struct alarm *alarm, ktime_t start, ktime_t period); void alarm_start(struct alarm *alarm, ktime_t start);
void alarm_cancel(struct alarm *alarm); int alarm_try_to_cancel(struct alarm *alarm);
int alarm_cancel(struct alarm *alarm);
u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval);
/*
* A alarmtimer is active, when it is enqueued into timerqueue or the
* callback function is running.
*/
static inline int alarmtimer_active(const struct alarm *timer)
{
return timer->state != ALARMTIMER_STATE_INACTIVE;
}
/*
* Helper function to check, whether the timer is on one of the queues
*/
static inline int alarmtimer_is_queued(struct alarm *timer)
{
return timer->state & ALARMTIMER_STATE_ENQUEUED;
}
/*
* Helper function to check, whether the timer is running the callback
* function
*/
static inline int alarmtimer_callback_running(struct alarm *timer)
{
return timer->state & ALARMTIMER_STATE_CALLBACK;
}
#endif #endif
...@@ -45,20 +45,22 @@ enum clock_event_nofitiers { ...@@ -45,20 +45,22 @@ enum clock_event_nofitiers {
*/ */
#define CLOCK_EVT_FEAT_PERIODIC 0x000001 #define CLOCK_EVT_FEAT_PERIODIC 0x000001
#define CLOCK_EVT_FEAT_ONESHOT 0x000002 #define CLOCK_EVT_FEAT_ONESHOT 0x000002
#define CLOCK_EVT_FEAT_KTIME 0x000004
/* /*
* x86(64) specific misfeatures: * x86(64) specific misfeatures:
* *
* - Clockevent source stops in C3 State and needs broadcast support. * - Clockevent source stops in C3 State and needs broadcast support.
* - Local APIC timer is used as a dummy device. * - Local APIC timer is used as a dummy device.
*/ */
#define CLOCK_EVT_FEAT_C3STOP 0x000004 #define CLOCK_EVT_FEAT_C3STOP 0x000008
#define CLOCK_EVT_FEAT_DUMMY 0x000008 #define CLOCK_EVT_FEAT_DUMMY 0x000010
/** /**
* struct clock_event_device - clock event device descriptor * struct clock_event_device - clock event device descriptor
* @event_handler: Assigned by the framework to be called by the low * @event_handler: Assigned by the framework to be called by the low
* level handler of the event source * level handler of the event source
* @set_next_event: set next event function * @set_next_event: set next event function using a clocksource delta
* @set_next_ktime: set next event function using a direct ktime value
* @next_event: local storage for the next event in oneshot mode * @next_event: local storage for the next event in oneshot mode
* @max_delta_ns: maximum delta value in ns * @max_delta_ns: maximum delta value in ns
* @min_delta_ns: minimum delta value in ns * @min_delta_ns: minimum delta value in ns
...@@ -81,6 +83,8 @@ struct clock_event_device { ...@@ -81,6 +83,8 @@ struct clock_event_device {
void (*event_handler)(struct clock_event_device *); void (*event_handler)(struct clock_event_device *);
int (*set_next_event)(unsigned long evt, int (*set_next_event)(unsigned long evt,
struct clock_event_device *); struct clock_event_device *);
int (*set_next_ktime)(ktime_t expires,
struct clock_event_device *);
ktime_t next_event; ktime_t next_event;
u64 max_delta_ns; u64 max_delta_ns;
u64 min_delta_ns; u64 min_delta_ns;
...@@ -140,7 +144,7 @@ extern void clockevents_set_mode(struct clock_event_device *dev, ...@@ -140,7 +144,7 @@ extern void clockevents_set_mode(struct clock_event_device *dev,
enum clock_event_mode mode); enum clock_event_mode mode);
extern int clockevents_register_notifier(struct notifier_block *nb); extern int clockevents_register_notifier(struct notifier_block *nb);
extern int clockevents_program_event(struct clock_event_device *dev, extern int clockevents_program_event(struct clock_event_device *dev,
ktime_t expires, ktime_t now); ktime_t expires, bool force);
extern void clockevents_handle_noop(struct clock_event_device *dev); extern void clockevents_handle_noop(struct clock_event_device *dev);
......
...@@ -46,7 +46,7 @@ struct dw_apb_clock_event_device * ...@@ -46,7 +46,7 @@ struct dw_apb_clock_event_device *
dw_apb_clockevent_init(int cpu, const char *name, unsigned rating, dw_apb_clockevent_init(int cpu, const char *name, unsigned rating,
void __iomem *base, int irq, unsigned long freq); void __iomem *base, int irq, unsigned long freq);
struct dw_apb_clocksource * struct dw_apb_clocksource *
dw_apb_clocksource_init(unsigned rating, char *name, void __iomem *base, dw_apb_clocksource_init(unsigned rating, const char *name, void __iomem *base,
unsigned long freq); unsigned long freq);
void dw_apb_clocksource_register(struct dw_apb_clocksource *dw_cs); void dw_apb_clocksource_register(struct dw_apb_clocksource *dw_cs);
void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs); void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs);
......
...@@ -303,7 +303,7 @@ extern void jiffies_to_timespec(const unsigned long jiffies, ...@@ -303,7 +303,7 @@ extern void jiffies_to_timespec(const unsigned long jiffies,
extern unsigned long timeval_to_jiffies(const struct timeval *value); extern unsigned long timeval_to_jiffies(const struct timeval *value);
extern void jiffies_to_timeval(const unsigned long jiffies, extern void jiffies_to_timeval(const unsigned long jiffies,
struct timeval *value); struct timeval *value);
extern clock_t jiffies_to_clock_t(long x); extern clock_t jiffies_to_clock_t(unsigned long x);
extern unsigned long clock_t_to_jiffies(unsigned long x); extern unsigned long clock_t_to_jiffies(unsigned long x);
extern u64 jiffies_64_to_clock_t(u64 x); extern u64 jiffies_64_to_clock_t(u64 x);
extern u64 nsec_to_clock_t(u64 x); extern u64 nsec_to_clock_t(u64 x);
......
...@@ -81,7 +81,10 @@ struct k_itimer { ...@@ -81,7 +81,10 @@ struct k_itimer {
unsigned long incr; unsigned long incr;
unsigned long expires; unsigned long expires;
} mmtimer; } mmtimer;
struct {
struct alarm alarmtimer; struct alarm alarmtimer;
ktime_t interval;
} alarm;
struct rcu_head rcu; struct rcu_head rcu;
} it; } it;
}; };
......
...@@ -575,7 +575,7 @@ EXPORT_SYMBOL(jiffies_to_timeval); ...@@ -575,7 +575,7 @@ EXPORT_SYMBOL(jiffies_to_timeval);
/* /*
* Convert jiffies/jiffies_64 to clock_t and back. * Convert jiffies/jiffies_64 to clock_t and back.
*/ */
clock_t jiffies_to_clock_t(long x) clock_t jiffies_to_clock_t(unsigned long x)
{ {
#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0 #if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
# if HZ < USER_HZ # if HZ < USER_HZ
......
...@@ -27,3 +27,5 @@ config GENERIC_CLOCKEVENTS_BUILD ...@@ -27,3 +27,5 @@ config GENERIC_CLOCKEVENTS_BUILD
default y default y
depends on GENERIC_CLOCKEVENTS || GENERIC_CLOCKEVENTS_MIGR depends on GENERIC_CLOCKEVENTS || GENERIC_CLOCKEVENTS_MIGR
config GENERIC_CLOCKEVENTS_MIN_ADJUST
bool
This diff is collapsed.
...@@ -94,42 +94,143 @@ void clockevents_shutdown(struct clock_event_device *dev) ...@@ -94,42 +94,143 @@ void clockevents_shutdown(struct clock_event_device *dev)
dev->next_event.tv64 = KTIME_MAX; dev->next_event.tv64 = KTIME_MAX;
} }
#ifdef CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST
/* Limit min_delta to a jiffie */
#define MIN_DELTA_LIMIT (NSEC_PER_SEC / HZ)
/**
* clockevents_increase_min_delta - raise minimum delta of a clock event device
* @dev: device to increase the minimum delta
*
* Returns 0 on success, -ETIME when the minimum delta reached the limit.
*/
static int clockevents_increase_min_delta(struct clock_event_device *dev)
{
/* Nothing to do if we already reached the limit */
if (dev->min_delta_ns >= MIN_DELTA_LIMIT) {
printk(KERN_WARNING "CE: Reprogramming failure. Giving up\n");
dev->next_event.tv64 = KTIME_MAX;
return -ETIME;
}
if (dev->min_delta_ns < 5000)
dev->min_delta_ns = 5000;
else
dev->min_delta_ns += dev->min_delta_ns >> 1;
if (dev->min_delta_ns > MIN_DELTA_LIMIT)
dev->min_delta_ns = MIN_DELTA_LIMIT;
printk(KERN_WARNING "CE: %s increased min_delta_ns to %llu nsec\n",
dev->name ? dev->name : "?",
(unsigned long long) dev->min_delta_ns);
return 0;
}
/**
* clockevents_program_min_delta - Set clock event device to the minimum delay.
* @dev: device to program
*
* Returns 0 on success, -ETIME when the retry loop failed.
*/
static int clockevents_program_min_delta(struct clock_event_device *dev)
{
unsigned long long clc;
int64_t delta;
int i;
for (i = 0;;) {
delta = dev->min_delta_ns;
dev->next_event = ktime_add_ns(ktime_get(), delta);
if (dev->mode == CLOCK_EVT_MODE_SHUTDOWN)
return 0;
dev->retries++;
clc = ((unsigned long long) delta * dev->mult) >> dev->shift;
if (dev->set_next_event((unsigned long) clc, dev) == 0)
return 0;
if (++i > 2) {
/*
* We tried 3 times to program the device with the
* given min_delta_ns. Try to increase the minimum
* delta, if that fails as well get out of here.
*/
if (clockevents_increase_min_delta(dev))
return -ETIME;
i = 0;
}
}
}
#else /* CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST */
/**
* clockevents_program_min_delta - Set clock event device to the minimum delay.
* @dev: device to program
*
* Returns 0 on success, -ETIME when the retry loop failed.
*/
static int clockevents_program_min_delta(struct clock_event_device *dev)
{
unsigned long long clc;
int64_t delta;
delta = dev->min_delta_ns;
dev->next_event = ktime_add_ns(ktime_get(), delta);
if (dev->mode == CLOCK_EVT_MODE_SHUTDOWN)
return 0;
dev->retries++;
clc = ((unsigned long long) delta * dev->mult) >> dev->shift;
return dev->set_next_event((unsigned long) clc, dev);
}
#endif /* CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST */
/** /**
* clockevents_program_event - Reprogram the clock event device. * clockevents_program_event - Reprogram the clock event device.
* @dev: device to program
* @expires: absolute expiry time (monotonic clock) * @expires: absolute expiry time (monotonic clock)
* @force: program minimum delay if expires can not be set
* *
* Returns 0 on success, -ETIME when the event is in the past. * Returns 0 on success, -ETIME when the event is in the past.
*/ */
int clockevents_program_event(struct clock_event_device *dev, ktime_t expires, int clockevents_program_event(struct clock_event_device *dev, ktime_t expires,
ktime_t now) bool force)
{ {
unsigned long long clc; unsigned long long clc;
int64_t delta; int64_t delta;
int rc;
if (unlikely(expires.tv64 < 0)) { if (unlikely(expires.tv64 < 0)) {
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
return -ETIME; return -ETIME;
} }
delta = ktime_to_ns(ktime_sub(expires, now));
if (delta <= 0)
return -ETIME;
dev->next_event = expires; dev->next_event = expires;
if (dev->mode == CLOCK_EVT_MODE_SHUTDOWN) if (dev->mode == CLOCK_EVT_MODE_SHUTDOWN)
return 0; return 0;
if (delta > dev->max_delta_ns) /* Shortcut for clockevent devices that can deal with ktime. */
delta = dev->max_delta_ns; if (dev->features & CLOCK_EVT_FEAT_KTIME)
if (delta < dev->min_delta_ns) return dev->set_next_ktime(expires, dev);
delta = dev->min_delta_ns;
clc = delta * dev->mult; delta = ktime_to_ns(ktime_sub(expires, ktime_get()));
clc >>= dev->shift; if (delta <= 0)
return force ? clockevents_program_min_delta(dev) : -ETIME;
return dev->set_next_event((unsigned long) clc, dev); delta = min(delta, (int64_t) dev->max_delta_ns);
delta = max(delta, (int64_t) dev->min_delta_ns);
clc = ((unsigned long long) delta * dev->mult) >> dev->shift;
rc = dev->set_next_event((unsigned long) clc, dev);
return (rc && force) ? clockevents_program_min_delta(dev) : rc;
} }
/** /**
...@@ -258,7 +359,7 @@ int clockevents_update_freq(struct clock_event_device *dev, u32 freq) ...@@ -258,7 +359,7 @@ int clockevents_update_freq(struct clock_event_device *dev, u32 freq)
if (dev->mode != CLOCK_EVT_MODE_ONESHOT) if (dev->mode != CLOCK_EVT_MODE_ONESHOT)
return 0; return 0;
return clockevents_program_event(dev, dev->next_event, ktime_get()); return clockevents_program_event(dev, dev->next_event, false);
} }
/* /*
......
...@@ -186,6 +186,7 @@ static struct timer_list watchdog_timer; ...@@ -186,6 +186,7 @@ static struct timer_list watchdog_timer;
static DECLARE_WORK(watchdog_work, clocksource_watchdog_work); static DECLARE_WORK(watchdog_work, clocksource_watchdog_work);
static DEFINE_SPINLOCK(watchdog_lock); static DEFINE_SPINLOCK(watchdog_lock);
static int watchdog_running; static int watchdog_running;
static atomic_t watchdog_reset_pending;
static int clocksource_watchdog_kthread(void *data); static int clocksource_watchdog_kthread(void *data);
static void __clocksource_change_rating(struct clocksource *cs, int rating); static void __clocksource_change_rating(struct clocksource *cs, int rating);
...@@ -247,12 +248,14 @@ static void clocksource_watchdog(unsigned long data) ...@@ -247,12 +248,14 @@ static void clocksource_watchdog(unsigned long data)
struct clocksource *cs; struct clocksource *cs;
cycle_t csnow, wdnow; cycle_t csnow, wdnow;
int64_t wd_nsec, cs_nsec; int64_t wd_nsec, cs_nsec;
int next_cpu; int next_cpu, reset_pending;
spin_lock(&watchdog_lock); spin_lock(&watchdog_lock);
if (!watchdog_running) if (!watchdog_running)
goto out; goto out;
reset_pending = atomic_read(&watchdog_reset_pending);
list_for_each_entry(cs, &watchdog_list, wd_list) { list_for_each_entry(cs, &watchdog_list, wd_list) {
/* Clocksource already marked unstable? */ /* Clocksource already marked unstable? */
...@@ -268,7 +271,8 @@ static void clocksource_watchdog(unsigned long data) ...@@ -268,7 +271,8 @@ static void clocksource_watchdog(unsigned long data)
local_irq_enable(); local_irq_enable();
/* Clocksource initialized ? */ /* Clocksource initialized ? */
if (!(cs->flags & CLOCK_SOURCE_WATCHDOG)) { if (!(cs->flags & CLOCK_SOURCE_WATCHDOG) ||
atomic_read(&watchdog_reset_pending)) {
cs->flags |= CLOCK_SOURCE_WATCHDOG; cs->flags |= CLOCK_SOURCE_WATCHDOG;
cs->wd_last = wdnow; cs->wd_last = wdnow;
cs->cs_last = csnow; cs->cs_last = csnow;
...@@ -283,8 +287,11 @@ static void clocksource_watchdog(unsigned long data) ...@@ -283,8 +287,11 @@ static void clocksource_watchdog(unsigned long data)
cs->cs_last = csnow; cs->cs_last = csnow;
cs->wd_last = wdnow; cs->wd_last = wdnow;
if (atomic_read(&watchdog_reset_pending))
continue;
/* Check the deviation from the watchdog clocksource. */ /* Check the deviation from the watchdog clocksource. */
if (abs(cs_nsec - wd_nsec) > WATCHDOG_THRESHOLD) { if ((abs(cs_nsec - wd_nsec) > WATCHDOG_THRESHOLD)) {
clocksource_unstable(cs, cs_nsec - wd_nsec); clocksource_unstable(cs, cs_nsec - wd_nsec);
continue; continue;
} }
...@@ -302,6 +309,13 @@ static void clocksource_watchdog(unsigned long data) ...@@ -302,6 +309,13 @@ static void clocksource_watchdog(unsigned long data)
} }
} }
/*
* We only clear the watchdog_reset_pending, when we did a
* full cycle through all clocksources.
*/
if (reset_pending)
atomic_dec(&watchdog_reset_pending);
/* /*
* Cycle through CPUs to check if the CPUs stay synchronized * Cycle through CPUs to check if the CPUs stay synchronized
* to each other. * to each other.
...@@ -344,23 +358,7 @@ static inline void clocksource_reset_watchdog(void) ...@@ -344,23 +358,7 @@ static inline void clocksource_reset_watchdog(void)
static void clocksource_resume_watchdog(void) static void clocksource_resume_watchdog(void)
{ {
unsigned long flags; atomic_inc(&watchdog_reset_pending);
/*
* We use trylock here to avoid a potential dead lock when
* kgdb calls this code after the kernel has been stopped with
* watchdog_lock held. When watchdog_lock is held we just
* return and accept, that the watchdog might trigger and mark
* the monitored clock source (usually TSC) unstable.
*
* This does not affect the other caller clocksource_resume()
* because at this point the kernel is UP, interrupts are
* disabled and nothing can hold watchdog_lock.
*/
if (!spin_trylock_irqsave(&watchdog_lock, flags))
return;
clocksource_reset_watchdog();
spin_unlock_irqrestore(&watchdog_lock, flags);
} }
static void clocksource_enqueue_watchdog(struct clocksource *cs) static void clocksource_enqueue_watchdog(struct clocksource *cs)
......
...@@ -194,7 +194,7 @@ static void tick_handle_periodic_broadcast(struct clock_event_device *dev) ...@@ -194,7 +194,7 @@ static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
for (next = dev->next_event; ;) { for (next = dev->next_event; ;) {
next = ktime_add(next, tick_period); next = ktime_add(next, tick_period);
if (!clockevents_program_event(dev, next, ktime_get())) if (!clockevents_program_event(dev, next, false))
return; return;
tick_do_periodic_broadcast(); tick_do_periodic_broadcast();
} }
...@@ -373,7 +373,7 @@ static int tick_broadcast_set_event(ktime_t expires, int force) ...@@ -373,7 +373,7 @@ static int tick_broadcast_set_event(ktime_t expires, int force)
{ {
struct clock_event_device *bc = tick_broadcast_device.evtdev; struct clock_event_device *bc = tick_broadcast_device.evtdev;
return tick_dev_program_event(bc, expires, force); return clockevents_program_event(bc, expires, force);
} }
int tick_resume_broadcast_oneshot(struct clock_event_device *bc) int tick_resume_broadcast_oneshot(struct clock_event_device *bc)
......
...@@ -94,7 +94,7 @@ void tick_handle_periodic(struct clock_event_device *dev) ...@@ -94,7 +94,7 @@ void tick_handle_periodic(struct clock_event_device *dev)
*/ */
next = ktime_add(dev->next_event, tick_period); next = ktime_add(dev->next_event, tick_period);
for (;;) { for (;;) {
if (!clockevents_program_event(dev, next, ktime_get())) if (!clockevents_program_event(dev, next, false))
return; return;
/* /*
* Have to be careful here. If we're in oneshot mode, * Have to be careful here. If we're in oneshot mode,
...@@ -137,7 +137,7 @@ void tick_setup_periodic(struct clock_event_device *dev, int broadcast) ...@@ -137,7 +137,7 @@ void tick_setup_periodic(struct clock_event_device *dev, int broadcast)
clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT); clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT);
for (;;) { for (;;) {
if (!clockevents_program_event(dev, next, ktime_get())) if (!clockevents_program_event(dev, next, false))
return; return;
next = ktime_add(next, tick_period); next = ktime_add(next, tick_period);
} }
......
...@@ -26,8 +26,6 @@ extern void clockevents_shutdown(struct clock_event_device *dev); ...@@ -26,8 +26,6 @@ extern void clockevents_shutdown(struct clock_event_device *dev);
extern void tick_setup_oneshot(struct clock_event_device *newdev, extern void tick_setup_oneshot(struct clock_event_device *newdev,
void (*handler)(struct clock_event_device *), void (*handler)(struct clock_event_device *),
ktime_t nextevt); ktime_t nextevt);
extern int tick_dev_program_event(struct clock_event_device *dev,
ktime_t expires, int force);
extern int tick_program_event(ktime_t expires, int force); extern int tick_program_event(ktime_t expires, int force);
extern void tick_oneshot_notify(void); extern void tick_oneshot_notify(void);
extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)); extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *));
......
...@@ -21,74 +21,6 @@ ...@@ -21,74 +21,6 @@
#include "tick-internal.h" #include "tick-internal.h"
/* Limit min_delta to a jiffie */
#define MIN_DELTA_LIMIT (NSEC_PER_SEC / HZ)
static int tick_increase_min_delta(struct clock_event_device *dev)
{
/* Nothing to do if we already reached the limit */
if (dev->min_delta_ns >= MIN_DELTA_LIMIT)
return -ETIME;
if (dev->min_delta_ns < 5000)
dev->min_delta_ns = 5000;
else
dev->min_delta_ns += dev->min_delta_ns >> 1;
if (dev->min_delta_ns > MIN_DELTA_LIMIT)
dev->min_delta_ns = MIN_DELTA_LIMIT;
printk(KERN_WARNING "CE: %s increased min_delta_ns to %llu nsec\n",
dev->name ? dev->name : "?",
(unsigned long long) dev->min_delta_ns);
return 0;
}
/**
* tick_program_event internal worker function
*/
int tick_dev_program_event(struct clock_event_device *dev, ktime_t expires,
int force)
{
ktime_t now = ktime_get();
int i;
for (i = 0;;) {
int ret = clockevents_program_event(dev, expires, now);
if (!ret || !force)
return ret;
dev->retries++;
/*
* We tried 3 times to program the device with the given
* min_delta_ns. If that's not working then we increase it
* and emit a warning.
*/
if (++i > 2) {
/* Increase the min. delta and try again */
if (tick_increase_min_delta(dev)) {
/*
* Get out of the loop if min_delta_ns
* hit the limit already. That's
* better than staying here forever.
*
* We clear next_event so we have a
* chance that the box survives.
*/
printk(KERN_WARNING
"CE: Reprogramming failure. Giving up\n");
dev->next_event.tv64 = KTIME_MAX;
return -ETIME;
}
i = 0;
}
now = ktime_get();
expires = ktime_add_ns(now, dev->min_delta_ns);
}
}
/** /**
* tick_program_event * tick_program_event
*/ */
...@@ -96,7 +28,7 @@ int tick_program_event(ktime_t expires, int force) ...@@ -96,7 +28,7 @@ int tick_program_event(ktime_t expires, int force)
{ {
struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev);
return tick_dev_program_event(dev, expires, force); return clockevents_program_event(dev, expires, force);
} }
/** /**
...@@ -104,11 +36,10 @@ int tick_program_event(ktime_t expires, int force) ...@@ -104,11 +36,10 @@ int tick_program_event(ktime_t expires, int force)
*/ */
void tick_resume_oneshot(void) void tick_resume_oneshot(void)
{ {
struct tick_device *td = &__get_cpu_var(tick_cpu_device); struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev);
struct clock_event_device *dev = td->evtdev;
clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT); clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT);
tick_program_event(ktime_get(), 1); clockevents_program_event(dev, ktime_get(), true);
} }
/** /**
...@@ -120,7 +51,7 @@ void tick_setup_oneshot(struct clock_event_device *newdev, ...@@ -120,7 +51,7 @@ void tick_setup_oneshot(struct clock_event_device *newdev,
{ {
newdev->event_handler = handler; newdev->event_handler = handler;
clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT); clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT);
tick_dev_program_event(newdev, next_event, 1); clockevents_program_event(newdev, next_event, true);
} }
/** /**
......
...@@ -158,9 +158,10 @@ update_ts_time_stats(int cpu, struct tick_sched *ts, ktime_t now, u64 *last_upda ...@@ -158,9 +158,10 @@ update_ts_time_stats(int cpu, struct tick_sched *ts, ktime_t now, u64 *last_upda
if (ts->idle_active) { if (ts->idle_active) {
delta = ktime_sub(now, ts->idle_entrytime); delta = ktime_sub(now, ts->idle_entrytime);
ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta);
if (nr_iowait_cpu(cpu) > 0) if (nr_iowait_cpu(cpu) > 0)
ts->iowait_sleeptime = ktime_add(ts->iowait_sleeptime, delta); ts->iowait_sleeptime = ktime_add(ts->iowait_sleeptime, delta);
else
ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta);
ts->idle_entrytime = now; ts->idle_entrytime = now;
} }
...@@ -196,11 +197,11 @@ static ktime_t tick_nohz_start_idle(int cpu, struct tick_sched *ts) ...@@ -196,11 +197,11 @@ static ktime_t tick_nohz_start_idle(int cpu, struct tick_sched *ts)
/** /**
* get_cpu_idle_time_us - get the total idle time of a cpu * get_cpu_idle_time_us - get the total idle time of a cpu
* @cpu: CPU number to query * @cpu: CPU number to query
* @last_update_time: variable to store update time in * @last_update_time: variable to store update time in. Do not update
* counters if NULL.
* *
* Return the cummulative idle time (since boot) for a given * Return the cummulative idle time (since boot) for a given
* CPU, in microseconds. The idle time returned includes * CPU, in microseconds.
* the iowait time (unlike what "top" and co report).
* *
* This time is measured via accounting rather than sampling, * This time is measured via accounting rather than sampling,
* and is as accurate as ktime_get() is. * and is as accurate as ktime_get() is.
...@@ -210,20 +211,35 @@ static ktime_t tick_nohz_start_idle(int cpu, struct tick_sched *ts) ...@@ -210,20 +211,35 @@ static ktime_t tick_nohz_start_idle(int cpu, struct tick_sched *ts)
u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time) u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time)
{ {
struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
ktime_t now, idle;
if (!tick_nohz_enabled) if (!tick_nohz_enabled)
return -1; return -1;
update_ts_time_stats(cpu, ts, ktime_get(), last_update_time); now = ktime_get();
if (last_update_time) {
update_ts_time_stats(cpu, ts, now, last_update_time);
idle = ts->idle_sleeptime;
} else {
if (ts->idle_active && !nr_iowait_cpu(cpu)) {
ktime_t delta = ktime_sub(now, ts->idle_entrytime);
idle = ktime_add(ts->idle_sleeptime, delta);
} else {
idle = ts->idle_sleeptime;
}
}
return ktime_to_us(idle);
return ktime_to_us(ts->idle_sleeptime);
} }
EXPORT_SYMBOL_GPL(get_cpu_idle_time_us); EXPORT_SYMBOL_GPL(get_cpu_idle_time_us);
/* /**
* get_cpu_iowait_time_us - get the total iowait time of a cpu * get_cpu_iowait_time_us - get the total iowait time of a cpu
* @cpu: CPU number to query * @cpu: CPU number to query
* @last_update_time: variable to store update time in * @last_update_time: variable to store update time in. Do not update
* counters if NULL.
* *
* Return the cummulative iowait time (since boot) for a given * Return the cummulative iowait time (since boot) for a given
* CPU, in microseconds. * CPU, in microseconds.
...@@ -236,13 +252,26 @@ EXPORT_SYMBOL_GPL(get_cpu_idle_time_us); ...@@ -236,13 +252,26 @@ EXPORT_SYMBOL_GPL(get_cpu_idle_time_us);
u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time) u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time)
{ {
struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
ktime_t now, iowait;
if (!tick_nohz_enabled) if (!tick_nohz_enabled)
return -1; return -1;
update_ts_time_stats(cpu, ts, ktime_get(), last_update_time); now = ktime_get();
if (last_update_time) {
update_ts_time_stats(cpu, ts, now, last_update_time);
iowait = ts->iowait_sleeptime;
} else {
if (ts->idle_active && nr_iowait_cpu(cpu) > 0) {
ktime_t delta = ktime_sub(now, ts->idle_entrytime);
iowait = ktime_add(ts->iowait_sleeptime, delta);
} else {
iowait = ts->iowait_sleeptime;
}
}
return ktime_to_us(ts->iowait_sleeptime); return ktime_to_us(iowait);
} }
EXPORT_SYMBOL_GPL(get_cpu_iowait_time_us); EXPORT_SYMBOL_GPL(get_cpu_iowait_time_us);
...@@ -634,8 +663,6 @@ static void tick_nohz_switch_to_nohz(void) ...@@ -634,8 +663,6 @@ static void tick_nohz_switch_to_nohz(void)
next = ktime_add(next, tick_period); next = ktime_add(next, tick_period);
} }
local_irq_enable(); local_irq_enable();
printk(KERN_INFO "Switched to NOHz mode on CPU #%d\n", smp_processor_id());
} }
/* /*
...@@ -787,10 +814,8 @@ void tick_setup_sched_timer(void) ...@@ -787,10 +814,8 @@ void tick_setup_sched_timer(void)
} }
#ifdef CONFIG_NO_HZ #ifdef CONFIG_NO_HZ
if (tick_nohz_enabled) { if (tick_nohz_enabled)
ts->nohz_mode = NOHZ_MODE_HIGHRES; ts->nohz_mode = NOHZ_MODE_HIGHRES;
printk(KERN_INFO "Switched to NOHz mode on CPU #%d\n", smp_processor_id());
}
#endif #endif
} }
#endif /* HIGH_RES_TIMERS */ #endif /* HIGH_RES_TIMERS */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment