ARM: 7486/1: sched_clock: update epoch_cyc on resume
Many clocks that are used to provide sched_clock will reset during suspend. If read_sched_clock returns 0 after suspend, sched_clock will appear to jump forward. This patch resets cd.epoch_cyc to the current value of read_sched_clock during resume, which causes sched_clock() just after suspend to return the same value as sched_clock() just before suspend. In addition, during the window where epoch_ns has been updated before suspend, but epoch_cyc has not been updated after suspend, it is unknown whether the clock has reset or not, and sched_clock() could return a bogus value. Add a suspended flag, and return the pre-suspend epoch_ns value during this period. The new behavior is triggered by calling setup_sched_clock_needs_suspend instead of setup_sched_clock. Signed-off-by: Colin Cross <ccross@android.com> Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
committed by
Russell King
parent
f1898f6be9
commit
237ec6f2e5
@@ -10,5 +10,7 @@
|
|||||||
|
|
||||||
extern void sched_clock_postinit(void);
|
extern void sched_clock_postinit(void);
|
||||||
extern void setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate);
|
extern void setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate);
|
||||||
|
extern void setup_sched_clock_needs_suspend(u32 (*read)(void), int bits,
|
||||||
|
unsigned long rate);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -21,6 +21,8 @@ struct clock_data {
|
|||||||
u32 epoch_cyc_copy;
|
u32 epoch_cyc_copy;
|
||||||
u32 mult;
|
u32 mult;
|
||||||
u32 shift;
|
u32 shift;
|
||||||
|
bool suspended;
|
||||||
|
bool needs_suspend;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void sched_clock_poll(unsigned long wrap_ticks);
|
static void sched_clock_poll(unsigned long wrap_ticks);
|
||||||
@@ -49,6 +51,9 @@ static unsigned long long cyc_to_sched_clock(u32 cyc, u32 mask)
|
|||||||
u64 epoch_ns;
|
u64 epoch_ns;
|
||||||
u32 epoch_cyc;
|
u32 epoch_cyc;
|
||||||
|
|
||||||
|
if (cd.suspended)
|
||||||
|
return cd.epoch_ns;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load the epoch_cyc and epoch_ns atomically. We do this by
|
* Load the epoch_cyc and epoch_ns atomically. We do this by
|
||||||
* ensuring that we always write epoch_cyc, epoch_ns and
|
* ensuring that we always write epoch_cyc, epoch_ns and
|
||||||
@@ -98,6 +103,13 @@ static void sched_clock_poll(unsigned long wrap_ticks)
|
|||||||
update_sched_clock();
|
update_sched_clock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __init setup_sched_clock_needs_suspend(u32 (*read)(void), int bits,
|
||||||
|
unsigned long rate)
|
||||||
|
{
|
||||||
|
setup_sched_clock(read, bits, rate);
|
||||||
|
cd.needs_suspend = true;
|
||||||
|
}
|
||||||
|
|
||||||
void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
|
void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
|
||||||
{
|
{
|
||||||
unsigned long r, w;
|
unsigned long r, w;
|
||||||
@@ -169,11 +181,23 @@ void __init sched_clock_postinit(void)
|
|||||||
static int sched_clock_suspend(void)
|
static int sched_clock_suspend(void)
|
||||||
{
|
{
|
||||||
sched_clock_poll(sched_clock_timer.data);
|
sched_clock_poll(sched_clock_timer.data);
|
||||||
|
if (cd.needs_suspend)
|
||||||
|
cd.suspended = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sched_clock_resume(void)
|
||||||
|
{
|
||||||
|
if (cd.needs_suspend) {
|
||||||
|
cd.epoch_cyc = read_sched_clock();
|
||||||
|
cd.epoch_cyc_copy = cd.epoch_cyc;
|
||||||
|
cd.suspended = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static struct syscore_ops sched_clock_ops = {
|
static struct syscore_ops sched_clock_ops = {
|
||||||
.suspend = sched_clock_suspend,
|
.suspend = sched_clock_suspend,
|
||||||
|
.resume = sched_clock_resume,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init sched_clock_syscore_init(void)
|
static int __init sched_clock_syscore_init(void)
|
||||||
|
Reference in New Issue
Block a user