summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMagnus Damm <damm@igel.co.jp>2009-04-28 08:17:54 +0000
committerPaul Mundt <lethal@linux-sh.org>2009-04-28 18:01:21 +0900
commit5b644c7a218702668d7b610994e7dcbc3d4705d3 (patch)
tree67418dc01db1e5abccbe5b526232eaf6811217e8
parentc2e0090c668fc99f5be65fd9907da781cb6a2ef5 (diff)
downloadlwn-5b644c7a218702668d7b610994e7dcbc3d4705d3.tar.gz
lwn-5b644c7a218702668d7b610994e7dcbc3d4705d3.zip
clocksource: improve sh_cmt clocksource overflow handling
This patch improves the sh_cmt clocksource handling. Currently the counter value is ignored in the case of overflow. With this patch the overflow flag is read before and after reading the counter, removing any counter value and overflow flag mismatch issues. Signed-off-by: Magnus Damm <damm@igel.co.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r--drivers/clocksource/sh_cmt.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index c24756489612..d607ac2d516b 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -111,16 +111,21 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_priv *p,
int *has_wrapped)
{
unsigned long v1, v2, v3;
+ int o1, o2;
+
+ o1 = sh_cmt_read(p, CMCSR) & p->overflow_bit;
/* Make sure the timer value is stable. Stolen from acpi_pm.c */
do {
+ o2 = o1;
v1 = sh_cmt_read(p, CMCNT);
v2 = sh_cmt_read(p, CMCNT);
v3 = sh_cmt_read(p, CMCNT);
- } while (unlikely((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
- || (v3 > v1 && v3 < v2)));
+ o1 = sh_cmt_read(p, CMCSR) & p->overflow_bit;
+ } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
+ || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
- *has_wrapped = sh_cmt_read(p, CMCSR) & p->overflow_bit;
+ *has_wrapped = o1;
return v2;
}
@@ -394,7 +399,7 @@ static cycle_t sh_cmt_clocksource_read(struct clocksource *cs)
raw = sh_cmt_get_counter(p, &has_wrapped);
if (unlikely(has_wrapped))
- raw = p->match_value;
+ raw += p->match_value;
spin_unlock_irqrestore(&p->lock, flags);
return value + raw;